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

3 years ago
  1. unit ImagingQuartz;
  2. {$I ImagingOptions.inc}
  3. {$IFNDEF MACOSX}
  4. {$FATAL 'Mac OSX only'}
  5. {$ENDIF}
  6. interface
  7. uses
  8. Types, SysUtils, Classes, ImagingTypes, Imaging, ImagingUtility,
  9. {$IFDEF DCC}
  10. Macapi.CocoaTypes, Macapi.CoreFoundation, Macapi.CoreGraphics, Macapi.QuartzCore, Macapi.ImageIO
  11. {$ELSE}
  12. CGBase, CGShading, CGColor, CGColorSpace, CGContext, CGBitmapContext, CGImageSource,
  13. CGImageDestination, CGDataProvider, CGDataConsumer, CFDictionary, CGAffineTransforms, CGPath
  14. {$ENDIF};
  15. type
  16. TQuartzImageHandler = class
  17. private
  18. FDefaultColorSpace: CGColorSpaceRef;
  19. function FindImageFormat(ImgRef: CGImageRef): TImageFormat;
  20. public
  21. constructor Create;
  22. destructor Destroy; override;
  23. function LoadImage(Stream: TCustomMemoryStream; var Images: TDynImageDataArray; OnlyFirstImage: Boolean): Boolean;
  24. end;
  25. implementation
  26. function CGRectFromRect(const R: TRect): CGRect;
  27. begin
  28. Result.origin.x := R.Left;
  29. Result.origin.Y := R.Top;
  30. Result.size.Width := R.Right - R.Left;
  31. Result.size.Height := R.Bottom - R.Top;
  32. end;
  33. { TMacImageHandler }
  34. constructor TQuartzImageHandler.Create;
  35. begin
  36. FDefaultColorSpace := CGColorSpaceCreateDeviceRGB;
  37. end;
  38. destructor TQuartzImageHandler.Destroy;
  39. begin
  40. CGColorSpaceRelease(FDefaultColorSpace);
  41. inherited;
  42. end;
  43. function TQuartzImageHandler.FindImageFormat(ImgRef: CGImageRef): TImageFormat;
  44. var
  45. ColorSpaceRef: CGColorSpaceRef;
  46. ColorModel: CGColorSpaceModel;
  47. AlphaInfo: CGImageAlphaInfo;
  48. BitmapInfo: CGBitmapInfo;
  49. BitsPerPixel, Components, BitsPerComponent: Integer;
  50. isMask: integer;
  51. intent: CGColorRenderingIntent;
  52. begin
  53. Result := ifUnknown;
  54. AlphaInfo := CGImageGetAlphaInfo(ImgRef);
  55. BitmapInfo := CGImageGetBitmapInfo(ImgRef);
  56. ColorSpaceRef := CGImageGetColorSpace(ImgRef);
  57. intent := CGImageGetRenderingIntent(ImgRef);
  58. isMask := CGImageIsMask(ImgRef);
  59. {
  60. Also check BitmapInfo
  61. kCGBitmapByteOrderDefault = NO
  62. kCGBitmapByteOrder16Little = NO
  63. kCGBitmapByteOrder32Little = NO
  64. kCGBitmapByteOrder16Big = NO
  65. kCGBitmapByteOrder32Big = NO
  66. float formats
  67. }
  68. if ColorSpaceRef <> nil then
  69. begin
  70. try
  71. BitsPerPixel := CGImageGetBitsPerPixel(ImgRef);
  72. BitsPerComponent := CGImageGetBitsPerComponent(ImgRef);
  73. ColorModel := CGColorSpaceGetModel(ColorSpaceRef);
  74. Components := CGColorSpaceGetNumberOfComponents(ColorSpaceRef);
  75. if (ColorModel = kCGColorSpaceModelMonochrome) and (Components = 1) then
  76. begin
  77. // Grayscale formats
  78. if AlphaInfo = kCGImageAlphaFirst then
  79. begin
  80. if (BitsPerComponent = 8) and (BitsPerPixel = 16) then
  81. Result := ifA8Gray8
  82. else if (BitsPerComponent = 16) and (BitsPerPixel = 32) then
  83. Result := ifA16Gray16;
  84. end
  85. else if AlphaInfo = kCGImageAlphaNone then
  86. begin
  87. if BitsPerPixel = 8 then
  88. Result := ifGray8
  89. else if BitsPerPixel = 16 then
  90. Result := ifGray16;
  91. end;
  92. end
  93. else if ColorModel = kCGColorSpaceModelRGB then
  94. begin
  95. // RGB
  96. if (BitsPerPixel = 16) and (AlphaInfo = kCGImageAlphaNoneSkipFirst) then
  97. begin
  98. Result := ifX1R5G5B5;
  99. end
  100. else if AlphaInfo = kCGImageAlphaFirst then
  101. begin
  102. if (BitsPerComponent = 8) and (BitsPerPixel = 32) then
  103. Result := ifA8R8G8B8
  104. else if (BitsPerComponent = 16) and (BitsPerPixel = 64) then
  105. Result := ifA16R16G16B16;
  106. end
  107. else if AlphaInfo = kCGImageAlphaNone then
  108. begin
  109. if (BitsPerComponent = 8) and (BitsPerPixel = 24) then
  110. Result := ifR8G8B8
  111. else if (BitsPerComponent = 16) and (BitsPerPixel = 48) then
  112. Result := ifR16G16B16;
  113. end;
  114. end;
  115. finally
  116. CGColorSpaceRelease(ColorSpaceRef);
  117. end;
  118. end;
  119. end;
  120. function TQuartzImageHandler.LoadImage(Stream: TCustomMemoryStream; var Images: TDynImageDataArray; OnlyFirstImage: Boolean): Boolean;
  121. var
  122. Provider: CGDataProviderRef;
  123. PixelsData: CFDataRef;
  124. PixelsPtr, DestPtr: PByteArray;
  125. ImgSourceRef: CGImageSourceRef;
  126. ImgRef: CGImageRef;
  127. CtxRef: CGContextRef;
  128. I, Count, Y: Integer;
  129. Width, Height, BytesPerRow, WidthBytes: Integer;
  130. ImgFormat: TImageFormat;
  131. begin
  132. Result := False;
  133. Provider := CGDataProviderCreateWithData(nil, Stream.Memory, Stream.Size, nil);
  134. if Provider <> nil then
  135. begin
  136. ImgSourceRef := CGImageSourceCreateWithDataProvider(Provider, nil);
  137. if ImgSourceRef <> nil then
  138. begin
  139. Count := CGImageSourceGetCount(ImgSourceRef);
  140. if (Count > 1) and OnlyFirstImage then
  141. Count := 1;
  142. SetLength(Images, Count);
  143. for I := 0 to Count - 1 do
  144. begin
  145. ImgRef := CGImageSourceCreateImageAtIndex(ImgSourceRef, I, nil);
  146. if ImgRef <> nil then
  147. begin
  148. Width := CGImageGetWidth(ImgRef);
  149. Height := CGImageGetHeight(ImgRef);
  150. BytesPerRow := CGImageGetBytesPerRow(ImgRef);
  151. ImgFormat := FindImageFormat(ImgRef);
  152. if ImgFormat = ifUnknown then
  153. begin
  154. NewImage(Width, Height, ifA8R8G8B8, Images[I]);
  155. CtxRef := CGBitmapContextCreate(Images[I].Bits, Width, Height, 8,
  156. Width * 4, FDefaultColorSpace, kCGImageAlphaPremultipliedFirst);
  157. CGContextDrawImage(CtxRef, CGRectFromRect(Rect(0, 0, Width, Height)), ImgRef);
  158. CGContextRelease(CtxRef);
  159. end
  160. else
  161. begin
  162. NewImage(Width, Height, ImgFormat, Images[I]);
  163. DestPtr := PByteArray(Images[I].Bits);
  164. WidthBytes := Images[I].Size div Height;
  165. PixelsData := CGDataProviderCopyData(CGImageGetDataProvider(ImgRef));
  166. PixelsPtr := PByteArray(CFDataGetBytePtr(PixelsData));
  167. for Y := 0 to Height - 1 do
  168. begin
  169. //
  170. Move(PixelsPtr[Y * BytesPerRow], DestPtr[Y * WidthBytes], WidthBytes);
  171. end;
  172. CFRelease(PixelsData);
  173. end;
  174. CGImageRelease(ImgRef);
  175. end;
  176. end;
  177. CFRelease(ImgSourceRef);
  178. end;
  179. end;
  180. end;
  181. end.