ImagingJpeg2000.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. {
  2. $Id$
  3. Vampyre Imaging Library
  4. by Marek Mauder
  5. http://imaginglib.sourceforge.net
  6. The contents of this file are used with permission, subject to the Mozilla
  7. Public License Version 1.1 (the "License"); you may not use this file except
  8. in compliance with the License. You may obtain a copy of the License at
  9. http://www.mozilla.org/MPL/MPL-1.1.html
  10. Software distributed under the License is distributed on an "AS IS" basis,
  11. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
  12. the specific language governing rights and limitations under the License.
  13. Alternatively, the contents of this file may be used under the terms of the
  14. GNU Lesser General Public License (the "LGPL License"), in which case the
  15. provisions of the LGPL License are applicable instead of those above.
  16. If you wish to allow use of your version of this file only under the terms
  17. of the LGPL License and not to allow others to use your version of this file
  18. under the MPL, indicate your decision by deleting the provisions above and
  19. replace them with the notice and other provisions required by the LGPL
  20. License. If you do not delete the provisions above, a recipient may use
  21. your version of this file under either the MPL or the LGPL License.
  22. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
  23. }
  24. { This unit contains image format loader/saver for Jpeg 2000 images.}
  25. unit ImagingJpeg2000;
  26. {$I ImagingOptions.inc}
  27. interface
  28. uses
  29. SysUtils, ImagingTypes, Imaging, ImagingColors, ImagingIO, ImagingUtility,
  30. ImagingExtras, OpenJpeg;
  31. type
  32. { Type Jpeg 2000 file (needed for OpenJPEG codec settings).}
  33. TJpeg2000FileType = (jtInvalid, jtJP2, jtJ2K, jtJPT);
  34. { Class for loading/saving Jpeg 2000 images. It uses OpenJPEG library
  35. compiled to object files and linked to Object Pascal program. Jpeg 2000
  36. supports wide variety of data formats. You can have arbitrary number
  37. of components/channels, each with different bitdepth and optional
  38. "signedness". Jpeg 2000 images can be lossy or lossless compressed.
  39. Imaging can load most data formats (except images
  40. with componenet bitdepth > 16 => no Imaging data format equivalents).
  41. Components with sample separation are loaded correctly, ICC profiles
  42. or palettes are not used, YCbCr images are translated to RGB.
  43. You can set various options when saving Jpeg-2000 images. Look at
  44. properties of TJpeg2000FileFormat for details.}
  45. TJpeg2000FileFormat = class(TImageFileFormat)
  46. protected
  47. FQuality: LongInt;
  48. FCodeStreamOnly: LongBool;
  49. FLosslessCompression: LongBool;
  50. function GetFileType(Handle: TImagingHandle): TJpeg2000FileType;
  51. function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
  52. OnlyFirstLevel: Boolean): Boolean; override;
  53. function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
  54. Index: LongInt): Boolean; override;
  55. procedure ConvertToSupported(var Image: TImageData;
  56. const Info: TImageFormatInfo); override;
  57. public
  58. constructor Create; override;
  59. function TestFormat(Handle: TImagingHandle): Boolean; override;
  60. procedure CheckOptionsValidity; override;
  61. published
  62. { Controls JPEG 2000 lossy compression quality. It is number in range 1..100.
  63. 1 means small/ugly file, 100 means large/nice file. Accessible trough
  64. ImagingJpeg2000Quality option. Default value is 80.}
  65. property Quality: LongInt read FQuality write FQuality;
  66. { Controls whether JPEG 2000 image is saved with full file headers or just
  67. as code stream. Default value is False. Accessible trough
  68. ImagingJpeg2000CodeStreamOnly option.}
  69. property CodeStreamOnly: LongBool read FCodeStreamOnly write FCodeStreamOnly;
  70. { Specifies JPEG 2000 image compression type. If True, saved JPEG 2000 files
  71. will be losslessly compressed. Otherwise lossy compression is used.
  72. Default value is False. Accessible trough
  73. ImagingJpeg2000LosslessCompression option.}
  74. property LosslessCompression: LongBool read FLosslessCompression write FLosslessCompression;
  75. end;
  76. implementation
  77. const
  78. SJpeg2000FormatName = 'JPEG 2000 Image';
  79. SJpeg2000Masks = '*.jp2,*.j2k,*.j2c,*.jpx,*.jpc';
  80. Jpeg2000SupportedFormats: TImageFormats = [ifGray8, ifGray16,
  81. ifA8Gray8, ifA16Gray16, ifR8G8B8, ifR16G16B16, ifA8R8G8B8, ifA16R16G16B16];
  82. Jpeg2000DefaultQuality = 80;
  83. Jpeg2000DefaultCodeStreamOnly = False;
  84. Jpeg2000DefaultLosslessCompression = False;
  85. const
  86. JP2Signature: TChar8 = #0#0#0#$0C#$6A#$50#$20#$20;
  87. J2KSignature: TChar4 = #$FF#$4F#$FF#$51;
  88. constructor TJpeg2000FileFormat.Create;
  89. begin
  90. inherited Create;
  91. FName := SJpeg2000FormatName;
  92. FCanLoad := True;
  93. FCanSave := True;
  94. FIsMultiImageFormat := False;
  95. FSupportedFormats := Jpeg2000SupportedFormats;
  96. FQuality := Jpeg2000DefaultQuality;
  97. FCodeStreamOnly := Jpeg2000DefaultCodeStreamOnly;
  98. FLosslessCompression := Jpeg2000DefaultLosslessCompression;
  99. AddMasks(SJpeg2000Masks);
  100. RegisterOption(ImagingJpeg2000Quality, @FQuality);
  101. RegisterOption(ImagingJpeg2000CodeStreamOnly, @FCodeStreamOnly);
  102. RegisterOption(ImagingJpeg2000LosslessCompression, @FLosslessCompression);
  103. end;
  104. procedure TJpeg2000FileFormat.CheckOptionsValidity;
  105. begin
  106. // Check if option values are valid
  107. if not (FQuality in [1..100]) then
  108. FQuality := Jpeg2000DefaultQuality;
  109. end;
  110. function TJpeg2000FileFormat.GetFileType(Handle: TImagingHandle): TJpeg2000FileType;
  111. var
  112. ReadCount: LongInt;
  113. Id: TChar8;
  114. begin
  115. Result := jtInvalid;
  116. with GetIO do
  117. begin
  118. ReadCount := Read(Handle, @Id, SizeOf(Id));
  119. if ReadCount = SizeOf(Id) then
  120. begin
  121. // Check if we have full JP2 file format or just J2K code stream
  122. if CompareMem(@Id, @JP2Signature, SizeOf(JP2Signature)) then
  123. Result := jtJP2
  124. else if CompareMem(@Id, @J2KSignature, SizeOf(J2KSignature)) then
  125. Result := jtJ2K;
  126. end;
  127. Seek(Handle, -ReadCount, smFromCurrent);
  128. end;
  129. end;
  130. function TJpeg2000FileFormat.LoadData(Handle: TImagingHandle;
  131. var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
  132. type
  133. TChannelInfo = record
  134. DestOffset: Integer;
  135. CompType: OPJ_COMPONENT_TYPE;
  136. Shift: Integer;
  137. SrcMaxValue: Integer;
  138. DestMaxValue: Integer;
  139. end;
  140. var
  141. FileType: TJpeg2000FileType;
  142. Buffer: PByte;
  143. BufferSize, ChannelSize, I: Integer;
  144. Info: TImageFormatInfo;
  145. dinfo: popj_dinfo_t;
  146. parameters: opj_dparameters_t;
  147. cio: popj_cio_t;
  148. image: popj_image_t;
  149. StartPos: Int64;
  150. Channels: array of TChannelInfo;
  151. procedure WriteSample(Dest: PByte; ChannelSize, Value: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF}
  152. begin
  153. case ChannelSize of
  154. 1: Dest^ := Value;
  155. 2: PWord(Dest)^ := Value;
  156. 4: PLongWord(Dest)^ := Value;
  157. end;
  158. end;
  159. procedure CopySample(Src, Dest: PByte; ChannelSize: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF}
  160. begin
  161. case ChannelSize of
  162. 1: Dest^ := Src^;
  163. 2: PWord(Dest)^ := PWord(Src)^;
  164. 4: PLongWord(Dest)^ := PLongWord(Src)^;
  165. end;
  166. end;
  167. procedure ReadChannel(const Image: TImageData; const Info: TChannelInfo; const Comp: opj_image_comp; BytesPerPixel: Integer);
  168. var
  169. X, Y, SX, SY, SrcIdx, LineBytes: Integer;
  170. DestPtr, NewPtr, LineUpPtr: PByte;
  171. DontScaleSamples: Boolean;
  172. begin
  173. DontScaleSamples := Info.SrcMaxValue = Info.DestMaxValue;
  174. LineBytes := Image.Width * BytesPerPixel;
  175. DestPtr := @PByteArray(Image.Bits)[Info.DestOffset];
  176. SrcIdx := 0;
  177. if (Comp.dx = 1) and (Comp.dy = 1) then
  178. begin
  179. // X and Y sample separation is 1 so just need to assign component values
  180. // to image pixels one by one
  181. for Y := 0 to Image.Height * Image.Width - 1 do
  182. begin
  183. if DontScaleSamples then
  184. WriteSample(DestPtr, ChannelSize, Comp.data[SrcIdx] + Info.Shift)
  185. else
  186. WriteSample(DestPtr, ChannelSize, MulDiv(Comp.data[SrcIdx] + Info.Shift, Info.DestMaxValue, Info.SrcMaxValue));
  187. Inc(SrcIdx);
  188. Inc(DestPtr, BytesPerPixel);
  189. end;
  190. end
  191. else
  192. begin
  193. // Sample separation is active - component is sub-sampled. Real component
  194. // dimensions are [Comp.w * Comp.dx, Comp.h * Comp.dy]
  195. for Y := 0 to Comp.h - 1 do
  196. begin
  197. LineUpPtr := @PByteArray(Image.Bits)[Y * Comp.dy * LineBytes + Info.DestOffset];
  198. DestPtr := LineUpPtr;
  199. for X := 0 to Comp.w - 1 do
  200. begin
  201. if DontScaleSamples then
  202. WriteSample(DestPtr, ChannelSize, Comp.data[SrcIdx] + Info.Shift)
  203. else
  204. WriteSample(DestPtr, ChannelSize, MulDiv(Comp.data[SrcIdx] + Info.Shift, Info.DestMaxValue, Info.SrcMaxValue));
  205. NewPtr := DestPtr;
  206. for SX := 1 to Comp.dx - 1 do
  207. begin
  208. if X * Comp.dx + SX >= Image.Width then Break;
  209. // Replicate pixels on line
  210. Inc(NewPtr, BytesPerPixel);
  211. CopySample(DestPtr, NewPtr, ChannelSize);
  212. end;
  213. Inc(SrcIdx);
  214. Inc(DestPtr, BytesPerPixel * Comp.dx);
  215. end;
  216. for SY := 1 to Comp.dy - 1 do
  217. begin
  218. if Y * Comp.dy + SY >= Image.Height then Break;
  219. // Replicate line
  220. NewPtr := @PByteArray(Image.Bits)[(Y * Comp.dy + SY) * LineBytes + Info.DestOffset];
  221. for X := 0 to Image.Width - 1 do
  222. begin
  223. CopySample(LineUpPtr, NewPtr, ChannelSize);
  224. Inc(LineUpPtr, BytesPerPixel);
  225. Inc(NewPtr, BytesPerPixel);
  226. end;
  227. end;
  228. end;
  229. end;
  230. end;
  231. procedure ConvertYCbCrToRGB(Pixels: PByte; NumPixels, BytesPerPixel: Integer);
  232. var
  233. I: Integer;
  234. PixPtr: PByte;
  235. CY, CB, CR: Byte;
  236. CYW, CBW, CRW: Word;
  237. begin
  238. PixPtr := Pixels;
  239. for I := 0 to NumPixels - 1 do
  240. begin
  241. if BytesPerPixel in [3, 4] then
  242. with PColor24Rec(PixPtr)^ do
  243. begin
  244. CY := R;
  245. CB := G;
  246. CR := B;
  247. YCbCrToRGB(CY, CB, CR, R, G, B);
  248. end
  249. else
  250. with PColor48Rec(PixPtr)^ do
  251. begin
  252. CYW := R;
  253. CBW := G;
  254. CRW := B;
  255. YCbCrToRGB16(CYW, CBW, CRW, R, G, B);
  256. end;
  257. Inc(PixPtr, BytesPerPixel);
  258. end;
  259. end;
  260. begin
  261. Result := False;
  262. image := nil;
  263. cio := nil;
  264. opj_set_default_decoder_parameters(@parameters);
  265. // Determine which codec to use
  266. FileType := GetFileType(Handle);
  267. case FileType of
  268. jtJP2: dinfo := opj_create_decompress(CODEC_JP2);
  269. jtJ2K: dinfo := opj_create_decompress(CODEC_J2K);
  270. jtJPT: dinfo := opj_create_decompress(CODEC_JPT);
  271. else
  272. Exit;
  273. end;
  274. // Set event manager to nil to avoid getting messages
  275. dinfo.event_mgr := nil;
  276. // Currently OpenJPEG can load images only from memory so we have to
  277. // preload whole input to mem buffer. Not good but no other way now.
  278. // At least we set stream pos to end of JP2 data after loading (we will now
  279. // the exact size by then).
  280. StartPos := GetIO.Tell(Handle);
  281. BufferSize := ImagingIO.GetInputSize(GetIO, Handle);
  282. GetMem(Buffer, BufferSize);
  283. SetLength(Images, 1);
  284. with GetIO, Images[0] do
  285. try
  286. Read(Handle, Buffer, BufferSize);
  287. cio := opj_cio_open(opj_common_ptr(dinfo), Buffer, BufferSize);
  288. opj_setup_decoder(dinfo, @parameters);
  289. // Decode image
  290. image := opj_decode(dinfo, cio);
  291. if image = nil then
  292. Exit;
  293. // Determine which Imaging data format to use accorsing to
  294. // decoded image components
  295. case image.numcomps of
  296. 2: case image.comps[0].prec of
  297. 1..8: Format := ifA8Gray8;
  298. 9..16: Format := ifA16Gray16;
  299. end;
  300. 3: case image.comps[0].prec of
  301. 1..8: Format := ifR8G8B8;
  302. 9..16: Format := ifR16G16B16;
  303. end;
  304. 4: case image.comps[0].prec of
  305. 1..8: Format := ifA8R8G8B8;
  306. 9..16: Format := ifA16R16G16B16;
  307. end;
  308. else
  309. // There is only one component or there is more than four =>
  310. // just load the first one as gray
  311. case image.comps[0].prec of
  312. 1..8: Format := ifGray8;
  313. 9..16: Format := ifGray16;
  314. 17..32: Format := ifGray32;
  315. end;
  316. end;
  317. // Exit if no compatible format was found
  318. if Format = ifUnknown then
  319. Exit;
  320. NewImage(image.x1 - image.x0, image.y1 - image.y0, Format, Images[0]);
  321. Info := GetFormatInfo(Format);
  322. ChannelSize := Info.BytesPerPixel div Info.ChannelCount;
  323. SetLength(Channels, Info.ChannelCount);
  324. // Get information about all channels/components of JP2 file
  325. for I := 0 to Info.ChannelCount - 1 do
  326. begin
  327. // Get component type for this channel and based on this
  328. // determine where in dest image bits write this channel's data
  329. Channels[I].CompType := image.comps[I].comp_type;
  330. case Channels[I].CompType of
  331. COMPTYPE_UNKNOWN:
  332. begin
  333. if Info.ChannelCount <> 4 then
  334. begin
  335. // Missing CDEF box in file - usually BGR order
  336. Channels[I].DestOffset := image.numcomps - I - 1
  337. end
  338. else
  339. begin
  340. // Missing CDEF box in file - usually ABGR order
  341. if I = 3 then
  342. Channels[I].DestOffset := 3
  343. else
  344. Channels[I].DestOffset := image.numcomps - I - 2
  345. end;
  346. end;
  347. COMPTYPE_R: Channels[I].DestOffset := 2;
  348. COMPTYPE_G: Channels[I].DestOffset := 1;
  349. COMPTYPE_B: Channels[I].DestOffset := 0;
  350. COMPTYPE_CB: Channels[I].DestOffset := 1;
  351. COMPTYPE_CR: Channels[I].DestOffset := 0;
  352. COMPTYPE_OPACITY: Channels[I].DestOffset := 3;
  353. COMPTYPE_Y:
  354. case image.color_space of
  355. CLRSPC_SYCC: Channels[I].DestOffset := 2; // Y is intensity part of YCC
  356. CLRSPC_GRAY: Channels[I].DestOffset := 0; // Y is independent gray channel
  357. end;
  358. end;
  359. // Scale channel offset
  360. Channels[I].DestOffset := Channels[I].DestOffset * ChannelSize;
  361. // Signed componets must be scaled to [0, 1] interval (depends on precision)
  362. if image.comps[I].sgnd = 1 then
  363. Channels[I].Shift := 1 shl (image.comps[I].prec - 1);
  364. // Max channel values used to easier scaling of precisions
  365. // not supported by Imaging to supported ones (like 12bits etc.).
  366. Channels[I].SrcMaxValue := 1 shl image.comps[I].prec - 1;
  367. Channels[I].DestMaxValue := 1 shl (ChannelSize * 8) - 1;
  368. end;
  369. // Images components are stored separately in JP2, each can have
  370. // different dimensions, bitdepth, ...
  371. for I := 0 to Info.ChannelCount - 1 do
  372. ReadChannel(Images[0], Channels[I], image.comps[I], Info.BytesPerPixel);
  373. // If we have YCbCr image we need to convert it to RGB
  374. if (image.color_space = CLRSPC_SYCC) and (Info.ChannelCount in [3, 4]) then
  375. ConvertYCbCrToRGB(Bits, Width * Height, Info.BytesPerPixel);
  376. // Set the input position just after end of image
  377. Seek(Handle, StartPos + Cardinal(cio.bp) - Cardinal(cio.start), smFromBeginning);
  378. Result := True;
  379. finally
  380. opj_image_destroy(image);
  381. opj_destroy_decompress(dinfo);
  382. opj_cio_close(cio);
  383. FreeMem(Buffer);
  384. end;
  385. end;
  386. function TJpeg2000FileFormat.SaveData(Handle: TImagingHandle;
  387. const Images: TDynImageDataArray; Index: LongInt): Boolean;
  388. var
  389. TargetSize, Rate: Single;
  390. ImageToSave: TImageData;
  391. MustBeFreed: Boolean;
  392. Info: TImageFormatInfo;
  393. I, Z, InvZ, Channel, ChannelSize, NumPixels: Integer;
  394. Pix: PByte;
  395. image: popj_image_t;
  396. cio: popj_cio_t;
  397. cinfo: popj_cinfo_t;
  398. parameters: opj_cparameters_t;
  399. compparams: popj_image_cmptparm_array;
  400. ColorSpace: OPJ_COLOR_SPACE;
  401. function GetComponentType(Comp: Integer): OPJ_COMPONENT_TYPE;
  402. begin
  403. if Info.HasAlphaChannel and (Comp = Info.ChannelCount - 1) then
  404. Result := COMPTYPE_OPACITY
  405. else if Info.HasGrayChannel then
  406. Result := COMPTYPE_Y
  407. else if Comp = 2 then
  408. Result := COMPTYPE_B
  409. else if Comp = 1 then
  410. Result := COMPTYPE_G
  411. else if Comp = 0 then
  412. Result := COMPTYPE_R
  413. else
  414. Result := COMPTYPE_UNKNOWN;
  415. end;
  416. begin
  417. Result := False;
  418. image := nil;
  419. compparams := nil;
  420. cinfo := nil;
  421. cio := nil;
  422. // Makes image to save compatible with Jpeg 2000 saving capabilities
  423. if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then
  424. with GetIO, ImageToSave do
  425. try
  426. Info := GetFormatInfo(Format);
  427. ChannelSize := Info.BytesPerPixel div Info.ChannelCount;
  428. // Fill component info structures and then create OpenJPEG image
  429. GetMem(compparams, Info.ChannelCount * SizeOf(opj_image_comptparm));
  430. for I := 0 to Info.ChannelCount - 1 do
  431. with compparams[I] do
  432. begin
  433. dx := 1;
  434. dy := 1;
  435. w := Width;
  436. h := Height;
  437. prec := (Info.BytesPerPixel div Info.ChannelCount) * 8;
  438. bpp := prec;
  439. sgnd := 0;
  440. comp_type := GetComponentType(I);
  441. x0 := 0;
  442. y0 := 0;
  443. end;
  444. if Info.HasGrayChannel then
  445. ColorSpace := CLRSPC_GRAY
  446. else
  447. ColorSpace := CLRSPC_SRGB;
  448. image := opj_image_create(Info.ChannelCount, @compparams[0], ColorSpace);
  449. if image = nil then Exit;
  450. image.x1 := Width;
  451. image.y1 := Height;
  452. if FCodeStreamOnly then
  453. cinfo := opj_create_compress(CODEC_J2K)
  454. else
  455. cinfo := opj_create_compress(CODEC_JP2);
  456. // Set event manager to nil to avoid getting messages
  457. cinfo.event_mgr := nil;
  458. // Set compression parameters based current file format properties
  459. opj_set_default_encoder_parameters(@parameters);
  460. parameters.cod_format := Iff(FCodeStreamOnly, 0, 1);
  461. parameters.numresolution := 6;
  462. parameters.tcp_numlayers := 1;
  463. parameters.cp_disto_alloc := 1;
  464. if FLosslessCompression then
  465. begin
  466. // Set rate to 0 -> lossless
  467. parameters.tcp_rates[0] := 0;
  468. end
  469. else
  470. begin
  471. // Quality -> Rate computation taken from ImageMagick
  472. Rate := 100.0 / Sqr(115 - FQuality);
  473. NumPixels := Width * Height * Info.BytesPerPixel;
  474. TargetSize := (NumPixels * Rate) + 550 + (Info.ChannelCount - 1) * 142;
  475. parameters.tcp_rates[0] := 1.0 / (TargetSize / NumPixels);
  476. end;
  477. // Setup encoder
  478. opj_setup_encoder(cinfo, @parameters, image);
  479. // Fill component samples in data with values taken from
  480. // image pixels.
  481. // Components should be ordered like this: RGBA, YA, RGB, etc.
  482. for Channel := 0 to Info.ChannelCount - 1 do
  483. begin
  484. Z := Channel;
  485. InvZ := Info.ChannelCount - 1 - Z;
  486. if Info.HasAlphaChannel then
  487. begin
  488. if Channel = Info.ChannelCount - 1 then
  489. InvZ := Z
  490. else
  491. InvZ := Info.ChannelCount - 2 - Z;
  492. end;
  493. Pix := @PByteArray(Bits)[InvZ * ChannelSize];
  494. for I := 0 to Width * Height - 1 do
  495. begin
  496. case ChannelSize of
  497. 1: image.comps[Z].data[I] := Pix^;
  498. 2: image.comps[Z].data[I] := PWord(Pix)^;
  499. 4: LongWord(image.comps[Z].data[I]) := PLongWord(Pix)^;
  500. end;
  501. Inc(Pix, Info.BytesPerPixel);
  502. end;
  503. end;
  504. // Open OpenJPEG output
  505. cio := opj_cio_open(opj_common_ptr(cinfo), nil, 0);
  506. // Try to encode the image
  507. if not opj_encode(cinfo, cio, image, nil) then
  508. Exit;
  509. // Finally write buffer with encoded image to output
  510. Write(Handle, cio.buffer, cio_tell(cio));
  511. Result := True;
  512. finally
  513. if MustBeFreed then
  514. FreeImage(ImageToSave);
  515. opj_destroy_compress(cinfo);
  516. opj_image_destroy(image);
  517. opj_cio_close(cio);
  518. FreeMem(compparams);
  519. end;
  520. end;
  521. procedure TJpeg2000FileFormat.ConvertToSupported(var Image: TImageData;
  522. const Info: TImageFormatInfo);
  523. var
  524. ConvFormat: TImageFormat;
  525. begin
  526. if Info.IsFloatingPoint then
  527. ConvFormat := IffFormat(Info.ChannelCount = 1, ifGray16, ifA16R16G16B16)
  528. else if Info.HasGrayChannel then
  529. ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16Gray16, ifGray16)
  530. else if Info.IsIndexed then
  531. ConvFormat := ifA8R8G8B8
  532. else if Info.BytesPerPixel div Info.ChannelCount > 1 then
  533. ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16R16G16B16, ifR16G16B16)
  534. else
  535. ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8);
  536. ConvertImage(Image, ConvFormat);
  537. end;
  538. function TJpeg2000FileFormat.TestFormat(Handle: TImagingHandle): Boolean;
  539. begin
  540. Result := False;
  541. if Handle <> nil then
  542. Result := GetFileType(Handle) <> jtInvalid;
  543. end;
  544. initialization
  545. RegisterImageFileFormat(TJpeg2000FileFormat);
  546. {
  547. File Notes:
  548. -- TODOS ----------------------------------------------------
  549. - nothing now
  550. -- 0.26.3 Changes/Bug Fixes -----------------------------------
  551. - Rewritten JP2 loading part (based on PasJpeg2000) to be
  552. more readable (it's a bit faster too) and handled more JP2 files better:
  553. components with precisions like 12bit (not direct Imaging equivalent)
  554. are properly scaled, images/components with offsets are loaded ok.
  555. -- 0.24.3 Changes/Bug Fixes -----------------------------------
  556. - Alpha channels are now saved properly in FPC (GCC optimization issue),
  557. FPC lossy compression enabled again!
  558. - Added handling of component types (CDEF Box), JP2 images with alpha
  559. are now properly recognized by other applications.
  560. - Fixed wrong color space when saving grayscale images
  561. -- 0.21 Changes/Bug Fixes -----------------------------------
  562. - Removed ifGray32 from supported formats, OpenJPEG crashes when saving them.
  563. - Added Seek after loading to set input pos to the end of image.
  564. - Saving added losy/lossless, quality option added.
  565. - Initial loading-only version created.
  566. }
  567. end.