(* ImageEn Build 7.0.0.06.2637 @ 7-4-17 14:58:42.679 *) (* Copyright (c) 1998-2017 by Carlotta Calandra. All rights reserved. Copyright (c) 2011-2017 by Xequte Software. This software comes without express or implied warranty. In no case shall the author be liable for any damage or unwanted behavior of any computer hardware and/or software. Author grants you the right to include the component in your application, whether COMMERCIAL, SHAREWARE, or FREEWARE. ImageEn, IEvolution and ImageEn ActiveX may not be included in any commercial, shareware or freeware libraries or components. www.ImageEn.com *) (* File version 1010 *) unit iej2000; {$R-} {$Q-} {$I ie.inc} {$ifdef IEINCLUDEJPEG2000} interface uses Windows, Graphics, Classes, SysUtils, ImageEnIO, hyiedefs, iexBitmaps; {$ifndef IEUSEDLLJPEG2000LIB} var __turboFloat: LongBool = False; {$endif} function J2KTryStreamJP2(Stream: TStream): boolean; function J2KTryStreamJ2K(Stream: TStream): boolean; procedure J2KReadStream(Stream: TStream; Bitmap: TIEBitmap; var IOParams: TIOParams; var xProgress: TProgressRec; Preview: boolean); procedure J2KWriteStream(Stream: TStream; Bitmap: TIEBitmap; var IOParams: TIOParams; var xProgress: TProgressRec; format: integer); procedure IEFinalize_iej2000; type EIEJPEG2000Exception = class(Exception); implementation uses ieview, imageenproc, ievision, iesettings, hyieutils; const IEJAS_IMAGE_CS_UNKNOWN = 0; IEJAS_IMAGE_CS_GRAY = 1; // Standard Gray IEJAS_IMAGE_CS_RGB = 2; // Standard RGB IEJAS_IMAGE_CS_YCBCR = 3; // Standard YCC IEJAS_IMAGE_CT_RGB_R = 0; IEJAS_IMAGE_CT_RGB_G = 1; IEJAS_IMAGE_CT_RGB_B = 2; IEJAS_IMAGE_CT_YCBCR_Y = 0; IEJAS_IMAGE_CT_YCBCR_CB = 1; IEJAS_IMAGE_CT_YCBCR_CR = 2; IEJAS_IMAGE_CT_GRAY_Y = 0; IEJAS_IMAGE_CT_OPACITY = $8000; procedure IEInitialize_iej2000; forward; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // static Jasper library wrappers {$ifndef IEUSEDLLJPEG2000LIB} {$RANGECHECKS OFF} {$Z4} type pjas_stream_t = pointer; pjas_image_t = pointer; pjas_matrix_t = pointer; jas_image_cmptparm_t = record tlx: dword; //* The x-coordinate of the top-left corner of the component. */ tly: dword; //* The y-coordinate of the top-left corner of the component. */ hstep: dword; //* The horizontal sampling period in units of the reference grid. */ vstep: dword; //* The vertical sampling period in units of the reference grid. */ width: dword; //* The width of the component in samples. */ height: dword; //* The height of the component in samples. */ prec: word; //* The precision of the component sample data. */ sgnd: integer; //* The signedness of the component sample data. */ end; pjas_image_cmptparm_t = ^jas_image_cmptparm_t; jas_image_cmptparm_t_array = array[0..8192] of jas_image_cmptparm_t; pjas_image_cmptparm_t_array = ^jas_image_cmptparm_t_array; /////// from jas // initialization procedure jas_init; external; // streams function jas_stream_fopen(filename, omode: PAnsiChar): pjas_stream_t; external; procedure jas_stream_close(jstream: pjas_stream_t); external; procedure jas_stream_flush(jstream: pjas_stream_t); external; // Get the format of image data in a stream. function jas_image_getfmt(jstream: pjas_stream_t): integer; external; // Create an image from a stream in some specified format. function jas_image_decode(jstream: pjas_stream_t; infmt: integer; inopts: PAnsiChar): pjas_image_t; external; // Write an image to a stream in a specified format. function jas_image_encode(image: pjas_image_t; jstream: pjas_stream_t; fmt: integer; optstr: PAnsiChar): integer; external; // Delete a component from an image. procedure jas_image_delcmpt(image: pjas_image_t; i: word); external; // Read a rectangular region of an image component. // The position and size of the rectangular region to be read is specified // relative to the component's coordinate system. function jas_image_readcmpt(image: pjas_image_t; cmptno: word; x, y, width, height: integer; data: pjas_matrix_t): integer; external; // matrix (components) function jas_matrix_create(numrows, numcols: integer): pjas_matrix_t; external; procedure jas_matrix_destroy(matrix: pjas_matrix_t); external; // Deallocate any resources associated with an image. procedure jas_image_destroy(image: pjas_image_t); external; // Clear the table of image formats. procedure jas_image_clearfmts; external; // Get the ID for the image format with the specified name. function jas_image_strtofmt(s: PAnsiChar): integer; external; // Get the name of the image format with the specified ID. function jas_image_fmttostr(fmt: integer): PAnsiChar; external; // Create an image. function jas_image_create(numcmpts: word; cmptparms: pjas_image_cmptparm_t_array; colormodel: integer): pjas_image_t; external; function jas_image_create0: pjas_image_t; external; function jas_image_addcmpt(image: pjas_image_t; cmptno: word; cmptparm: pjas_image_cmptparm_t): integer; external; function jas_image_getcmptbytype(image: pjas_image_t; ctype: integer): integer; external; function jas_getdbglevel: integer; external; function jas_setdbglevel(dbglevel: integer): integer; external; procedure jas_image_writecmptsample(image: pjas_image_t; cmptno: integer; x, y: integer; v: dword); external; procedure iejas_image_setcmpttype(image: pjas_image_t; cmptno: integer; ctype: integer); external; //// end from jas //// from xlib // [IMAGE] Get the number of image components. function iejas_image_numcmpts(image: pjas_image_t): integer; external; // [IMAGE] The x-coordinate of the top-left corner of the image bounding box. function iejas_image_getleft(image: pjas_image_t): integer; external; // [IMAGE] The y-coordinate of the top-left corner of the image bounding box. function iejas_image_gettop(image: pjas_image_t): integer; external; // [IMAGE] The x-coordinate of the bottom-right corner of the image bounding box (plus one). function iejas_image_getright(image: pjas_image_t): integer; external; // [IMAGE] The y-coordinate of the bottom-right corner of the image bounding box (plus one). function iejas_image_getbottom(image: pjas_image_t): integer; external; // [MATRIX] get i,j value of the function iejas_matrix_get(matrix: pjas_matrix_t; i, j: integer): integer; external; // [IMAGE] Get the width of a component. function iejas_image_cmptwidth(image: pjas_image_t; compno: integer): integer; external; // [IMAGE] Get the height of a component. function iejas_image_cmptheight(image: pjas_image_t; compno: integer): integer; external; // [IMAGE] Get the precision of the sample data for a component. function iejas_image_cmptprec(image: pjas_image_t; compno: integer): integer; external; // [IMAGE] Get the width of the image in units of the image reference grid. function iejas_image_width(image: pjas_image_t): integer; external; // [IMAGE] Get the height of the image in units of the image reference grid. function iejas_image_height(image: pjas_image_t): integer; external; // [IMAGE] Get the color model used by the image. function iejas_image_colorspace(image: pjas_image_t): integer; external; procedure iejas_image_setcolorspace(image: pjas_image_t; colorspace: integer); external; // [IMAGE] Get the x-coordinate of the top-left corner of a component. function iejas_image_cmpttlx(image: pjas_image_t; cmptno: integer): integer; external; // [IMAGE] Get the y-coordinate of the top-left corner of a component. function iejas_image_cmpttly(image: pjas_image_t; cmptno: integer): integer; external; // [IMAGE] Get the horizontal subsampling factor for a component function iejas_image_cmpthstep(image: pjas_image_t; cmptno: integer): integer; external; // [IMAGE] Get the vertical subsampling factor for a component. function iejas_image_cmptvstep(image: pjas_image_t; cmptno: integer): integer; external; ///// end xlib // color spaces const JPC_NUMAGGCTXS = 1; JPC_NUMZCCTXS = 9; JPC_NUMMAGCTXS = 3; JPC_NUMSCCTXS = 5; JPC_NUMUCTXS = 1; JPC_AGGCTXNO = 0; JPC_ZCCTXNO = (JPC_AGGCTXNO + JPC_NUMAGGCTXS); JPC_MAGCTXNO = (JPC_ZCCTXNO + JPC_NUMZCCTXS); JPC_SCCTXNO = (JPC_MAGCTXNO + JPC_NUMMAGCTXS); JPC_UCTXNO = (JPC_SCCTXNO + JPC_NUMSCCTXS); JPC_NUMCTXS = (JPC_UCTXNO + JPC_NUMUCTXS); var _jpc_zcctxnolut: array[0..4 * 256] of integer; _jpc_spblut: array[0..256] of integer; _jpc_scctxnolut: array[0..256] of integer; _jpc_magctxnolut: array[0..4096] of integer; _jpc_signmsedec: array[0..128] of integer; _jpc_refnmsedec: array[0..128] of integer; _jpc_signmsedec0: array[0..128] of integer; _jpc_refnmsedec0: array[0..128] of integer; _jpc_mqctxs: array[0..JPC_NUMCTXS] of integer; /////////////////////////////////////////////////////// function _malloc(size: Integer): Pointer; cdecl; begin result := allocmem(size); end; procedure _free(P: Pointer); cdecl; begin FreeMem(P); end; function _memset(P: Pointer; B: Byte; count: Integer): pointer; cdecl; begin FillChar(P^, count, B); result := P; end; function _memcpy(dest, source: Pointer; count: Integer): pointer; cdecl; begin Move(source^, dest^, count); result := dest; end; function __ftol: integer; var f: double; begin asm lea eax, f // BC++ passes floats on the FPU stack fstp qword ptr [eax] // Delphi passes floats on the CPU stack end; if f > 2147483647.0 then f := 2147483647.0; if f < -2147483648.0 then f := 2147483648.0; result := integer(Trunc(f)); end; procedure __assert(__cond: PAnsiChar; __file: PAnsiChar; __line: integer); cdecl; begin end; procedure _abort; cdecl; begin end; procedure _iejdebug(p: PAnsiChar); cdecl; begin // //outputdebugstring(p); end; function _memmove(dest, source: Pointer; count: Integer): pointer; cdecl; begin Move(source^, dest^, count); result := dest; end; function _strlen(str: PAnsiChar): integer; cdecl; begin result := IEStrLen(str); end; function _realloc(block: pointer; size: integer): pointer; cdecl; begin reallocmem(block, size); result := block; end; function _fscanf(f: pointer; format: PAnsiChar): integer; cdecl; begin result := 0; end; // not used in Jasper procedure _unlink; cdecl; begin end; // not used in Jasper procedure _setmode; cdecl; begin end; // not used in Jasper procedure _fputc; cdecl; begin end; type TIETmpStream = class(TMemoryStream) public constructor Create; destructor Destroy; override; end; constructor TIETmpStream.Create; begin inherited Create; end; destructor TIETmPStream.Destroy; begin inherited; end; function _open(path: PAnsiChar; access, mode: integer): integer; cdecl; begin if path = 'TEMPSTREAM' then result := integer(TIETmpStream.Create) else result := integer(path); end; function _read(stream: integer; buf: pointer; len: integer): integer; cdecl; var st: TStream; begin st := TStream(pointer(stream)); result := st.Read(pbyte(buf)^, len); end; function _close(stream: integer): integer; cdecl; var st: tstream; begin result := 0; st := TStream(pointer(stream)); if (st is TIETmpStream) then begin FreeAndNil(st); end; end; function _write(stream: integer; buf: pointer; len: integer): integer; cdecl; var st: tstream; begin st := TStream(pointer(stream)); result := st.Write(pbyte(buf)^, len); end; function _lseek(stream: integer; offset: integer; fromwhere: integer): integer; cdecl; var st: tstream; begin st := TStream(pointer(stream)); case fromwhere of 0: // SEEK_SET result := st.Seek(offset, soBeginning); 1: // SEEK_CUR result := st.Seek(offset, soCurrent); 2: // SEEK_END result := st.Seek(offset, soEnd); else result := -1; end; end; // we suppose that s is not null function _tmpnam(s: PAnsiChar): PAnsiChar; cdecl; begin result := s; IEStrPCopy(s, 'TEMPSTREAM'); end; // used only for stdio io procedure _fread; cdecl; begin end; // used only for stdio io function _fwrite(buf: PAnsiChar; size, n: integer; fil: pointer): integer; cdecl; begin result := size * n; end; // used only for stdio io procedure _fseek; cdecl; begin end; // used only for stdio io procedure _fclose; cdecl; begin end; function _isspace(c: integer): integer; cdecl; begin result := integer(c <= 32); end; function _isalpha(c: integer): integer; cdecl; begin result := integer(((c >= 65) and (c <= 90)) or ((c >= 97) and (c <= 122)) or (c = 95)); end; function _isdigit(c: integer): integer; cdecl; begin result := integer((c >= 48) and (c <= 57)); end; function _atol(s: PAnsiChar): integer; cdecl; begin result := IEStrToIntDef(s, 0); end; function _strchr(s: PAnsiChar; c: integer): PAnsiChar; cdecl; begin result := IEStrScan(s, AnsiChar(c)); end; function _atof(s: PAnsiChar): double; cdecl; var q: AnsiString; p1: integer; begin q := AnsiString(s); p1 := IEPos(' ', q); if p1 = 0 then p1 := length(q) + 1; setlength(q, p1 - 1); result := IEStrToFloatDefA(q, 0); end; function _sqrt(x: double): double; cdecl; begin result := sqrt(x); end; function _strrchr(s: PAnsiChar; c: integer): PAnsiChar; cdecl; begin result := IEStrRScan(s, AnsiChar(c)); end; function _isprint(c: integer): integer; cdecl; begin result := integer(c > 31); end; function _strncpy(dest, src: PAnsiChar; maxlen: integer): PAnsiChar; cdecl; begin result := IEStrMove(dest, src, maxlen); end; procedure __llmul; asm push edx push eax mov eax, [esp+16] mul dword ptr [esp] mov ecx, eax mov eax, [esp+4] mul dword ptr [esp+12] add ecx, eax mov eax, [esp] mul dword ptr [esp+12] add edx, ecx pop ecx pop ecx ret 8 end; procedure __lldiv; asm push ebp push ebx push esi push edi xor edi,edi mov ebx,20[esp] mov ecx,24[esp] or ecx,ecx jnz @__lldiv@slow_ldiv or edx,edx jz @__lldiv@quick_ldiv or ebx,ebx jz @__lldiv@quick_ldiv @__lldiv@slow_ldiv: or edx,edx jns @__lldiv@onepos neg edx neg eax sbb edx,0 or edi,1 @__lldiv@onepos: or ecx,ecx jns @__lldiv@positive neg ecx neg ebx sbb ecx,0 xor edi,1 @__lldiv@positive: mov ebp,ecx mov ecx,64 push edi xor edi,edi xor esi,esi @__lldiv@xloop: shl eax,1 rcl edx,1 rcl esi,1 rcl edi,1 cmp edi,ebp jb @__lldiv@nosub ja @__lldiv@subtract cmp esi,ebx jb @__lldiv@nosub @__lldiv@subtract: sub esi,ebx sbb edi,ebp inc eax @__lldiv@nosub: loop @__lldiv@xloop pop ebx test ebx,1 jz @__lldiv@finish neg edx neg eax sbb edx,0 @__lldiv@finish: pop edi pop esi pop ebx pop ebp ret 8 @__lldiv@quick_ldiv: div ebx xor edx,edx jmp @__lldiv@finish end; procedure jpc_seglist_remove; external; procedure jpc_seg_destroy; external; procedure jpc_seglist_insert; external; procedure jpc_decode; external; procedure jp2_decode; external; procedure jp2_encode; external; procedure jp2_validate; external; procedure jpc_seg_alloc; external; procedure jas_stream_puts; external; {$L jp2_enc.obj} {$L jpc_enc.obj} {$L jpc_dec.obj} {$L jpc_t1dec.obj} {$L jpc_t1enc.obj} {$L jpc_t2enc.obj} {$L jpc_t2dec.obj} {$L jpc_t2cod.obj} {$L jpc_t1cod.obj} {$L jpc_tsfb.obj} {$L jpc_qmfb.obj} {$L jpc_mct.obj} {$L jpc_bs.obj} {$L jas_getopt.obj} {$L jp2_dec.obj} {$L jas_init.obj} {$L jpc_mqdec.obj} {$L jpc_mqenc.obj} {$L jpc_mqcod.obj} {$L jas_tvp.obj} {$L jp2_cod.obj} {$L jas_image.obj} {$L jpc_cs.obj} {$L jas_seq.obj} {$L jas_malloc.obj} {$L jas_stream.obj} {$L jas_string.obj} {$L jas_version.obj} {$L jpc_math.obj} {$L jpc_util.obj} {$L jpc_tagtree.obj} {$L jas_debug.obj} {$L xlibcj2.obj} ////////////////////////////////////////////////////// type IEJP2K_Image = pjas_image_t; IEJP2K_Matrix = pjas_matrix_t; IEJP2K_ComponentParamsList = array of jas_image_cmptparm_t; procedure IEJP2K_initialize(); begin jas_init(); end; procedure IEJP2K_finalize(); begin jas_image_clearfmts(); end; function IEJP2K_imageCreate(stream: TStream): IEJP2K_Image; overload; var js: pjas_stream_t; begin js := jas_stream_fopen(pointer(stream), 'rb'); try result := jas_image_decode(js, -1, nil); finally jas_stream_close(js); end; end; function IEJP2K_imageCreate(numComponents: word; parameters: IEJP2K_ComponentParamsList; colorModel: integer): IEJP2K_Image; overload; begin result := jas_image_create(numComponents, @parameters[0], colorModel); end; procedure IEJP2K_imageDestroy(var image: IEJP2K_image); begin if image <> nil then begin jas_image_destroy(image); image := nil; end; end; procedure IEJP2K_imageEncode(image: IEJP2K_image; stream: TStream; format: integer; options: string); var js: pjas_stream_t; begin js := jas_stream_fopen(pointer(Stream), 'w+b'); try jas_image_encode(image, js, format, PAnsiChar(AnsiString(options))); jas_stream_flush(js); finally jas_stream_close(js); end; end; function IEJP2K_getImageWidth(image: IEJP2K_Image): integer; begin result := iejas_image_width(image); end; function IEJP2K_getImageHeight(image: IEJP2K_Image): integer; begin result := iejas_image_height(image); end; function IEJP2K_getColorSpace(image: IEJP2K_Image): integer; begin result := iejas_image_colorspace(image); end; // note: component can be JAS_IMAGE_CT_RGB_R, etc... no need to call JAS_IMAGE_CT_COLOR function IEJP2K_getComponentByType(image: IEJP2K_Image; component: integer): integer; begin result := jas_image_getcmptbytype(image, (component and $7FFF)); end; // note: component can be JAS_IMAGE_CT_RGB_R, etc... no need to call JAS_IMAGE_CT_COLOR procedure IEJP2K_setComponentType(image: IEJP2K_Image; index: integer; component: integer); begin iejas_image_setcmpttype(image, index, (component and $7FFF)); end; function IEJP2K_getComponentPrecision(image: IEJP2K_Image; index: integer): integer; begin result := iejas_image_cmptprec(image, index); end; function IEJP2K_getNumComponents(image: IEJP2K_Image): integer; begin result := iejas_image_numcmpts(image); end; function IEJP2K_getComponentHeight(image: IEJP2K_Image; index: integer): integer; begin result := iejas_image_cmptheight(image, index); end; function IEJP2K_getComponentWidth(image: IEJP2K_Image; index: integer): integer; begin result := iejas_image_cmptwidth(image, index); end; function IEJP2K_matrixCreate(numRows: integer; numCols: integer): IEJP2K_Matrix; begin result := jas_matrix_create(numRows, numCols); end; procedure IEJP2K_matrixDestroy(var matrix: IEJP2K_Matrix); begin jas_matrix_destroy(matrix); matrix := nil; end; function IEJP2K_matrixGetValue(matrix: IEJP2K_Matrix; i: integer; j: integer): integer; begin result := iejas_matrix_get(matrix, i, j); end; function IEJP2K_readComponent(image: IEJP2K_Image; index: word; x: integer; y: integer; width: integer; height: integer; data: IEJP2K_Matrix): integer; begin result := jas_image_readcmpt(image, index, x, y, width, height, data); end; function IEJP2K_getComponentTopLeftY(image: IEJP2K_Image; index: integer): integer; begin result := iejas_image_cmpttly(image, index); end; function IEJP2K_getComponentTopLeftX(image: IEJP2K_Image; index: integer): integer; begin result := iejas_image_cmpttlx(image, index); end; function IEJP2K_getComponentVStep(image: IEJP2K_Image; index: integer): integer; begin result := iejas_image_cmptvstep(image, index); end; function IEJP2K_getComponentHStep(image: IEJP2K_Image; index: integer): integer; begin result := iejas_image_cmpthstep(image, index); end; function IEJP2K_createComponentParametersList(size: integer): IEJP2K_ComponentParamsList; begin SetLength(result, size); end; procedure IEJP2K_destroyComponentParametersList(var parameters: IEJP2K_ComponentParamsList); begin SetLength(parameters, 0); end; procedure IEJP2K_setComponentParameters(parameters: IEJP2K_ComponentParamsList; index: integer; tlx: dword; tly: dword; hstep: dword; vstep: dword; width: dword; height: dword; prec: word; sgnd: integer); begin parameters[index].tlx := tlx; parameters[index].tly := tly; parameters[index].hstep := hstep; parameters[index].vstep := vstep; parameters[index].width := width; parameters[index].height := height; parameters[index].prec := prec; parameters[index].sgnd := sgnd; end; procedure IEJP2K_writeComponentSample(image: IEJP2K_Image; index: integer; x: integer; y: integer; v: dword); begin jas_image_writecmptsample(image, index, x, y, v); end; procedure IEJP2K_writeRowRGB8(image: IEJP2K_Image; width: integer; rowIndex: integer; bgr8Array: PRGB; alphaArray: pbyte; colors: integer); var x: integer; mul: double; begin mul := colors / 255; for x := 0 to width - 1 do begin with bgr8Array^ do begin IEJP2K_writeComponentSample(image, 0, x, rowIndex, trunc(r * mul)); IEJP2K_writeComponentSample(image, 1, x, rowIndex, trunc(g * mul)); IEJP2K_writeComponentSample(image, 2, x, rowIndex, trunc(b * mul)); end; if alphaArray <> nil then begin IEJP2K_writeComponentSample(image, 3, x, rowIndex, trunc(alphaArray^ * mul)); inc(alphaArray); end; inc(bgr8Array); end; end; procedure IEJP2K_readLinearBGR8(image: IEJP2K_Image; blueMatrix: IEJP2K_Matrix; greenMatrix: IEJP2K_Matrix; redMatrix: IEJP2K_Matrix; rowIndex: integer; bluePrec: integer; greenPrec: integer; redPrec: integer; destBGR8: pbyte; width: integer); var j: integer; begin for j := 0 to width - 1 do begin destBGR8^ := (IEJP2K_matrixGetValue(blueMatrix, rowIndex, j) shl (32 - bluePrec)) shr 24; inc(destBGR8); destBGR8^ := (IEJP2K_matrixGetValue(greenMatrix, rowIndex, j) shl (32 - greenPrec)) shr 24; inc(destBGR8); destBGR8^ := (IEJP2K_matrixGetValue(redMatrix, rowIndex, j) shl (32 - redPrec)) shr 24; inc(destBGR8); end; end; {$endif} // IEUSEDLLJPEG2000LIB /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // dynamic (DLL) Jasper library wrappers {$ifdef IEUSEDLLJPEG2000LIB} type IEJP2K_Image = TIELibJP2KImage; IEJP2K_Matrix = TIELibJP2KMatrix; IEJP2K_ComponentParamsList = TIELibJP2KComponentParamsList; procedure IEJP2K_initialize(); begin if IELibAvailable() then IELib.JP2KInitialize() else raise EIEJPEG2000Exception.Create(IERS_IEVISIONNOTFOUND); end; procedure IEJP2K_finalize(); begin if IELibAvailable() then IELib.JP2KFinalize(); end; function IEJP2K_imageCreate(stream: TStream): IEJP2K_Image; overload; begin result := IELib.createJP2KImage(IELib.createCustomStream(TIEVCLStreamProvider.Create(stream))); // TIEVCLStreamProvider will be freed by IEJP2K_Image (that is TIELibJP2KImage) end; function IEJP2K_imageCreate(numComponents: word; parameters: IEJP2K_ComponentParamsList; colorModel: integer): IEJP2K_Image; overload; begin result := IELib.createJP2KImage(numComponents, parameters, colorModel); end; procedure IEJP2K_imageDestroy(var image: IEJP2K_image); begin image := nil; end; procedure IEJP2K_imageEncode(image: IEJP2K_image; stream: TStream; format: integer; options: string); begin image.encode(IELib.createCustomStream(TIEVCLStreamProvider.Create(stream)), format, PAnsiChar(AnsiString(options))); // TIEVCLStreamProvider will be freed by IEJP2K_Image (that is TIELibJP2KImage) end; function IEJP2K_getImageWidth(image: IEJP2K_Image): integer; begin result := image.getWidth(); end; function IEJP2K_getImageHeight(image: IEJP2K_Image): integer; begin result := image.getHeight(); end; function IEJP2K_getColorSpace(image: IEJP2K_Image): integer; begin result := image.getColorSpace(); end; // note: component can be JAS_IMAGE_CT_RGB_R, etc... no need to call JAS_IMAGE_CT_COLOR function IEJP2K_getComponentByType(image: IEJP2K_Image; component: integer): integer; begin result := image.getComponentByType(component); end; // note: component can be JAS_IMAGE_CT_RGB_R, etc... no need to call JAS_IMAGE_CT_COLOR procedure IEJP2K_setComponentType(image: IEJP2K_Image; index: integer; component: integer); begin image.setComponentType(index, component); end; function IEJP2K_getComponentPrecision(image: IEJP2K_Image; index: integer): integer; begin result := image.getComponentPrecision(index); end; function IEJP2K_getNumComponents(image: IEJP2K_Image): integer; begin result := image.getNumComponents(); end; function IEJP2K_getComponentHeight(image: IEJP2K_Image; index: integer): integer; begin result := image.getComponentHeight(index); end; function IEJP2K_getComponentWidth(image: IEJP2K_Image; index: integer): integer; begin result := image.getComponentWidth(index); end; function IEJP2K_matrixCreate(numRows: integer; numCols: integer): IEJP2K_Matrix; begin result := IELib.createJP2KMatrix(numRows, numCols); end; procedure IEJP2K_matrixDestroy(var matrix: IEJP2K_Matrix); begin matrix := nil; end; function IEJP2K_matrixGetValue(matrix: IEJP2K_Matrix; i: integer; j: integer): integer; begin result := matrix.getValue(i, j); end; function IEJP2K_readComponent(image: IEJP2K_Image; index: word; x: integer; y: integer; width: integer; height: integer; data: IEJP2K_Matrix): integer; begin result := image.readComponent(index, x, y, width, height, data); end; function IEJP2K_getComponentTopLeftY(image: IEJP2K_Image; index: integer): integer; begin result := image.getComponentTopLeftY(index); end; function IEJP2K_getComponentTopLeftX(image: IEJP2K_Image; index: integer): integer; begin result := image.getComponentTopLeftX(index); end; function IEJP2K_getComponentVStep(image: IEJP2K_Image; index: integer): integer; begin result := image.getComponentVStep(index); end; function IEJP2K_getComponentHStep(image: IEJP2K_Image; index: integer): integer; begin result := image.getComponentHStep(index); end; function IEJP2K_createComponentParametersList(size: integer): IEJP2K_ComponentParamsList; begin result := IELib.createJP2KComponentParamsList(size); end; procedure IEJP2K_destroyComponentParametersList(var parameters: IEJP2K_ComponentParamsList); begin parameters := nil; end; procedure IEJP2K_setComponentParameters(parameters: IEJP2K_ComponentParamsList; index: integer; tlx: dword; tly: dword; hstep: dword; vstep: dword; width: dword; height: dword; prec: word; sgnd: integer); begin parameters.assign(index, tlx, tly, hstep, vstep, width, height, prec, sgnd); end; procedure IEJP2K_writeComponentSample(image: IEJP2K_Image; index: integer; x: integer; y: integer; v: dword); begin image.writeComponentSample(index, x, y, v); end; procedure IEJP2K_writeRowRGB8(image: IEJP2K_Image; width: integer; rowIndex: integer; bgr8Array: PRGB; alphaArray: pbyte; colors: integer); begin image.writeRowRGB8(width, rowIndex, pbyte(bgr8Array), alphaArray, colors); end; procedure IEJP2K_readLinearBGR8(image: IEJP2K_Image; blueMatrix: IEJP2K_Matrix; greenMatrix: IEJP2K_Matrix; redMatrix: IEJP2K_Matrix; rowIndex: integer; bluePrec: integer; greenPrec: integer; redPrec: integer; destBGR8: pbyte; width: integer); begin image.readLinearBGR8(blueMatrix, greenMatrix, redMatrix, rowIndex, bluePrec, greenPrec, redPrec, destBGR8, width); end; {$endif} /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// function vctocc(i, co, cs: integer): integer; begin result := (i - co) div cs; end; // return true if is a jp2 stream function J2KTryStreamJP2(Stream: TStream): boolean; var base: int64; dw1, dw2, dw3: dword; begin base := Stream.position; result := false; // try jp2 - try jp2 signature Stream.read(dw1, 4); // LBox Stream.read(dw2, 4); // TBox Stream.read(dw3, 4); // DBox dw1 := IESwapDWord(dw1); dw2 := IESwapDWord(dw2); dw3 := IESwapDWord(dw3); if (dw1 = 12) and (dw2 = $6A502020) and (dw3 = $0D0A870A) then result := true; Stream.position := base; end; // return true if is a jpc or j2k stream function J2KTryStreamJ2K(Stream: TStream): boolean; var base: int64; w1, w2: word; begin base := Stream.position; result := false; // try j2k, jpc -SOC, SIZ Stream.read(w1, 2); // SOC Stream.read(w2, 2); // SIZ w1 := IESwapWord(w1); w2 := IESwapWord(w2); if (w1 = $FF4F) and (w2 = $FF51) then result := true; Stream.position := base; end; var CrToRedTable, CbToBlueTable, CrToGreenTable, CbToGreenTable: array[0..255] of Integer; YCbCrCoefficients: array[0..2] of Single; procedure CreateYCbCrLookup; var F1, F2, F3, F4: Single; LumaRed, LumaGreen, LumaBlue: Single; I: Integer; Offset1: Integer; begin YCbCrCoefficients[0] := 0.299; YCbCrCoefficients[1] := 0.587; YCbCrCoefficients[2] := 0.114; LumaRed := YCbCrCoefficients[0]; LumaGreen := YCbCrCoefficients[1]; LumaBlue := YCbCrCoefficients[2]; F1 := 2 - 2 * LumaRed; F2 := LumaRed * F1 / LumaGreen; F3 := 2 - 2 * LumaBlue; F4 := LumaBlue * F3 / LumaGreen; Offset1 := -128; for I := 0 to 255 do begin CrToRedTable[I] := Round(F1 * Offset1); CbToBlueTable[I] := Round(F3 * Offset1); CrToGreenTable[I] := -Round(F2 * Offset1); CbToGreenTable[I] := -Round(F4 * Offset1); Inc(Offset1); end; end; procedure J2KReadStream(Stream: TStream; Bitmap: TIEBitmap; var IOParams: TIOParams; var xProgress: TProgressRec; Preview: boolean); var im: IEJP2K_Image; numcmpts, numc: integer; i, j, q: integer; prow: pbyte; image_width, image_height: integer; cmp: array [0..10] of integer; mt: array [0..10] of IEJP2K_Matrix; v: array [0..3] of integer; u: array [0..3] of double; vi: integer; arx0, ary0: pintegerarray; arx1, ary1: pintegerarray; arx2, ary2: pintegerarray; isLinear: boolean; bStream: TIEBufferedReadStream; pb: pbyte; pw: pword; begin IEInitialize_iej2000(); if (not J2KTryStreamJP2(Stream)) and (not J2KTryStreamJ2K(Stream)) then begin xProgress.Aborting^ := true; exit; end; im := nil; try bStream := TIEBufferedReadStream.Create(Stream, 8192); try im := IEJP2K_imageCreate(bStream); finally bStream.Free(); end; if im = nil then begin xProgress.Aborting^ := true; exit; end; numcmpts := IEJP2K_getNumComponents(im); // samples per pixel image_width := IEJP2K_getImageWidth(im); image_height := IEJP2K_getImageHeight(im); numc := 3; IOParams.ImageCount := 1; case IEJP2K_getColorSpace(im) of IEJAS_IMAGE_CS_RGB: begin cmp[0] := IEJP2K_getComponentByType(im, IEJAS_IMAGE_CT_RGB_R); if cmp[0] > 255 then cmp[0] := 0; cmp[1] := IEJP2K_getComponentByType(im, IEJAS_IMAGE_CT_RGB_G); if cmp[1] > 255 then cmp[1] := 1; cmp[2] := IEJP2K_getComponentByType(im, IEJAS_IMAGE_CT_RGB_B); if cmp[2] > 255 then cmp[2] := 2; // has alpha channel? if numcmpts = 4 then begin cmp[3] := IEJP2K_getComponentByType(im, IEJAS_IMAGE_CT_OPACITY and $7FFF); if cmp[3] > 255 then cmp[3] := 3; end; IOParams.BitsPerSample := IEJP2K_getComponentPrecision(im, cmp[0]); IOParams.SamplesPerPixel := 3; end; IEJAS_IMAGE_CS_YCBCR: begin cmp[0] := IEJP2K_getComponentByType(im, IEJAS_IMAGE_CT_YCBCR_Y); if cmp[0] > 255 then cmp[0] := 0; cmp[1] := IEJP2K_getComponentByType(im, IEJAS_IMAGE_CT_YCBCR_CB); if cmp[1] > 255 then cmp[1] := 0; cmp[2] := IEJP2K_getComponentByType(im, IEJAS_IMAGE_CT_YCBCR_CR); if cmp[2] > 255 then cmp[2] := 0; IOParams.BitsPerSample := IEJP2K_getComponentPrecision(im, cmp[0]); IOParams.SamplesPerPixel := 3; end; IEJAS_IMAGE_CS_GRAY: begin cmp[0] := IEJP2K_getComponentByType(im, IEJAS_IMAGE_CT_GRAY_Y); if cmp[0] > 255 then cmp[0] := 0; IOParams.BitsPerSample := IEJP2K_getComponentPrecision(im, cmp[0]); IOParams.SamplesPerPixel := 1; numc := 1; end; else begin // unsupported color space xProgress.Aborting^ := true; IEJP2K_imageDestroy(im); exit; end; end; IOParams.DpiX := IEGlobalSettings().DefaultDPIX; IOParams.DpiY := IEGlobalSettings().DefaultDPIY; IOParams.FreeColorMap(); IOParams.Width := image_width; IOParams.Height := image_height; IOParams.OriginalWidth := image_width; IOParams.OriginalHeight := image_height; if not Preview then begin for q := 0 to high(mt) do mt[q] := nil; arx0 := nil; ary0 := nil; arx1 := nil; ary1 := nil; arx2 := nil; ary2 := nil; try if numcmpts = 2 then numcmpts := 1; for q := 0 to numcmpts - 1 do begin mt[q] := IEJP2K_matrixCreate(IEJP2K_getComponentHeight(im, q), IEJP2K_getComponentWidth(im, q)); IEJP2K_readComponent(im, q, 0, 0, IEJP2K_getComponentWidth(im, q), IEJP2K_getComponentHeight(im, q), mt[q]); end; if Bitmap.Location <> ieTBitmap then begin // native pixel format case IEJP2K_getColorSpace(im) of IEJAS_IMAGE_CS_RGB: begin Bitmap.Allocate(image_width, image_height, ie24RGB); end; IEJAS_IMAGE_CS_YCBCR: begin Bitmap.Allocate(image_width, image_height, ie24RGB); end; IEJAS_IMAGE_CS_GRAY: begin if IOParams.BitsPerSample = 1 then Bitmap.Allocate(image_width, image_height, ie1g) else if IOParams.BitsPerSample = 8 then Bitmap.Allocate(image_width, image_height, ie8g) else if IOParams.BitsPerSample > 8 then Bitmap.Allocate(image_width, image_height, ie16g) else Bitmap.Allocate(image_width, image_height, ie24RGB); // unsupported native end; end; end else begin // using TBitmap if (IOParams.BitsPerSample = 1) and (IOParams.SamplesPerPixel = 1) then Bitmap.Allocate(image_width, image_height, ie1g) else Bitmap.Allocate(image_width, image_height, ie24RGB); end; xProgress.per1 := 100 / image_height; isLinear := true; for q := 0 to imin(numc, numcmpts) - 1 do begin for i := 0 to image_height - 1 do begin if vctocc(i, IEJP2K_getComponentTopLeftY(im, cmp[q]), IEJP2K_getComponentVStep(im, cmp[q])) <> i then begin isLinear := false; break; end; for j := 0 to image_width -1 do begin if vctocc(j, IEJP2K_getComponentTopLeftX(im, cmp[0]), IEJP2K_getComponentHStep(im, cmp[0])) <> j then begin isLinear := false; break; end; end; if not isLinear then break; end; if not isLinear then break; end; if (not isLinear) and (numcmpts = 3) then begin getmem(arx0, sizeof(integer) * image_width); getmem(ary0, sizeof(integer) * image_height); getmem(arx1, sizeof(integer) * image_width); getmem(ary1, sizeof(integer) * image_height); getmem(arx2, sizeof(integer) * image_width); getmem(ary2, sizeof(integer) * image_height); for i := 0 to image_height - 1 do begin ary0[i] := vctocc(i, IEJP2K_getComponentTopLeftY(im, cmp[0]), IEJP2K_getComponentVStep(im, cmp[0])); if (ary0[i] < 0) or (ary0[i] >= IEJP2K_getComponentHeight(im, cmp[0])) then ary0[i] := 0; ary1[i] := vctocc(i, IEJP2K_getComponentTopLeftY(im, cmp[1]), IEJP2K_getComponentVStep(im, cmp[1])); if (ary1[i] < 0) or (ary1[i] >= IEJP2K_getComponentHeight(im, cmp[1])) then ary1[i] := 0; ary2[i] := vctocc(i, IEJP2K_getComponentTopLeftY(im, cmp[2]), IEJP2K_getComponentVStep(im, cmp[2])); if (ary2[i] < 0) or (ary2[i] >= IEJP2K_getComponentHeight(im, cmp[2])) then ary2[i] := 0; for j := 0 to image_width - 1 do begin arx0[j] := vctocc(j, IEJP2K_getComponentTopLeftX(im, cmp[0]), IEJP2K_getComponentHStep(im, cmp[0])); if (arx0[j] < 0) or (arx0[j] >= IEJP2K_getComponentWidth(im, cmp[0])) then arx0[j] := 0; arx1[j] := vctocc(j, IEJP2K_getComponentTopLeftX(im, cmp[1]), IEJP2K_getComponentHStep(im, cmp[1])); if (arx1[j] < 0) or (arx1[j] >= IEJP2K_getComponentWidth(im, cmp[1])) then arx1[j] := 0; arx2[j] := vctocc(j, IEJP2K_getComponentTopLeftX(im, cmp[2]), IEJP2K_getComponentHStep(im, cmp[2])); if (arx2[j] < 0) or (arx2[j] >= IEJP2K_getComponentWidth(im, cmp[2])) then arx2[j] := 0; end; end; end; if (not isLinear) and (numcmpts = 1) then begin getmem(arx0, sizeof(integer) * image_width); getmem(ary0, sizeof(integer) * image_height); for i := 0 to image_height - 1 do begin ary0[i] := vctocc(i, IEJP2K_getComponentTopLeftY(im, cmp[0]), IEJP2K_getComponentVStep(im, cmp[0])); if (ary0[i] < 0) or (ary0[i] >= IEJP2K_getComponentHeight(im, cmp[0])) then ary0[i] := 0; for j := 0 to image_width - 1 do begin arx0[j] := vctocc(j, IEJP2K_getComponentTopLeftX(im, cmp[0]), IEJP2K_getComponentHStep(im, cmp[0])); if (arx0[j] < 0) or (arx0[j] >= IEJP2K_getComponentWidth(im, cmp[0])) then arx0[j] := 0; end; end; end; if numcmpts = 3 then begin for i := 0 to image_height - 1 do begin prow := bitmap.ScanLine[i]; case IEJP2K_getColorSpace(im) of IEJAS_IMAGE_CS_RGB: begin if isLinear then begin IEJP2K_readLinearBGR8(im, mt[cmp[2]], mt[cmp[1]], mt[cmp[0]], i, IEJP2K_getComponentPrecision(im, cmp[2]), IEJP2K_getComponentPrecision(im, cmp[1]), IEJP2K_getComponentPrecision(im, cmp[0]), prow, image_width); end else begin for j := 0 to image_width - 1 do begin prow^ := (IEJP2K_matrixGetValue(mt[cmp[2]], ary2[i], arx2[j]) shl (32 - IEJP2K_getComponentPrecision(im, cmp[2]))) shr 24; inc(prow); prow^ := (IEJP2K_matrixGetValue(mt[cmp[1]], ary1[i], arx1[j]) shl (32 - IEJP2K_getComponentPrecision(im, cmp[1]))) shr 24; inc(prow); prow^ := (IEJP2K_matrixGetValue(mt[cmp[0]], ary0[i], arx0[j]) shl (32 - IEJP2K_getComponentPrecision(im, cmp[0]))) shr 24; inc(prow); end; end; end; IEJAS_IMAGE_CS_YCBCR: begin if isLinear then begin for j := 0 to image_width - 1 do begin v[0] := (IEJP2K_matrixGetValue(mt[cmp[0]], i, j) shl (32 - IEJP2K_getComponentPrecision(im, cmp[0]))) shr 24; v[1] := (IEJP2K_matrixGetValue(mt[cmp[1]], i, j) shl (32 - IEJP2K_getComponentPrecision(im, cmp[1]))) shr 24; v[2] := (IEJP2K_matrixGetValue(mt[cmp[2]], i, j) shl (32 - IEJP2K_getComponentPrecision(im, cmp[2]))) shr 24; u[0] := blimit(v[0] + CrToRedTable[v[2]]); u[1] := blimit(v[0] + CbToGreenTable[v[1]] + CrToGreentable[v[2]]); u[2] := blimit(v[0] + CbToBlueTable[v[1]]); v[0] := trunc(u[0]); v[1] := trunc(u[1]); v[2] := trunc(u[2]); prow^ := blimit(v[2]); inc(prow); prow^ := blimit(v[1]); inc(prow); prow^ := blimit(v[0]); inc(prow); end; end else begin for j := 0 to image_width - 1 do begin v[0] := (IEJP2K_matrixGetValue(mt[cmp[0]], ary0[i], arx0[j]) shl (32 - IEJP2K_getComponentPrecision(im, cmp[0]))) shr 24; v[1] := (IEJP2K_matrixGetValue(mt[cmp[1]], ary1[i], arx1[j]) shl (32 - IEJP2K_getComponentPrecision(im, cmp[1]))) shr 24; v[2] := (IEJP2K_matrixGetValue(mt[cmp[2]], ary2[i], arx2[j]) shl (32 - IEJP2K_getComponentPrecision(im, cmp[2]))) shr 24; u[0] := blimit(v[0] + CrToRedTable[v[2]]); u[1] := blimit(v[0] + CbToGreenTable[v[1]] + CrToGreentable[v[2]]); u[2] := blimit(v[0] + CbToBlueTable[v[1]]); v[0] := trunc(u[0]); v[1] := trunc(u[1]); v[2] := trunc(u[2]); prow^ := blimit(v[2]); inc(prow); prow^ := blimit(v[1]); inc(prow); prow^ := blimit(v[0]); inc(prow); end; end; end; end; // OnProgress with xProgress do if assigned(fOnProgress) then fOnProgress(Sender, trunc(per1 * (i))); if xProgress.Aborting^ then break; end; end else if (numcmpts = 4) and isLinear then begin // alpha channel currently not supported (this is discarded now) for i := 0 to image_height - 1 do begin prow := bitmap.ScanLine[i]; case IEJP2K_getColorSpace(im) of IEJAS_IMAGE_CS_RGB: begin IEJP2K_readLinearBGR8(im, mt[cmp[2]], mt[cmp[1]], mt[cmp[0]], i, IEJP2K_getComponentPrecision(im, cmp[2]), IEJP2K_getComponentPrecision(im, cmp[1]), IEJP2K_getComponentPrecision(im, cmp[0]), prow, image_width); end; end; // OnProgress with xProgress do if assigned(fOnProgress) then fOnProgress(Sender, trunc(per1 * (i))); if xProgress.Aborting^ then break; end; end else if (numcmpts = 1) or (IEJP2K_getColorSpace(im) = IEJAS_IMAGE_CS_GRAY) then begin for i := 0 to image_height - 1 do begin case Bitmap.PixelFormat of ie1g: begin prow := bitmap.ScanLine[i]; for j := 0 to image_width - 1 do begin if isLinear then vi := (IEJP2K_matrixGetValue(mt[cmp[0]], i, j) shl (32 - IEJP2K_getComponentPrecision(im, cmp[0]))) shr 24 else vi := (IEJP2K_matrixGetValue(mt[cmp[0]], ary0[i], arx0[j]) shl (32 - IEJP2K_getComponentPrecision(im, cmp[0]))) shr 24; _SetPixelbw(pbyte(prow), j, vi); end; end; ie8g: begin pb := bitmap.ScanLine[i]; for j := 0 to image_width - 1 do begin if isLinear then pb^ := (IEJP2K_matrixGetValue(mt[cmp[0]], i, j) shl (32 - IEJP2K_getComponentPrecision(im, cmp[0]))) shr 24 else pb^ := (IEJP2K_matrixGetValue(mt[cmp[0]], ary0[i], arx0[j]) shl (32 - IEJP2K_getComponentPrecision(im, cmp[0]))) shr 24; inc(pb); end; end; ie16g: begin pw := bitmap.ScanLine[i]; for j := 0 to image_width - 1 do begin if isLinear then pw^ := (IEJP2K_matrixGetValue(mt[cmp[0]], i, j) shl (32 - IEJP2K_getComponentPrecision(im, cmp[0]))) shr 16 else pw^ := (IEJP2K_matrixGetValue(mt[cmp[0]], ary0[i], arx0[j]) shl (32 - IEJP2K_getComponentPrecision(im, cmp[0]))) shr 16; inc(pw); end; end; ie24RGB: begin prow := bitmap.ScanLine[i]; for j := 0 to image_width - 1 do begin if isLinear then vi := (IEJP2K_matrixGetValue(mt[cmp[0]], i, j) shl (32 - IEJP2K_getComponentPrecision(im, cmp[0]))) shr 24 else vi := (IEJP2K_matrixGetValue(mt[cmp[0]], ary0[i], arx0[j]) shl (32 - IEJP2K_getComponentPrecision(im, cmp[0]))) shr 24; prow^ := vi; inc(prow); prow^ := vi; inc(prow); prow^ := vi; inc(prow); end; end; end; // OnProgress with xProgress do if assigned(fOnProgress) then fOnProgress(Sender, trunc(per1 * (i))); if xProgress.Aborting^ then break; end; end; finally for q := 0 to high(mt) do if mt[q] <> nil then IEJP2K_matrixDestroy(mt[q]); // free even when they are "nil" freemem(arx0); freemem(ary0); freemem(arx1); freemem(ary1); freemem(arx2); freemem(ary2); end; end; // not preview finally IEJP2K_imageDestroy(im); end; end; // fmt can be JAS_IMAGE_CM_GRAY(1), JAS_IMAGE_CM_RGB(2), JAS_IMAGE_CM_YCC(3) // format: 0=jp2 1=j2k/jpc procedure J2KWriteStream(Stream: TStream; Bitmap: TIEBitmap; var IOParams: TIOParams; var xProgress: TProgressRec; format: integer); var im: IEJP2K_Image; cmptparams: IEJP2K_ComponentParamsList; outopts: string; ww, hh, y, x, vv, colors: integer; row: PRGB; pb: pbyte; pw: pword; NullProgress: TProgressRec; a: pbyte; HasAlpha: boolean; bStream: TIEBufferedWriteStream; RedToGrayCoef, GreenToGrayCoef, BlueToGrayCoef: integer; begin IEInitialize_iej2000(); NullProgress := NullProgressRec( xProgress.Aborting, False ); im := nil; ww := Bitmap.Width; hh := Bitmap.Height; case Bitmap.PixelFormat of ie1g: begin IOParams.BitsPerSample := 1; IOParams.J2000_ColorSpace := ioJ2000_GRAYLEV; end; ie8g: begin IOParams.BitsPerSample := 8; IOParams.J2000_ColorSpace := ioJ2000_GRAYLEV; end; ie16g: begin IOParams.BitsPerSample := 16; IOParams.J2000_ColorSpace := ioJ2000_GRAYLEV; end; end; colors := (1 shl IOParams.BitsPerSample) - 1; if hh = 0 then xProgress.per1 := 0 else xProgress.per1 := 100 / hh; xProgress.val := 0; cmptparams := nil; case IOParams.J2000_ColorSpace of ioJ2000_GRAYLEV: begin // gray scale or black/white cmptparams := IEJP2K_createComponentParametersList(1); IEJP2K_setComponentParameters(cmptparams, 0, 0, 0, 1, 1, ww, hh, IOParams.BitsPerSample, 0); im := IEJP2K_imageCreate(1, cmptparams, IEJAS_IMAGE_CS_GRAY); IEJP2K_setComponentType(im, 0, IEJAS_IMAGE_CT_GRAY_Y); if bitmap.PixelFormat = ie24RGB then begin // gray scale RedToGrayCoef := IEGlobalSettings().RedToGrayCoef; GreenToGrayCoef := IEGlobalSettings().GreenToGrayCoef; BlueToGrayCoef := IEGlobalSettings().BlueToGrayCoef; for y := 0 to hh - 1 do begin row := Bitmap.Scanline[y]; for x := 0 to ww - 1 do begin with row^ do begin vv := trunc((((r * RedToGrayCoef + g * GreenToGrayCoef + b * BlueToGrayCoef) div 100) / 255) * colors); IEJP2K_writeComponentSample(im, 0, x, y, vv); end; inc(row); end; // OnProgress with xProgress do if assigned(fOnProgress) then fOnProgress(Sender, trunc(per1 * y)); if xProgress.Aborting^ then break; end; end else if Bitmap.PixelFormat = ie8g then begin // native 8 bit gray scale for y := 0 to hh - 1 do begin pb := Bitmap.Scanline[y]; for x := 0 to ww - 1 do begin IEJP2K_writeComponentSample(im, 0, x, y, pb^); inc(pb); end; // OnProgress with xProgress do if assigned(fOnProgress) then fOnProgress(Sender, trunc(per1 * y)); if xProgress.Aborting^ then break; end; end else if Bitmap.PixelFormat = ie16g then begin // native 16 bit gray scale for y := 0 to hh - 1 do begin pw := Bitmap.Scanline[y]; for x := 0 to ww - 1 do begin IEJP2K_writeComponentSample(im, 0, x, y, pw^); inc(pw); end; // OnProgress with xProgress do if assigned(fOnProgress) then fOnProgress(Sender, trunc(per1 * y)); if xProgress.Aborting^ then break; end; end else begin // black/white for y := 0 to hh - 1 do begin row := Bitmap.Scanline[y]; for x := 0 to ww - 1 do begin if _GetPixelbw(pbyte(row), x) <> 0 then IEJP2K_writeComponentSample(im, 0, x, y, 1) else IEJP2K_writeComponentSample(im, 0, x, y, 0); end; // OnProgress with xProgress do if assigned(fOnProgress) then fOnProgress(Sender, trunc(per1 * y)); if xProgress.Aborting^ then break; end; end; end; ioJ2000_YCbCr, // for now YCC=RGB ioJ2000_RGB: begin HasAlpha := Bitmap.HasAlphaChannel and not Bitmap.AlphaChannel.Full; if HasAlpha then begin cmptparams := IEJP2K_createComponentParametersList(4); IEJP2K_setComponentParameters(cmptparams, 0, 0, 0, 1, 1, ww, hh, IOParams.BitsPerSample, 0); IEJP2K_setComponentParameters(cmptparams, 1, 0, 0, 1, 1, ww, hh, IOParams.BitsPerSample, 0); IEJP2K_setComponentParameters(cmptparams, 2, 0, 0, 1, 1, ww, hh, IOParams.BitsPerSample, 0); IEJP2K_setComponentParameters(cmptparams, 3, 0, 0, 1, 1, ww, hh, IOParams.BitsPerSample, 0); im := IEJP2K_imageCreate(4, cmptparams, IEJAS_IMAGE_CS_RGB); end else begin cmptparams := IEJP2K_createComponentParametersList(3); IEJP2K_setComponentParameters(cmptparams, 0, 0, 0, 1, 1, ww, hh, IOParams.BitsPerSample, 0); IEJP2K_setComponentParameters(cmptparams, 1, 0, 0, 1, 1, ww, hh, IOParams.BitsPerSample, 0); IEJP2K_setComponentParameters(cmptparams, 2, 0, 0, 1, 1, ww, hh, IOParams.BitsPerSample, 0); im := IEJP2K_imageCreate(3, cmptparams, IEJAS_IMAGE_CS_RGB); end; IEJP2K_setComponentType(im, 0, IEJAS_IMAGE_CT_RGB_R); IEJP2K_setComponentType(im, 1, IEJAS_IMAGE_CT_RGB_G); IEJP2K_setComponentType(im, 2, IEJAS_IMAGE_CT_RGB_B); if HasAlpha then IEJP2K_setComponentType(im, 3, IEJAS_IMAGE_CT_OPACITY); a := nil; for y := 0 to hh - 1 do begin row := Bitmap.Scanline[y]; if HasAlpha then a := Bitmap.AlphaChannel.ScanLine[y]; IEJP2K_writeRowRGB8(im, ww, y, row, a, colors); // OnProgress with xProgress do if assigned(fOnProgress) then fOnProgress(Sender, trunc(per1 * y)); if xProgress.Aborting^ then break; end; end; // Attention: YCbCr is not supported for writing. Unfortunately only Y channel is loaded. (* ioJ2000_YCbCr: begin im := jas_image_create0(); iejas_image_setcolorspace(im, JAS_IMAGE_CS_YCBCR); jas_image_addcmpt(im, 0, cmptparams); jas_image_addcmpt(im, 1, cmptparams); jas_image_addcmpt(im, 2, cmptparams); IEJP2K_setComponentType(im, 0, (JAS_IMAGE_CT_YCBCR_Y)); IEJP2K_setComponentType(im, 1, (JAS_IMAGE_CT_YCBCR_CB)); IEJP2K_setComponentType(im, 2, (JAS_IMAGE_CT_YCBCR_CR)); for y := 0 to hh-1 do begin row := Bitmap.Scanline[y]; for x := 0 to ww-1 do begin with row^ do begin yy := trunc( 0.29900 * R + 0.58700 * G + 0.11400 * B ); cb := trunc( -0.16874 * R - 0.33126 * G + 0.50000 * B + 128 ); Cr := trunc( 0.50000 * R - 0.41869 * G - 0.08131 * B + 128 ); IEJP2K_writeComponentSample(im, 0, x, y, yy); IEJP2K_writeComponentSample(im, 1, x, y, cb); IEJP2K_writeComponentSample(im, 2, x, y, cr); end; inc(row); end; // OnProgress with xProgress do if assigned(fOnProgress) then fOnProgress(Sender, trunc(per1*y)); if xProgress.Aborting^ then break; end; end; //*) end; outopts := 'rate=' + IEFloatToStrS(IOParams.J2000_Rate); if IOParams.J2000_ScalableBy = ioJ2000_Rate then outopts := outopts + ' prg=lrcp' else if IOParams.J2000_ScalableBy = ioJ2000_Resolution then outopts := outopts + ' prg=rlcp'; bStream := TIEBufferedWriteStream.Create(Stream, 8192); IEJP2K_imageEncode(im, bStream, format, outopts); bStream.Free(); IEJP2K_imageDestroy(im); IEJP2K_destroyComponentParametersList(cmptparams); end; var iej2000Init: boolean = false; procedure IEInitialize_iej2000(); begin if not iej2000Init then begin CreateYCbCrLookup(); IEJP2K_initialize(); iej2000Init := true; end; end; procedure IEFinalize_iej2000(); begin if iej2000Init then IEJP2K_finalize(); end; {$else} // IEINCLUDEJPEG2000 interface implementation {$endif} // IEINCLUDEJPEG2000 end.