ImagingJpegIJL.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. {
  2. Vampyre Imaging Library
  3. by Marek Mauder
  4. http://imaginglib.sourceforge.net
  5. The contents of this file are used with permission, subject to the Mozilla
  6. Public License Version 1.1 (the "License"); you may not use this file except
  7. in compliance with the License. You may obtain a copy of the License at
  8. http://www.mozilla.org/MPL/MPL-1.1.html
  9. Software distributed under the License is distributed on an "AS IS" basis,
  10. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
  11. the specific language governing rights and limitations under the License.
  12. Alternatively, the contents of this file may be used under the terms of the
  13. GNU Lesser General Public License (the "LGPL License"), in which case the
  14. provisions of the LGPL License are applicable instead of those above.
  15. If you wish to allow use of your version of this file only under the terms
  16. of the LGPL License and not to allow others to use your version of this file
  17. under the MPL, indicate your decision by deleting the provisions above and
  18. replace them with the notice and other provisions required by the LGPL
  19. License. If you do not delete the provisions above, a recipient may use
  20. your version of this file under either the MPL or the LGPL License.
  21. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
  22. }
  23. { This unit contains image format alternative loader/saver for Jpeg images
  24. using Intel Jpeg Library (Win32 only).}
  25. unit ImagingJpegIJL;
  26. {$I ImagingOptions.inc}
  27. {$IFNDEF WIN32}
  28. {$ERROR 'IJL 1.5 only for Win32'}
  29. {$ENDIF}
  30. interface
  31. uses
  32. SysUtils, ImagingTypes, Imaging, ImagingUtility, ImagingIO;
  33. type
  34. { Class for loading/saving Jpeg images. This is alternative to
  35. default built-in Jpeg handler (which uses JpegLib).
  36. This handler uses Intel Jpeg Library 1.5 (DLL needed) and is
  37. much faster than JpegLib (2-4x). Also supports reading and writing of
  38. alpha channels in Jpeg files.}
  39. TJpegFileFormatIJL = class(TImageFileFormat)
  40. private
  41. FQuality: LongInt;
  42. procedure JpegError(Code: Integer);
  43. protected
  44. procedure Define; override;
  45. function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
  46. OnlyFirstLevel: Boolean): Boolean; override;
  47. function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
  48. Index: LongInt): Boolean; override;
  49. procedure ConvertToSupported(var Image: TImageData;
  50. const Info: TImageFormatInfo); override;
  51. public
  52. function TestFormat(Handle: TImagingHandle): Boolean; override;
  53. procedure CheckOptionsValidity; override;
  54. published
  55. { Controls Jpeg save compression quality. It is number in range 1..100.
  56. 1 means small/ugly file, 100 means large/nice file. Accessible trough
  57. ImagingJpegQuality option.}
  58. property Quality: LongInt read FQuality write FQuality;
  59. end;
  60. implementation
  61. {$MINENUMSIZE 4} // Min enum size: 4 B
  62. uses
  63. Types;
  64. const
  65. SJpegFormatName = 'JPEG Image (IJL)';
  66. SJpegMasks = '*.jpg,*.jpeg,*.jfif,*.jpe,*.jif,*.jpa';
  67. JpegSupportedFormats: TImageFormats = [ifGray8, ifR8G8B8, ifA8R8G8B8];
  68. JpegDefaultQuality = 90;
  69. JpegDefaultProgressive = False;
  70. resourcestring
  71. SJpegError = 'JPEG Error';
  72. const
  73. { Jpeg file identifiers.}
  74. JpegMagic: TChar2 = #$FF#$D8;
  75. SIJLLibrary = 'ijl15.dll';
  76. const
  77. IJL_SETUP = -1;
  78. IJL_OK = 0;
  79. IJL_NONE = 0;
  80. IJL_OTHER = 255;
  81. JBUFSIZE = 4096; // Size of file I/O buffer (4K).
  82. type
  83. {
  84. Purpose: Possible types of data read/write/other operations to be
  85. performed by the functions IJL_Read and IJL_Write.
  86. See the Developer's Guide for details on appropriate usage.
  87. Fields:
  88. IJL_JFILE_XXXXXXX Indicates JPEG data in a stdio file.
  89. IJL_JBUFF_XXXXXXX Indicates JPEG data in an addressable buffer.
  90. }
  91. TIJLIOType = (
  92. // Read JPEG parameters (i.e., height, width, channels, sampling, etc.)
  93. // from a JPEG bit stream.
  94. IJL_JFILE_READPARAMS = 0,
  95. IJL_JBUFF_READPARAMS = 1,
  96. // Read a JPEG Interchange Format image.
  97. IJL_JFILE_READWHOLEIMAGE = 2,
  98. IJL_JBUFF_READWHOLEIMAGE = 3,
  99. // Read JPEG tables from a JPEG Abbreviated Format bit stream.
  100. IJL_JFILE_READHEADER = 4,
  101. IJL_JBUFF_READHEADER = 5,
  102. // Read image info from a JPEG Abbreviated Format bit stream.
  103. IJL_JFILE_READENTROPY = 6,
  104. IJL_JBUFF_READENTROPY = 7,
  105. // Write an entire JFIF bit stream.
  106. IJL_JFILE_WRITEWHOLEIMAGE = 8,
  107. IJL_JBUFF_WRITEWHOLEIMAGE = 9,
  108. // Write a JPEG Abbreviated Format bit stream.
  109. IJL_JFILE_WRITEHEADER = 10,
  110. IJL_JBUFF_WRITEHEADER = 11,
  111. // Write image info to a JPEG Abbreviated Format bit stream.
  112. IJL_JFILE_WRITEENTROPY = 12,
  113. IJL_JBUFF_WRITEENTROPY = 13,
  114. // Scaled Decoding Options:
  115. // Reads a JPEG image scaled to 1/2 size.
  116. IJL_JFILE_READONEHALF = 14,
  117. IJL_JBUFF_READONEHALF = 15,
  118. // Reads a JPEG image scaled to 1/4 size.
  119. IJL_JFILE_READONEQUARTER = 16,
  120. IJL_JBUFF_READONEQUARTER = 17,
  121. // Reads a JPEG image scaled to 1/8 size.
  122. IJL_JFILE_READONEEIGHTH = 18,
  123. IJL_JBUFF_READONEEIGHTH = 19,
  124. // Reads an embedded thumbnail from a JFIF bit stream.
  125. IJL_JFILE_READTHUMBNAIL = 20,
  126. IJL_JBUFF_READTHUMBNAIL = 21
  127. );
  128. {
  129. Purpose: Possible color space formats.
  130. Note these formats do *not* necessarily denote
  131. the number of channels in the color space.
  132. There exists separate "channel" fields in the
  133. JPEG_CORE_PROPERTIES data structure specifically
  134. for indicating the number of channels in the
  135. JPEG and/or DIB color spaces.}
  136. TIJL_COLOR = (
  137. IJL_RGB = 1, // Red-Green-Blue color space.
  138. IJL_BGR = 2, // Reversed channel ordering from IJL_RGB.
  139. IJL_YCBCR = 3, // Luminance-Chrominance color space as defined
  140. // by CCIR Recommendation 601.
  141. IJL_G = 4, // Grayscale color space.
  142. IJL_RGBA_FPX = 5, // FlashPix RGB 4 channel color space that
  143. // has pre-multiplied opacity.
  144. IJL_YCBCRA_FPX = 6 // FlashPix YCbCr 4 channel color space that
  145. // has pre-multiplied opacity.
  146. //IJL_OTHER = 255 // Some other color space not defined by the IJL.
  147. // (This means no color space conversion will
  148. // be done by the IJL.)
  149. );
  150. { Purpose: Possible subsampling formats used in the JPEG.}
  151. TIJL_JPGSUBSAMPLING = (
  152. IJL_NOSUBSAMP = 0,
  153. IJL_411 = 1, // Valid on a JPEG w/ 3 channels.
  154. IJL_422 = 2, // Valid on a JPEG w/ 3 channels.
  155. IJL_4114 = 3, // Valid on a JPEG w/ 4 channels.
  156. IJL_4224 = 4 // Valid on a JPEG w/ 4 channels.
  157. );
  158. { Purpose: Possible subsampling formats used in the DIB. }
  159. TIJL_DIBSUBSAMPLING = TIJL_JPGSUBSAMPLING;
  160. { Purpose: This is the primary data structure between the IJL and
  161. the external user. It stores JPEG state information
  162. and controls the IJL. It is user-modifiable.
  163. Context: Used by all low-level IJL routines to store
  164. pseudo-global information.}
  165. TJpegCoreProperties = packed record
  166. UseJPEGPROPERTIES : LongBool; // default = 0
  167. // DIB specific I/O data specifiers.
  168. DIBBytes : PByte; // default = NULL
  169. DIBWidth : UInt32; // default = 0
  170. DIBHeight : UInt32; // default = 0
  171. DIBPadBytes : UInt32; // default = 0
  172. DIBChannels : UInt32; // default = 3
  173. DIBColor : TIJL_COLOR; // default = IJL_BGR
  174. DIBSubsampling : TIJL_DIBSUBSAMPLING; // default = IJL_NONE
  175. // JPEG specific I/O data specifiers.
  176. JPGFile : PAnsiChar; // default = NULL
  177. JPGBytes : PByte; // default = NULL
  178. JPGSizeBytes : UInt32; // default = 0
  179. JPGWidth : UInt32; // default = 0
  180. JPGHeight : UInt32; // default = 0
  181. JPGChannels : UInt32; // default = 3
  182. JPGColor : TIJL_COLOR; // default = IJL_YCBCR
  183. JPGSubsampling : TIJL_JPGSUBSAMPLING; // default = IJL_411
  184. JPGThumbWidth : UInt32; // default = 0
  185. JPGThumbHeight : UInt32; // default = 0
  186. // JPEG conversion properties.
  187. NeedsConvert : LongBool; // default = TRUE
  188. NeedsResample : LongBool; // default = TRUE
  189. Quality : UInt32; // default = 75
  190. // Low-level properties.
  191. PropsAndUnused : array[0..19987] of Byte;
  192. end;
  193. PJpegCoreProperties = ^TJpegCoreProperties;
  194. function ijlInit(var Props: TJpegCoreProperties): Integer; stdcall; external SIJLLibrary;
  195. function ijlFree(var Props: TJpegCoreProperties): Integer; stdcall; external SIJLLibrary;
  196. function ijlRead(var Props: TJpegCoreProperties; IoType : TIJLIOTYPE): Integer; stdcall; external SIJLLibrary;
  197. function ijlWrite(var Props: TJpegCoreProperties; IoType : TIJLIOTYPE): Integer; stdcall; external SIJLLibrary;
  198. function ijlErrorStr(Code : Integer) : PAnsiChar; stdcall; external SIJLLibrary;
  199. { TJpegFileFormatIJL class implementation }
  200. procedure TJpegFileFormatIJL.Define;
  201. begin
  202. inherited;
  203. FName := SJpegFormatName;
  204. FCanLoad := True;
  205. FCanSave := True;
  206. FIsMultiImageFormat := False;
  207. FSupportedFormats := JpegSupportedFormats;
  208. FQuality := JpegDefaultQuality;
  209. AddMasks(SJpegMasks);
  210. RegisterOption(ImagingJpegQuality, @FQuality);
  211. end;
  212. procedure TJpegFileFormatIJL.CheckOptionsValidity;
  213. begin
  214. // Check if option values are valid
  215. if not (FQuality in [1..100]) then
  216. FQuality := JpegDefaultQuality;
  217. end;
  218. procedure TJpegFileFormatIJL.ConvertToSupported(var Image: TImageData;
  219. const Info: TImageFormatInfo);
  220. begin
  221. if Info.HasAlphaChannel then
  222. ConvertImage(Image, ifA8R8G8B8)
  223. else if Info.HasGrayChannel then
  224. ConvertImage(Image, ifGray8)
  225. else
  226. ConvertImage(Image, ifR8G8B8);
  227. end;
  228. function TJpegFileFormatIJL.TestFormat(Handle: TImagingHandle): Boolean;
  229. var
  230. ReadCount: LongInt;
  231. ID: array[0..9] of AnsiChar;
  232. begin
  233. Result := False;
  234. if Handle <> nil then
  235. with GetIO do
  236. begin
  237. FillChar(ID, SizeOf(ID), 0);
  238. ReadCount := Read(Handle, @ID, SizeOf(ID));
  239. Seek(Handle, -ReadCount, smFromCurrent);
  240. Result := (ReadCount = SizeOf(ID)) and
  241. CompareMem(@ID, @JpegMagic, SizeOf(JpegMagic));
  242. end;
  243. end;
  244. procedure TJpegFileFormatIJL.JpegError(Code: Integer);
  245. begin
  246. raise EImagingError.Create(SJpegError + ': ' + ijlErrorStr(Code));
  247. end;
  248. function TJpegFileFormatIJL.LoadData(Handle: TImagingHandle;
  249. var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
  250. var
  251. Props: TJpegCoreProperties;
  252. Status: Integer;
  253. Buffer: TDynByteArray;
  254. InputLen: Integer;
  255. JpegFmt: TImageFormat;
  256. begin
  257. // Copy IO functions to global var used in JpegLib callbacks
  258. Result := False;
  259. SetLength(Images, 1);
  260. with Images[0] do
  261. try
  262. InputLen := GetInputSize(GetIO, Handle);
  263. Status := IjlInit(Props);
  264. if Status = IJL_OK then
  265. begin
  266. // Load input to memory and read Jpeg props
  267. SetLength(Buffer, InputLen);
  268. Props.JPGSizeBytes := InputLen;
  269. Props.JPGBytes := @Buffer[0];
  270. GetIO.Read(Handle, @Buffer[0], InputLen);
  271. Status := ijlRead(Props, IJL_JBUFF_READPARAMS);
  272. end;
  273. if Status = IJL_OK then
  274. begin
  275. // Set image and DIB props based on Jpeg params read from input
  276. case Props.JPGChannels of
  277. 1:
  278. begin
  279. JpegFmt := ifGray8;
  280. Props.DIBColor := IJL_G;
  281. end;
  282. 3:
  283. begin
  284. JpegFmt := ifR8G8B8;
  285. Props.DIBColor := IJL_BGR;
  286. end;
  287. 4:
  288. begin
  289. JpegFmt := ifA8R8G8B8;
  290. Props.DIBColor := IJL_RGBA_FPX;
  291. end
  292. else
  293. Exit;
  294. end;
  295. NewImage(Props.JPGWidth, Props.JPGHeight, JpegFmt, Images[0]);
  296. Props.DIBWidth := Props.JPGWidth;
  297. Props.DIBHeight := Props.JPGHeight;
  298. Props.DIBChannels := Props.JPGChannels;
  299. Props.DIBPadBytes := 0;
  300. Props.DIBBytes := Bits;
  301. // Now read the image bits
  302. Status := ijlRead(Props, IJL_JBUFF_READWHOLEIMAGE);
  303. end;
  304. if Status <> IJL_OK then
  305. JpegError(Status);
  306. // Decoded images with alpha are in ABGR format so R and B chanels are switched
  307. if JpegFmt = ifA8R8G8B8 then
  308. SwapChannels(Images[0], ChannelRed, ChannelBlue);
  309. Result := True;
  310. finally
  311. ijlFree(Props);
  312. end;
  313. end;
  314. function TJpegFileFormatIJL.SaveData(Handle: TImagingHandle;
  315. const Images: TDynImageDataArray; Index: LongInt): Boolean;
  316. var
  317. Props: TJpegCoreProperties;
  318. Status: Integer;
  319. Info: TImageFormatInfo;
  320. ImageToSave: TImageData;
  321. MustBeFreed: Boolean;
  322. Buffer: TDynByteArray;
  323. begin
  324. Result := False;
  325. // Makes image to save compatible with Jpeg saving capabilities
  326. if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then
  327. with ImageToSave do
  328. try
  329. Status := ijlInit(Props);
  330. if Status = IJL_OK then
  331. begin
  332. Info := GetFormatInfo(Format);
  333. // Set all the needed props
  334. Props.DIBWidth := Width;
  335. Props.DIBHeight := Height;
  336. Props.DIBChannels := Info.ChannelCount;
  337. Props.DIBPadBytes := 0;
  338. Props.DIBBytes := Bits;
  339. Props.Quality := FQuality;
  340. Props.JPGWidth := Width;
  341. Props.JPGHeight := Height;
  342. Props.JPGChannels := Info.ChannelCount;
  343. SetLength(Buffer, Size);
  344. Props.JPGSizeBytes := Size;
  345. Props.JPGBytes := @Buffer[0];
  346. case Info.ChannelCount of
  347. 1:
  348. begin
  349. Props.DIBColor := IJL_G;
  350. Props.JPGColor := IJL_G;
  351. Props.JPGSubsampling := IJL_NOSUBSAMP;
  352. end;
  353. 3:
  354. begin
  355. Props.DIBColor := IJL_BGR;
  356. Props.JPGColor := IJL_YCBCR;
  357. Props.JPGSubsampling := IJL_411;
  358. end;
  359. 4:
  360. begin
  361. Props.DIBColor := IJL_RGBA_FPX;
  362. Props.JPGColor := IJL_YCBCRA_FPX;
  363. Props.JPGSubsampling := IJL_4114;
  364. SwapChannels(ImageToSave, ChannelRed, ChannelBlue); // IJL expects ABGR order
  365. end;
  366. end;
  367. // Encode image
  368. Status := ijlWrite(Props, IJL_JBUFF_WRITEWHOLEIMAGE);
  369. end;
  370. if Status <> IJL_OK then
  371. JpegError(Status);
  372. // Write temp buffer to file
  373. GetIO.Write(Handle, @Buffer[0], Props.JPGSizeBytes);
  374. Result := True;
  375. finally
  376. ijlFree(Props);
  377. if MustBeFreed then
  378. FreeImage(ImageToSave)
  379. else if Format = ifA8R8G8B8 then
  380. SwapChannels(ImageToSave, ChannelRed, ChannelBlue); // Swap image back to ARGB if not temp
  381. end;
  382. end;
  383. initialization
  384. RegisterImageFileFormat(TJpegFileFormatIJL);
  385. {
  386. File Notes:
  387. -- TODOS ----------------------------------------------------
  388. - nothing now
  389. -- 0.26.3 Changes/Bug Fixes ---------------------------------
  390. - Initial version created.
  391. }
  392. end.