Repo for the search and displace ingest module that takes odf, docx and pdf and transforms it into .md to be used with search and displace operations
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

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.