| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643 |
- {
- Vampyre Imaging Library
- by Marek Mauder
- https://github.com/galfar/imaginglib
- https://imaginglib.sourceforge.io
- - - - - -
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at https://mozilla.org/MPL/2.0.
- }
- { This unit contains image format loader/saver for Jpeg 2000 images.}
- unit ImagingJpeg2000;
- {$I ImagingOptions.inc}
- interface
- {
- JPEG2000 support needs precompiled C object files and only some targets are
- available.
- Delphi targets: Windows 32b
- FPC targets: Windows 32b, Linux 32+64b, OSX 32b
- }
- {$IF (Defined(DCC) and Defined(MSWINDOWS) and Defined(CPUX86)) or
- (Defined(FPC) and Defined(MSWINDOWS) and Defined(CPUX86)) or
- (Defined(FPC) and Defined(LINUX) and (Defined(CPUX86) or Defined(CPUX64))) or
- (Defined(FPC) and Defined(MACOS) and Defined(CPUX86))}
- uses
- SysUtils, ImagingTypes, Imaging, ImagingColors, ImagingIO, ImagingUtility,
- ImagingExtFileFormats, OpenJpeg;
- type
- { Type Jpeg 2000 file (needed for OpenJPEG codec settings).}
- TJpeg2000FileType = (jtInvalid, jtJP2, jtJ2K, jtJPT);
- { Class for loading/saving Jpeg 2000 images. It uses OpenJPEG library
- compiled to object files and linked to Object Pascal program. Jpeg 2000
- supports wide variety of data formats. You can have arbitrary number
- of components/channels, each with different bitdepth and optional
- "signedness". Jpeg 2000 images can be lossy or lossless compressed.
- Imaging can load most data formats (except images
- with component bitdepth > 16 => no Imaging data format equivalents).
- Components with sample separation are loaded correctly, ICC profiles
- or palettes are not used, YCbCr images are translated to RGB.
- You can set various options when saving Jpeg-2000 images. Look at
- properties of TJpeg2000FileFormat for details.}
- TJpeg2000FileFormat = class(TImageFileFormat)
- private
- FQuality: LongInt;
- FCodeStreamOnly: LongBool;
- FLosslessCompression: LongBool;
- FScaleOutput: LongBool;
- function GetFileType(Handle: TImagingHandle): TJpeg2000FileType;
- protected
- procedure Define; override;
- function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
- OnlyFirstLevel: Boolean): Boolean; override;
- function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
- Index: LongInt): Boolean; override;
- procedure ConvertToSupported(var Image: TImageData;
- const Info: TImageFormatInfo); override;
- public
- function TestFormat(Handle: TImagingHandle): Boolean; override;
- procedure CheckOptionsValidity; override;
- published
- { Controls JPEG 2000 lossy compression quality. It is number in range 1..100.
- 1 means small/ugly file, 100 means large/nice file. Accessible trough
- ImagingJpeg2000Quality option. Default value is 80.}
- property Quality: LongInt read FQuality write FQuality;
- { Controls whether JPEG 2000 image is saved with full file headers or just
- as code stream. Default value is False. Accessible trough
- ImagingJpeg2000CodeStreamOnly option.}
- property CodeStreamOnly: LongBool read FCodeStreamOnly write FCodeStreamOnly;
- { Specifies JPEG 2000 image compression type. If True, saved JPEG 2000 files
- will be losslessly compressed. Otherwise lossy compression is used.
- Default value is False. Accessible trough
- ImagingJpeg2000LosslessCompression option.}
- property LosslessCompression: LongBool read FLosslessCompression write FLosslessCompression;
- { Specifies JPEG 2000 output scaling. Since JPEG 2000 supports arbitrary Bit Depths,
- the default behaviour is to scale the images up tp the next 8^n bit depth.
- This can be disabled by setting this option to False.
- Default value is True. Accessible through
- ImagingJpeg2000ScaleOutput option.}
- property ScaleOutput: LongBool read FScaleOutput write FScaleOutput;
- end;
- implementation
- const
- SJpeg2000FormatName = 'JPEG 2000 Image';
- SJpeg2000Masks = '*.jp2,*.j2k,*.j2c,*.jpx,*.jpc';
- Jpeg2000SupportedFormats: TImageFormats = [ifGray8, ifGray16,
- ifA8Gray8, ifA16Gray16, ifR8G8B8, ifR16G16B16, ifA8R8G8B8, ifA16R16G16B16];
- Jpeg2000DefaultQuality = 80;
- Jpeg2000DefaultCodeStreamOnly = False;
- Jpeg2000DefaultLosslessCompression = False;
- Jpeg2000DefaultScaleOutput = True;
- const
- JP2Signature: TChar8 = #0#0#0#$0C#$6A#$50#$20#$20;
- J2KSignature: TChar4 = #$FF#$4F#$FF#$51;
- procedure TJpeg2000FileFormat.Define;
- begin
- inherited;
- FName := SJpeg2000FormatName;
- FFeatures := [ffLoad, ffSave];
- FSupportedFormats := Jpeg2000SupportedFormats;
- FQuality := Jpeg2000DefaultQuality;
- FCodeStreamOnly := Jpeg2000DefaultCodeStreamOnly;
- FLosslessCompression := Jpeg2000DefaultLosslessCompression;
- FScaleOutput := Jpeg2000DefaultScaleOutput;
- AddMasks(SJpeg2000Masks);
- RegisterOption(ImagingJpeg2000Quality, @FQuality);
- RegisterOption(ImagingJpeg2000CodeStreamOnly, @FCodeStreamOnly);
- RegisterOption(ImagingJpeg2000LosslessCompression, @FLosslessCompression);
- RegisterOption(ImagingJpeg2000ScaleOutput, @FScaleOutput);
- end;
- procedure TJpeg2000FileFormat.CheckOptionsValidity;
- begin
- // Check if option values are valid
- if not (FQuality in [1..100]) then
- FQuality := Jpeg2000DefaultQuality;
- end;
- function TJpeg2000FileFormat.GetFileType(Handle: TImagingHandle): TJpeg2000FileType;
- var
- ReadCount: LongInt;
- Id: TChar8;
- begin
- Result := jtInvalid;
- with GetIO do
- begin
- ReadCount := Read(Handle, @Id, SizeOf(Id));
- if ReadCount = SizeOf(Id) then
- begin
- // Check if we have full JP2 file format or just J2K code stream
- if CompareMem(@Id, @JP2Signature, SizeOf(JP2Signature)) then
- Result := jtJP2
- else if CompareMem(@Id, @J2KSignature, SizeOf(J2KSignature)) then
- Result := jtJ2K;
- end;
- Seek(Handle, -ReadCount, smFromCurrent);
- end;
- end;
- function TJpeg2000FileFormat.LoadData(Handle: TImagingHandle;
- var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
- type
- TChannelInfo = record
- DestOffset: Integer;
- CompType: OPJ_COMPONENT_TYPE;
- Shift: Integer;
- SrcMaxValue: Integer;
- DestMaxValue: Integer;
- end;
- var
- FileType: TJpeg2000FileType;
- Buffer: PByte;
- BufferSize, ChannelSize, I: Integer;
- Info: TImageFormatInfo;
- dinfo: popj_dinfo_t;
- parameters: opj_dparameters_t;
- cio: popj_cio_t;
- image: popj_image_t;
- StartPos: Int64;
- Channels: array of TChannelInfo;
- procedure WriteSample(Dest: PByte; ChannelSize, Value: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF}
- begin
- case ChannelSize of
- 1: Dest^ := Value;
- 2: PWord(Dest)^ := Value;
- 4: PUInt32(Dest)^ := Value;
- end;
- end;
- procedure CopySample(Src, Dest: PByte; ChannelSize: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF}
- begin
- case ChannelSize of
- 1: Dest^ := Src^;
- 2: PWord(Dest)^ := PWord(Src)^;
- 4: PUInt32(Dest)^ := PUInt32(Src)^;
- end;
- end;
- procedure ReadChannel(const Image: TImageData; const Info: TChannelInfo; const Comp: opj_image_comp; BytesPerPixel: Integer);
- var
- X, Y, SX, SY, SrcIdx, LineBytes: Integer;
- DestPtr, NewPtr, LineUpPtr: PByte;
- DontScaleSamples: Boolean;
- begin
- DontScaleSamples := (Info.SrcMaxValue = Info.DestMaxValue) or not FScaleOutput;
- LineBytes := Image.Width * BytesPerPixel;
- DestPtr := @PByteArray(Image.Bits)[Info.DestOffset];
- SrcIdx := 0;
- if (Comp.dx = 1) and (Comp.dy = 1) then
- begin
- // X and Y sample separation is 1 so just need to assign component values
- // to image pixels one by one
- for Y := 0 to Image.Height * Image.Width - 1 do
- begin
- if DontScaleSamples then
- WriteSample(DestPtr, ChannelSize, Comp.data[SrcIdx] + Info.Shift)
- else
- WriteSample(DestPtr, ChannelSize, MulDiv(Comp.data[SrcIdx] + Info.Shift, Info.DestMaxValue, Info.SrcMaxValue));
- Inc(SrcIdx);
- Inc(DestPtr, BytesPerPixel);
- end;
- end
- else
- begin
- // Sample separation is active - component is sub-sampled. Real component
- // dimensions are [Comp.w * Comp.dx, Comp.h * Comp.dy]
- for Y := 0 to Comp.h - 1 do
- begin
- LineUpPtr := @PByteArray(Image.Bits)[Y * Comp.dy * LineBytes + Info.DestOffset];
- DestPtr := LineUpPtr;
- for X := 0 to Comp.w - 1 do
- begin
- if DontScaleSamples then
- WriteSample(DestPtr, ChannelSize, Comp.data[SrcIdx] + Info.Shift)
- else
- WriteSample(DestPtr, ChannelSize, MulDiv(Comp.data[SrcIdx] + Info.Shift, Info.DestMaxValue, Info.SrcMaxValue));
- NewPtr := DestPtr;
- for SX := 1 to Comp.dx - 1 do
- begin
- if X * Comp.dx + SX >= Image.Width then Break;
- // Replicate pixels on line
- Inc(NewPtr, BytesPerPixel);
- CopySample(DestPtr, NewPtr, ChannelSize);
- end;
- Inc(SrcIdx);
- Inc(DestPtr, BytesPerPixel * Comp.dx);
- end;
- for SY := 1 to Comp.dy - 1 do
- begin
- if Y * Comp.dy + SY >= Image.Height then Break;
- // Replicate line
- NewPtr := @PByteArray(Image.Bits)[(Y * Comp.dy + SY) * LineBytes + Info.DestOffset];
- for X := 0 to Image.Width - 1 do
- begin
- CopySample(LineUpPtr, NewPtr, ChannelSize);
- Inc(LineUpPtr, BytesPerPixel);
- Inc(NewPtr, BytesPerPixel);
- end;
- end;
- end;
- end;
- end;
- procedure ConvertYCbCrToRGB(Pixels: PByte; NumPixels, BytesPerPixel: Integer);
- var
- I: Integer;
- PixPtr: PByte;
- CY, CB, CR: Byte;
- CYW, CBW, CRW: Word;
- begin
- PixPtr := Pixels;
- for I := 0 to NumPixels - 1 do
- begin
- if BytesPerPixel in [3, 4] then
- with PColor24Rec(PixPtr)^ do
- begin
- CY := R;
- CB := G;
- CR := B;
- YCbCrToRGB(CY, CB, CR, R, G, B);
- end
- else
- with PColor48Rec(PixPtr)^ do
- begin
- CYW := R;
- CBW := G;
- CRW := B;
- YCbCrToRGB16(CYW, CBW, CRW, R, G, B);
- end;
- Inc(PixPtr, BytesPerPixel);
- end;
- end;
- begin
- Result := False;
- image := nil;
- cio := nil;
- opj_set_default_decoder_parameters(@parameters);
- // Determine which codec to use
- FileType := GetFileType(Handle);
- case FileType of
- jtJP2: dinfo := opj_create_decompress(CODEC_JP2);
- jtJ2K: dinfo := opj_create_decompress(CODEC_J2K);
- jtJPT: dinfo := opj_create_decompress(CODEC_JPT);
- else
- Exit;
- end;
- // Set event manager to nil to avoid getting messages
- dinfo.event_mgr := nil;
- // Currently OpenJPEG can load images only from memory so we have to
- // preload whole input to mem buffer. Not good but no other way now.
- // At least we set stream pos to end of JP2 data after loading (we will now
- // the exact size by then).
- StartPos := GetIO.Tell(Handle);
- BufferSize := ImagingIO.GetInputSize(GetIO, Handle);
- GetMem(Buffer, BufferSize);
- SetLength(Images, 1);
- with GetIO, Images[0] do
- try
- Read(Handle, Buffer, BufferSize);
- cio := opj_cio_open(opj_common_ptr(dinfo), Buffer, BufferSize);
- opj_setup_decoder(dinfo, @parameters);
- // Decode image
- image := opj_decode(dinfo, cio);
- if image = nil then
- Exit;
- // Determine which Imaging data format to use according to
- // decoded image components
- case image.numcomps of
- 2: case image.comps[0].prec of
- 1..8: Format := ifA8Gray8;
- 9..16: Format := ifA16Gray16;
- end;
- 3: case image.comps[0].prec of
- 1..8: Format := ifR8G8B8;
- 9..16: Format := ifR16G16B16;
- end;
- 4: case image.comps[0].prec of
- 1..8: Format := ifA8R8G8B8;
- 9..16: Format := ifA16R16G16B16;
- end;
- else
- // There is only one component or there is more than four =>
- // just load the first one as gray
- case image.comps[0].prec of
- 1..8: Format := ifGray8;
- 9..16: Format := ifGray16;
- 17..32: Format := ifGray32;
- end;
- end;
- // Exit if no compatible format was found
- if Format = ifUnknown then
- Exit;
- NewImage(image.x1 - image.x0, image.y1 - image.y0, Format, Images[0]);
- Info := GetFormatInfo(Format);
- ChannelSize := Info.BytesPerPixel div Info.ChannelCount;
- SetLength(Channels, Info.ChannelCount);
- // Get information about all channels/components of JP2 file
- for I := 0 to Info.ChannelCount - 1 do
- begin
- // Get component type for this channel and based on this
- // determine where in dest image bits write this channel's data
- Channels[I].CompType := image.comps[I].comp_type;
- case Channels[I].CompType of
- COMPTYPE_UNKNOWN:
- begin
- if Info.ChannelCount <> 4 then
- begin
- // Missing CDEF box in file - usually BGR order
- Channels[I].DestOffset := image.numcomps - I - 1
- end
- else
- begin
- // Missing CDEF box in file - usually ABGR order
- if I = 3 then
- Channels[I].DestOffset := 3
- else
- Channels[I].DestOffset := image.numcomps - I - 2
- end;
- end;
- COMPTYPE_R: Channels[I].DestOffset := 2;
- COMPTYPE_G: Channels[I].DestOffset := 1;
- COMPTYPE_B: Channels[I].DestOffset := 0;
- COMPTYPE_CB: Channels[I].DestOffset := 1;
- COMPTYPE_CR: Channels[I].DestOffset := 0;
- COMPTYPE_OPACITY: Channels[I].DestOffset := 3;
- COMPTYPE_Y:
- case image.color_space of
- CLRSPC_SYCC: Channels[I].DestOffset := 2; // Y is intensity part of YCC
- CLRSPC_GRAY: Channels[I].DestOffset := 0; // Y is independent gray channel
- end;
- end;
- // Scale channel offset
- Channels[I].DestOffset := Channels[I].DestOffset * ChannelSize;
- // Signed componets must be scaled to [0, 1] interval (depends on precision)
- if image.comps[I].sgnd = 1 then
- Channels[I].Shift := 1 shl (image.comps[I].prec - 1);
- // Max channel values used to easier scaling of precisions
- // not supported by Imaging to supported ones (like 12bits etc.).
- Channels[I].SrcMaxValue := 1 shl image.comps[I].prec - 1;
- Channels[I].DestMaxValue := 1 shl (ChannelSize * 8) - 1;
- end;
- // Images components are stored separately in JP2, each can have
- // different dimensions, bitdepth, ...
- for I := 0 to Info.ChannelCount - 1 do
- ReadChannel(Images[0], Channels[I], image.comps[I], Info.BytesPerPixel);
- // If we have YCbCr image we need to convert it to RGB
- if (image.color_space = CLRSPC_SYCC) and (Info.ChannelCount in [3, 4]) then
- ConvertYCbCrToRGB(Bits, Width * Height, Info.BytesPerPixel);
- // Set the input position just after end of image
- Seek(Handle, StartPos + Cardinal(cio.bp) - Cardinal(cio.start), smFromBeginning);
- Result := True;
- finally
- opj_image_destroy(image);
- opj_destroy_decompress(dinfo);
- opj_cio_close(cio);
- FreeMem(Buffer);
- end;
- end;
- function TJpeg2000FileFormat.SaveData(Handle: TImagingHandle;
- const Images: TDynImageDataArray; Index: LongInt): Boolean;
- var
- TargetSize, Rate: Single;
- ImageToSave: TImageData;
- MustBeFreed: Boolean;
- Info: TImageFormatInfo;
- I, Z, InvZ, Channel, ChannelSize, NumPixels: Integer;
- Pix: PByte;
- image: popj_image_t;
- cio: popj_cio_t;
- cinfo: popj_cinfo_t;
- parameters: opj_cparameters_t;
- compparams: popj_image_cmptparm_array;
- ColorSpace: OPJ_COLOR_SPACE;
- function GetComponentType(Comp: Integer): OPJ_COMPONENT_TYPE;
- begin
- if Info.HasAlphaChannel and (Comp = Info.ChannelCount - 1) then
- Result := COMPTYPE_OPACITY
- else if Info.HasGrayChannel then
- Result := COMPTYPE_Y
- else if Comp = 2 then
- Result := COMPTYPE_B
- else if Comp = 1 then
- Result := COMPTYPE_G
- else if Comp = 0 then
- Result := COMPTYPE_R
- else
- Result := COMPTYPE_UNKNOWN;
- end;
- begin
- Result := False;
- image := nil;
- compparams := nil;
- cinfo := nil;
- cio := nil;
- // Makes image to save compatible with Jpeg 2000 saving capabilities
- if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then
- with GetIO, ImageToSave do
- try
- Info := GetFormatInfo(Format);
- ChannelSize := Info.BytesPerPixel div Info.ChannelCount;
- // Fill component info structures and then create OpenJPEG image
- GetMem(compparams, Info.ChannelCount * SizeOf(opj_image_comptparm));
- for I := 0 to Info.ChannelCount - 1 do
- with compparams[I] do
- begin
- dx := 1;
- dy := 1;
- w := Width;
- h := Height;
- prec := (Info.BytesPerPixel div Info.ChannelCount) * 8;
- bpp := prec;
- sgnd := 0;
- comp_type := GetComponentType(I);
- x0 := 0;
- y0 := 0;
- end;
- if Info.HasGrayChannel then
- ColorSpace := CLRSPC_GRAY
- else
- ColorSpace := CLRSPC_SRGB;
- image := opj_image_create(Info.ChannelCount, @compparams[0], ColorSpace);
- if image = nil then Exit;
- image.x1 := Width;
- image.y1 := Height;
- if FCodeStreamOnly then
- cinfo := opj_create_compress(CODEC_J2K)
- else
- cinfo := opj_create_compress(CODEC_JP2);
- // Set event manager to nil to avoid getting messages
- cinfo.event_mgr := nil;
- // Set compression parameters based current file format properties
- opj_set_default_encoder_parameters(@parameters);
- parameters.cod_format := Iff(FCodeStreamOnly, 0, 1);
- parameters.numresolution := 6;
- parameters.tcp_numlayers := 1;
- parameters.cp_disto_alloc := 1;
- if FLosslessCompression then
- begin
- // Set rate to 0 -> lossless
- parameters.tcp_rates[0] := 0;
- end
- else
- begin
- // Quality -> Rate computation taken from ImageMagick
- Rate := 100.0 / Sqr(115 - FQuality);
- NumPixels := Width * Height * Info.BytesPerPixel;
- TargetSize := (NumPixels * Rate) + 550 + (Info.ChannelCount - 1) * 142;
- parameters.tcp_rates[0] := 1.0 / (TargetSize / NumPixels);
- end;
- // Setup encoder
- opj_setup_encoder(cinfo, @parameters, image);
- // Fill component samples in data with values taken from
- // image pixels.
- // Components should be ordered like this: RGBA, YA, RGB, etc.
- for Channel := 0 to Info.ChannelCount - 1 do
- begin
- Z := Channel;
- InvZ := Info.ChannelCount - 1 - Z;
- if Info.HasAlphaChannel then
- begin
- if Channel = Info.ChannelCount - 1 then
- InvZ := Z
- else
- InvZ := Info.ChannelCount - 2 - Z;
- end;
- Pix := @PByteArray(Bits)[InvZ * ChannelSize];
- for I := 0 to Width * Height - 1 do
- begin
- case ChannelSize of
- 1: image.comps[Z].data[I] := Pix^;
- 2: image.comps[Z].data[I] := PWord(Pix)^;
- 4: UInt32(image.comps[Z].data[I]) := PUInt32(Pix)^;
- end;
- Inc(Pix, Info.BytesPerPixel);
- end;
- end;
- // Open OpenJPEG output
- cio := opj_cio_open(opj_common_ptr(cinfo), nil, 0);
- // Try to encode the image
- if not opj_encode(cinfo, cio, image, nil) then
- Exit;
- // Finally write buffer with encoded image to output
- Write(Handle, cio.buffer, cio_tell(cio));
- Result := True;
- finally
- if MustBeFreed then
- FreeImage(ImageToSave);
- opj_destroy_compress(cinfo);
- opj_image_destroy(image);
- opj_cio_close(cio);
- FreeMem(compparams);
- end;
- end;
- procedure TJpeg2000FileFormat.ConvertToSupported(var Image: TImageData;
- const Info: TImageFormatInfo);
- var
- ConvFormat: TImageFormat;
- begin
- if Info.IsFloatingPoint then
- ConvFormat := IffFormat(Info.ChannelCount = 1, ifGray16, ifA16R16G16B16)
- else if Info.HasGrayChannel then
- ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16Gray16, ifGray16)
- else if Info.IsIndexed then
- ConvFormat := ifA8R8G8B8
- else if Info.BytesPerPixel div Info.ChannelCount > 1 then
- ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16R16G16B16, ifR16G16B16)
- else
- ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8);
- ConvertImage(Image, ConvFormat);
- end;
- function TJpeg2000FileFormat.TestFormat(Handle: TImagingHandle): Boolean;
- begin
- Result := False;
- if Handle <> nil then
- Result := GetFileType(Handle) <> jtInvalid;
- end;
- initialization
- RegisterImageFileFormat(TJpeg2000FileFormat);
- {$ELSE}
- implementation
- begin
- {$IFEND}
- {
- File Notes:
- -- TODOS ----------------------------------------------------
- - nothing now
- -- 0.27 Changes ---------------------------------------------
- - by Hanno Hugenberg <[email protected]>
- - introduced the ImagingJpeg2000ScaleOutput parameter for keeping
- the original decoded images by avoiding upscaling of output images
- -- 0.26.3 Changes/Bug Fixes -----------------------------------
- - Rewritten JP2 loading part (based on PasJpeg2000) to be
- more readable (it's a bit faster too) and handled more JP2 files better:
- components with precisions like 12bit (not direct Imaging equivalent)
- are properly scaled, images/components with offsets are loaded ok.
- -- 0.24.3 Changes/Bug Fixes -----------------------------------
- - Alpha channels are now saved properly in FPC (GCC optimization issue),
- FPC lossy compression enabled again!
- - Added handling of component types (CDEF Box), JP2 images with alpha
- are now properly recognized by other applications.
- - Fixed wrong color space when saving grayscale images
- -- 0.21 Changes/Bug Fixes -----------------------------------
- - Removed ifGray32 from supported formats, OpenJPEG crashes when saving them.
- - Added Seek after loading to set input pos to the end of image.
- - Saving added lossy/lossless, quality option added.
- - Initial loading-only version created.
- }
- end.
|