You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
206 lines
6.0 KiB
206 lines
6.0 KiB
unit ImagingQuartz;
|
|
|
|
{$I ImagingOptions.inc}
|
|
|
|
{$IFNDEF MACOSX}
|
|
{$FATAL 'Mac OSX only'}
|
|
{$ENDIF}
|
|
|
|
interface
|
|
|
|
uses
|
|
Types, SysUtils, Classes, ImagingTypes, Imaging, ImagingUtility,
|
|
{$IFDEF DCC}
|
|
Macapi.CocoaTypes, Macapi.CoreFoundation, Macapi.CoreGraphics, Macapi.QuartzCore, Macapi.ImageIO
|
|
{$ELSE}
|
|
CGBase, CGShading, CGColor, CGColorSpace, CGContext, CGBitmapContext, CGImageSource,
|
|
CGImageDestination, CGDataProvider, CGDataConsumer, CFDictionary, CGAffineTransforms, CGPath
|
|
{$ENDIF};
|
|
|
|
type
|
|
TQuartzImageHandler = class
|
|
private
|
|
FDefaultColorSpace: CGColorSpaceRef;
|
|
function FindImageFormat(ImgRef: CGImageRef): TImageFormat;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
function LoadImage(Stream: TCustomMemoryStream; var Images: TDynImageDataArray; OnlyFirstImage: Boolean): Boolean;
|
|
end;
|
|
|
|
implementation
|
|
|
|
function CGRectFromRect(const R: TRect): CGRect;
|
|
begin
|
|
Result.origin.x := R.Left;
|
|
Result.origin.Y := R.Top;
|
|
Result.size.Width := R.Right - R.Left;
|
|
Result.size.Height := R.Bottom - R.Top;
|
|
end;
|
|
|
|
{ TMacImageHandler }
|
|
|
|
constructor TQuartzImageHandler.Create;
|
|
begin
|
|
FDefaultColorSpace := CGColorSpaceCreateDeviceRGB;
|
|
end;
|
|
|
|
destructor TQuartzImageHandler.Destroy;
|
|
begin
|
|
CGColorSpaceRelease(FDefaultColorSpace);
|
|
inherited;
|
|
end;
|
|
|
|
function TQuartzImageHandler.FindImageFormat(ImgRef: CGImageRef): TImageFormat;
|
|
var
|
|
ColorSpaceRef: CGColorSpaceRef;
|
|
ColorModel: CGColorSpaceModel;
|
|
AlphaInfo: CGImageAlphaInfo;
|
|
BitmapInfo: CGBitmapInfo;
|
|
BitsPerPixel, Components, BitsPerComponent: Integer;
|
|
|
|
isMask: integer;
|
|
intent: CGColorRenderingIntent;
|
|
begin
|
|
Result := ifUnknown;
|
|
AlphaInfo := CGImageGetAlphaInfo(ImgRef);
|
|
BitmapInfo := CGImageGetBitmapInfo(ImgRef);
|
|
ColorSpaceRef := CGImageGetColorSpace(ImgRef);
|
|
|
|
intent := CGImageGetRenderingIntent(ImgRef);
|
|
isMask := CGImageIsMask(ImgRef);
|
|
|
|
{
|
|
Also check BitmapInfo
|
|
kCGBitmapByteOrderDefault = NO
|
|
kCGBitmapByteOrder16Little = NO
|
|
kCGBitmapByteOrder32Little = NO
|
|
kCGBitmapByteOrder16Big = NO
|
|
kCGBitmapByteOrder32Big = NO
|
|
|
|
float formats
|
|
}
|
|
|
|
if ColorSpaceRef <> nil then
|
|
begin
|
|
try
|
|
BitsPerPixel := CGImageGetBitsPerPixel(ImgRef);
|
|
BitsPerComponent := CGImageGetBitsPerComponent(ImgRef);
|
|
ColorModel := CGColorSpaceGetModel(ColorSpaceRef);
|
|
Components := CGColorSpaceGetNumberOfComponents(ColorSpaceRef);
|
|
|
|
if (ColorModel = kCGColorSpaceModelMonochrome) and (Components = 1) then
|
|
begin
|
|
// Grayscale formats
|
|
if AlphaInfo = kCGImageAlphaFirst then
|
|
begin
|
|
if (BitsPerComponent = 8) and (BitsPerPixel = 16) then
|
|
Result := ifA8Gray8
|
|
else if (BitsPerComponent = 16) and (BitsPerPixel = 32) then
|
|
Result := ifA16Gray16;
|
|
end
|
|
else if AlphaInfo = kCGImageAlphaNone then
|
|
begin
|
|
if BitsPerPixel = 8 then
|
|
Result := ifGray8
|
|
else if BitsPerPixel = 16 then
|
|
Result := ifGray16;
|
|
end;
|
|
end
|
|
else if ColorModel = kCGColorSpaceModelRGB then
|
|
begin
|
|
// RGB
|
|
if (BitsPerPixel = 16) and (AlphaInfo = kCGImageAlphaNoneSkipFirst) then
|
|
begin
|
|
Result := ifX1R5G5B5;
|
|
end
|
|
else if AlphaInfo = kCGImageAlphaFirst then
|
|
begin
|
|
if (BitsPerComponent = 8) and (BitsPerPixel = 32) then
|
|
Result := ifA8R8G8B8
|
|
else if (BitsPerComponent = 16) and (BitsPerPixel = 64) then
|
|
Result := ifA16R16G16B16;
|
|
end
|
|
else if AlphaInfo = kCGImageAlphaNone then
|
|
begin
|
|
if (BitsPerComponent = 8) and (BitsPerPixel = 24) then
|
|
Result := ifR8G8B8
|
|
else if (BitsPerComponent = 16) and (BitsPerPixel = 48) then
|
|
Result := ifR16G16B16;
|
|
end;
|
|
end;
|
|
finally
|
|
CGColorSpaceRelease(ColorSpaceRef);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TQuartzImageHandler.LoadImage(Stream: TCustomMemoryStream; var Images: TDynImageDataArray; OnlyFirstImage: Boolean): Boolean;
|
|
var
|
|
Provider: CGDataProviderRef;
|
|
PixelsData: CFDataRef;
|
|
PixelsPtr, DestPtr: PByteArray;
|
|
ImgSourceRef: CGImageSourceRef;
|
|
ImgRef: CGImageRef;
|
|
CtxRef: CGContextRef;
|
|
I, Count, Y: Integer;
|
|
Width, Height, BytesPerRow, WidthBytes: Integer;
|
|
ImgFormat: TImageFormat;
|
|
begin
|
|
Result := False;
|
|
Provider := CGDataProviderCreateWithData(nil, Stream.Memory, Stream.Size, nil);
|
|
if Provider <> nil then
|
|
begin
|
|
ImgSourceRef := CGImageSourceCreateWithDataProvider(Provider, nil);
|
|
if ImgSourceRef <> nil then
|
|
begin
|
|
Count := CGImageSourceGetCount(ImgSourceRef);
|
|
if (Count > 1) and OnlyFirstImage then
|
|
Count := 1;
|
|
SetLength(Images, Count);
|
|
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
ImgRef := CGImageSourceCreateImageAtIndex(ImgSourceRef, I, nil);
|
|
if ImgRef <> nil then
|
|
begin
|
|
Width := CGImageGetWidth(ImgRef);
|
|
Height := CGImageGetHeight(ImgRef);
|
|
BytesPerRow := CGImageGetBytesPerRow(ImgRef);
|
|
ImgFormat := FindImageFormat(ImgRef);
|
|
|
|
if ImgFormat = ifUnknown then
|
|
begin
|
|
NewImage(Width, Height, ifA8R8G8B8, Images[I]);
|
|
CtxRef := CGBitmapContextCreate(Images[I].Bits, Width, Height, 8,
|
|
Width * 4, FDefaultColorSpace, kCGImageAlphaPremultipliedFirst);
|
|
CGContextDrawImage(CtxRef, CGRectFromRect(Rect(0, 0, Width, Height)), ImgRef);
|
|
CGContextRelease(CtxRef);
|
|
end
|
|
else
|
|
begin
|
|
NewImage(Width, Height, ImgFormat, Images[I]);
|
|
DestPtr := PByteArray(Images[I].Bits);
|
|
WidthBytes := Images[I].Size div Height;
|
|
|
|
PixelsData := CGDataProviderCopyData(CGImageGetDataProvider(ImgRef));
|
|
PixelsPtr := PByteArray(CFDataGetBytePtr(PixelsData));
|
|
|
|
for Y := 0 to Height - 1 do
|
|
begin
|
|
//
|
|
Move(PixelsPtr[Y * BytesPerRow], DestPtr[Y * WidthBytes], WidthBytes);
|
|
end;
|
|
CFRelease(PixelsData);
|
|
end;
|
|
|
|
CGImageRelease(ImgRef);
|
|
end;
|
|
end;
|
|
CFRelease(ImgSourceRef);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|