Files
UnrealEngine/Engine/Source/Runtime/ImageWrapper/Private/Formats/IcnsImageWrapper.cpp
2025-05-18 13:04:45 +08:00

235 lines
6.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Formats/IcnsImageWrapper.h"
#include "ImageWrapperPrivate.h"
#include "ImageCoreUtils.h"
/* FIcnsImageWrapper structors
*****************************************************************************/
FIcnsImageWrapper::FIcnsImageWrapper()
: FImageWrapperBase()
{ }
/* FImageWrapper interface
*****************************************************************************/
bool FIcnsImageWrapper::SetCompressed(const void* InCompressedData, int64 InCompressedSize)
{
#if PLATFORM_MAC
if ( ! FImageWrapperBase::SetCompressed(InCompressedData, InCompressedSize) )
{
return false;
}
// set image properties from header
// always read as BGRA8 regardless of the image format in the file :
Format = ERGBFormat::BGRA;
BitDepth = 8;
Width = Height = 0;
// get width and height from image data :
{
SCOPED_AUTORELEASE_POOL;
NSData* ImageData = [NSData dataWithBytesNoCopy:CompressedData.GetData() length:CompressedData.Num() freeWhenDone:NO];
NSImage* Image = [[NSImage alloc] initWithData:ImageData];
if (Image)
{
Width = Image.size.width;
Height = Image.size.height;
// TODO: We have decoded the image this far we might want to store this data/object so ::Uncompress doesn't have to do it again
[Image release];
}
}
if ( Width == 0 )
{
return false;
}
if ( ! FImageCoreUtils::IsImageImportPossible(Width,Height) )
{
SetError(TEXT("Image dimensions are not possible to import"));
return false;
}
return true;
#else
return false;
#endif
}
// CanSetRawFormat returns true if SetRaw will accept this format
bool FIcnsImageWrapper::CanSetRawFormat(const ERGBFormat InFormat, const int32 InBitDepth) const
{
//checkf(false, TEXT("ICNS compression not supported"));
return false;
}
// returns InFormat if supported, else maps to something supported
ERawImageFormat::Type FIcnsImageWrapper::GetSupportedRawFormat(const ERawImageFormat::Type InFormat) const
{
//checkf(false, TEXT("ICNS compression not supported"));
return ERawImageFormat::BGRA8;
}
bool FIcnsImageWrapper::SetRaw(const void* InRawData, int64 InRawSize, const int32 InWidth, const int32 InHeight, const ERGBFormat InFormat, const int32 InBitDepth, const int32 InBytesPerRow)
{
// Only support tightly packed
check(InBytesPerRow == 0);
#if PLATFORM_MAC
// CanSetRawFormat returns false, this will always fail, remove?
return FImageWrapperBase::SetRaw(InRawData, InRawSize, InWidth, InHeight, InFormat, InBitDepth, InBytesPerRow);
#else
return false;
#endif
}
void FIcnsImageWrapper::Compress(int32 Quality)
{
checkf(false, TEXT("ICNS compression not supported"));
}
void FIcnsImageWrapper::Uncompress(const ERGBFormat InFormat, const int32 InBitDepth)
{
#if PLATFORM_MAC
SCOPED_AUTORELEASE_POOL;
NSData* ImageData = [NSData dataWithBytesNoCopy:CompressedData.GetData() length:CompressedData.Num() freeWhenDone:NO];
NSImage* Image = [[NSImage alloc] initWithData:ImageData];
if (Image)
{
NSBitmapImageRep* Bitmap = [NSBitmapImageRep imageRepWithData:[Image TIFFRepresentation]];
if (Bitmap)
{
check(InFormat == ERGBFormat::BGRA || InFormat == ERGBFormat::RGBA);
check(InBitDepth == 8);
Format = InFormat;
BitDepth = InBitDepth;
Width = [Bitmap pixelsWide];
Height = [Bitmap pixelsHigh];
// InBitDepth of 8 above must be the per channel value not the image pixel bit depth
const size_t SrcBitDepth = (Bitmap.bitsPerPixel / Bitmap.samplesPerPixel);
check(SrcBitDepth == 8);
// Non compressed total image size
const size_t SrcImageSize = Width * Height * Bitmap.samplesPerPixel;
// 4 channel output BGRA or RGBA
const size_t DestBytesPerPixel = 4;
const size_t DestImageSize = Width * Height * DestBytesPerPixel;
RawData.Empty();
RawData.AddUninitialized(DestImageSize);
if(SrcImageSize == DestImageSize && Bitmap.bytesPerPlane == SrcImageSize && Bitmap.numberOfPlanes == 1)
{
// Exact match direct copy
FMemory::Memcpy(RawData.GetData(), [Bitmap bitmapData], DestImageSize);
}
else if(Bitmap.bytesPerPlane == SrcImageSize && Bitmap.numberOfPlanes == 1)
{
// Manual copy, could be 24bit or gray scale. Be conservative about the number of availble source channels during the copy
uint8* SrcData = [Bitmap bitmapData];
#define SRC_IMAGE_INDEX ((Y * Bitmap.bytesPerRow) + (X * Bitmap.samplesPerPixel))
#define DEST_IMAGE_INDEX ((Y * (DestBytesPerPixel * Width)) + (X * DestBytesPerPixel))
for(size_t Y = 0;Y < Height;++Y)
{
if(Bitmap.samplesPerPixel >= 4)
{
for(size_t X = 0;X < Width;++X)
{
size_t SrcIndex = SRC_IMAGE_INDEX;
size_t DestIndex = DEST_IMAGE_INDEX;
RawData[DestIndex + 0] = SrcData[SrcIndex + 0];
RawData[DestIndex + 1] = SrcData[SrcIndex + 1];
RawData[DestIndex + 2] = SrcData[SrcIndex + 2];
RawData[DestIndex + 3] = SrcData[SrcIndex + 3];
}
}
else if(Bitmap.samplesPerPixel == 3)
{
for(size_t X = 0;X < Width;++X)
{
size_t SrcIndex = SRC_IMAGE_INDEX;
size_t DestIndex = DEST_IMAGE_INDEX;
RawData[DestIndex + 0] = SrcData[SrcIndex + 0];
RawData[DestIndex + 1] = SrcData[SrcIndex + 1];
RawData[DestIndex + 2] = SrcData[SrcIndex + 2];
RawData[DestIndex + 3] = 0xff;
}
}
else if(Bitmap.samplesPerPixel == 2)
{
// Placeholder - not sure if this is correct
for(size_t X = 0;X < Width;++X)
{
size_t SrcIndex = SRC_IMAGE_INDEX;
size_t DestIndex = DEST_IMAGE_INDEX;
RawData[DestIndex + 0] = SrcData[SrcIndex + 0];
RawData[DestIndex + 1] = SrcData[SrcIndex + 1];
RawData[DestIndex + 2] = 0x00;
RawData[DestIndex + 3] = 0xff;
}
}
else if(Bitmap.samplesPerPixel == 1)
{
// Assume gray scale - copy single input channel to all color output channels
for(size_t X = 0;X < Width;++X)
{
size_t SrcIndex = SRC_IMAGE_INDEX;
size_t DestIndex = DEST_IMAGE_INDEX;
RawData[DestIndex + 0] = SrcData[SrcIndex + 0];
RawData[DestIndex + 1] = SrcData[SrcIndex + 0];
RawData[DestIndex + 2] = SrcData[SrcIndex + 0];
RawData[DestIndex + 3] = 0xff;
}
}
}
#undef SRC_IMAGE_INDEX
#undef DEST_IMAGE_INDEX
}
else
{
// Unhandled case (e.g. Planar)
SetError(TEXT("FIcnsImageWrapper: Cannot uncompress, unsupported format."));
RawData.Reset();
}
if ((size_t)RawData.Num() >= DestImageSize && Format == ERGBFormat::BGRA)
{
for (size_t Index = 0; Index < DestImageSize; Index += 4)
{
uint8 Byte = RawData[Index];
RawData[Index] = RawData[Index + 2];
RawData[Index + 2] = Byte;
}
}
}
[Image release];
}
#else
checkf(false, TEXT("ICNS uncompressing not supported on this platform"));
#endif
}