(* 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 1001 Doc revision 1004 *) unit iexBitmaps; {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} {$R-} {$Q-} {$I ie.inc} interface uses Windows, Messages, Forms, Classes, StdCtrls, Graphics, Controls, Contnrs, SysUtils, SyncObjs, hyiedefs, iewords, ievision, iegdiplus, Dialogs, iexTransitions, hyieutils; const IEMAXICOIMAGES = 16; // Jpeg markers JPEG_APP0 = $E0; JPEG_APP1 = $E1; JPEG_APP2 = $E2; JPEG_APP3 = $E3; JPEG_APP4 = $E4; JPEG_APP5 = $E5; JPEG_APP6 = $E6; JPEG_APP7 = $E7; JPEG_APP8 = $E8; JPEG_APP9 = $E9; JPEG_APP10 = $EA; JPEG_APP11 = $EB; JPEG_APP12 = $EC; JPEG_APP13 = $ED; JPEG_APP14 = $EE; JPEG_APP15 = $EF; JPEG_COM = $FE; // IPTC items compatible with Adobe PhotoShop PhotoShop_IPTC_Records = 2; IPTC_PS_Title = 5; IPTC_PS_Caption = 120; IPTC_PS_Keywords = 25; IPTC_PS_Category = 15; IPTC_PS_Category_2 = 20; IPTC_PS_City = 90; IPTC_PS_State_Province = 95; IPTC_PS_Country = 101; IPTC_PS_Instructions = 40; IPTC_PS_Date_Created = 55; IPTC_PS_Time_Created = 60; IPTC_PS_Byline_1 = 80; IPTC_PS_Byline_2 = 85; IPTC_PS_Country_Code = 100; IPTC_PS_Transmission_Reference = 103; IPTC_PS_Credit = 110; IPTC_PS_Source = 115; IPTC_PS_Writer = 122; IPTC_PS_Edit_Status = 7; IPTC_PS_Urgency = 10; IPTC_PS_Fixture_Identifier = 22; IPTC_PS_Release_Date = 30; IPTC_PS_Release_Time = 35; IPTC_PS_Reference_Service = 45; IPTC_PS_Reference_Date = 47; IPTC_PS_Reference_Number = 50; IPTC_PS_Originating_Program = 65; IPTC_PS_Program_Version = 70; IPTC_PS_Object_Cycle = 75; IPTC_PS_Copyright_Notice = 116; IPTC_PS_Image_Type = 130; // Possible values for EXIF_Orientation: {!! EXIF Orientation Consts Declaration } _exoCorrectOrientation = 1; // Image is Orientated Correctly _exoNeedsHorizontalFlip = 2; // Image is Horizontally Flipped _exoNeeds180Rotate = 3; // Image is Offset by 180º _exoNeedsVerticalFlip = 4; // Image is Vertically Flipped _exoNeedsHorzAndVertFlip = 5; // Image is Flipped Horiz. and Offset 90º CCW _exoNeeds90RotateCW = 6; // Image is Offset by 90º CCW _exoNeedsFlipHorzAnd90Rotate = 7; // Image is Flipped Horiz. and offset 90º CW _exoNeeds270RotateCW = 8; // Image is Offset by 90º clockwise {!!} Camera_Raw_File_Extensions = '*.CRW;*.CR2;*.DNG;*.NEF;*.RAW;*.RAF;*.X3F;*.ORF;*.SRF;*.MRW;*.DCR;*.BAY;*.PEF;*.SR2;*.ARW;*.KDC;' + '*.MEF;*.3FR;*.K25;*.ERF;*.CAM;*.CS1;*.DC2;*.DCS;*.FFF;*.MDC;*.MOS;*.NRW;*.PTX;*.PXN;*.RDC;*.RW2;' + '*.RWL;*.IIQ;*.SRW'; const // Operations of TIECustomMultiBitmap.UpdateParams() IEM_OP_NONE = 0; IEM_OP_INSERT = 1; IEM_OP_DELETE = 2; IEM_OP_MOVE = 3; IEM_OP_SWAP = 4; IEM_OP_MOVEGROUP = 5; IEM_OP_CLEAR = 6; IEM_OP_ALLOCATE = 7; const IEEXIFUSERCOMMENTCODE_UNICODE: AnsiString = #$55#$4E#$49#$43#$4F#$44#$45#$00; IEEXIFUSERCOMMENTCODE_ASCII: AnsiString = #$41#$53#$43#$49#$49#$00#$00#$00; IEEXIFUSERCOMMENTCODE_JIS: AnsiString = #$4A#$49#$53#$00#$00#$00#$00#$00; IEEXIFUSERCOMMENTCODE_UNDEFINED: AnsiString = #$00#$00#$00#$00#$00#$00#$00#$00; const IEMVIEWSNAPSHOTVERSION = 9; type ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIFF support // Colormap item TTIFFColor = packed record R, G, B: word; end; TTIFFHeader = packed record Id: word; Ver: word; PosIFD: dword; end; PTIFFHeader = ^TTIFFHeader; TTIFFTAG = packed record IdTag: word; // tag identified DataType: word; // data type DataNum: integer; // data count DataPos: dword; // data position end; PTIFFTAG = ^TTIFFTAG; TBigTIFFTAG = packed record IdTag: word; // tag identified DataType: word; // data type DataNum: int64; // data count DataPos: int64; // data position end; TIFD = array[0..MaxInt div 16] of TTIFFTAG; PIFD = ^TIFD; TBigIFD = array[0..MaxInt div 32] of TBigTIFFTag; PBigIFD = ^TBigIFD; TIETIFFIFDReader = class LittleEndian: boolean; // true: Intel (LittleEndian) - false: Motorola (BigEndian) Stream: TStream; IFD: PIFD; BigIFD: PBigIFD; NumTags: integer; StreamBase: int64; IsBigTIFF: boolean; // true = BigTIFF (ver=43), false = classic TIFF (ver <> 43) DataPosSize: integer; // 4 = classic TIFF, 8 = BigTIFF constructor Create(); destructor Destroy(); override; function ReadIFD(ImageIndex: integer; Offset: int64; var ImageCount: integer): boolean; procedure Assign(Source: TIETIFFIFDReader); procedure Clear(); function GetDataNum(tagIndex: integer): int64; function GetDataType(tagIndex: integer): word; function GetDataPos(tagIndex: integer): int64; function GetItem(tagIndex: integer; dataIndex: int64): int64; function GetDataLengthInBytes(tagIndex: integer): int64; function FindTAG(tagID: word): integer; function ReadInteger(tagID: word; idx: int64; def: int64): int64; function ReadRational(tagID: word; idx: integer; defaultValue: double): double; function ReadArrayIntegers(var ar: pint64array; tagID: word): integer; function ReadRawDataAsArrayOfByte(tagID: word): TIEArrayOfByte; function ReadRawData(tagID: word; var Size: integer): pointer; function ReadString(tagID: word; truncToEZ: boolean = true): AnsiString; function ReadWideString(tagID: word): WideString; end; TIETIFFIFDWriter = class private Items: TList; function GetCount(): integer; function GetTag(Index: integer): PTIFFTAG; public constructor Create(); destructor Destroy(); override; procedure AddTag(IdTag: word; DataType: word; DataNum: integer; DataPos: dword); procedure ReorderTags(); procedure WriteSingleLong(tag: integer; val: integer); procedure WriteSingleUndefined(tag: integer; val: dword; writeIfInList: TList = nil); procedure WriteMiniString(tag: integer; ss: AnsiString); procedure WriteMiniByteString(tag: integer; ss: AnsiString); procedure WriteSingleShort(tag: integer; val: word; writeIfInList: TList = nil); procedure WriteSingleByte(tag: integer; val: byte); procedure WriteSingleRational(Stream: TStream; tag: integer; value: double; var Aborting: boolean; writeIfInList: TList=nil); procedure WriteMultiRational(Stream: TStream; tag: integer; values: array of double; var Aborting: boolean); procedure WriteString(Stream: TStream; tag: integer; ss: AnsiString; var Aborting: boolean); procedure WriteWideString(Stream: TStream; tag: integer; ss: WideString; var Aborting: boolean); procedure WriteArrayOfByte(Stream: TStream; Tag: word; DataType: word; Buffer: TIEArrayOfByte; var Aborting: boolean); procedure WriteMultiLongEx(Stream: TStream; tag: integer; arr: array of dword; arraylen: integer; var Aborting: boolean); procedure WriteMultiShort(Stream: TStream; tag: integer; const vals: array of word; var Aborting: boolean); property Count: integer read GetCount; property Tag[Index: integer]: PTIFFTAG read GetTag; end; // TIFF support ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {!! TIEMarkerList Description TIEMarkerList contains the list of markers loaded from a jpeg. Methods and properties !!} TIEMarkerList = class private fData: TList; // list of TMemoryStream fType: TList; // list of byte function GetCount: integer; function GetMarkerData(idx: integer): PAnsiChar; function GetMarkerStream(idx: integer): TStream; function GetMarkerType(idx: integer): byte; function GetMarkerLength(idx: integer): word; function SortCompare(Index1, Index2: integer): integer; procedure SortSwap(Index1, Index2: integer); public constructor Create; destructor Destroy; override; function AddMarker(marker: byte; data: PAnsiChar; datalen: word): integer; procedure SetMarker(idx: integer; marker: byte; data: PAnsiChar; datalen: word); procedure InsertMarker(idx: integer; data: PAnsiChar; marker: byte; datalen: word); procedure Clear; property MarkerData[idx: integer]: PAnsiChar read GetMarkerData; property MarkerStream[idx: integer]: TStream read GetMarkerStream; property MarkerLength[idx: integer]: word read GetMarkerLength; property MarkerType[idx: integer]: byte read GetMarkerType; function IndexOf(marker: byte): integer; procedure SaveToStream(Stream: TStream); procedure LoadFromStream(Stream: TStream); procedure DeleteMarker(idx: integer); procedure DeleteMarkerInstances(markerType: byte); property Count: integer read GetCount; procedure Assign(Source: TIEMarkerList); procedure Sort; end; TIPTCInfo = packed record fRecord: integer; fDataSet: integer; fLength: integer; end; PIPTCInfo = ^TIPTCInfo; {!! TIEIPTCInfoList Description A list of all the IPTC information contained in a file. It is available via the property Params.IPTC_Info IPTC records can contains text, objects and images. Applications can read/write information from IPTC_Info using string objects or a memory buffer. Each IPTC_Info item has a record number and a dataset number. These values specify the type of data contained in the item, according to IPTC - NAA Information Interchange Model Version 4 (See: www.iptc.org). For JPEG files ImageEn can read/write IPTC fields from the APP13 marker. ImageEn can also read/write IPTC textual information of PhotoShop (access In Photoshop under "File Info"). View a list IPTC Photoshop items. Note: A set of IPTC helper functions are available in Methods and Properties !!} TIEIPTCInfoList = class private fBuffer: TList; fInfo: TList; fUserChanged: boolean; function GetStrings(idx: integer): string; procedure SetStrings(idx: integer; Value: string); function GetRecordNumber(idx: integer): integer; procedure SetRecordNumber(idx: integer; Value: integer); function GetDataSet(idx: integer): integer; procedure SetDataSet(idx: integer; Value: integer); function GetCount: integer; public constructor Create; destructor Destroy; override; property StringItem[idx: integer]: string read GetStrings write SetStrings; property RecordNumber[idx: integer]: integer read GetRecordNumber write SetRecordNumber; property DataSet[idx: integer]: integer read GetDataSet write SetDataSet; function AddStringItem(ARecordNumber: integer; ADataSet: integer; Value: AnsiString): integer; function AddBufferItem(ARecordNumber: integer; ADataSet: integer; Buffer: pointer; BufferLength: integer): integer; procedure InsertStringItem(idx: integer; ARecordNumber: integer; ADataSet: integer; Value: AnsiString); procedure Clear; function IndexOf(ARecordNumber: integer; ADataSet: integer): integer; procedure DeleteItem(idx: integer); property Count: integer read GetCount; procedure Assign(Source: TIEIPTCInfoList); procedure SaveToStream(Stream: TStream); procedure LoadFromStream(Stream: TStream); function LoadFromStandardBuffer(Buffer: pointer; BufferLength: integer): boolean; procedure SaveToStandardBuffer(var Buffer: pointer; var BufferLength: integer; WriteHeader: boolean); property UserChanged: boolean read fUserChanged write fUserChanged; function GetItemData(idx: integer): pointer; function GetItemLength(idx: integer): integer; end; // annotation types const IEAnnotImageEmbedded = 1; IEAnnotImageReference = 2; IEAnnotStraightLine = 3; IEAnnotFreehandLine = 4; IEAnnotHollowRectangle = 5; IEAnnotFilledRectangle = 6; IEAnnotTypedText = 7; IEAnnotTextFromFile = 8; IEAnnotTextStamp = 9; IEAnnotAttachANote = 10; IEAnnotForm = 12; IEAnnotOCRRegion = 13; // TIEBitmap maximum channels const IEMAXCHANNELS = 4; type {!! TIEBaseBitmap Description This is the base abstract class for object. Applications cannot create TIEBaseBitmap objects, instead use TIEBitmap. Implemented Properties !!} TIEBaseBitmap = class protected fAccess: TIEDataAccess; function GetScanLine(Row: integer): pointer; virtual; abstract; function GetBitCount: integer; virtual; abstract; function GetHeight: integer; virtual; abstract; function GetWidth: integer; virtual; abstract; procedure SetWidth(Value: integer); virtual; abstract; procedure SetHeight(Value: integer); virtual; abstract; function GetPixelFormat: TIEPixelFormat; virtual; abstract; function GetRowLen: integer; virtual; abstract; function GetPaletteBuffer: pointer; virtual; abstract; function GetPalette(index: integer): TRGB; virtual; abstract; procedure SetPalette(index: integer; Value: TRGB); virtual; abstract; function GetPaletteLen: integer; virtual; abstract; function GetPaletteUsed(): integer; virtual; abstract; procedure SetPaletteUsed(Value: integer); virtual; abstract; public property Scanline[row: integer]: pointer read GetScanline; property BitCount: integer read GetBitCount; property Width: integer read GetWidth write SetWidth; property Height: integer read GetHeight write SetHeight; property PixelFormat: TIEPixelFormat read GetPixelFormat; function Allocate(ImageWidth, ImageHeight: integer; ImagePixelFormat: TIEPixelFormat): boolean; virtual; abstract; procedure Assign(Source: TObject); virtual; abstract; procedure AssignImage(Source: TIEBaseBitmap); virtual; abstract; property RowLen: integer read GetRowLen; {!! TIEBaseBitmap.Access Declaration property Access: ; Description Specifies whether the bitmap is readable or/and writable. This works only when Location is ieFile to speed up reading and writing operations. The default value is [iedRead, iedWrite] which allows read and write. Examples // set write-only when loading input.tif (in reality this is automatic!) ImageEnView.IEBitmap.Access := [iedWrite]; ImageEnView.IO.LoadFromFile('D:\Input.tif'); ImageEnView.IEBitmap.Access := [iedWrite, iedRead]; // restore // set read-only when saving output.tif (in reality this is automatic!) ImageEnView.IEBitmap.Access := [iedRead]; ImageEnView.IO.SaveToFile('D:\Output.tif'); ImageEnView.IEBitmap.Access := [iedWrite, iedRead]; // restore !!} property Access: TIEDataAccess read fAccess write fAccess; {!! TIEBaseBitmap.Palette Declaration property Palette[index: integer]: ; Description Returns the color of the palette entry index. See Also - - - !!} property Palette[index: integer]: TRGB read GetPalette write SetPalette; property PaletteBuffer: pointer read GetPaletteBuffer; {!! TIEBaseBitmap.PaletteUsed Declaration property PaletteUsed: integer; Description Specifies the number of colors used by the palette. !!} property PaletteUsed: integer read GetPaletteUsed write SetPaletteUsed; {!! TIEBaseBitmap.PaletteLength Declaration property PaletteLength: integer; Description Returns the count of entries in the palette. !!} property PaletteLength: integer read GetPaletteLen; procedure CopyPaletteTo(Dest: TIEBaseBitmap); virtual; abstract; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEICC type IE_PROFILE = record dwType: DWORD; pProfileData: pointer; cbDataSize: DWORD; end; IE_PPROFILE = ^IE_PROFILE; IE_HPROFILE = THANDLE; IE_PHPROFILE = ^IE_HPROFILE; IE_HTRANSFORM = THandle; TIE_ICMProgressProcCallback = function(ulMax: dword; ulCurrent: dword ; ulCallbackData: LPARAM): longbool; stdcall; TIE_OpenColorProfile = function(pProfile: IE_PPROFILE; dwDesiredAccess: DWORD ; dwShareMode: DWORD ; dwCreationMode: DWORD): IE_HPROFILE; stdcall; TIE_CloseColorProfile = function(hProfile: IE_HPROFILE): longbool; stdcall; TIE_CreateMultiProfileTransform = function(pahProfiles: IE_PHPROFILE; nProfiles: DWORD; padwIntent: PDWORD; nIntents: DWORD; dwFlags: DWORD; indexPreferredCMM: DWORD): IE_HTRANSFORM; stdcall; TIE_DeleteColorTransform = function(hColorTransform: IE_HTRANSFORM ): longbool; stdcall; TIE_TranslateColors = function(hColorTransform: IE_HTRANSFORM; paInputColors: pointer ; nColors: DWORD ; ctInput: dword ; paOutputColors: pointer ; ctOutput: dword): longbool; stdcall; var IE_OpenColorProfile: TIE_OpenColorProfile; IE_CloseColorProfile: TIE_CloseColorProfile; IE_CreateMultiProfileTransform: TIE_CreateMultiProfileTransform; IE_DeleteColorTransform: TIE_DeleteColorTransform; IE_TranslateColors: TIE_TranslateColors; const IE_COLOR_GRAY = 1; IE_COLOR_RGB = 2; IE_COLOR_XYZ = 3; IE_COLOR_Yxy = 4; IE_COLOR_Lab = 5; IE_COLOR_3_CHANNEL = 6; IE_COLOR_CMYK = 7; IE_COLOR_5_CHANNEL = 8; IE_COLOR_6_CHANNEL = 9; IE_COLOR_7_CHANNEL = 10; IE_COLOR_8_CHANNEL = 11; IE_COLOR_NAMED = 12; const IE_PROFILE_READ = 1; IE_PROFILE_READWRITE = 2; IE_PROFILE_FILENAME = 1; IE_PROFILE_MEMBUFFER = 2; IE_LCS_SIGNATURE: AnsiString = 'PSOC'; IE_LCS_CALIBRATED_RGB = $00000000; IE_LCS_sRGB: AnsiString = 'sRGB'; IE_LCS_WINDOWS_COLOR_SPACE: AnsiString = 'Win '; IE_LCS_GM_BUSINESS = $00000001; IE_LCS_GM_GRAPHICS = $00000002; IE_LCS_GM_IMAGES = $00000004; IE_LCS_GM_ABS_COLORIMETRIC = $00000008; IE_PROOF_MODE = $00000001; IE_NORMAL_MODE = $00000002; IE_BEST_MODE = $00000003; IE_ENABLE_GAMUT_CHECKING = $00010000; IE_USE_RELATIVE_COLORIMETRIC = $00020000; IE_FAST_TRANSLATE = $00040000; IE_INDEX_DONT_CARE = 0; IE_INTENT_PERCEPTUAL = 0; IE_INTENT_RELATIVE_COLORIMETRIC = 1; IE_INTENT_SATURATION = 2; IE_INTENT_ABSOLUTE_COLORIMETRIC = 3; const IE_CS2IF: array [0..8] of dword = ( IE_COLOR_RGB, IE_COLOR_RGB, IE_COLOR_CMYK, IE_COLOR_CMYK, IE_COLOR_Lab, IE_COLOR_GRAY, IE_COLOR_RGB, IE_COLOR_RGB, IE_COLOR_3_CHANNEL); type {!! TIEICC Description TIEICC class contains a color profile. It is used for loading an image ICC profile and for displaying the ICC profile (which is sRGB by default). Note: several constants are defined in ielcms unit. Methods and Properties !!} TIEICC = class private fUseLCMS: boolean; fRaw: pbyte; fRawLen: integer; fProfile: pointer; fProfileStream: TIEMemStream; fMSProfile: THandle; // MSCMS profile handle fApplied: boolean; // current transform data fTransform: pointer; fInputFormat: integer; fOutputFormat: integer; fDestination: TIEICC; fIntent: integer; fFlags: integer; fMSTransform: THandle; // informative data fCopyright: AnsiString; fDescription: AnsiString; fInputColorSpace: AnsiString; fOutputColorSpace: AnsiString; // procedure OpenProfileFromRaw(); procedure CloseProfileFromRaw(); procedure ExtractInfo(); public property MSTransform: THandle read fMSTransform; constructor Create(UseLCMS: boolean = true); // UseLCMS=true works only when IEINCLUDECMS is defined, otherwise it is always False destructor Destroy(); override; procedure LoadFromBuffer(buffer: pointer; bufferlen: integer); procedure Clear(); procedure SaveToStream(Stream: TStream; StandardICC: boolean); procedure LoadFromStream(Stream: TStream; StandardICC: boolean); procedure LoadFromFile(const FileName: string); procedure Assign(source: TIEICC); function IsValid(): boolean; {!! TIEICC.IsApplied Declaration property IsApplied: boolean; Description Returns True if , or have been called since the profile was loaded. !!} property IsApplied: boolean read fApplied; // true after FreeTransform property Raw: pbyte read fRaw; property RawLength: integer read fRawLen; // preset profiles procedure Assign_sRGBProfile(); procedure Assign_LabProfile(WhitePoint_x, WhitePoint_y, WhitePoint_Y_: double); procedure Assign_LabProfileFromTemp(TempK: integer); procedure Assign_LabProfileD50(); procedure Assign_XYZProfile(); procedure Assign_AdobeRGB1998(); procedure Assign_CMYKProfile(); // transform function InitTransform(Destination: TIEICC; InputFormat: integer; OutputFormat: integer; Intent: integer; Flags: integer): boolean; procedure FreeTransform(); function Transform(Destination: TIEICC; InputFormat: integer; OutputFormat: integer; Intent: integer; Flags: integer; InputBuffer: pointer; OutputBuffer: pointer; ImageWidth: integer): boolean; function Apply(SourceBitmap: TIEBaseBitmap; SourceFormat: integer; DestinationBitmap: TIEBaseBitmap; DestinationFormat: integer; DestinationProfile: TIEICC; Intent: integer; Flags: integer): boolean; function Apply2(Bitmap: TIEBaseBitmap; SourceFormat: integer; DestinationFormat: integer; DestinationProfile: TIEICC; Intent: integer; Flags: integer): boolean; function ConvertBitmap(Bitmap: TIEBaseBitmap; DestPixelFormat: TIEPixelFormat; DestProfile: TIEICC): boolean; function IsTransforming: boolean; function CheckTransform(InputFormat: integer): boolean; overload; function CheckTransform(InputFormat: TIEColorSpace): boolean; overload; // informative {!! TIEICC.Copyright Declaration property Copyright: AnsiString; Description Returns the copyright string found inside the ICC profile. !!} property Copyright: AnsiString read fCopyright; {!! TIEICC.Description Declaration property Description: AnsiString; Description Returns the profile description found inside the ICC profile. !!} property Description: AnsiString read fDescription; {!! TIEICC.InputColorSpace Declaration property InputColorSpace: AnsiString; Description Contains the signature of the data color space used. Allowed signatures: Color space Signature XYZData 'XYZ ' labData 'Lab ' luvData 'Luv ' YCbCrData 'YCbr' YxyData 'Yxy ' rgbData 'RGB ' grayData 'GRAY' hsvData 'HSV ' hlsData 'HLS ' cmykData 'CMYK' cmyData 'CMY ' 2colorData '2CLR' 3colorData (if not listed above) '3CLR' 4colorData (if not listed above) '4CLR' 5colorData '5CLR' 6colorData '6CLR' 7colorData '7CLR' 8colorData '8CLR' 9colorData '9CLR' 10colorData 'ACLR' 11colorData 'BCLR' 12colorData 'CCLR' 13colorData 'DCLR' 14colorData 'ECLR' 15colorData 'FCLR'
!!} property InputColorSpace: AnsiString read fInputColorSpace; {!! TIEICC.OutputColorSpace Declaration property OutputColorSpace: AnsiString; Description Returns the profile connection space field (output color space). Allowed signatures: Color space Signature XYZData 'XYZ ' labData 'Lab '
!!} property OutputColorSpace: AnsiString read fOutputColorSpace; end; // TIEICC ///////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// {!! TIELocation Declaration TIELocation = (ieMemory, ieFile, ieTBitmap); Description Value Description ieMemory Uses standard memory. Canvas not available. Used for fast and little images. ieFile Uses memory mapped files. Canvas not available. Used for big images. ieTBitmap Uses TBitmap VCL object. Canvas available. Used for drawing and compatibility. Location can be assigned before or after Allocate. Assigning Location on a existing image it converts the image to new location.
Example // Optimize TImageEnView to handle very large images ImageEnView1.LegacyBitmap := False; ImageEnView1.IEBitmap.Location := ieFile; See Also -
- - !!} TIELocation = ( ieMemory, // use GetMem, no Canvas available (FOR FAST AND LITTLE IMAGES) ieFile, // use Memory mapped file, no Canvas available (FOR BIG IMAGES) ieTBitmap // use TBitmap VCL object, Canvas available (FOR DRAWING) ); {!! TIEMemoryAllocator Declaration } TIEMemoryAllocator = (iemaVCL, iemaSystem, iemaAuto); {!!} {!! TIEBitmapOrigin Declaration } TIEBitmapOrigin = (ieboBOTTOMLEFT, ieboTOPLEFT); {!!} type TIEMask = class; TIEDibbitmap = class; TIEBitmap = class; {!! TIEMultiCallBack Declaration } TIEMultiCallBack = procedure(Bitmap: TIEBitmap; var IOParams: TObject; ImDpiX, ImDpiY: integer) of object; {!!} /////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEBitmap {!! TIERenderVirtualPixel Declaration TIERenderVirtualPixel = procedure(Sender: TObject; SrcX, SrcY: integer; var outval: TRGB) of object; Description Parameter Description Sender event sender object SrcX Source pixel column SrcY Source pixel row outval RGB Value to fill
!!} TIERenderVirtualPixel = procedure(Sender: TObject; SrcX, SrcY: integer; var outval) of object; {!! TIEVirtualBitmapProvider Declaration TIEVirtualBitmapProvider = class Description An abstract class that can be assigned to the property. Custom classes should inherit from TIEVirtualBitmapProvider to be assignable to VirtualBitmapProvider property. Methods and Properties - abstract - abstract !!} TIEVirtualBitmapProvider = class public {!! TIEVirtualBitmapProvider.Render Declaration procedure Render(Container: ; DestBitmap: ; DestWidth: integer; DestHeight: integer; DestX1, DestY1, DestX2, DestY2: integer; SrcCols, SrcRows: PInteger; Transparency: integer; RenderOperation: ; Opacity: double); virtual; abstract; Description Renders a set of pixels to the specified rectangle. Parameter Description Container TIEBitmap object that owns this object. DestBitmap Destination TIEBitmap. DestWidth Destination width. DestHeight Destination height. DestX1 Starting column of destination rectangle. DestY1 Starting row of destination rectangle. DestX2 Ending column of destination rectangle. DestY2 Ending row of destination rectangle. SrcCols Array of source columns (has DestX2-DestX1+1 items). SrcRows Array of source rows (has DestY2-DestY1+1 items). Transparency Rendering transparency (0=transparent, 255=opaque). RenderOperation Rendering operation to perform. Opacity Rendering opacity (0=transparent, 1.0=opaque).
Opacity vs Transparency Both the Opacity and Transparency parameters provide the same functionality. Transparency is the traditional ImageEn value, whereas Opacity provides easier PSD compatibility. While they can be used in combination, generally only one will be used, i.e. leave Opacity=1 and make use of transparency, or alternatively, leave Transparency=255 and make use of Opacity. For example, for 50% opacity: Transparency = 255 and Opacity = 0.5, or Transparency = 128 and Opacity = 1.0 !!} procedure Render(Container: TIEBitmap; DestBitmap: TIEBitmap; DestWidth: integer; DestHeight: integer; DestX1, DestY1, DestX2, DestY2: integer; SrcCols, SrcRows: PInteger; Transparency: integer; RenderOperation: TIERenderOperation; Opacity: double); virtual; abstract; {!! TIEVirtualBitmapProvider.GetSegment Declaration function GetSegment(Container:
; Row: integer; Col: integer; Width: integer): pointer; virtual; abstract; Description Returns a pointer to row segment. Parameter Description Container TIEBitmap object that owns this object. Row Segment row. Col Segment column. Width Width (in pixels) of the row.
!!} function GetSegment(Container: TIEBitmap; Row: integer; Col: integer; Width: integer): pointer; virtual; abstract; end; {!! TIEBitmap Description TIEBitmap is a replacement for the VCL TBitmap class. It has many methods and properties compatible with TBitmap and enhances it by supporting multi-threading, large images and a wide range of image formats. TIEBitmap can store images in memory mapped files (for big images), in memory (fast access) or can encapsulate TBitmap objects (for canvas drawing and compatibility). Methods and Properties General
Assignment between Objects File I/O (inherited from ) (Load from file/stream) (Save to file/stream) Canvas Access Alpha Channel (Transparency) Pixel Access Palette and Color (inherited from ) (inherited from ) (inherited from ) Image Manipulation IEVision related Events !!} TIOParams = class; TIEBitmap = class(TIEBaseBitmap) private // image data fmemmap: TIEFileBuffer; fWorkingMap: pointer; // last mapped memory buffer fRGBPalette: PIERGBPalette; fRGBPaletteLen: integer; fPaletteUsed: integer; // number of colors used of the palette fAlphaChannel: TIEBitmap; fMemory: pointer; // used only when fLocation=ieMemory fRealMemory: pointer; // non aligned fMemory pointer fBitmap: TBitmap; // used only when fLocation=ieTBitmap fBitmapScanlines: TIEArrayOfPointer; // used by scanline[] for TBitmap object fScanlinesToUnMapPtr: TList; // list of scanlines to unmap, valid only for ieFile and using GetRow (and FreeRow) fScanlinesToUnMapRow: TList; // list of scanlines to unmap, like fScanlinesToUnMapPtr but contains the row index to unmap fOrigin: TIEBitmapOrigin; // bitmap origin (topleft or bottomleft) // image properties fFilename: string; // Last filename used for saving or loading of images fFileType: TIOFileType; // Last file type used for saving or loading of images fWidth, fHeight: integer; fBitCount: integer; fChannelCount: integer; fRowLen: int64; fPixelFormat: TIEPixelFormat; fIsAlpha: boolean; // if true this object is the alpha channel of another TIEBitmap object fLocation: TIELocation; fFull: boolean; // True if all bits are 1, Modified by SetPixels__, SetAlpha, Fill fEncapsulatedFromTBitmap: boolean; // True if fBitmap comes from an original TBitmap. Do not free it. fEncapsulatedFromMemory: boolean; // True if fMemory comes from an original memory. Do not free it. fMinFileSize: int64; // if fRowLen*height < fMinFileSize Location will be ieMemory otherwise will be ieFile fDefaultDitherMethod: TIEDitherMethod; // default method used to convert color image to black/white fColorProfile: TIEICC; // image color profile fRenderColorProfile: TIEICC; // the sRGB color profile used for rendering // rendering options fBlackValue: double; // pixels with value <= fBlackValue will be black (appliable only to ie8g, ie16g, ie24RGB) - boths fBlackValue and fWhiteValue to zero disables them fWhiteValue: double; // pixels with value >= fWhiteValue will be white (appliable only to ie8g, ie16g, ie24RGB) fChannelOffset: array[0..IEMAXCHANNELS - 1] of integer; fEnableChannelOffset: boolean; // automatically set to true when one of fChannelOffset values are <>0 fContrast: integer; fAdjustmentsMask: TIEMask; // where to apply fBlackValue/fWhiteValue/fChannelOffset/fContrast/RenderOperation. Nil = the whole image // fBitAlignment: integer; // number of bits of alignment (32 bit is the default) - works only for ieMemory images fMemoryAllocator: TIEMemoryAllocator; // others fFullReallocate: boolean; // next AllocateImage will be forced to reallocate image (even size and pixelformat doesn't change) fCanvasCurrentAlpha: integer; // when -1 then pf8bit and graypal are not set for this TBitmap fIECanvas: TIECanvas; fOnChanged: TNotifyEvent; // Occurs on editing of the image fModified: Boolean; // True if the file has changed since loading // fragmented memory allocation fFragmentsCount: integer; // number of fragments fRowsPerFragment: integer; // image rows per fragment fFragments: ppointerarray; // array of pointers to fragments // virtual bitmap support fOnRenderVirtualPixel: TIERenderVirtualPixel; // if assigned then this is a virtual bitmap fVirtualBitmapProvider: TObject; // if assigned then this is a virtual bitmap (alternative or in conjunction with fOnRenderVirtualPixel) fVirtualBitmapRowBuffer: pointer; // used as temporary buffer in Scanline[] // support for CreateROI fROIOriginalBitmap: TIEBitmap; // <>nil: this is a ROI fROIOriginalRect: TRect; fROICanvas: TIECanvas; fIsResource: Boolean; // True during LoadFromResource calls to handle resource formats that do not have headers // support for Save and Restore methods fSavedBitmaps: TObjectList; // a list of TIEBitmap objects // function AllocateImage: boolean; procedure SetPixelFormat(Value: TIEPixelFormat); procedure ConvertToPixelFormat(DestPixelFormat: TIEPixelFormat); function GetPixels_ie1g(x, y: integer): boolean; function GetPixels_ie8(x, y: integer): byte; function GetPixels_ie16g(x, y: integer): word; function GetPixels_ie24RGB(x, y: integer): TRGB; function GetPixels_ie32RGB(x, y: integer): TRGBA; function GetPixels_ie32f(x, y: integer): single; function GetPixels_ieCMYK(x, y: integer): TCMYK; function GetPixels_ieCIELab(x, y: integer): TCIELab; function GetPixels_ie48RGB(x, y: integer): TRGB48; function GetPPixels_ie24RGB(x, y: integer): PRGB; function GetPPixels_ie32RGB(x, y: integer): PRGBA; function GetPPixels_ie48RGB(x, y: integer): PRGB48; function GetPixels(x, y: integer): TRGB; procedure SetPixels(x, y: integer; value: TRGB); procedure SetPixels_ie1g(x, y: integer; Value: boolean); procedure SetPixels_ie8(x, y: integer; Value: byte); procedure SetPixels_ie16g(x, y: integer; Value: word); procedure SetPixels_ie24RGB(x, y: integer; Value: TRGB); procedure SetPixels_ie32RGB(x, y: integer; Value: TRGBA); procedure SetPixels_ie32f(x, y: integer; Value: single); procedure SetPixels_ieCMYK(x, y: integer; Value: TCMYK); procedure SetPixels_ieCIELab(x, y: integer; Value: TCIELab); procedure SetPixels_ie48RGB(x, y: integer; Value: TRGB48); function GetAlpha(x, y: integer): byte; procedure SetAlpha(x, y: integer; Value: byte); procedure SetLocation(Value: TIELocation); procedure UpdateTBitmapPalette; procedure CopyPaletteFromTBitmap(source: TBitmap; colors: integer); function GetHasAlphaChannel: boolean; procedure FreeBitmapScanlines; procedure BuildBitmapScanlines; function GetVclBitmap: TBitmap; procedure SetChannelOffset(idx: integer; value: integer); function GetChannelOffset(idx: integer): integer; procedure SetBitAlignment(value: integer); function GetChannelCount: integer; procedure SetChannelCount(Value: Integer); procedure SetCanvasCurrentAlpha(v: integer); procedure FragmentedAlloc(); procedure FreeFragments(); procedure AllocateMemory(size: int64; var StartBuffer: pointer; var AlignedBuffer: pointer); procedure SetOrigin(value: TIEBitmapOrigin); procedure SetVirtualBitmapProvider(value: TObject); procedure ReleaseROI(); procedure DestroyMe(Sender: TObject); function GetMemory(): pointer; function GetAdjustmentsMask(): TIEMask; function GetParams: TIOParams; function GetParamsEnabled: Boolean; procedure SetParamsEnabled(const Value: Boolean); procedure UpdateOwner(); procedure SetModified(Value: Boolean); procedure AssignMetaInfo(Source: TIEBitmap); procedure BlendAlpha(BackgroundColor: TColor); protected fIOParams: TIOParams; function GetIsVirtual(): boolean; virtual; function GetCanvas: TCanvas; function GetIECanvas: TIECanvas; function GetAlphaChannel: TIEBitmap; virtual; function GetAlphaChannelOpt: TIEBitmap; virtual; function GetBitCount: integer; override; procedure SetBitCount(Value: Integer); function GetWidth: integer; override; function GetHeight: integer; override; procedure SetWidth(Value: integer); override; procedure SetHeight(Value: integer); override; function GetRowLen: integer; override; procedure SetRowLen(Value: Integer); function GetScanLine(Row: integer): pointer; override; function GetPixelFormat: TIEPixelFormat; override; function GetPalette(index: integer): TRGB; override; function GetPaletteBuffer: pointer; override; procedure SetPalette(index: integer; Value: TRGB); override; function GetPaletteLen: integer; override; function GetPaletteUsed(): integer; override; procedure SetPaletteUsed(Value: integer); override; procedure FreeAllMaps; procedure Render_ie24RGB(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation); virtual; procedure Render_ie24RGB_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation; Opacity: double); virtual; procedure Render_ie32RGB(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation); virtual; procedure Render_ie32RGB_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation; Opacity: double); virtual; procedure Render_ie1g(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean); virtual; procedure Render_ie1g_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; Opacity: double); virtual; procedure Render_ie8g(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean); virtual; procedure Render_ie8g_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; Opacity: double); virtual; procedure Render_ie8p(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean); virtual; procedure Render_ie8p_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; Opacity: double); virtual; procedure Render_ie16g(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean); virtual; procedure Render_ie16g_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; Opacity: double); virtual; procedure Render_ie32f(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean); virtual; procedure Render_ie32f_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; Opacity: double); virtual; procedure Render_ieCMYK(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean); virtual; procedure Render_ieCMYK_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; Opacity: double); virtual; procedure Render_ieCIELab(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean); virtual; procedure Render_ieCIELab_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; Opacity: double); virtual; procedure Render_ie48RGB(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation); virtual; procedure Render_ie48RGB_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation; Opacity: double); virtual; procedure Render_ieVirtual(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation); virtual; procedure Render_ieVirtual_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation; Opacity: double); virtual; public fOwner: TComponent; // The TImageEnView this is attached to, if any constructor Create; overload; virtual; constructor Create(ImageWidth, ImageHeight: integer; ImagePixelFormat: TIEPixelFormat = ie24RGB); overload; constructor Create(const FileName: string; IOParams: TIOParams = nil); overload; constructor Create(image: TIEBitmap); overload; constructor Create(image: TIEBitmap; Rect: TRect); overload; constructor Create(image: TBitmap; Rect: TRect); overload; constructor Create(Buffer: pointer; BufferSize: integer; Format: integer = 0); overload; constructor CreateAsAlphaChannel(ImageWidth, ImageHeight: integer; ImageLocation: TIELocation); destructor Destroy; override; function CreateROIBitmap(Rect: TRect; ROIPixelFormat: TIEPixelFormat = ienull; PerformAlphaCompositing: boolean = false): TIEBitmap; function CreateROICanvas(Rect: TRect; AntiAlias: boolean = true; UseGDIPlus: boolean = true; PerformAlphaCompositing: boolean = false): TIECanvas; overload; function CreateROICanvas(AntiAlias: boolean = true; UseGDIPlus: boolean = true; PerformAlphaCompositing: boolean = false): TIECanvas; overload; {!! TIEBitmap.Filename Declaration property Filename: string; Description The last filename used when reading or writing the bitmap to file. !!} property Filename: string read fFilename write fFilename; {!! TIEBitmap.FileType Declaration property FileType: ; Description The file type when last reading reading or writing the bitmap to file. !!} property FileType: TIOFileType read fFileType write fFileType; property Width: integer read GetWidth write SetWidth; property Height: integer read GetHeight write SetHeight; property PixelFormat: TIEPixelFormat read GetPixelFormat write SetPixelFormat; procedure Assign(Source: TObject); override; // for TIEBitmap and TBitmap procedure AssignImage(Source: TIEBaseBitmap); override; // assign without alpha channel procedure AssignRect(Source: TObject; SourceRect: TRect); property ScanLine[Row: integer]: pointer read GetScanLine; function GetSegment(Row: integer; Col: integer; Width: integer): pointer; virtual; procedure UpdateFromTBitmap; procedure AdjustCanvasOrientation; procedure StretchValues(); procedure FixContrast(); procedure FixChannelOffset(); function CheckFormat(AllowedFormats: TIEPixelFormatSet; AutoConvert: boolean): boolean; {!! TIEBitmap.Memory Declaration property Memory: pointer; Description Returns the image pointer when Location is ieMemory or ieTBitmap and it is not fragmented. !!} property Memory: pointer read GetMemory; {$ifdef IEVISION} function GetIEVisionImage(): TIEVisionImage; procedure AssignIEVisionImage(Source: TIEVisionImage); {$endif} function Read(const FileName: string; IOParams: TIOParams = nil; bCheckUnknown: Boolean = True): boolean; overload; function Read(Stream: TStream; FileType: TIOFileType = 0; IOParams: TIOParams = nil): boolean; overload; function Read(Buffer: pointer; BufferSize: integer; FileType: TIOFileType = 0; IOParams: TIOParams = nil): boolean; overload; function Write(const FileName: string; IOParams: TIOParams = nil): boolean; overload; function Write(Stream: TStream; FileType: TIOFileType; IOParams: TIOParams = nil): boolean; overload; procedure SaveState(); procedure RestoreState(); function GetHash(Algorithm: TIEHashAlgorithm=iehaMD5): AnsiString; {!! TIEBitmap.TBitmapScanlines Declaration property TBitmapScanlines: ; Description Returns an array of pointers for each scanline of the bitmap. !!} property TBitmapScanlines: TIEArrayOfPointer read fBitmapScanlines; property Canvas: TCanvas read GetCanvas; property IECanvas: TIECanvas read GetIECanvas; {!! TIEBitmap.EncapsulatedFromTBitmap Declaration property EncapsulatedFromTBitmap: boolean; Description Returns True if the image is encapsulated from a TBitmap object (using ). !!} property EncapsulatedFromTBitmap: boolean read fEncapsulatedFromTBitmap write fEncapsulatedFromTBitmap; {!! TIEBitmap.EncapsulatedFromMemory Declaration property EncapsulatedFromMemory: boolean; Description Returns True if the image is encapsulated from a memory buffer (using ). !!} property EncapsulatedFromMemory: boolean read fEncapsulatedFromMemory write fEncapsulatedFromMemory; property Rowlen: integer read GetRowlen write SetRowLen; function Allocate(ImageWidth, ImageHeight: integer; ImagePixelFormat: TIEPixelFormat=ie24RGB): boolean; override; procedure EncapsulateTBitmap(obj: TBitmap; DoFreeImage: boolean=false); procedure EncapsulateMemory(mem: pointer; bmpWidth, bmpHeight: integer; bmpPixelFormat: TIEPixelFormat; DoFreeImage: boolean; Origin: TIEBitmapOrigin = ieboBOTTOMLEFT); procedure FreeImage(freeAlpha: boolean = true); procedure SwitchTo(Target: TIEBitmap); property AlphaChannel: TIEBitmap read GetAlphaChannel; property AlphaChannelOpt: TIEBitmap read GetAlphaChannelOpt; procedure SyncAlphaChannel(AntiAlias: Boolean = True); procedure ReplaceAlphaChannel(Value: TIEBitmap); function DetachAlphaChannel(CreateIfNotExists: Boolean = false): TIEBitmap; {!! TIEBitmap.IsAlpha Declaration property IsAlpha: boolean; Description Returns True if this bitmap is an alpha channel (i.e. ImageEnView.IEBitmap.AlphaChannel). !!} property IsAlpha: boolean read fIsAlpha write fIsAlpha; property Location: TIELocation read fLocation write SetLocation; procedure CopyToTBitmap(Dest: TBitmap); procedure CopyWithMask1(Dest: TIEBitmap; SourceMask: TIEMask; Background: TColor); overload; procedure CopyWithMask1(Dest: TIEBitmap; SourceMask: TIEMask); overload; procedure CopyWithMask2(Dest: TIEBitmap; DestMask: TIEMask); procedure CopyFromMemory(SrcBuffer: pointer; SrcWidth: integer; SrcHeight: integer; SrcPixelFormat: TIEPixelFormat; SrcOrigin: TIEBitmapOrigin; SrcRowLen: integer); procedure CopyFromTBitmap(Source: TBitmap); procedure CopyFromTIEMask(Source: TIEMask); procedure CopyToTIEMask(Dest: TIEMask); procedure CopyRectTo(Dest: TIEBitmap; SrcX, SrcY, DstX, DstY: integer; RectWidth, RectHeight: integer; CopyAlpha: boolean = false); function CopyToClipboard(IncludeImageEnFormat: Boolean = True; DpiX: Integer = 200; DpiY: Integer = 200): Boolean; function PasteFromClipboard(): Boolean; procedure MergeAlphaRectTo(Dest: TIEBitmap; SrcX, SrcY, DstX, DstY: integer; RectWidth, RectHeight: integer); function GetRow(Row: integer): pointer; virtual; procedure FreeRow(Row: integer); virtual; procedure Resize(NewWidth, NewHeight: integer; BackgroundValue: double = 0; FillAlpha: integer = 255; HorizAlign: TIEHAlign = iehLeft; VertAlign: TIEVAlign = ievTop); overload; procedure Resize(AddLeft, AddTop, AddRight, AddBottom: integer; BackgroundValue: double; FillAlpha: integer = 255); overload; procedure Resample(NewWidth, NewHeight: integer; FilterType: TResampleFilter = rfNone; bMaintainAspectRatio : Boolean = False); overload; procedure Resample(ScaleBy: Double; FilterType: TResampleFilter = rfNone); overload; procedure Rotate(Angle: double; AntiAliasMode: TIEAntialiasMode = ierFast; BackgroundColor: TColor = clWhite); {$ifdef IEIncludeDeprecatedInV4} overload; {$endif} {$ifdef IEIncludeDeprecatedInV4} // Deprecated in 5.0.0 procedure Rotate(Angle: double; AntiAlias: boolean; AntialiasMode: TIEAntialiasMode; BackgroundColor: TColor); overload; {$ifdef IEWarningForDeprecated} deprecated {$ifdef IESupportDeprecatedDescription} 'Remove the AntiAlias parameter - http://imageen.com/help/Compatibility.html' {$endif}; {$endif} {$endif} procedure RotateEx(Angle: double; AntialiasMode: TIEAntialiasMode; BackgroundColor: TColor; OnProgress: TIEProgressEvent; Sender: TObject); procedure Flip(Dir: TFlipDir); procedure Crop(x1, y1, x2, y2 : Integer); overload; procedure Crop(Rect : TRect); overload; function CropAlpha(): Boolean; property VclBitmap: TBitmap read GetVclBitmap write fBitmap; procedure MoveRegion(x1, y1, x2, y2, DstX, DstY: integer; BackgroundValue: double; FillSource: boolean = true); procedure CopyFromTDibBitmap(Source: TIEDibBitmap); procedure MergeFromTDibBitmap(Source: TIEDibBitmap; x, y: integer); procedure CopyToTDibBitmap(Dest: TIEDibBitmap; source_x, source_y, sourceWidth, sourceHeight: integer); procedure CopyFromDIB(Source: THandle); overload; procedure CopyFromDIB(BitmapInfo: pointer; Pixels: pointer=nil); overload; function CreateDIB: THandle; overload; function CreateDIB(x1, y1, x2, y2: integer): THandle; overload; property Pixels_ie1g[x, y: integer]: boolean read GetPixels_ie1g write SetPixels_ie1g; property Pixels_ie8[x, y: integer]: byte read GetPixels_ie8 write SetPixels_ie8; property Pixels_ie16g[x, y: integer]: word read GetPixels_ie16g write SetPixels_ie16g; property Pixels_ie24RGB[x, y: integer]: TRGB read GetPixels_ie24RGB write SetPixels_ie24RGB; property Pixels_ie32RGB[x, y: integer]: TRGBA read GetPixels_ie32RGB write SetPixels_ie32RGB; property Pixels_ie32f[x, y: integer]: single read GetPixels_ie32f write SetPixels_ie32f; property Pixels_ieCMYK[x, y: integer]: TCMYK read GetPixels_ieCMYK write Setpixels_ieCMYK; property Pixels_ieCIELab[x, y: integer]: TCIELab read GetPixels_ieCIELab write Setpixels_ieCIELab; property Pixels_ie48RGB[x, y: integer]: TRGB48 read GetPixels_ie48RGB write SetPixels_ie48RGB; property PPixels_ie24RGB[x, y: integer]: PRGB read GetPPixels_ie24RGB; property PPixels_ie32RGB[x, y: integer]: PRGBA read GetPPixels_ie32RGB; property PPixels_ie48RGB[x, y: integer]: PRGB48 read GetPPixels_ie48RGB; property Pixels[x, y: integer]: TRGB read GetPixels write SetPixels; // return always RGB (also with ie1g, ie8...) property Alpha[x, y: integer]: byte read GetAlpha write SetAlpha; procedure RenderToTIEBitmap(ABitmap: TIEBitmap; var XLUT, YLUT: pinteger; UpdRect: PRect; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; EnableAlpha: boolean; SolidBackground: boolean; Transparency: integer; Filter: TResampleFilter; FreeTables: boolean; RenderOperation: TIERenderOperation = ielNormal; Opacity: double = 1.0); procedure RenderToTBitmap(ABitmap: TBitmap; var XLUT, YLUT: pinteger; UpdRect: PRect; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; EnableAlpha: boolean; SolidBackground: boolean; Transparency: integer; Filter: TResampleFilter; FreeTables: boolean; RenderOperation: TIERenderOperation = ielNormal; Opacity: double = 1.0); procedure RenderToTBitmapEx(Dest: TBitmap; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; Transparency: integer = 255; Filter: TResampleFilter = rfNone; RenderOperation: TIERenderOperation = ielNormal; Opacity: double = 1.0); overload; procedure RenderToTBitmapEx(Dest: TBitmap; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; bEnableAlpha: Boolean; Transparency: integer; Filter: TResampleFilter; RenderOperation: TIERenderOperation = ielNormal; Opacity: double = 1.0); overload; procedure RenderToTIEBitmapEx(Dest: TIEBitmap; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; bEnableAlpha: Boolean = True; Transparency: integer = 255; Filter: TResampleFilter = rfNone; RenderOperation: TIERenderOperation = ielNormal; Opacity: double = 1.0); procedure RenderToCanvasWithAlpha(Dest: TCanvas; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; Transparency: integer = 255; Filter: TResampleFilter = rfNone; RenderOperation: TIERenderOperation = ielNormal; Opacity: double = 1.0); procedure StretchRectTo(Dest: TIEBitmap; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; Filter: TResampleFilter; Transparency: integer = 255; Opacity: double = 1.0); procedure RenderToCanvas(DestCanvas: TCanvas; xDst, yDst, dxDst, dyDst: integer; Filter: TResampleFilter; Gamma: double = 0; BackgroundColor: TColor = clWhite); procedure DrawToCanvas(DestCanvas: TCanvas; xDst, yDst : integer); procedure DrawToCanvasWithAlpha(DestCanvas: TCanvas; xDst, yDst : integer; Transparency: integer; Opacity: Double); procedure DrawToTIEBitmap(Dest: TIEBitmap; XDest, YDest : Integer); overload; procedure DrawToTIEBitmap(Dest: TIEBitmap; XDest, YDest : Integer; SrcRect : TIERectangle); overload; procedure DrawToTIEBitmap(Dest: TIEBitmap; DestRect : TIERectangle; SrcRect : TIERectangle; Filter: TResampleFilter = rfLanczos3); overload; procedure SynchronizeRGBA(RGBAtoAlpha: boolean; UpdatePixelFormat: Boolean = False); procedure MergeWithAlpha(Bitmap: TIEBitmap; DstX: integer=0; DstY: integer=0; DstWidth: integer=-1; DstHeight: integer=-1; Transparency: integer=255; ResampleFilter: TResampleFilter = rfNone; Operation: TIERenderOperation = ielNormal; Resample: boolean = true; SrcX: integer = 0; SrcY: integer = 0; Opacity: double = 1.0); procedure Changed(); {!! TIEBitmap.Full Declaration property Full: boolean; Description Returns true if all pixels are 1 (or white). See also: . !!} property Full: boolean read fFull write fFull; {!! TIEBitmap.Origin Declaration property Origin: ; Description Specifies the bitmap origin. Default: bottom-left, which is Windows compatible. Other libraries may require top-left (like OpenCV). !!} property Origin: TIEBitmapOrigin read fOrigin write SetOrigin; procedure SyncFull; // set Full to True if all values are 255 procedure Fill(Value: double); overload; procedure Fill(Value: TRGBA); overload; procedure FillRect(x1, y1, x2, y2: integer; Value: double); property HasAlphaChannel: boolean read GetHasAlphaChannel; {!! TIEBitmap.MinFileSize Declaration property MinFileSize: int64; Description Specifies the minimum memory needed by the image to allow use of memory mapped file. If the memory needed by the image is less than MinFileSize, the image will be stored in memory (also if the Location is ieFile). If the global setting is not -1, it overrides the MinFileSize value. Default: 90% of available free memory See Also - - !!} property MinFileSize: int64 read fMinFileSize write fMinFileSize; procedure RemoveAlphaChannel(Merge: boolean = false; BackgroundColor: TColor = clWhite); procedure FeatherAlphaEdges(iFeatherDepth : Integer); {!! TIEBitmap.DefaultDitherMethod Declaration property DefaultDitherMethod: ; Description Specifies the default dithering method to apply when a color image needs to be converted to black/white. Default: ieThreshold !!} property DefaultDitherMethod: TIEDitherMethod read fDefaultDitherMethod write fDefaultDitherMethod; {!! TIEBitmap.BlackValue Declaration property BlackValue: double; Description Specifies (along with ) the value range from black to white. For example, if your image is a gray scale (256 levels) where only values from 100 to 200 are used (100 is black and 200 is white), to display the image you must write: ImageEnView.IEBitmap.BlackValue := 100; ImageEnView.IEBitmap.WhiteValue := 200; ImageEnView.Update; Demo Demos\Display\DisplayAdjust\Display.dpr !!} property BlackValue: double read fBlackValue write fBlackValue; {!! TIEBitmap.WhiteValue Declaration property BlackValue: double; Description Specifies (along with ) the values range from black to white. For example, if your image is a gray scale (256 levels) where only values from 100 to 200 are used (100 is black and 200 is white), to display the image you must write: ImageEnView.IEBitmap.BlackValue := 100; ImageEnView.IEBitmap.WhiteValue := 200; ImageEnView.Update; Demo Demos\Display\DisplayAdjust\Display.dpr !!} property WhiteValue: double read fWhiteValue write fWhiteValue; procedure AutoCalcBWValues; property ChannelOffset[idx: integer]: integer read GetChannelOffset write SetChannelOffset; {!! TIEBitmap.Contrast Declaration property Contrast: integer; Description Specifies a dynamic contrast to apply. It does not modify the image, only how it is displayed. Allowed values are 0 to 100. Example ImageEnView.IEBitmap.Contrast := 20; ImageEnView.Update; Demo Demos\Display\DisplayAdjust\Display.dpr !!} property Contrast: integer read fContrast write fContrast; {!! TIEBitmap.AdjustmentsMask Declaration property AdjustmentsMask: ; Description Use the AdjustmentsMask to select which pixels are affected by , , , and layers blending operations. To reset the adjustments mask (apply changes to the whole image) use: ImageEnView1.IEBitmap.AdjustmentsMask.Empty(); ImageEnView1.Update(); Example // copy ImageEnView current selection to AdjustmentsMask and apply Contrast in real time ImageEnView.IEBitmap.AdjustmentsMask.Assign( ImageEnView1.SelectionMask ); ImageEnView.IEBitmap.Contrast := 20; ImageEnView.Update(); Demo Demos\Display\DisplayAdjust\Display.dpr !!} property AdjustmentsMask: TIEMask read GetAdjustmentsMask; function IsGrayScale: boolean; function IsAllBlack: boolean; property BitAlignment: integer read fBitAlignment write SetBitAlignment; function IsEmpty: boolean; procedure Clear; procedure CopyAndConvertFormat(Source: TIEBitmap); property ChannelCount: integer read GetChannelCount write SetChannelCount; // informative only field property BitCount: integer read GetBitCount write SetBitCount; // informative only field {!! TIEBitmap.MemoryAllocator Declaration property MemoryAllocator: ; Description Specifies the method used to allocate bitmap memory. !!} property MemoryAllocator: TIEMemoryAllocator read fMemoryAllocator write fMemoryAllocator; // function CalcRAWSize: integer; procedure SaveRAWToBufferOrStream(Buffer: pointer; Stream: TStream; StreamHasSize: boolean = true); function LoadRAWFromBufferOrStream(Buffer: pointer; Stream: TStream): boolean; procedure LoadFromResource(Instance: THandle; const ResName: string; ResType: PChar; Format: integer = 0); overload; procedure LoadFromResource(Instance: THandle; const ResID: Integer; ResType: PChar; Format: integer = 0); overload; // property CanvasCurrentAlpha: integer read fCanvasCurrentAlpha write SetCanvasCurrentAlpha; procedure CopyPaletteTo(Dest: TIEBaseBitmap); override; property FragmentsCount: integer read fFragmentsCount; {!! TIEBitmap.OnChanged Declaration property OnChanged: TNotifyEvent; Description Occurs whenever the TIEBitmap is modified, e.g. , , or any method of . OnChanged does not occur for changes to: - - - - - See Also - !!} property OnChanged: TNotifyEvent read fOnChanged write fOnChanged; property Modified: Boolean read fModified write SetModified; {!! TIEBitmap.OnRenderVirtualPixel Declaration property OnRenderVirtualPixel: ; Description Occurs whenever a pixel must be rendered if is ieVirtual. Applications should set OnRenderVirtualPixel after = ieVirtual. Example ImageEnView1.LegacyBitmap := false; ImageEnView1.IEBitmap.OnRenderVirtualPixel := DrawVirtualPixel; ImageEnView1.Update(); ... procedure TForm1.DrawVirtualPixel(Sender: TObject; SrcX, SrcY: integer; var outval: TRGB); begin outval := CreateRGB(SrcX mod 255, SrcY mod 255, 255); end; !!} property OnRenderVirtualPixel: TIERenderVirtualPixel read fOnRenderVirtualPixel write fOnRenderVirtualPixel; {!! TIEBitmap.VirtualBitmapProvider Declaration property VirtualBitmapProvider: TObject; Description Specifies a bitmap content provider. The assigned object will be de-allocated when TIEBitmap destruction, assigning Nil or replacing it with a new object. Using this property it is possible to create a bitmap without allocating memory. When the image (or part of it) needs to be displayed a method will be called. This is an alternative way to . At the moment only classes inherited from the abstract class are supported. Example 1 ImageEnView1.LegacyBitmap := false; ImageEnView1.IEBitmap.VirtualBitmapProvider := TIESlippyMap.Create(); with TIESlippyMap(ImageEnView1.IEBitmap.VirtualBitmapProvider) do begin // move to London Latitude := 51.503614574056016; Longitude := -0.12774750793460043; // location at bitmap center PointPosition := Point(ImageEnView1.IEBitmap.Width div 2, ImageEnView1.IEBitmap.Height div 2); // zoom Zoom := 14; end; ImageEnView1.Update(); Example 2 type TMyRenderer = class(TIEVirtualBitmapProvider) public procedure Render(Container: TIEBitmap; DestWidth: integer; DestHeight: integer; DestScanlines: PPointerArray; DestX1, DestY1, DestX2, DestY2: integer; SrcCols, SrcRows: PInteger; Transparency: integer; RenderOperation: TIERenderOperation; Opacity: double); override; function GetSegment(Container: TIEBitmap; Row: integer; Col: integer; Width: integer): pointer; override; end; procedure TMyRenderer.Render(Container: TIEBitmap; DestWidth: integer; DestHeight: integer; DestScanlines: PPointerArray; DestX1, DestY1, DestX2, DestY2: integer; SrcCols, SrcRows: PInteger; Transparency: integer; RenderOperation: TIERenderOperation; Opacity: double); begin ...application specific... end; function TMyRenderer.GetSegment(Container: TIEBitmap; Row: integer; Col: integer; Width: integer): pointer; begin ...application specific... end; // assign TMyRenderer to ImageEnView1.IEBitmap ImageEnView1.LegacyBitmap := false; ImageEnView1.IEBitmap.VirtualBitmapProvider := TMyRenderer.Create(); ImageEnView1.Update(); See Also - - !!} property VirtualBitmapProvider: TObject read fVirtualBitmapProvider write SetVirtualBitmapProvider; {!! TIEBitmap.IsVirtual Declaration property IsVirtual: boolean; Description Returns true when or is assigned, meaning that the image content is virtual (no buffer is allocated). !!} property IsVirtual: boolean read GetIsVirtual; {!! TIEBitmap.ColorProfile Declaration property ColorProfile: ; Description Contains the bitmap color profile loaded from TIFF, Jpeg or PSD file format. Currently used for CMYK pixel format only. See also: Example // Apply color profile on rendering IEGlobalSettings().ApplyColorProfileOnRendering := True; // not actually necessary, this is the default ImageEnView1.IO.NativePixelFormat := True; // this says "do not convert to RGB" ImageEnView1.IO.LoadFromFile('cmyk-jpeg.jpg'); // Apply color profile before rendering IEGlobalSettings().EnableCMS := True; IEGlobalSettings().ApplyColorProfileOnRendering := False; ImageEnView1.IO.NativePixelFormat := False; // this says "convert to RGB" ImageEnView1.IO.LoadFromFile('cmyk-jpeg.jpg'); // Do not apply color profile IEGlobalSettings().EnableCMS := False; IEGlobalSettings().ApplyColorProfileOnRendering := False; ImageEnView1.IO.NativePixelFormat := False; // this says "convert to RGB" ImageEnView1.IO.LoadFromFile('cmyk-jpeg.jpg'); !!} property ColorProfile: TIEICC read fColorProfile; property ParamsEnabled: Boolean read GetParamsEnabled write SetParamsEnabled; property Params: TIOParams read GetParams; end; // TIEBitmap /////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// // TIEVirtualRotatedBitmap TIEVirtualRotatedBitmap = class(TIEBitmap) private fSource: TIEBitmap; fSourceWidth, fSourceHeight: Integer; fSourcePixelFormat: TIEPixelFormat; fFreeSourceOnDestroy: Boolean; fRotation: Double; fRotationRad: Double; fBackgroundRGB: TRGB; fBackgroundGray: byte; fArx1, fArx2: array of integer; fAry1, fAry2: array of integer; public constructor Create(Source: TIEBitmap; Rotation: Double; Background: TColor = clBlack; FreeSourceOnDestroy: Boolean = false); destructor Destroy(); override; procedure RenderVirtualPixel(Sender: TObject; SrcX, SrcY: integer; var outval); end; ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// // TIEVirtualClippedBitmap // // todo: Doesn't work for ie1g bitmaps TIEVirtualClippedBitmap = class(TIEBitmap) private fSource: TIEBitmap; fRect: TRect; fFreeSourceOnDestroy: Boolean; fAlphaChannel: TIEVirtualClippedBitmap; protected function GetAlphaChannel(): TIEBitmap; override; function GetAlphaChannelOpt: TIEBitmap; override; function GetScanLine(Row: integer): pointer; override; function GetPalette(index: integer): TRGB; override; function GetPaletteBuffer(): pointer; override; function GetPaletteLen(): integer; override; function GetPaletteUsed(): integer; override; public constructor Create(Source: TIEBitmap; Rect: TRect; FreeSourceOnDestroy: Boolean = false); destructor Destroy(); override; function GetSegment(Row: integer; Col: integer; Width: integer): pointer; override; function GetRow(Row: integer): pointer; override; procedure FreeRow(Row: integer); override; procedure RenderVirtualPixel(Sender: TObject; SrcX, SrcY: integer; var outval); end; ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// // TIEMask {!! TIEMask Description Contains a selection, which is a map of selected and unselected pixels. A selection map can have a depth of 1 bit or 8 bit. For a map of 1 bit, 0 is a non-selected pixel, while 1 is selected. For a map of 8 bit, 0 is non-selected pixel, 1-254 is a "semi" selected pixel, and 255 is fully selected pixel. component uses this class to store current selection in property. Methods and Properties !!} TIEMask = class private fWidth: integer; // width of bit mask fHeight: integer; // height of bit mask fBitsperpixel: integer; // max 8 bits per pixel fRowlen: int64; // len in bytes of a row fBits: pbyte; // bit mask (0=not selected, 1=selected) fX1, fY1, fX2, fY2: integer; // bounding rect fBitmapInfoHeader1: TBitmapInfoHeader256; fTmpBmp: pbyte; // used by DrawOutline fTmpBmpWidth, fTmpBmpHeight: integer; // used by DrawOutline fTmpBmpScanline: ppointerarray; // used by DrawOutline fFull: boolean; // true if all pixels are 1 or 255 fDrawPixelBitmap: TBitmap; fDrawPixelPtr: PRGB; function DrawHorizontalLine(Alpha: integer; xleft, xright, y: integer): integer; procedure DrawSinglePolygon(Alpha: integer; SelPoly: PPointArray; SelPolyCount: integer); function GetScanLine(Row: integer): pointer; procedure CheckMemoryAllocation(); function GetBits(): pbyte; protected public constructor Create; destructor Destroy; override; procedure SetPixel(x, y: integer; Alpha: integer); function GetPixel(x, y: integer): integer; procedure SetRectangle(Rect: TRect; Alpha: integer); overload; procedure SetRectangle(x1, y1, x2, y2: integer; Alpha: integer); overload; procedure SetEllipse(CenterX, CenterY, Width, Height: integer; Alpha: integer); procedure AllocateBits(width, height: integer; bitsperpixel: integer); procedure Resize(NewWidth, NewHeight: integer); procedure FreeBits; procedure CopyBitmap(Dest, Source: TBitmap; dstonlymask, srconlymask: boolean); procedure CopyIEBitmap(Dest, Source: TIEBitmap; dstonlymask, srconlymask: boolean; UseAlphaChannel: boolean); procedure CopyIEBitmapAlpha(Dest, Source: TIEBitmap; dstonlymask, srconlymask: boolean); procedure DrawPolygon(Alpha: integer; SelPoly: PPointArray; SelPolyCount: integer); procedure CombineWithAlpha(SourceAlpha: TIEBitmap; ox, oy: integer; SynchronizeBoundingRect: boolean); procedure Fill(Alpha: integer = 255); procedure Empty; function IsPointInside(x, y: integer): boolean; procedure TranslateBitmap(var ox, oy: integer; CutSel: boolean); procedure InvertCanvas(Dest: TCanvas; xDst, yDst, dxDst, dyDst: integer; xMask, yMask, dxMask, dyMask: integer); procedure DrawOuter(Dest: TBitmap; xDst, yDst, dxDst, dyDst: integer; xMask, yMask, dxMask, dyMask: integer; AlphaBlend: integer=-1; Color: TColor=clBlack); procedure DrawOutline(Dest: TCanvas; xDst, yDst, dxDst, dyDst: integer; xMask, yMask, dxMask, dyMask: integer; AniCounter: integer; Color1, Color2: TColor; actualRect: PRect = nil); procedure Negative(MaxVal: integer); procedure SyncFull; // set Full to True if all values are 255 procedure SyncRect; // set X1, Y1, X2, Y2 procedure Intersect(x1, y1, x2, y2: integer); function CreateResampledMask(NewWidth, NewHeight: integer): TIEMask; {!! TIEMask.Width Declaration property Width: integer; Description Returns the width of the selection mask. It must be equal to the image width. (read-only) !!} property Width: integer read fWidth; {!! TIEMask.Height Declaration property Height: integer; Description Returns the height of the selection mask. It must be equal to the image height. (read-only) !!} property Height: integer read fHeight; {!! TIEMask.BitsPerPixel Declaration property BitsPerPixel: integer; Description Returns the color depth (bits per pixels) of the mask. ImageEn supports: - 1 bit mask: 0 is a non-selected pixel, while 1 is selected. - 8 bit mask: 0 is non-selected pixel, 1-254 is a "semi" selected pixel, and 255 is fully selected pixel. !!} property BitsPerPixel: integer read fBitsPerPixel; {!! TIEMask.X1 Declaration property X1: integer; Description Specifies the upper-left side of the non-empty selection (an empty mask has 1). !!} property X1: integer read fX1 write fX1; {!! TIEMask.Y1 Declaration property Y1: integer; Description Specifies the upper-left side of the non-empty selection (an empty mask has 1). !!} property Y1: integer read fY1 write fY1; {!! TIEMask.X2 Declaration property X2: integer; Description Specifies the bottom-right side of the non-empty selection. !!} property X2: integer read fX2 write fX2; {!! TIEMask.Y2 Declaration property Y2: integer; Description Specifies the bottom-right side of the non-empty selection. !!} property Y2: integer read fY2 write fY2; function IsEmpty: boolean; property ScanLine[row: integer]: pointer read GetScanLine; procedure Assign(Source: TIEMask); overload; procedure Assign(Source: TIEBitmap); overload; {!! TIEMask.Rowlen Declaration property Rowlen: int64; Description Returns the length of a row in bytes. !!} property Rowlen: int64 read fRowlen; {!! TIEMask.Bits Declaration property Bits: pbyte; Description Contains the raw buffer of the selection mask. !!} property Bits: pbyte read GetBits; {!! TIEMask.Full Declaration property Full: boolean; Description True when the mask contains all 1 values (i.e. the image has all pixels selected). !!} property Full: boolean read fFull write fFull; end; // TIEMask ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// TIEVirtualImageInfo = record pos: int64; vsize: int64; ptr: pointer; // pointer to a memory buffer. it is <>nil if view mapped bitmapped: boolean; // true if this image is in the fBmpToRelease list orig_width: integer; // assigned by class user (info for original image when here is stored a thumbnail) orig_height: integer; // assigned by class user (info for original image when here is stored a thumbnail) HasAlphaChannel: boolean; currentaccess: TIEDataAccess; ImWidth: integer; ImHeight: integer; ImBitCount: integer; ImPixelFormat: TIEPixelFormat; // specifies how ImBitCount is organized (not actually used by TIEVirtualImageList) Identifier: cardinal; // A hash of a string that describes the content so we can locate it in another way than via index (typically the filename) end; PIEVirtualImageInfo = ^TIEVirtualImageInfo; TIEVirtualToReleaseBmp = record info: PIEVirtualImageInfo; bmp: TIEBitmap; refcount: integer; end; PIEVirtualToReleaseBmp = ^TIEVirtualToReleaseBmp; TIEVirtualFreeBlock = record pos: int64; vsize: dword; // size of the free block end; PIEVirtualFreeBlock = ^TIEVirtualFreeBlock; TIEVirtualImageList = class private fmemmap: TIEFileBuffer; fUseDisk: boolean; fSize: int64; // allocated size fImageInfo: TList; fToDiscardList: TList; // list of the image to unmap (the first is the next to discard) fFreeBlocks: TList; // list of free blocks in the file fInsPos: int64; // next free space fAllocationBlock: dword; fMaxImagesInMemory: integer; fImagesInMemory: integer; fBmpToRelease: TList; // list of to-release bitmaps (TBitmap) objects, list of TIEVirtualToReleaseBmp fLastVImageSize: dword; fDescriptor: string; // a descriptor which identifies the file inside the temp directory fLock: TCriticalSection; function GetImageCount: integer; function BmpToReleaseIndexOf(image: pointer): integer; procedure MergeConsecutiveBlocks(); protected procedure ReAllocateBits; procedure FreeBits; procedure RemoveImageInfo(idx: integer; deleteItem: boolean); procedure DiscardImage(info: PIEVirtualImageInfo); procedure DiscardOne; procedure DiscardAll; procedure MapImage(image: pointer; access: TIEDataAccess); function AllocImage(image: pointer; Width, Height, Bitcount: integer; PixelFormat: TIEPixelFormat; HasAlpha: boolean; MapNow: boolean): boolean; procedure DirectCopyToBitmap(image: pointer; bitmap: TIEBitmap); procedure CreateEx; procedure DestroyEx; public constructor Create(const Descriptor: string; UseDisk: boolean); destructor Destroy; override; procedure PrepareSpaceFor(Width, Height: integer; Bitcount: integer; ImageCount: integer); function AddBlankImage(Width, Height, Bitcount: integer; PixelFormat: TIEPixelFormat; HasAlpha: boolean; MapNow: boolean): pointer; // bitmaps import/export function AddBitmap(bitmap: TBitmap): pointer; function AddIEBitmap(bitmap: TIEBaseBitmap): pointer; function AddIEBitmapNoMap(bitmap: TIEBaseBitmap): pointer; function AddBitmapRect(bitmap: TBitmap; xsrc, ysrc, dxsrc, dysrc: integer): pointer; procedure CopyToIEBitmap(image: pointer; bitmap: TIEBitmap); procedure CopyFromIEBitmap(image: pointer; bitmap: TIEBitmap); function GetBitmap(image: pointer): TIEBitmap; procedure ReleaseBitmap(bitmap: TIEBitmap; changed: boolean); procedure ReleaseBitmapByImage(image: pointer; changed: boolean); // property MaxImagesInMemory: integer read fMaxImagesInMemory write fMaxImagesInMemory; property ImageCount: integer read GetImageCount; procedure Delete(image: pointer); // image info function GetImageWidth(image: pointer): integer; function GetImageHeight(image: pointer): integer; function GetImageOriginalWidth(image: pointer): integer; function GetImageOriginalHeight(image: pointer): integer; procedure SetImageOriginalWidth(image: pointer; Value: integer); procedure SetImageOriginalHeight(image: pointer; Value: integer); procedure SetImageIdentifier(image: pointer; const Value: WideString); function GetImageBitCount(image: pointer): integer; function GetImageBits(image: pointer): pointer; function GetImagePixelFormat(image: pointer): TIEPixelFormat; function GetImagePalette(image: pointer): pointer; function GetAlphaBits(image: pointer): pointer; function GetImageFilePos(image: pointer): int64; function FindImageIndex(image: pointer): integer; function GetImageFromIndex(index: integer): pointer; function GetImageByIdentifier(const value: String): pointer; // input/output procedure SaveToStream(Stream: TStream); function LoadFromStream(Stream: TStream): boolean; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEDibBitmap {!! TIEDibBitmap Description TIEDibBitmap encapsulates a Windows DIB section. It inherits from . Methods and Properties - - - - - - - - - - - - - !!} // a DIB section (used for little image processing and transfers tasks) // BitCount supported: // 1 : black/white images // 24: true color images TIEDibBitmap = class(TIEBaseBitmap) private fWidth, fHeight: dword; fBitCount: dword; fRowLen: dword; fHDC: THandle; fDIB: THandle; fBitmapInfoHeader1: TBitmapInfoHeader256; fBits: pointer; protected function GetBitCount: integer; override; function GetWidth: integer; override; function GetHeight: integer; override; procedure SetWidth(Value: integer); override; procedure SetHeight(Value: integer); override; function GetPixelFormat: TIEPixelFormat; override; function GetRowLen: integer; override; function GetScanLine(row: integer): pointer; override; function GetPalette(index: integer): TRGB; override; function GetPaletteBuffer: pointer; override; procedure SetPalette(index: integer; Value: TRGB); override; function GetPaletteLen: integer; override; function GetPaletteUsed(): integer; override; procedure SetPaletteUsed(Value: integer); override; public constructor Create; destructor Destroy; override; function AllocateBits(BmpWidth, BmpHeight, BmpBitCount: dword): boolean; function Allocate(ImageWidth, ImageHeight: integer; ImagePixelFormat: TIEPixelFormat): boolean; override; procedure FreeBits; {!! TIEDibBitmap.HDC Declaration property HDC: THandle; Description Returns the device context (HDC) handle of this DIB section. !!} property HDC: THandle read fHDC; {!! TIEDibBitmap.DIB Declaration property DIB: Thandle; Description Returns the DIB handle. !!} property DIB: Thandle read fDIB; {!! TIEDibBitmap.Width Declaration property Width: dword Description Returns the DIB width. !!} property Width: dword read fWidth; {!! TIEDibBitmap.Height Declaration property Height: dword; Description Returns the DIB height. !!} property Height: dword read fHeight; {!! TIEDibBitmap.BitCount Declaration property BitCount: dword; Description Returns the DIB bit count (1 or 24). !!} property BitCount: dword read fBitCount; {!! TIEDibBitmap.Scanline Declaration property Scanline[row: integer]: pointer; Description Returns a pointer to the specified row. !!} property Scanline[row: integer]: pointer read GetScanline; {!! TIEDibBitmap.Bits Declaration property Bits: pointer; Description Returns a pointer to bitmap bits. !!} property Bits: pointer read fBits; {!! TIEDibBitmap.Rowlen Declaration property Rowlen: integer; Description Returns the row length in bytes. !!} property Rowlen: integer read GetRowlen; procedure CopyToTBitmap(Dest: TBitmap); procedure Assign(Source: TObject); override; procedure AssignImage(Source: TIEBaseBitmap); override; procedure CopyPaletteTo(Dest: TIEBaseBitmap); override; end; // TIEDibBitmap //////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////// {$ifdef IEINCLUDEIMAGINGANNOT} OIAN_MARK_ATTRIBUTES = record uType: integer; lrBounds: TRect; rgbColor1: TRGBQUAD; rgbColor2: TRGBQUAD; bHighlighting: longbool; bTransparent: longbool; uLineSize: dword; uReserved1: dword; uReserved2: dword; lfFont: TLOGFONTA; bReserved3: dword; Time: integer; bVisible: longbool; dwReserved4: dword; lReserved: array[0..9] of integer; end; {!! TIEImagingObject Declaration TIEImagingObject = class; Description Internal representation of an imaging object. !!} TIEImagingObject = class private attrib: OIAN_MARK_ATTRIBUTES; points: PIEPointArray; pointsLen: integer; text: PAnsiChar; image: TIEBitmap; public constructor Create; destructor Destroy; override; end; {!! TIEImagingAnnot Description Contains the (Wang) imaging annotations loaded (or to save) from a TIFF. Using a object you can create new objects, copy to or from a (as vectorial objects) or (as layers), or just draw onto the bitmap. Note: TIEImagingAnnot supports only a subset of TImageEnVect objects. For full TImageEnVect support, use instead (available as the property). Methods and Properties - - - - - - - - - - - - - Example // Save image and layers in TImageEnView to 'TIFF_with_layers.tiff' ImageEnView1.IO.Params.ImagingAnnot.CopyFromTImageEnView(); ImageEnView1.IO.SaveToFile('TIFF_with_layers.tiff'); // Load image and layers in 'TIFF_with_layers.tiff' to TImageEnView ImageEnView1.IO.LoadFromFile('TIFF_with_layers.tiff'); ImageEnView1.IO.Params.ImagingAnnot.CopyToTImageEnView(); !!} TIEImagingAnnot = class private fParent: TObject; // optional parent object fUserChanged: boolean; fObjects: TList; function GetObject(idx: integer): TIEImagingObject; function GetObjectsCount: integer; public constructor Create; destructor Destroy; override; procedure LoadFromStandardBuffer(buffer: pointer; buflen: integer); procedure SaveToStandardBuffer(var Buffer: pointer; var BufferLength: integer); property UserChanged: boolean read fUserChanged write fUserChanged; procedure Clear; procedure Assign(Source: TIEImagingAnnot); procedure SaveToStream(Stream: TStream); procedure LoadFromStream(Stream: TStream); procedure CopyToTImageEnVect(Target: TObject=nil); procedure CopyFromTImageEnVect(Target: TObject=nil); procedure CopyToTImageEnView(Target: TObject=nil); procedure CopyFromTImageEnView(Target: TObject=nil); procedure DrawToBitmap(target: TIEBitmap; Antialias: boolean); property Objects[idx: integer]: TIEImagingObject read GetObject; property ObjectsCount: integer read GetObjectsCount; property Parent: TObject read fParent write fParent; end; {$endif} // IEINCLUDEIMAGINGANNOT {!! TIEImageEnAnnot Description Contains the objects loaded (or to save) from a TIFF or JPEG. Using a object you can create new objects, copy to or from a (as vectorial objects) or (as layers), or just draw onto the bitmap. Methods and Properties - - - - - - - - - Example // Save image and layers in TImageEnView to 'jpeg_with_layers.jpg' ImageEnView1.IO.Params.ImageEnAnnot.CopyFromTImageEnView(); ImageEnView1.IO.SaveToFile('jpeg_with_layers.jpg'); // Load image and layers in 'jpeg_with_layers.jpg' to TImageEnView ImageEnView1.IO.LoadFromFile('jpeg_with_layers.jpg'); ImageEnView1.IO.Params.ImageEnAnnot.CopyToTImageEnView(); !!} TIEImageEnAnnot = class private fParent: TObject; // optional parent object fData: TMemoryStream; fIEVectObjects: Boolean; // true if object cotnains TImageEnVect annotions. False if it has TImageEnView layers function GetObjectsCount(): integer; public constructor Create(parent: TObject); // parent must be TIOParams destructor Destroy(); override; class function BufferContainsImageEnAnnot(buffer: pointer; buflen: integer; out IsIEVectObjects: Boolean): boolean; class function TIFFContainsImageEnAnnot(Stream: TStream; ImageIndex: integer): boolean; overload; class function TIFFContainsImageEnAnnot(const Filename: WideString; ImageIndex: integer): boolean; overload; procedure LoadFromBuffer(buffer: pointer; buflen: integer); procedure SaveToBuffer(var Buffer: pointer; var BufferLength: integer); procedure Clear(); procedure Assign(Source: TIEImageEnAnnot); procedure SaveToStream(Stream: TStream); procedure LoadFromStream(Stream: TStream); procedure CopyToTImageEnVect(Target: TObject = nil); procedure CopyFromTImageEnVect(Target: TObject = nil); procedure CopyToTImageEnView(Target: TObject=nil); procedure CopyFromTImageEnView(Target: TObject=nil); procedure DrawToBitmap(target: TIEBitmap; Antialias: boolean); function IsEmpty(): boolean; property Parent: TObject read fParent; property ObjectsCount: integer read GetObjectsCount; {!! TIEImageEnAnnot.HasVectorialObjects Declaration property HasVectorialObjects: Boolean; (Read-only) Description Returns true if the TIEImageEnAnnot object contains objects (i.e. was used). Returns False if it contains layers (i.e. was used). !!} property HasVectorialObjects: Boolean read fIEVectObjects; end; // a bitmap in memory that doesn't use system handles // BitCount supported: // 1 : black/white // 8 : gray (no palette) // 16 : gray (no palette) // 24 : true color // 32 : true color + alpha (or 32 bit floating point) // 64 : double (64 bit floating point) TIEWorkBitmap = class private fWidth, fHeight: integer; fBitCount: integer; fRowLen: integer; fBits: pointer; // fragmented memory allocation fRowsPerFragment: integer; // image rows per fragment fFragments: array of pointer; // array of pointers to fragments function GetScanline(row: integer): pointer; procedure FragmentedAlloc(); procedure FreeFragments(); public constructor Create(BmpWidth, BmpHeight, BmpBitCount: integer); destructor Destroy; override; procedure AllocateBits(BmpWidth, BmpHeight, BmpBitCount: integer); procedure FreeBits; property Width: integer read fWidth; property Height: integer read fHeight; property BitCount: integer read fBitCount; property Scanline[row: integer]: pointer read GetScanline; property Bits: pointer read fBits; property Rowlen: integer read fRowlen; function GetPByte(row, col: integer): pbyte; function GetPWord(row, col: integer): pword; function GetPRGB(row, col: integer): PRGB; function GetPDouble(row, col: integer): PDouble; function GetPSingle(row, col: integer): PSingle; function GetPInteger(row, col: integer): pinteger; procedure SetBit(row, col: integer; value: integer); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIOParams {!! TIOPSCompression Declaration TIOPSCompression = (ioPS_RLE, ioPS_G4FAX, ioPS_G3FAX2D, ioPS_JPEG); Description Value Description ioPS_RLE Run length compression ioPS_G4FAX G4Fax (black & white images only) ioPS_G3FAX2D G3Fax (black & white images only) ioPS_JPEG DCT-JPEG (color images only)
!!} TIOPSCompression = ( ioPS_RLE, ioPS_G4FAX, ioPS_G3FAX2D, ioPS_JPEG ); {!! TIOPDFCompression Declaration TIOPDFCompression = ( ioPDF_UNCOMPRESSED, ioPDF_RLE, ioPDF_G4FAX, ioPDF_G3FAX2D, ioPDF_JPEG, ioPDF_LZW ); Description Value Description ioPDF_UNCOMPRESSED No compression ioPDF_RLE Run length compression ioPDF_G4FAX G4Fax (black & white images only) ioPDF_G3FAX2D G3Fax (black & white images only) ioPDF_JPEG DCT-JPEG (color images only) ioPDF_LZW LZW compression (color and black/white images)
!!} TIOPDFCompression = ( ioPDF_UNCOMPRESSED, ioPDF_RLE, ioPDF_G4FAX, ioPDF_G3FAX2D, ioPDF_JPEG, ioPDF_LZW ); {!! TIOPDFPaperSize Declaration TIOPDFPaperSize = (iepA0, iepA1, iepA2, iepA3, iepA4, iepA5, iepA6, iepB5, iepLetter, iepLegal, iepLedger, iepTabloid, iepAuto, iepUnknown); Description Standard paper sizes that can be specified for
and . If iepAuto is selected (PDF only) then the page will be output at the size of the image (which may create huge PDF pages). Example procedure TMainForm.FormCreate(Sender: TObject); var a: TPDFPaperSize; begin // Fill combobox with available PDF paper sizes cmbPaperSize.Clear; for a := Low(TPDFPaperSize) to High(TPDFPaperSize) do cmbPaperSize.Items.Add(IEPaperSizeToStr(a)); // Make "US Letter" the selected one cmbPaperSize.ItemIndex := cmbPaperSize.Items.IndexOf(IEPaperSizeToStr(iepLetter)); end; // Set PDF paper size to user's selection ImageEnView1.IO.Params.PDF_PaperSize := IEStrToPaperSize(cmbPaperSize.Text); See Also - - - - !!} TIOPDFPaperSize = (iepA0, iepA1, iepA2, iepA3, iepA4, iepA5, iepA6, iepB5, iepLetter, iepLegal, iepLedger, iepTabloid, iepAuto, iepUnknown); {!! TIOTIFFCompression Declaration type TIOTIFFCompression = (ioTIFF_UNCOMPRESSED, ioTIFF_CCITT1D, ioTIFF_G3FAX1D, ioTIFF_G3FAX2D, ioTIFF_G4FAX, ioTIFF_LZW, ioTIFF_OLDJPEG, ioTIFF_JPEG, ioTIFF_PACKBITS, ioTIFF_ZIP, ioTIFF_DEFLATE, ioTIFF_UNKNOWN); Description Value Description Supported Pixel Formats Supports Alpha Channel? ioTIFF_UNCOMPRESSED Uncompressed TIFF All Yes ioTIFF_CCITT1D Bilevel Huffman compression Black/White Only No ioTIFF_G3FAX1D Bilevel Group 3 CCITT compression, mono-dimensional Black/White Only No ioTIFF_G3FAX2D Bilevel Group 3 CCITT compression, bi-dimensional Black/White Only No ioTIFF_G4FAX Bilevel Group 4 CCITT compression, bi-dimensional Black/White Only No ioTIFF_LZW LZW compression All Yes ioTIFF_OLDJPEG Ver 6.0 JPEG compression (unsupported) True Color Images Only No ioTIFF_JPEG JPEG compression True Color Images Only No ioTIFF_PACKBITS RLE compression All Yes ioTIFF_ZIP ZIP compression (non-TIFF standard) All No ioTIFF_DEFLATE Adobe ZIP compression (non-TIFF standard) All No ioTIFF_UNKNOWN Unknown compression
For black/white compressions (ioTIFF_CCITT1D, ioTIFF_G3FAX1D, ioTIFF_G3FAX2D and ioTIFF_G4FAX) make sure that
= 1 and = 1. Example ImageEnView1.IO.Params.TIFF_Compression := ioTIFF_G4FAX; ImageEnView1.IO.Params.BitsPerSample := 1; ImageEnView1.IO.Params.SamplesPerPixel := 1; ImageEnView1.IO.SaveToFile('D:\output.tif'); !!} TIOTIFFCompression = ( ioTIFF_UNCOMPRESSED, ioTIFF_CCITT1D, ioTIFF_G3FAX1D, ioTIFF_G3FAX2D, ioTIFF_G4FAX, ioTIFF_LZW, ioTIFF_OLDJPEG, ioTIFF_JPEG, ioTIFF_PACKBITS, ioTIFF_ZIP, ioTIFF_DEFLATE, ioTIFF_UNKNOWN); {!! TIOTIFFPhotometInterpret Declaration type TIOTIFFPhotometInterpret = (ioTIFF_WHITEISZERO, ioTIFF_BLACKISZERO, ioTIFF_RGB, ioTIFF_RGBPALETTE, ioTIFF_TRANSPMASK, ioTIFF_CMYK, ioTIFF_YCBCR, ioTIFF_CIELAB); !!} TIOTIFFPhotometInterpret = ( ioTIFF_WHITEISZERO, ioTIFF_BLACKISZERO, ioTIFF_RGB, ioTIFF_RGBPALETTE, ioTIFF_TRANSPMASK, ioTIFF_CMYK, ioTIFF_YCBCR, ioTIFF_CIELAB); {!! TIOJPEGColorspace Declaration type TIOJPEGColorspace=(ioJPEG_RGB, ioJPEG_GRAYLEV, ioJPEG_YCbCr, ioJPEG_CMYK, ioJPEG_YCbCrK); Description Value Description ioJPEG_RGB Separate RGB channels ioJPEG_GRAYLEV Unique intensity channel (gray levels) ioJPEG_YCbCr Three channels (CCIR Recommendation 601-1) ioJPEG_CMYK Four channels (Cyan Magenta Yellow Black) - linear conversion ioJPEG_YCbCrK Four channels (YCbCr and Black)
!!} TIOJPEGColorspace = ( ioJPEG_RGB, ioJPEG_GRAYLEV, ioJPEG_YCbCr, ioJPEG_CMYK, ioJPEG_YCbCrK); {$IFDEF IEINCLUDEJPEG2000} {!! TIOJ2000ColorSpace Declaration TIOJ2000ColorSpace = ( ioJ2000_GRAYLEV, ioJ2000_RGB, ioJ2000_YCbCr); Description Value Description ioJ2000_GRAYLEV Gray scale image ioJ2000_RGB RGB image ioJ2000_YcbCr YcbCr image (currently supported only for loading)
!!} TIOJ2000ColorSpace = ( ioJ2000_GRAYLEV, ioJ2000_RGB, ioJ2000_YCbCr); {!! TIOJ2000ScalableBy Declaration TIOJ2000ScalableBy = ( ioJ2000_Rate, ioJ2000_Resolution); Description Value Description ioJ2000_Rate Layer-resolution-component-position (LRCP) progressive (i.e. rate scalable) ioJ2000_Resolution Resolution-layer-component-position (RLCP) progressive (i.e. resolution scalable)
!!} TIOJ2000ScalableBy = ( ioJ2000_Rate, ioJ2000_Resolution); {$ENDIF} {!! TIOJPEGDctMethod Declaration type TIOJPEGDctMethod = (ioJPEG_ISLOW, ioJPEG_IFAST, ioJPEG_FLOAT); Description Value Description ioJPEG_ISLOW Slow but accurate integer algorithm (default) ioJPEG_IFAST Faster, less accurate integer method ioJPEG_FLOAT Floating-point method (machine dependent)
!!} TIOJPEGDctMethod = ( ioJPEG_ISLOW, ioJPEG_IFAST, ioJPEG_FLOAT); {!! TIOJPEGCromaSubsampling Declaration type TIOJPEGCromaSubsampling = (ioJPEG_MEDIUM, ioJPEG_HIGH, ioJPEG_NONE); Description Value Description ioJPEG_MEDIUM 4:2:2 croma sub-sampling. Medium quality ioJPEG_HIGH 4:1:1 croma sub-sampling. Default quality for jpegs. Lowest quality ioJPEG_NONE 4:4:4 croma sub-sampling. Highest quality
!!} TIOJPEGCromaSubsampling = ( ioJPEG_MEDIUM, ioJPEG_HIGH, ioJPEG_NONE); {!! TIOJPEGScale Declaration TIOJPEGScale = ( ioJPEG_AUTOCALC, ioJPEG_FULLSIZE, ioJPEG_HALF, ioJPEG_QUARTER, ioJPEG_EIGHTH); Description Value Description ioJPEG_AUTOCALC The JPEG Scale is selected automatically to ensure it is larger than your minimum dimensions. You need to specify this using the and properties ioJPEG_FULLSIZE The full image is loaded (default). Slowest loading ioJPEG_HALF Image is loaded at 1/2 size ioJPEG_QUARTER Image is loaded at 1/4 size ioJPEG_EIGHTH Image is loaded at 1/8 size. Very fast loading
Example // Load JPEG as fast as possible while still being larger than the display size ImageEnView.IO.Params.Width := ImageEnView1.ClientWidth; ImageEnView.IO.Params.Height := ImageEnView1.ClientHeight; ImageEnView.IO.Params.JPEG_Scale := ioJPEG_AUTOCALC; ImageEnView.IO.LoadFromFile('D:\MyImage.jpeg’); !!} TIOJPEGScale = ( ioJPEG_AUTOCALC, ioJPEG_FULLSIZE, ioJPEG_HALF, ioJPEG_QUARTER, ioJPEG_EIGHTH); {!! TIOBMPVersion Declaration type TIOBMPVersion = (ioBMP_BM, ioBMP_BM3, ioBMP_BMOS2V1, ioBMP_BMOS2V2); Description Value Description ioBMP_BM Old Windows bitmap ioBMP_BM3 Windows 3.x or newer bitmap ioBMP_BMOS2V1 IBM OS/2 version 1.x bitmap ioBMP_BMOS2V2 IBM OS/2 version 2.x bitmap
!!} TIOBMPVersion = ( ioBMP_BM, ioBMP_BM3, ioBMP_BMOS2V1, ioBMP_BMOS2V2, ioBMP_V4, ioBMP_V5); {!! TIOBMPCompression Declaration type TIOBMPCompression = (ioBMP_UNCOMPRESSED, ioBMP_RLE); Description ioBMP_UNCOMPRESSED: Uncompressed bitmap ioBMP_RLE: Compressed bitmap (generally smaller than uncompressed, but not always) !!} TIOBMPCompression = ( ioBMP_UNCOMPRESSED, ioBMP_RLE); {!! TIOPCXCompression Declaration type TIOPCXCompression = (ioPCX_UNCOMPRESSED, ioPCX_RLE); Description ioPCX_UNCOMPRESSED: Uncompressed PCX (incompatible with most PCX readers). ioPCX_RLE: Compressed PCX (standard PCX). !!} TIOPCXCompression = ( ioPCX_UNCOMPRESSED, ioPCX_RLE); {!! TIOPNGFilter Declaration } TIOPNGFilter = ( ioPNG_FILTER_NONE, ioPNG_FILTER_SUB, ioPNG_FILTER_PAETH, ioPNG_FILTER_UP, ioPNG_FILTER_AVG, ioPNG_FILTER_ALL); {!!} {!! TIEGIFAction Declaration } TIEGIFAction = ( ioGIF_None, ioGIF_DontRemove, ioGIF_DrawBackground, ioGIF_RestorePrev); {!!} {!! TIOICOSizes Declaration } TIOICOSizes = array[0..IEMAXICOIMAGES - 1] of TSize; {!!} {!! TIOICOBitCount Declaration } TIOICOBitCount = array[0..IEMAXICOIMAGES - 1] of integer; {!!} {!! TIOBMPRAWChannelOrder Declaration } TIOBMPRAWChannelOrder=(coRGB, coBGR); {!!} {!! TIOBMPRAWDataFormat Declaration TIOBMPRAWDataFormat = (dfBinary, dfTextDecimal, dfTextHex); Description Value Description dfBinary Binary raw data dfTextDecimal Ascii text as decimal values dfTextHex Ascii text as hexadecimal values
!!} TIOBMPRAWDataFormat = (dfBinary, dfTextDecimal, dfTextHex); {!! TIOBMPRAWPlanes Declaration TIOBMPRAWPlanes = (plInterleaved, plPlanar); Description plInterleaved channels are B,G,R,B,G,R... plPlanar channels are BBB.., GGG.., RRR... !!} TIOBMPRAWPlanes = (plInterleaved, plPlanar); {!! TIOByteOrder Declaration TIOByteOrder = (ioBigEndian, ioLittleEndian); Description ioBigEndian: Motorola Byte Order ioLittleEndian: Intel Byte Order !!} TIOByteOrder = (ioBigEndian, ioLittleEndian); // {!! TIEDicomRange Declaration TIEDicomRange = (iedrAdjust, iedrSetBlackWhite); Description Value Description iedrAdjust Adjust pixels values iedrSetBlackWhite Set TIEBitmap.WhiteValue and TIEBitmap.BlackValue
!!} TIEDicomRange = (iedrAdjust, iedrSetBlackWhite); {!! TIEDicomCompression Declaration } TIEDicomCompression = (iedcUncompressed_Implicit, // uncompressed, little endian, implicit (IEDICOM_TRANSFERSYNTAX_UNCOMP_LITTLEENDIAN_IMPLICIT) iedcUncompressed, // uncompressed, little endian, explicit (IEDICOM_TRANSFERSYNTAX_UNCOMP_LITTLEENDIAN_EXPLICIT) iedcUncompressed_BE, // uncompressed, big endian, explicit (IEDICOM_TRANSFERSYNTAX_UNCOMP_BIGENDIAN_EXPLICIT) iedcRLE, // RLE iedcLSJPEG1, // lossless jpeg (IEDICOM_TRANSFERSYNTAX_LOSSLESSJPEG1) iedcLSJPEG2, // lessless jpeg (IEDICOM_TRANSFERSYNTAX_LOSSLESSJPEG2) iedcJPEG, // jpeg 8 bit (IEDICOM_TRANSFERSYNTAX_LOSSYJPEG8BIT) iedcJPEG12Bit, // jpeg 12 bit (IEDICOM_TRANSFERSYNTAX_LOSSYJPEG12BIT) iedcJPEG2000, // Lossy jpeg 2000 (IEDICOM_TRANSFERSYNTAX_LOSSYJPEG2000) iedcLosslessJPEG2000, // Lossless jpeg 2000 (IEDICOM_TRANSFERSYNTAX_LOSSLESSJPEG2000) iedcMPEG); // MPEG (IEDICOM_TRANSFERSYNTAX_MPEG) {!!} {!! TIOParams Description Provides access to the properties of all image and video file formats supported by ImageEn, such as compression type, text comments, bits per sample, samples per pixel, etc. The properties for this class are set when loading an image or can be retrieved (without loading of the image) using
(excluding save-only formats, such as PDF, PS, etc). You can modify these properties before saving your image (naturally this is only relevant to formats which ImageEn can save, which excludes EMF, WMF, CUR, etc). See Also - TImageEnIO.Params - TIEBitmap.Params - TIEMultiBitmap.Params - TImageEnDBView.IOParams Methods and Properties Property Storage Handling (load stored paramaters) (load stored paramaters) (load paramaters of an image) (store paramaters) (store paramaters) General Adobe PDF Adobe PSD BMP CUR Dicom DCX GIF HDP ICO IEN (ImageEn native image format with layers) JPEG JPEG 2000 PCX PNG PostScript PXM RAW (Camera Digital Images) RealRAW (not camera RAW) TGA TIFF SVG (Scalable Vector Graphics) AVI MediaFile (AVI, MPEG, WMV, etc) EXIF Tags (for JPEG, TIFF and RAW) Windows EXIF Tags (for JPEG, TIFF and RAW) GPS EXIF Tags (for JPEG, TIFF and RAW) IPTC Tags (for JPEG and TIFF) Adobe XMP Info (for JPEG, TIFF and PSD) Extra Parameters !!} {$ifdef IEINCLUDEDICOM} TIEDicomTags = Class; {$endif} TIETagsHandler = Class; TIOParams = class private fAttachedTo: TObject; // Either a TImageEnIO or a TIEBitmap fDict: TIEDictionary; fBitsPerSample: integer; fFileName: WideString; fSamplesPerPixel: integer; fWidth: integer; fHeight: integer; fFileType: TIOFileType; fImageIndex: Integer; fImageCount: Integer; fGetThumbnail: Boolean; fIsResource: Boolean; fEnableAdjustOrientation: Boolean; fOriginalWidth: integer; fOriginalHeight: integer; fTIFF_Compression: TIOTIFFCompression; fTIFF_ImageIndex: integer; fTIFF_SubIndex: integer; // SubIFD index (-1 read root) fTIFF_NewSubfileType: integer; fTIFF_PhotometInterpret: TIOTIFFPhotometInterpret; fTIFF_PlanarConf: integer; fTIFF_XPos: integer; fTIFF_YPos: integer; fTIFF_GetTile: integer; // -1, load all tiles fTIFF_DocumentName: AnsiString; fTIFF_ImageDescription: AnsiString; fTIFF_PageName: AnsiString; fTIFF_PageNumber: integer; fTIFF_PageCount: integer; fTIFF_Orientation: integer; fTIFF_LZWDecompFunc: TTIFFLZWDecompFunc; fTIFF_LZWCompFunc: TTIFFLZWCompFunc; fTIFF_EnableAdjustOrientation: boolean; fTIFF_JPEGQuality: integer; fTIFF_JPEGColorSpace: TIOJPEGColorSpace; fTIFF_ZIPCompression: integer; // 0=fast 1=normal (default) 2=max fTIFF_StripCount: integer; // 0=automatic (default), not read from TIFF, but used only in the writer fTIFF_ImageCount: integer; fTIFF_FillOrder: integer; fTIFF_ByteOrder: TIOByteOrder; fTIFF_PhotoshopImageResources: TIEArrayOfByte; fTIFF_PhotoshopImageSourceData: TIEArrayOfByte; fTIFF_BigTIFF: boolean; fDCX_ImageIndex: Integer; fGIF_Version: AnsiString; fGIF_ImageIndex: integer; fGIF_XPos: integer; fGIF_YPos: integer; fGIF_DelayTime: integer; fGIF_FlagTranspColor: boolean; fGIF_TranspColor: TRGB; fGIF_Interlaced: boolean; fGIF_WinWidth: integer; fGIF_WinHeight: integer; fGIF_Background: TRGB; fGIF_Ratio: integer; fGIF_Comments: TStringList; fGIF_Action: TIEGIFAction; fGIF_RAWLoad: boolean; fGIF_LZWDecompFunc: TGIFLZWDecompFunc; fGIF_LZWCompFunc: TGIFLZWCompFunc; fGIF_ImageCount: integer; fJPEG_ColorSpace: TIOJPEGColorSpace; fJPEG_Quality: integer; fJPEG_DCTMethod: TIOJPEGDCTMethod; fJPEG_CromaSubsampling: TIOJPEGCromaSubsampling; fJPEG_OptimalHuffman: boolean; fJPEG_Smooth: integer; fJPEG_Progressive: boolean; fJPEG_Scale: TIOJPEGScale; fJPEG_MarkerList: TIEMarkerList; fJPEG_Scale_Used: integer; fJPEG_WarningTot: integer; fJPEG_WarningCode: integer; fJPEG_EnableAdjustOrientation: Boolean; fJPEG_GetExifThumbnail: Boolean; {$IFDEF IEINCLUDEJPEG2000} fJ2000_ColorSpace: TIOJ2000ColorSpace; fJ2000_Rate: double; fJ2000_ScalableBy: TIOJ2000ScalableBy; {$ENDIF} fPCX_Version: integer; fPCX_Compression: TIOPCXCompression; fBMP_Version: TIOBMPVersion; fBMP_Compression: TIOBMPCompression; fBMP_HandleTransparency: Boolean; fICO_ImageIndex: integer; fICO_Background: TRGB; fCUR_ImageIndex: integer; fCUR_XHotSpot: integer; fCUR_YHotSpot: integer; fCUR_Background: TRGB; fPNG_Interlaced: boolean; fPNG_Background: TRGB; fPNG_Filter: TIOPNGFilter; fPNG_Compression: integer; fPNG_TextKeys: TStringList; fPNG_TextValues: TStringList; {$ifdef IEINCLUDEDICOM} fDICOM_Tags: TIEDicomTags; fDICOM_WindowCenterOffset: double; fDICOM_Range: TIEDicomRange; fDICOM_JPEGQuality: integer; fDICOM_J2000Rate: double; fDICOM_RescaleIntercept: double; fDICOM_RescaleSlope: double; fDICOM_WindowCenter: double; fDICOM_WindowWidth: double; {$endif} fTGA_XPos: integer; fTGA_YPos: integer; fTGA_Compressed: boolean; fTGA_Descriptor: AnsiString; fTGA_Author: AnsiString; fTGA_Date: TDateTime; fTGA_ImageName: AnsiString; fTGA_Background: TRGB; fTGA_AspectRatio: double; fTGA_Gamma: double; fTGA_GrayLevel: boolean; fIPTC_Info: TIEIPTCInfoList; {$ifdef IEINCLUDEIMAGINGANNOT} fImagingAnnot: TIEImagingAnnot; {$endif} fImageEnAnnot: TIEImageEnAnnot; fPXM_Comments: TStringList; fEXIF_Tags: TList; // a list of received tags (codes) and a list of tags to write. ONLY FOR NUMERIC TAGS (excluded GPS and non subifd tags). fEXIF_HasEXIFData: boolean; fEXIF_Orientation: integer; fEXIF_Bitmap: TIEBitmap; fEXIF_ImageDescription: AnsiString; fEXIF_Make: AnsiString; fEXIF_Model: AnsiString; fEXIF_XResolution: double; fEXIF_YResolution: double; fEXIF_ResolutionUnit: integer; fEXIF_Software: AnsiString; fEXIF_Artist: AnsiString; fEXIF_DateTime: AnsiString; fEXIF_WhitePoint: array[0..1] of double; fEXIF_PrimaryChromaticities: array[0..5] of double; fEXIF_YCbCrCoefficients: array[0..2] of double; fEXIF_YCbCrPositioning: integer; fEXIF_ReferenceBlackWhite: array[0..5] of double; fEXIF_Copyright: AnsiString; fEXIF_ExposureTime: double; fEXIF_FNumber: double; fEXIF_ExposureProgram: integer; fEXIF_ISOSpeedRatings: array[0..1] of integer; fEXIF_ExifVersion: AnsiString; fEXIF_DateTimeOriginal: AnsiString; fEXIF_DateTimeDigitized: AnsiString; fEXIF_CompressedBitsPerPixel: double; fEXIF_ShutterSpeedValue: double; fEXIF_ApertureValue: double; fEXIF_BrightnessValue: double; fEXIF_ExposureBiasValue: double; fEXIF_MaxApertureValue: double; fEXIF_SubjectDistance: double; fEXIF_MeteringMode: integer; fEXIF_LightSource: integer; fEXIF_Flash: integer; fEXIF_FocalLength: double; fEXIF_SubsecTime: AnsiString; fEXIF_SubsecTimeOriginal: AnsiString; fEXIF_SubsecTimeDigitized: AnsiString; fEXIF_FlashPixVersion: AnsiString; fEXIF_ColorSpace: integer; fEXIF_ExifImageWidth: integer; fEXIF_ExifImageHeight: integer; fEXIF_RelatedSoundFile: AnsiString; fEXIF_FocalPlaneXResolution: double; fEXIF_FocalPlaneYResolution: double; fEXIF_FocalPlaneResolutionUnit: integer; fEXIF_ExposureIndex: double; fEXIF_SensingMethod: integer; fEXIF_FileSource: integer; fEXIF_SceneType: integer; fEXIF_UserComment: WideString; fEXIF_UserCommentCode: AnsiString; fEXIF_MakerNote: TIETagsHandler; fEXIF_XPRating: Integer; fEXIF_XPTitle: WideString; fEXIF_XPComment: WideString; fEXIF_XPAuthor: WideString; fEXIF_XPKeywords: WideString; fEXIF_XPSubject: WideString; fEXIF_ExposureMode: Integer; fEXIF_WhiteBalance: Integer; fEXIF_DigitalZoomRatio: Double; fEXIF_FocalLengthIn35mmFilm: Integer; fEXIF_SceneCaptureType: Integer; fEXIF_GainControl: Integer; fEXIF_Contrast: Integer; fEXIF_Saturation: Integer; fEXIF_Sharpness: Integer; fEXIF_SubjectDistanceRange: Integer; fEXIF_ImageUniqueID: AnsiString; fEXIF_GPSVersionID: AnsiString; fEXIF_GPSLatitudeRef: AnsiString; fEXIF_GPSLatitudeDegrees: Double; fEXIF_GPSLatitudeMinutes: Double; fEXIF_GPSLatitudeSeconds: Double; fEXIF_GPSLongitudeRef: AnsiString; fEXIF_GPSLongitudeDegrees: Double; fEXIF_GPSLongitudeMinutes: Double; fEXIF_GPSLongitudeSeconds: Double; fEXIF_GPSAltitudeRef: AnsiString; fEXIF_GPSAltitude: Double; fEXIF_GPSTimeStampHour: Double; fEXIF_GPSTimeStampMinute: Double; fEXIF_GPSTimeStampSecond: Double; fEXIF_GPSSatellites: AnsiString; fEXIF_GPSStatus: AnsiString; fEXIF_GPSMeasureMode: AnsiString; fEXIF_GPSDOP: Double; fEXIF_GPSSpeedRef: AnsiString; fEXIF_GPSSpeed: Double; fEXIF_GPSTrackRef: AnsiString; fEXIF_GPSTrack: Double; fEXIF_GPSImgDirectionRef: AnsiString; fEXIF_GPSImgDirection: Double; fEXIF_GPSMapDatum: AnsiString; fEXIF_GPSDestLatitudeRef: AnsiString; fEXIF_GPSDestLatitudeDegrees: Double; fEXIF_GPSDestLatitudeMinutes: Double; fEXIF_GPSDestLatitudeSeconds: Double; fEXIF_GPSDestLongitudeRef: AnsiString; fEXIF_GPSDestLongitudeDegrees: Double; fEXIF_GPSDestLongitudeMinutes: Double; fEXIF_GPSDestLongitudeSeconds: Double; fEXIF_GPSDestBearingRef: AnsiString; fEXIF_GPSDestBearing: Double; fEXIF_GPSDestDistanceRef: AnsiString; fEXIF_GPSDestDistance: Double; fEXIF_GPSDateStamp: AnsiString; fEXIF_InteropIndex: AnsiString; fEXIF_InteropVersion: AnsiString; fEXIF_CameraOwnerName : AnsiString; fEXIF_BodySerialNumber : AnsiString; fEXIF_LensMake : AnsiString; fEXIF_LensModel : AnsiString; fEXIF_LensSerialNumber : AnsiString; fEXIF_Gamma : Double; fEXIF_SubjectArea : array[0..3] of Integer; fEXIF_SubjectLocationX : Integer; fEXIF_SubjectLocationY : Integer; fAVI_FrameCount: integer; fAVI_FrameDelayTime: double; {$ifdef IEINCLUDEDIRECTSHOW} fMEDIAFILE_FrameCount: integer; fMEDIAFILE_FrameDelayTime: double; {$endif} fPS_PaperWidth: integer; fPS_PaperHeight: integer; fPS_Compression: TIOPSCompression; fPS_Title: AnsiString; fPDF_PaperWidth: integer; // in Adobe PDF points (1 point=1/72 of inch). fPDF_PaperHeight: integer; // in Adobe PDF points (1 point=1/72 of inch). fPDF_Compression: TIOPDFCompression; fPDF_Title: AnsiString; fPDF_Author: AnsiString; fPDF_Subject: AnsiString; fPDF_Keywords: AnsiString; fPDF_Creator: AnsiString; fPDF_Producer: AnsiString; {$ifdef IEINCLUDERAWFORMATS} fRAW_HalfSize: Boolean; fRAW_Gamma: Double; fRAW_Bright: Double; fRAW_RedScale: Double; fRAW_BlueScale: Double; fRAW_QuickInterpolate: Boolean; fRAW_UseAutoWB: Boolean; fRAW_UseCameraWB: Boolean; fRAW_FourColorRGB: Boolean; fRAW_Camera: AnsiString; fRAW_GetExifThumbnail: Boolean; fRAW_AutoAdjustColors: Boolean; fRAW_ExtraParams: AnsiString; {$endif} fBMPRAW_ChannelOrder: TIOBMPRAWChannelOrder; fBMPRAW_Planes: TIOBMPRAWPlanes; fBMPRAW_RowAlign: Integer; fBMPRAW_HeaderSize: Integer; fBMPRAW_DataFormat: TIOBMPRAWDataFormat; fPSD_LoadLayers: Boolean; fPSD_ReplaceLayers: Boolean; fPSD_HasPremultipliedAlpha: Boolean; fPSD_LargeDocumentFormat: Boolean; fPSD_SelectLayer: AnsiString; fHDP_ImageQuality: Double; fHDP_Lossless: Boolean; fXMP_Info: AnsiString; // IEN Format fIEN_Compression: Integer; fIEN_Description: Widestring; fIEN_GetThumbnail: Boolean; // SVG fSVG_ImageCompression: TIOFileType; function GetFileTypeStr: string; procedure SetEXIF_WhitePoint(index: integer; v: double); function GetEXIF_WhitePoint(index: integer): double; procedure SetEXIF_PrimaryChromaticities(index: integer; v: double); function GetEXIF_PrimaryChromaticities(index: integer): double; procedure SetEXIF_YCbCrCoefficients(index: integer; v: double); function GetEXIF_YCbCrCoefficients(index: integer): double; procedure SetEXIF_ReferenceBlackWhite(index: integer; v: double); function GetEXIF_ReferenceBlackWhite(index: integer): double; procedure SetEXIF_ISOSpeedRatings(index: integer; v: integer); function GetEXIF_ISOSpeedRatings(index: integer): integer; procedure SetEXIF_SubjectArea(index: integer; v: integer); function GetEXIF_SubjectArea(index: integer): integer; procedure SetDpi(Value: integer); procedure SetTIFF_Orientation(Value: integer); procedure SetEXIF_Orientation(Value: integer); procedure SetEXIF_XResolution(Value: double); procedure SetEXIF_YResolution(Value: double); function GetInputICC: TIEICC; function GetOutputICC: TIEICC; function GetDefaultICC: TIEICC; {$ifdef IEINCLUDEIMAGINGANNOT} function GetImagingAnnot: TIEImagingAnnot; {$endif} procedure SetImageIndex(value: Integer); procedure SetImageCount(value: Integer); procedure SetGetThumbnail(value: Boolean); procedure SetIsResource(value: Boolean); procedure SetJPEG_GetExifThumbnail(value: Boolean); {$ifdef IEINCLUDERAWFORMATS} procedure SetRAW_GetExifThumbnail(value: Boolean); {$endif} procedure SetEnableAdjustOrientation(value: Boolean); procedure EXIFTagsAdd(tag: Integer); procedure EXIFTagsDel(tag: Integer); procedure SetEXIF_ExposureTime(value: Double); procedure SetEXIF_FNumber(value: Double); procedure SetEXIF_ExposureProgram(value: Integer); procedure SetEXIF_CompressedBitsPerPixel(value: Double); procedure SetEXIF_ShutterSpeedValue(value: Double); procedure SetEXIF_ApertureValue(value: Double); procedure SetEXIF_BrightnessValue(value: Double); procedure SetEXIF_ExposureBiasValue(value: Double); procedure SetEXIF_MaxApertureValue(value: Double); procedure SetEXIF_SubjectDistance(value: Double); procedure SetEXIF_MeteringMode(value: Integer); procedure SetEXIF_LightSource(value: Integer); procedure SetEXIF_Flash(value: Integer); procedure SetEXIF_FocalLength(value: Double); procedure SetEXIF_ColorSpace(value: Integer); procedure SetEXIF_ExifImageWidth(value: Integer); procedure SetEXIF_ExifImageHeight(value: Integer); procedure SetEXIF_FocalPlaneXResolution(value: Double); procedure SetEXIF_FocalPlaneYResolution(value: Double); procedure SetEXIF_FocalPlaneResolutionUnit(value: Integer); procedure SetEXIF_ExposureIndex(value: Double); procedure SetEXIF_SensingMethod(value: Integer); procedure SetEXIF_FileSource(value: Integer); procedure SetEXIF_SceneType(value: Integer); procedure SetDpiX(Value: Integer); procedure SetDpiY(Value: Integer); function GetEXIF_GPSLatitude(): Double; procedure SetEXIF_GPSLatitude(value: Double); function GetEXIF_GPSLongitude(): Double; procedure SetEXIF_GPSLongitude(value: Double); function GetEXIF_DateTime2: TDateTime; procedure SetEXIF_DateTime2(const Value: TDateTime); function GetEXIF_DateTimeOriginal2: TDateTime; procedure SetEXIF_DateTimeOriginal2(const Value: TDateTime); function GetEXIF_DateTimeDigitized2: TDateTime; procedure SetEXIF_DateTimeDigitized2(const Value: TDateTime); function GetEXIF_GPSLatitude_Str: string; function GetEXIF_GPSLongitude_Str: string; procedure SetEXIF_Gamma(value: Double); procedure SetEXIF_SubjectLocationX(value: Integer); procedure SetEXIF_SubjectLocationY(value: Integer); function GetIPTC_Photoshop(FieldID: Integer): string; procedure SetIPTC_Photoshop(FieldID: Integer; const Value: string); function GetImageDelayTime: integer; function GetDICOM_Compression(): TIEDicomCompression; procedure SetDICOM_Compression(Value: TIEDicomCompression); procedure SetXMP_Info(Value: AnsiString); function GetPDF_PaperSize : TIOPDFPaperSize; procedure SetPDF_PaperSize(const value : TIOPDFPaperSize); function GetPS_PaperSize : TIOPDFPaperSize; procedure SetPS_PaperSize(const value : TIOPDFPaperSize); function GetImageEnIO: TObject; public // IsNativePixelFormat: boolean; fDpiX: integer; fDpiY: integer; // Read-Only fields fColorMap: PRGBROW; fColorMapCount: integer; fIEN_LayerCount: Integer; fIEN_Version: Integer; // ICO (they are not properties) {!! TIOParams.ICO_Sizes Declaration ICO_Sizes: ; Description An array of TSize structures which specify the dimensions of all images contained in an icon file. Note: The last item must specify the size as 0 x 0. Example // save the current image in 'output.ico', It will contain three images with 64x64 32bit (24bit + alphachannel), 32x32 256 colors and 32x32 16 colors // 64 x 64 x 32bit ImageEnView.IO.Params.ICO.BitCount[0] := 32; ImageEnView.IO.Params.ICO.Sizes[0].cx := 64; ImageEnView.IO.Params.ICO.Sizes[0].cy := 64; // 32 x 32 x 8bit ImageEnView.IO.Params.ICO.BitCount[1] := 8; ImageEnView.IO.Params.ICO.Sizes[1].cx := 32; ImageEnView.IO.Params.ICO.Sizes[1].cy := 32; // 32 x 32 x 4bit ImageEnView.IO.Params.ICO.BitCount[2] := 4; ImageEnView.IO.Params.ICO.Sizes[2].cx := 32; ImageEnView.IO.Params.ICO.Sizes[2].cy := 32; // I don't want other images ImageEnView.IO.Params.ICO.BitCount[3] := 0; ImageEnView.IO.Params.ICO.Sizes[3].cx := 0; ImageEnView.IO.Params.ICO.Sizes[3].cy := 0; // save ImageEnView.IO.SaveToFile('D:\output.ico'); !!} ICO_Sizes: TIOICOSizes; {!! TIOParams.ICO_BitCount Declaration ICO_BitCount: ; Description An array of integers which specify the bit count of all images contained in an icon file. The last bitcount must be set to 0. Example // save the current image in 'output.ico', It will contain three images with 64x64 32bit (24bit + alphachannel), 32x32 256 colors and 32x32 16 colors // 64 x 64 x 32bit ImageEnView.IO.Params.ICO.BitCount[0] := 32; ImageEnView.IO.Params.ICO.Sizes[0].cx := 64; ImageEnView.IO.Params.ICO.Sizes[0].cy := 64; // 32 x 32 x 8bit ImageEnView.IO.Params.ICO.BitCount[1] := 8; ImageEnView.IO.Params.ICO.Sizes[1].cx := 32; ImageEnView.IO.Params.ICO.Sizes[1].cy := 32; // 32 x 32 x 4bit ImageEnView.IO.Params.ICO.BitCount[2] := 4; ImageEnView.IO.Params.ICO.Sizes[2].cx := 32; ImageEnView.IO.Params.ICO.Sizes[2].cy := 32; // I don't want other images ImageEnView.IO.Params.ICO.BitCount[3] := 0; ImageEnView.IO.Params.ICO.Sizes[3].cx := 0; ImageEnView.IO.Params.ICO.Sizes[3].cy := 0; // save ImageEnView.IO.SaveToFile('D:\output.ico'); !!} ICO_BitCount: TIOICOBitCount; // fInputICC: TIEICC; fOutputICC: TIEICC; fDefaultICC: TIEICC; // GENERIC {!! TIOParams.FileName Declaration property FileName: WideString; Description Returns the filename of the last loaded or saved image. !!} property FileName: WideString read fFileName write fFileName; property FileTypeStr: string read GetFileTypeStr; {!! TIOParams.FileType Declaration property FileType: ; Description Returns the file type of the last loaded or saved image, e.g. after a calling LoadFromFileGIF this property will have the ioGIF value. Default: ioUnknown Example if OpenImageEnDialog1.Execute then begin ImageEnView1.IO.LoadFromFile(OpenImageEnDialog1.FileName); case ImageEnView1.IO.Params.FileType of ioTIFF : ShowMessage('You have loaded a TIFF file'); ioGIF : ShowMessage('You have loaded a GIF file'); ... end; end; !!} property FileType: TIOFileType read fFileType write fFileType; {!! TIOParams.BitsPerSample Declaration property BitsPerSample: integer; Description Specifies the depth, in bits, for each sample. Allowed values: Value Description 1 1 bit black & white 2 to 7 Color mapped bitmap (from 4 to 128 colors) 8 Color mapped (256 colors), 8 bit gray scale, 24 bit RGB, 48 bit CMYK, 24 bit CIELab 16 16 bit gray scale or 48 bit RGB 32 32 bit floating point
Default: 8 See also:
Example // saves 256 colormapped bitmap ImageEnView1.IO.Params.BitsPerSample := 8; ImageEnView1.IO.Params.SamplesPerPixel := 1; ImageEnView1.IO.Params.SaveToFile('D:\Alfa.bmp'); !!} property BitsPerSample: integer read fBitsPerSample write fBitsPerSample; {!! TIOParams.SamplesPerPixel Declaration property SamplesPerPixel: integer; Description Specifies the Samples (channels) for each pixel. Allowed values: Parameter Description 1 Single channel, colormapped or gray scale image 3 Three channels, RGB or CIELab 4 Four channels, CMYK or BGRA
Default: 3 See also:
Example // saves 256 colormapped bitmap ImageEnView1.IO.Params.BitsPerSample := 8; ImageEnView1.IO.Params.SamplesPerPixel := 1; ImageEnView1.IO.Params.SaveToFile('D:\Alfa.bmp'); !!} property SamplesPerPixel: integer read fSamplesPerPixel write fSamplesPerPixel; {!! TIOParams.Width Declaration property Width: integer; Description Returns the width of the image in pixels. !!} property Width: integer read fWidth write fWidth; {!! TIOParams.Height Declaration property Height: integer; Description Returns the height of the image in pixels. !!} property Height: integer read fHeight write fHeight; property DpiX: integer read fDpiX write SetDpiX; property DpiY: integer read fDpiY write SetDpiY; property Dpi: integer read fDpiX write SetDpi; {!! TIOParams.ColorMap Declaration property ColorMap: ; Description Returns the color map of the current image. Note: Not all image types have a valid colormap (in which case ColorMap will be nil). See also: Example // Show the palette of the file "myfile.gif" var fPalDial : TImageEnPaletteDialog; begin ImageEnView1.IO.LoadFromFile('C:\myfile.gif'); fPalDial := TImageEnPaletteDialog.Create(self); fPalDial.SetPalette(ImageEnView1.IO.Params.ColorMap^, ImageEnView1.IO.Params.ColorMapCount); fPalDial.Execute; fPalDial.free; end; !!} property ColorMap: PRGBROW read fColorMap; {!! TIOParams.ColorMapCount Declaration property ColorMapCount: integer; Description Returns the number of entries in the array. See also: !!} property ColorMapCount: integer read fColorMapcount; {!! TIOParams.ImageIndex Declaration property ImageIndex: Integer; Description Specifies the index of the next page/frame to load. You must set this property before calling read methods like LoadFromFile. This property is valid for all multi-page file formats (TIFF, GIF, DCX, Dicom, etc..). Note: Setting ImageIndex is the same as setting the relevant format image index: , , , or . See Also - - Examples // Load the second page of the TIFF ImageEnView1.IO.Params.ImageIndex := 1; ImageEnView1.IO.LoadFromFile('C:\input.tif'); // Print all pages of a TIFF Printer.BeginDoc; for I := 0 to ImageEnView1.IO.Params.ImageCount - 1 do begin ImageEnView1.IO.Params.ImageIndex := I; ImageEnView1.IO.LoadFromFile('C:\input.tif'); ImageEnView1.IO.PrintImage(Printer.Canvas); end; Printer.EndDoc; !!} property ImageIndex: Integer read fImageIndex write SetImageIndex; {!! TIOParams.ImageCount Declaration property ImageCount: integer Description Returns the number of pages/frames/images in the current file. Many image file formats can store multiple images, including TIFF, GIF, DCX, ICO and cursor. This property is valid for all file formats (i.e. returning 1 for formats that do not support multiple images). It provides generic access to file specific properties: , , and . You can use to load/navigate images within the loaded file. See Also - - - Examples // Show the number of pages in a TIFF ImageEnView1.IO.LoadFromFile('C:\input.tif'); iPages := ImageEnView1.IO.Params.ImageCount; ShowMessage('Page Count: ' + IntToStr(iPages)); // Print all pages of a TIFF Printer.BeginDoc; for I := 0 to ImageEnView1.IO.Params.ImageCount - 1 do begin ImageEnView1.IO.Params.ImageIndex := I; ImageEnView1.IO.LoadFromFile('C:\input.tif'); ImageEnView1.IO.PrintImage(Printer.Canvas); end; Printer.EndDoc; !!} property ImageCount: Integer read fImageCount write SetImageCount; {!! TIOParams.ImageDelayTime Declaration property ImageDelayTime : Integer (Read-only) Description If the current file supports animation and has multiple frames, then this property provides access to the delay in MS (milliseconds) between images. E.g. if ImageDelayTime = 2000 then each frame should be shown for 2 seconds when animated. This is a read-only property which provides generic access to one of: - - - - The frame interval tag of DICOM files Example // Set frame load timer to correct interval to animate the image FrameLoadTimer.Interval := ImageEnView1.IO.Params.ImageDelayTime; !!} property ImageDelayTime : integer read GetImageDelayTime; {!! TIOParams.GetThumbnail Declaration property GetThumbnail: Boolean; Description Specifies that the thumbnail for an image will be loaded instead of the full image. A thumbnail is often available for images returned by digital cameras (EXIF Thumbnail). It applies to JPEG, RAW, IEN, PSD files, and also images loaded using . If enabled and the file does not contain a thumbnail the full image will be automatically loaded instead. The property sets: - - - Default: False Note: Must be set before loading an image Example // Load only the thumbnail of our image (if it has one) ImageEnView1.IO.Params.GetThumbnail := true; ImageEnView1.IO.LoadFromFile('C:\Input.jpg'); !!} property GetThumbnail: Boolean read fGetThumbnail write SetGetThumbnail; {!! TIOParams.Dict Declaration property Dict: ; Description Contains a dictionary of additional properties. The key "XMP" will contain a sub-dictionary parsed from XMP info. Demo Demos\InputOutput\XMP\XMP.dpr Example // loads first page of specified PDF rasterizing at 150dpi (assumes ImageMagick and GhostScript are installed) TIEMiscPluginsImageMagick.RegisterPlugin(); ImageEnView1.IO.Params.ImageIndex := 0; ImageEnView1.IO.Params.Dict.Insert('PDF:Density', 150); ImageEnView1.IO.LoadFromFile('mybook.pdf'); // gets XMP doc id docid := ImageEnView1.IO.Params.Dict.GetString('xapMM:DocumentID', true); !!} property Dict: TIEDictionary read fDict; {!! TIOParams.IsResource Declaration property IsResource: Boolean; Description Some formats (BMP, ICO, CUR) do not contain all headers when stored as resources (e.g. in EXE, DLL, etc...). If you set IsResource = true, ImageEn will skip loading of these headers so the image can be loaded correctly. Default: False Demo Demos\InputOutput\ResourceLoader\ResourceLoader.dpr Example // loads resource 143 in "Bitmap" of "explorer.exe" (should be a little Windows logo) var re: TIEResourceExtractor; buffer: Pointer; bufferLen: Integer; begin re := TIEResourceExtractor.Create('explorer.exe'); try buffer := re.GetBuffer('Bitmap', 'INTRESOURCE:143', bufferLen); ImageEnView1.IO.Params.IsResource := true; ImageEnView1.IO.LoadFromBuffer(buffer, bufferLen, ioBMP); finally re.Free; end; end; !!} property IsResource: Boolean read fIsResource write SetIsResource; {!! TIOParams.EnableAdjustOrientation Declaration property EnableAdjustOrientation: Boolean; Description If enabled before loading a file which contains EXIF orientation information, the image will be automatically rotated for display (the actual file is not modified). Orientation information is often found in digital photos from high-end cameras. ImageEn uses the data found in or to determine the correct orientation. Note: This property also sets and . Default: False Example ImageEnView1.IO.Params.EnableAdjustOrientation := True; ImageEnView1.IO.LoadFromFile('C:\input.jpg'); !!} property EnableAdjustOrientation: Boolean read fEnableAdjustOrientation write SetEnableAdjustOrientation; // ICC property InputICCProfile: TIEICC read GetInputICC; property OutputICCProfile: TIEICC read GetOutputICC; property DefaultICCProfile: TIEICC read GetDefaultICC; // IPTC {!! TIOParams.IPTC_Info Declaration property IPTC_Info: ; Description A list of all IPTC information contained in a file. View object details at . IPTC records can contains text, objects and images. Applications can read/write information from IPTC_Info using string objects or a memory buffer. Each IPTC_Info item has a record number and a dataset number. These values specify the type of data contained in the item, according to IPTC - NAA Information Interchange Model Version 4 (See: www.iptc.org). For JPEG files ImageEn can read/write IPTC fields from the APP13 marker. ImageEn can also read/write IPTC textual information of PhotoShop (access In Photoshop under "File Info"). View a list IPTC Photoshop items. Note: A set of IPTC helper functions are available in iexMetaHelpers.pas Demo Demos\InputOutput\IPTC\IPTC.dpr Examples // Read the PhotoShop image description ImageEnView1.IO.LoadFromFile('C:\image.jpg'); Idx := ImageEnView1.IO.Params.IPTC_Info.IndexOf(2, 120); Caption := ImageEnView1.IO.Params.IPTC_Info.StringItem[idx]; // write the image description ImageEnView1.IO.Params.IPTC_Info.StringItem[idx] := 'This is the new caption'; ImageEnView1.IO.SaveToFile('D:\image.jpg'); See Also - Photoshop IPTC consts - - - - !!} property IPTC_Info: TIEIPTCInfoList read fIPTC_Info; property IPTC_Photoshop[FieldID: Integer]: string read GetIPTC_Photoshop write SetIPTC_Photoshop; // Imaging annotations {$ifdef IEINCLUDEIMAGINGANNOT} property ImagingAnnot: TIEImagingAnnot read GetImagingAnnot; {$endif} {!! TIOParams.ImageEnAnnot Declaration property ImageEnAnnot: ; Description Provides access to the objects or layers loaded (or to be saved) from a TIFF or JPEG. Using a object you can create new objects, copy to or from a (as vectorial objects) or (as layers), or just draw onto the bitmap. ImagingAnnot vs ImageEnAnnot handles annotations that are supported by other third party applications, but does not support all objects of TImageEnVect. ImageEnAnnot supports all objects of TImageEnVect and TImageEnView, but are not understood by other applications. Example // Load an image and all annotations from input.tif to a TImageEnVect. This allows the annotations to be edited: ImageEnVect1.IO.LoadFromFile('C:\input.tif'); ImageEnVect1.IO.Params.ImageEnAnnot.CopyToTImageEnVect(); // Load an image and all annotations from input.jpg to a TImageEnView. This allows the annotations to be edited: ImageEnView1.IO.LoadFromFile('C:\input.jpg'); ImageEnView1.IO.Params.ImageEnAnnot.CopyToTImageEnView(); // Load an image and all annotations from input.tif, but just draw annotation on the image (display only, cannot be edited): ImageEnVect1.IO.LoadFromFile('C:\input.tif'); ImageEnVect1.IO.Params.ImageEnAnnot.DrawToBitmap( ImageEnVect1.IEBitmap, True ); ImageEnVect1.Update(); // Save an image and all annotations to output.tif ImageEnVect1.IO.Params.ImageEnAnnot.CopyFromTImageEnVect(); ImageEnVect1.IO.SaveToFile('C:\output.tif'); !!} property ImageEnAnnot: TIEImageEnAnnot read fImageEnAnnot; // TIFF {!! TIOParams.TIFF_Compression Declaration property TIFF_Compression: ; Description Specifies the compression type for TIFF images. Default: ioTIFF_UNCOMPRESSED !!} property TIFF_Compression: TIOTIFFCompression read fTIFF_Compression write fTIFF_Compression; {!! TIOParams.TIFF_ImageIndex Declaration property TIFF_ImageIndex: integer; Description The index (zero-based) of the current page of the loaded TIFF image. You can also use to load/navigate images within the loaded file. Note: You can use for generic access to the ImageIndex (not specific to an image format). Examples // Want the second page of the TIFF ImageEnView1.IO.Params.TIFF_ImageIndex := 1; ImageEnView1.IO.LoadFromFile('C:\input.tif'); // Print all pages of a TIFF Printer.BeginDoc; for I := 0 to ImageEnView1.IO.Params.TIFF_ImageCount - 1 do begin ImageEnView1.IO.Params.TIFF_ImageIndex := I; ImageEnView1.IO.LoadFromFile('C:\input.tif'); ImageEnView1.IO.PrintImage(Printer.Canvas); end; Printer.EndDoc; See Also - - - !!} property TIFF_ImageIndex: integer read fTIFF_ImageIndex write SetImageIndex; {!! TIOParams.TIFF_SubIndex Declaration property TIFF_SubIndex: Integer; Description A TIFF can contain several pages. You can load image or parameters from a page using (or just ). Each page can also contain sub-images, so you can load a specific sub-page using TIFF_SubIndex. This is useful, for example, to load an embedded JPEG from a DNG (camera raw format), which is located in the first page and the second sub-index. Default: -1 Example // Load the embedded Jpeg from a DNG ImageEnView1.IO.Params.TIFF_ImageIndex := 0; ImageEnView1.IO.Params.TIFF_SubIndex := 1; ImageEnView1.IO.LoadFromFileTIFF('DCS001.DNG'); !!} property TIFF_SubIndex: Integer read fTIFF_SubIndex write fTIFF_SubIndex; {!! TIOParams.TIFF_ImageCount Declaration property TIFF_ImageCount: Integer; (Read-only) Description Returns the number of images/pages contained in the current TIFF. You can use to load/navigate images within the loaded file. Note: You can use for generic access to the image count (not specific to an image format). For non-component access, see . See Also - - - - - Examples // Show number of pages in a TIFF ImageEnView1.IO.LoadFromFile('C:\input.tif'); iPages := ImageEnView1.IO.Params.ImageCount; ShowMessage('Page Count: ' + IntToStr(iPages)); // Print all pages of a TIFF Printer.BeginDoc; for I := 0 to ImageEnView1.IO.Params.ImageCount - 1 do begin ImageEnView1.IO.Params.ImageIndex := I; ImageEnView1.IO.LoadFromFile('C:\input.tif'); ImageEnView1.IO.PrintImage(Printer.Canvas); end; Printer.EndDoc; !!} property TIFF_ImageCount: integer read fTIFF_ImageCount write SetImageCount; {!! TIOParams.TIFF_PhotometInterpret Declaration property TIFF_PhotometInterpret: ; Description Specifies the Photometric interpretation of a TIFF image. Default: ioTIFF_RGB !!} property TIFF_PhotometInterpret: TIOTIFFPhotometInterpret read fTIFF_PhotometInterpret write fTIFF_PhotometInterpret; {!! TIOParams.TIFF_PlanarConf Declaration property TIFF_PlanarConf: integer; Description Specifies the Planar configuration of a TIFF image: Value Description 1 The component values for each pixel are stored contiguously (ex. RGBRGBRGB...) 2 The components are stored in separate component planes (ex. RRRRRR...GGGGGGG.....BBBBBB)
Default: 1 !!} property TIFF_PlanarConf: integer read fTIFF_PlanarConf write fTIFF_PlanarConf; {!! TIOParams.TIFF_NewSubfileType Declaration property TIFF_NewSubfileType: integer; Description A general indication of the kind of data contained in the current sub-file. This field is made up of a set of 32 flag bits. Currently defined values are: Bit Description Bit 0 is 1 if the image is a reduced-resolution version of another image in this TIFF file, else the bit is 0. Bit 1 is 1 if the image is a single page of a multi-page image (see the PageNumber field description), else the bit is 0. Bit 2 is 1 if the image defines a transparency mask for another image in this TIFF file. The PhotometricInterpretation value must be 4, designating a transparency mask.
Default: 0 !!} property TIFF_NewSubfileType: integer read fTIFF_NewSubfileType write fTIFF_NewSubfileType; {!! TIOParams.TIFF_XPos Declaration property TIFF_XPos: integer; Description Returns the X position of the Top-left of the original scanned image. Default: 0 !!} property TIFF_XPos: integer read fTIFF_XPos write fTIFF_XPos; {!! TIOParams.TIFF_GetTile Declaration property TIFF_GetTile: integer; Description Specifies the tile number to load when loading a tiled TIFF file (tiles are often used in large Tiff files to reduce load time). If -1 is specified, all tiles are loaded. Default: -1 (Load all tiles) Example // Load first tile of a TIFF ImageEnView1.IO.Params.TIFF_GetTile := 1; ImageEnView1.IO.SaveToFile('D:\BigBigTiff.tif'); !!} property TIFF_GetTile: integer read fTIFF_GetTile write fTIFF_GetTile; {!! TIOParams.TIFF_YPos Declaration property TIFF_YPos: integer; Description Returns the Y position of the top-left of the original scanned image. Default: 0 !!} property TIFF_YPos: integer read fTIFF_YPos write fTIFF_YPos; {!! TIOParams.TIFF_DocumentName Declaration property TIFF_DocumentName: AnsiString; Description Specifies the document name of a TIFF image. Default: '' Example ImageEnView1.IO.Params.TIFF_DocumentName := 'Sanremo'; ImageEnView1.IO.Params.TIFF_ImageDescription := 'The city of the flowers'; ImageEnView1.IO.SaveToFile('D:\Italy.tif'); !!} property TIFF_DocumentName: AnsiString read fTIFF_DocumentName write fTIFF_DocumentName; {!! TIOParams.TIFF_ImageDescription Declaration property TIFF_ImageDescription: AnsiString; Description Specifies the image description of a TIFF image. Default: '' Example ImageEnView1.IO.Params.TIFF_DocumentName := 'Sanremo'; ImageEnView1.IO.Params.TIFF_ImageDescription := 'The city of the flowers'; ImageEnView1.IO.SaveToFile('D:\Italy.tif'); !!} property TIFF_ImageDescription: AnsiString read fTIFF_ImageDescription write fTIFF_ImageDescription; {!! TIOParams.TIFF_PageName Declaration property TIFF_PageName: AnsiString; Description Specifies the page name of a TIFF image. Default: '' !!} property TIFF_PageName: AnsiString read fTIFF_PageName write fTIFF_PageName; {!! TIOParams.TIFF_PageNumber Declaration property TIFF_PageNumber: integer; Description Specifies the page number of a TIFF image. Default: -1 !!} property TIFF_PageNumber: integer read fTIFF_PageNumber write fTIFF_PageNumber; {!! TIOParams.TIFF_PageCount Declaration property TIFF_PageCount: integer; Description Returns the number of pages in a TIFF file. !!} property TIFF_PageCount: integer read fTIFF_PageCount write fTIFF_PageCount; {!! TIOParams.TIFF_Orientation Declaration property TIFF_Orientation: Integer; Description Specifies the orientation of the original image. ImageEn can automatically display an image with the correct if
is True. Allowed values: Value Description _exoCorrectOrientation (1) Image is Orientated Correctly (top left side) _exoNeedsHorizontalFlip (2) Image is Horizontally Flipped (top right side) _exoNeeds180Rotate (3) Image is Offset by 180º (bottom right side) _exoNeedsVerticalFlip (4) Image is Vertically Flipped (bottom left side) _exoNeedsHorzAndVertFlip (5) Image is Flipped Horiz. and Offset 90º CCW (left side top) _exoNeeds90RotateCW (6) Image is Offset by 90º CCW (right side top) _exoNeedsFlipHorzAnd90Rotate (7) Image is Flipped Horiz. and offset 90º CW (right side bottom) _exoNeeds270RotateCW (8) Image is Offset by 90º clockwise (left side bottom)
Note: Support for orientations other than 1 is not a baseline TIFF requirement. Default: _exoCorrectOrientation (1) See also:
!!} property TIFF_Orientation: integer read fTIFF_Orientation write SetTIFF_Orientation; {!! TIOParams.TIFF_EnableAdjustOrientation Declaration property TIFF_EnableAdjustOrientation: Boolean; Description If enabled before loading a file which contains EXIF orientation information, the image will be automatically rotated for display (the actual file is not modified). Orientation information is often found in digital photos from high-end cameras. ImageEn uses the data found in to determine the correct orientation for TIFF images. See also: Default: False !!} property TIFF_EnableAdjustOrientation: boolean read fTIFF_EnableAdjustOrientation write fTIFF_EnableAdjustOrientation; property TIFF_LZWDecompFunc: TTIFFLZWDecompFunc read fTIFF_LZWDecompFunc write fTIFF_LZWDecompFunc; property TIFF_LZWCompFunc: TTIFFLZWCompFunc read fTIFF_LZWCompFunc write fTIFF_LZWCompFunc; {!! TIOParams.TIFF_JPEGQuality Declaration property TIFF_JPEGQuality: Integer; Description Specifies the quality factor for a TIFF compressed as JPEG. Range is 1 to 100. High values improve image quality but require more disk space. Default: 80 !!} property TIFF_JPEGQuality: integer read fTIFF_JPEGQuality write fTIFF_JPEGQuality; {!! TIOParams.TIFF_JPEGColorSpace Declaration property TIFF_JPEGColorSpace: ; Description Specifies the desired color space for the Jpeg included in a TIFF file. Default: ioJPEG_YCBCR Example ImageEnView.IO.Params.TIFF_JPEGColorSpace := ioJPEG_RGB; ImageEnView.IO.Params.TIFF_Compression := ioTIFF_JPEG; ImageEnView.IO.SaveToFile('D:\output.tif'); !!} property TIFF_JPEGColorSpace: TIOJPEGColorSpace read fTIFF_JPEGColorSpace write fTIFF_JPEGColorSpace; {!! TIOParams.TIFF_FillOrder Declaration property TIFF_FillOrder: integer; Description Specifies the logical order of bits within a byte. Value Description 1 Pixels are arranged within a byte such that pixels with lower column values are stored in the higher-order bits of the byte 2 Pixels are arranged within a byte such that pixels with lower column values are stored in the lower-order bits of the byte
Default: 1 !!} property TIFF_FillOrder: integer read fTIFF_FillOrder write fTIFF_FillOrder; {!! TIOParams.TIFF_ZIPCompression Declaration property TIFF_ZIPCompression: Integer; Description Specifies the compression level used when using ioTIFF_ZIP compression. Value Description 0 Fastest 1 Normal (default) 2 Maximum compression
Default: 1 !!} property TIFF_ZIPCompression: Integer read fTIFF_ZIPCompression write fTIFF_ZIPCompression; {!! TIOParams.TIFF_StripCount Declaration property TIFF_StripCount: Integer; Description Specifies the number of strips to use when creating a TIFF file. Default: 0 (value is chosen automatically) Note: TIFF_StripCount is not read when loading a TIFF. Example // Create a TIFF with a unique strip ImageEnView1.IO.TIFF_StripCount := 1; ImageEnView1.IO.SaveToFile('D:\out.tiff'); !!} property TIFF_StripCount: Integer read fTIFF_StripCount write fTIFF_StripCount; {!! TIOParams.TIFF_ByteOrder Declaration property TIFF_ByteOrder:
; Description Returns the byte order of the current TIFF image. This property is read-only because ImageEn always uses ioLittleEndian when saving TIFF files. ioBigEndian byte order is used by Motorola, while ioLittleEndian is used by Intel processors. This function is useful when using or which merge two tiff images without decoding them, because the created TIFF will be unreadable if the images have different byte orders. !!} property TIFF_ByteOrder: TIOByteOrder read fTIFF_ByteOrder write fTIFF_ByteOrder; {!! TIOParams.TIFF_PhotoshopImageResources Declaration property TIFF_PhotoshopImageResources: ; Description Contains Photoshop raw image resources. ImageEn doesn't use this data, but will maintain it when saving. !!} property TIFF_PhotoshopImageResources: TIEArrayOfByte read fTIFF_PhotoshopImageResources write fTIFF_PhotoshopImageResources; {!! TIOParams.TIFF_PhotoshopImageSourceData Declaration property TIFF_PhotoshopImageSourceData: ; Description Contains Photoshop raw image source data. ImageEn doesn't use this data, but will maintain it for saving. !!} property TIFF_PhotoshopImageSourceData: TIEArrayOfByte read fTIFF_PhotoshopImageSourceData write fTIFF_PhotoshopImageSourceData; {!! TIOParams.TIFF_BigTIFF Declaration property TIFF_BigTIFF: boolean; Description Returns true if the TIFF is a BigTIFF (>4GB). !!} property TIFF_BigTIFF: boolean read fTIFF_BigTIFF write fTIFF_BigTIFF; // GIF {!! TIOParams.GIF_Version Declaration property GIF_Version: AnsiString; Description Returns the GIF standard version, either "GIF87a" or "GIF89a". Default: 'GIF89a' !!} property GIF_Version: AnsiString read fGIF_Version write fGIF_Version; {!! TIOParams.GIF_ImageIndex Declaration property GIF_ImageIndex: integer; Description The index (zero-based) of the current image of the loaded GIF image. You can also use to load/navigate images within the loaded file. Note: You can use for generic access to the ImageIndex (not specific to an image format). See Also - - - Examples // Want the second page of the GIF ImageEnView1.IO.Params.GIF_ImageIndex := 1; ImageEnView1.IO.LoadFromFile('C:\Animation.gif'); // Print all images of a GIF Printer.BeginDoc; for I := 0 to ImageEnView1.IO.Params.GIF_ImageCount - 1 do begin ImageEnView1.IO.Params.GIF_ImageIndex := I; ImageEnView1.IO.LoadFromFile('C:\input.gif'); ImageEnView1.IO.PrintImage(Printer.Canvas); end; Printer.EndDoc; !!} property GIF_ImageIndex: integer read fGIF_ImageIndex write SetImageIndex; {!! TIOParams.GIF_ImageCount Declaration property GIF_ImageCount: Integer; (Read-only) Description Returns the number of images contained in the currently loaded GIF. You can use to load/navigate images within the loaded file. Note: You can use for generic access to the image count (not specific to an image format). For non-component access, see . See Also - - - - - Examples // Return the frame count of 'animated.gif' without load the GIF ImageEnView1.IO.ParamsFromFile('C:\Animated.gif'); iImageCount := ImageEnView1.IO.Params.GIF_ImageCount; // Print all images of a GIF Printer.BeginDoc; for I := 0 to ImageEnView1.IO.Params.GIF_ImageCount - 1 do begin ImageEnView1.IO.Params.GIF_ImageIndex := I; ImageEnView1.IO.LoadFromFile('C:\input.gif'); ImageEnView1.IO.PrintImage(Printer.Canvas); end; Printer.EndDoc; !!} property GIF_ImageCount: integer read fGIF_ImageCount write SetImageCount; {!! TIOParams.GIF_XPos Declaration property GIF_XPos: integer; Description The X coordinate where the top-left of the frame will be shown. Due to optimization secondary frames of a GIF may not contain all the image data of the original frame, but only what data has changed. This property allows you to draw the subsequent frames at the correct position. Default: 0 !!} property GIF_XPos: integer read fGIF_XPos write fGIF_XPos; {!! TIOParams.GIF_YPos Declaration property GIF_YPos: integer; Description The Y coordinate where the top-left of the frame will be shown. Due to optimization secondary frames of a GIF may not contain all the image data of the original frame, but only what data has changed. This property allows you to draw the subsequent frames at the correct position. Default: 0 !!} property GIF_YPos: integer read fGIF_YPos write fGIF_YPos; {!! TIOParams.GIF_DelayTime Declaration property GIF_DelayTime: integer; Description Specifies the period (in 1/100th sec) for which the current frame remains shown. Default: 0 Demo Demos\ImageEditing\AnimatedGIF\AnimatedGIF.dpr Example ImageEnView1.IO.Params.GIF_DelayTime := 10; // Set current frame to display for 1/10th of a second !!} property GIF_DelayTime: integer read fGIF_DelayTime write fGIF_DelayTime; {!! TIOParams.GIF_FlagTranspColor Declaration property GIF_FlagTranspColor: boolean; Description If enabled then the property specifies the transparency color of the image. If false, is not valid. Default: False Note: If the image contains an alpha channel (transparency channel) this property is handled automatically. Example ImageEnView1.IO.Params.GIF_FlagTranspColor := True; ImageEnView1.IO.Params.GIF_TranspColor := CreateRGB(0, 0, 0); // black is the transparent color !!} property GIF_FlagTranspColor: boolean read fGIF_FlagTranspColor write fGIF_FlagTranspColor; {!! TIOParams.GIF_TranspColor Declaration property GIF_TranspColor: ; Description Specifies the transparency color. Default: (0, 0, 0), i.e. Black Notes: - Only valid if = True - The specified color should exist within the image See Also - - - !!} property GIF_TranspColor: TRGB read fGIF_TranspColor write fGIF_TranspColor; {!! TIOParams.GIF_Interlaced Declaration property GIF_Interlaced: boolean; Description Returns True if the GIF image is interlaced. !!} property GIF_Interlaced: boolean read fGIF_Interlaced write fGIF_Interlaced; {!! TIOParams.GIF_WinWidth Declaration property GIF_WinWidth: integer; Description Returns the width of the window where the GIF is shown. !!} property GIF_WinWidth: integer read fGIF_WinWidth write fGIF_WinWidth; {!! TIOParams.GIF_WinHeight Declaration property GIF_WinHeight: integer; Description Returns the height of the window where the GIF is shown. !!} property GIF_WinHeight: integer read fGIF_WinHeight write fGIF_WinHeight; {!! TIOParams.GIF_Background Declaration property GIF_Background: ; Description Returns the background color of the GIF. Note: This color should exist in the image. Default: (0, 0, 0), i.e. Black See Also - - - !!} property GIF_Background: TRGB read fGIF_Background write fGIF_Background; {!! TIOParams.GIF_Ratio Declaration property GIF_Ratio: integer; Description Returns the aspect ratio of the GIF image, which is calculated as follows: Width / Height = (Ratio + 15) / 64 !!} property GIF_Ratio: integer read fGIF_Ratio write fGIF_Ratio; {!! TIOParams.GIF_Comments Declaration property GIF_Comments: TStringList; Description Returns the text comments contained in a GIF file. Example ImageEnIO.Params.Gif_Comments.Clear; ImageEnIO.Params.GIF_Comments.Add('Hello world!'); ImageEnIO.SaveToFile('D:\output.gif'); !!} property GIF_Comments: TStringList read fGIF_Comments; {!! TIOParams.GIF_Action Declaration property GIF_Action: ; Description Specifies how frames are displayed in a multi-frame GIF. Default: ioGIF_DrawBackground !!} property GIF_Action: TIEGIFAction read fGIF_Action write fGIF_Action; {!! TIOParams.GIF_RAWLoad Declaration property GIF_RAWLoad: boolean; Description If true ImageEn doesn't process the GIF disposal method (i.e. doesn't merge frames when required). This property is not applicable to multi-page loading (like TImageEnMIO and TImageEnMView). If is attached to TImageEnView, the layer positions ( and ) are also set. Default: False !!} property GIF_RAWLoad: boolean read fGIF_RAWLoad write fGIF_RAWLoad; property GIF_LZWDecompFunc: TGIFLZWDecompFunc read fGIF_LZWDecompFunc write fGIF_LZWDecompFunc; property GIF_LZWCompFunc: TGIFLZWCompFunc read fGIF_LZWCompFunc write fGIF_LZWCompFunc; // DCX {!! TIOParams.DCX_ImageIndex Declaration property DCX_ImageIndex: Integer; Description The index (zero-based) of the current page of the loaded DCX image. You can also use to load/navigate images within the loaded file. Note: You can use for generic access to the ImageIndex (not specific to an image format). See Also - - - Examples // Load the second page of 'input.dcx' ImageEnView1.IO.Params.DCX_ImageIndex := 1; ImageEnView1.IO.LoadFromFile('C:\input.dcx'); // Print all pages of a DCX image Printer.BeginDoc; for I := 0 to ImageEnView1.IO.Params.ImageCount - 1 do begin ImageEnView1.IO.Params.DCX_ImageIndex := I; ImageEnView1.IO.LoadFromFile('C:\input.dcx'); ImageEnView1.IO.PrintImage(Printer.Canvas); end; Printer.EndDoc; !!} property DCX_ImageIndex: Integer read fDCX_ImageIndex write SetImageIndex; // JPEG {!! TIOParams.JPEG_ColorSpace Declaration property JPEG_ColorSpace: ; Description Specifies the saved/loaded color space. Default: ioJPEG_YCbCr !!} property JPEG_ColorSpace: TIOJPEGColorSpace read fJPEG_ColorSpace write fJPEG_ColorSpace; {!! TIOParams.JPEG_Quality Declaration property JPEG_Quality: integer; Description The quality factor for the current JPEG image. Range is 1 to 100, though typical range is 60 (low quality) to 95 (high quality). Higher values will improve image quality but require more disk space. Default: 80 Note: This property is not stored in a JPEG image, so it is never set when loading an image. Instead you set it when saving a JPEG to specify your desired compression. It is possible to estimate the original JPEG compression using or . Example // load a jpeg and save it using the same compression quality ImageEnView1.IO.LoadFromFile('C:\input.jpg'); ImageEnView1.IO.Params.JPEG_Quality := IECalcJpegFileQuality('C:\input.jpg'); ImageEnView1.IO.SaveToFile('D:\output.jpg'); !!} property JPEG_Quality: integer read fJPEG_Quality write fJPEG_Quality; {!! TIOParams.JPEG_DCTMethod Declaration property JPEG_DCTMethod: ; Description Specifies the DCT method of the current JPEG. Default: ioJPEG_ISLOW !!} property JPEG_DCTMethod: TIOJPEGDCTMethod read fJPEG_DCTMethod write fJPEG_DCTMethod; {!! TIOParams.JPEG_CromaSubsampling Declaration property JPEG_CromaSubsampling: ; Description Specifies the croma sub-sampling, which affects the JPEG quality. Default: ioJPEG_HIGH Note: This property is valid only when = ioJPEG_YCbCr. !!} property JPEG_CromaSubsampling: TIOJPEGCromaSubsampling read fJPEG_CromaSubsampling write fJPEG_CromaSubsampling; {!! TIOParams.JPEG_OptimalHuffman Declaration property JPEG_OptimalHuffman: boolean; Description If enabled, an optimal Huffman table is used by the JPEG compressor (to improve the compression level). If False, a standard table is used. Default: False !!} property JPEG_OptimalHuffman: boolean read fJPEG_OptimalHuffman write fJPEG_OptimalHuffman; {!! TIOParams.JPEG_Smooth Declaration property JPEG_Smooth: integer; Description The smoothing factor for the JPEG. Range is 0 (No smoothing) to 100 is (max). If JPEG_Smooth is not zero, the JPEG compressor smoothes the image before compressing it. This improves the level of compression. Default: 0 !!} property JPEG_Smooth: integer read fJPEG_Smooth write fJPEG_Smooth; {!! TIOParams.JPEG_Progressive Declaration property JPEG_Progressive: boolean; Description Returns true if the current image is a progressive JPEG. Default: False !!} property JPEG_Progressive: boolean read fJPEG_Progressive write fJPEG_Progressive; {!! TIOParams.JPEG_Scale Declaration property JPEG_Scale: ; Description Specifies the size at which to load a JPEG image. It is used to speed up loading when a full size image is not required. Default: ioJPEG_FULLSIZE Example // This is the fastest way to load a thumbnailed jpeg of about 100x100 pixels ImageEnView1.IO.Params.Width := 100; ImageEnView1.IO.Params.Height := 100; ImageEnView1.IO.Params.JPEG_Scale := ioJPEG_AUTOCALC; ImageEnView1.IO.LoadFromFile('C:\myimage.jpg'); !!} property JPEG_Scale: TIOJPEGScale read fJPEG_Scale write fJPEG_Scale; {!! TIOParams.JPEG_MarkerList Declaration property JPEG_MarkerList: ; Description Contains a list of of the markers within a JPEG file (from APP0 to APP15 and COM). JPEG markers can contain text, objects and images. Applications can read/write raw markers from JPEG_MarkerList using a stream or memory buffer. Examples // Read the JPEG_COM marker (idx is integer, Comment is string) ImageEnView1.IO.LoadFromFile('C:\image.jpg'); Idx := ImageEnView1.IO.Params.JPEG_MarkerList.IndexOf(JPEG_COM); Comment := ImageEnView1.IO.Params.JPEG_MarkerList.MarkerData[idx]; // Now writes the JPEG_COM marker Comment := 'This is the new comment'; ImageEnView1.IO.Params.JPEG_MarkerList.SetMarker(idx, JPEG_COM, PAnsiChar(Comment), length(Comment)); ImageEnView1.IO.SaveToFile('D:\image.jpg'); !!} property JPEG_MarkerList: TIEMarkerList read fJPEG_MarkerList; {!! TIOParams.JPEG_Scale_Used Declaration property JPEG_Scale_Used: Integer; Description Returns the denominator of the scale used to load the current Jpeg image (e.g. if it was loaded at 1/4 size, then 4 will be returned). It is used only when is ioJPEG_AUTOCALC. Default: 1 Example ImageEnView1.IO.Params.Width := 100; ImageEnView1.IO.Params.Height := 100; ImageEnView1.IO.Params.JPEG_Scale := ioJPEG_AUTOCALC; ImageEnView1.IO.LoadFromFile('C:\my.jpg'); Case ImageEnView1.IO.Params.JPEG_Scale_Used of 1: ShowMessage('Full-size'); 2: ShowMessage('Half-size'); 4: ShowMessage('Quarter-size'); 8: ShowMessage('Eighth-size'); end; !!} property JPEG_Scale_Used: integer read fJPEG_Scale_Used write fJPEG_Scale_Used; {!! TIOParams.JPEG_WarningTot Declaration property JPEG_WarningTot: Integer; Description Returns a count of all warnings encountered while loading the current Jpeg. Note: You should use the property to see if the image is corrupt. !!} property JPEG_WarningTot: integer read fJPEG_WarningTot write fJPEG_WarningTot; {!! TIOParams.JPEG_WarningCode Declaration property JPEG_WarningCode: Integer; Description Returns the last warning code encountered while loading the current Jpeg. Value Error Description 0 ARITH_NOTIMPL There are legal restrictions on arithmetic coding 1 BAD_ALIGN_TYPE ALIGN_TYPE is wrong 2 BAD_ALLOC_CHUNK MAX_ALLOC_CHUNK is wrong 3 BAD_BUFFER_MODE Bogus buffer control mode 4 BAD_COMPONENT_ID Invalid component ID in SOS 5 BAD_DCT_COEF DCT coefficient out of range 6 BAD_DCTSIZE IDCT output block size not supported 7 BAD_HUFF_TABLE Bogus Huffman table definition 8 BAD_IN_COLORSPACE Bogus input colorspace 9 BAD_J_COLORSPACE Bogus JPEG colorspace 10 BAD_LENGTH Bogus marker length 11 BAD_LIB_VERSION Wrong JPEG library version 12 BAD_MCU_SIZE Sampling factors too large for interleaved scan 13 BAD_POOL_ID Invalid memory pool code 14 BAD_PRECISION Unsupported JPEG data precision 15 BAD_PROGRESSION Invalid progressive parameters 16 BAD_PROG_SCRIPT Invalid progressive parameters 17 BAD_SAMPLING Bogus sampling factors 18 BAD_SCAN_SCRIPT Invalid scan script 19 BAD_STATE Improper call to JPEG library 20 BAD_STRUCT_SIZE JPEG parameter struct mismatch 21 BAD_VIRTUAL_ACCESS Bogus virtual array access 22 BUFFER_SIZE Buffer passed to JPEG library is too small 23 CANT_SUSPEND Suspension not allowed here 24 CCIR601_NOTIMPL CCIR601 sampling not implemented yet 25 COMPONENT_COUNT Too many color components 26 CONVERSION_NOTIMPL Unsupported color conversion request 27 DAC_INDEX Bogus DAC 28 DAC_VALUE Bogus DAC 29 DHT_INDEX Bogus DHT 30 DQT_INDEX Bogus DQT 31 EMPTY_IMAGE Empty JPEG image (DNL not supported) 32 EMS_READ Read from EMS failed 33 EMS_WRITE Write to EMS failed 34 EOI_EXPECTED Didn't expect more than one scan 35 FILE_READ Input file read error 36 FILE_WRITE Output file write error - out of disk space? 37 FRACT_SAMPLE_NOTIMPL Fractional sampling not implemented yet 38 HUFF_CLEN_OVERFLOW Huffman code size table overflow 39 HUFF_MISSING_CODE Missing Huffman code table entry 40 IMAGE_TOO_BIG Image too big 41 INPUT_EMPTY Empty input file 42 INPUT_EOF Premature end of input file 43 MISMATCHED_QUANT_TABLE Cannot transcode due to multiple use of quantization table 44 MISSING_DATA Scan script does not transmit all data 45 MODE_CHANGE Invalid color quantization mode change 46 NOTIMPL Not implemented yet 47 NOT_COMPILED Requested feature was omitted at compile time 48 NO_BACKING_STORE Backing store not supported 49 NO_HUFF_TABLE Huffman table was not defined 50 NO_IMAGE JPEG datastream contains no image 51 NO_QUANT_TABLE Quantization table was not defined 52 NO_SOI Not a Jpeg file 53 OUT_OF_MEMORY Insufficient memory 54 QUANT_COMPONENTS Cannot quantize 55 QUANT_FEW_COLORS Cannot quantize 56 QUANT_MANY_COLORS Cannot quantize 57 SOF_DUPLICATE Invalid Jpeg file structure: two SOF markers 58 SOF_NO_SOS Invalid Jpeg file structure: missing SOS marker 59 SOF_UNSUPPORTED Unsupported JPEG process 60 SOI_DUPLICATE Invalid Jpeg file structure: two SOI markers 61 SOS_NO_SOF Invalid Jpeg file structure: SOS before SOF 62 TFILE_CREATE Failed to create temporary file 63 TFILE_READ Read failed on temporary file 64 TFILE_SEEK Seek failed on temporary file 65 TFILE_WRITE Write failed on temporary file - out of disk space? 66 TOO_LITTLE_DATA Application transferred too few scanlines 67 UNKNOWN_MARKER Unsupported marker 68 VIRTUAL_BUG Virtual array controller messed up 69 WIDTH_OVERFLOW Image too wide for this implementation 70 XMS_READ Read from XMS failed 71 XMS_WRITE Write to XMS failed 72 COPYRIGHT 73 VERSION 74 16BIT_TABLES Caution: quantization tables are too coarse for baseline JPEG 75 ADOBE Adobe APP14 marker 76 APP0 Unknown APP0 marker 77 APP14 Unknown APP14 marker 78 DAC Define Arithmetic Table 79 DHT Define Huffman Table 80 DQT Define Quantization Table 81 DRI Define Restart Interval 82 EMS_CLOSE Freed EMS handle 83 EMS_OPEN Obtained EMS handle 84 EOI End Of Image 85 HUFFBITS 86 JFIF JFIF APP0 marker 87 JFIF_BADTHUMBNAILSIZE Warning: thumbnail image size does not match data length 88 JFIF_EXTENSION JFIF extension marker 89 JFIF_THUMBNAIL 90 MISC_MARKER Miscellaneous marker 91 PARMLESS_MARKER Unexpected marker 92 QUANTVALS 93 QUANT_3_NCOLORS 94 QUANT_NCOLORS 95 QUANT_SELECTED 96 RECOVERY_ACTION 97 RST 98 SMOOTH_NOTIMPL Smoothing not supported with nonstandard sampling ratios 99 SOF 100 SOF_COMPONENT 101 SOI Start of Image 102 SOS Start Of Scan 103 SOS_COMPONENT 104 SOS_PARAMS 105 TFILE_CLOSE Closed temporary file 106 TFILE_OPEN Opened temporary file 107 THUMB_JPEG JFIF extension marker 108 THUMB_PALETTE JFIF extension marker 109 THUMB_RGB JFIF extension marker 110 UNKNOWN_IDS Unrecognized component IDs, assuming YCbCr 111 XMS_CLOSE Freed XMS handle 112 XMS_OPEN Obtained XMS handle 113 ADOBE_XFORM Unknown Adobe color transform code 114 BOGUS_PROGRESSION Inconsistent progression sequence 115 EXTRANEOUS_DATA Corrupt JPEG data: extraneous bytes before marker 116 HIT_MARKER Corrupt JPEG data: premature end of data segment 117 HUFF_BAD_CODE Corrupt JPEG data: bad Huffman code 118 JFIF_MAJOR Warning: unknown JFIF revision number 119 JPEG_EOF Premature end of Jpeg file 120 MUST_RESYNC Corrupt JPEG data 121 NOT_SEQUENTIAL Invalid SOS parameters for sequential JPEG 122 TOO_MUCH_DATA Application transferred too many scanlines
!!} property JPEG_WarningCode: integer read fJPEG_WarningCode write fJPEG_WarningCode; {!! TIOParams.JPEG_OriginalWidth Declaration property JPEG_OriginalWidth: Integer; Description Returns the actual width of a Jpeg image before it was scaled (using
). Note: This is the same value as . See also: !!} property JPEG_OriginalWidth: integer read fOriginalWidth write fOriginalWidth; {!! TIOParams.JPEG_OriginalHeight Declaration property JPEG_OriginalHeight: Integer; Description Returns the actual height of a Jpeg image before it was scaled (using ). Note: This is the same value as . See also: !!} property JPEG_OriginalHeight: integer read fOriginalHeight write fOriginalHeight; {!! TIOParams.OriginalWidth Declaration property OriginalWidth: Integer; Description Returns the actual width of an image before it was scaled during loading. JPEG and Raw images can be loaded at a reduced size to speed up the loading. This property allows you to access the true size of the image. See also: !!} property OriginalWidth: integer read fOriginalWidth write fOriginalWidth; {!! TIOParams.OriginalHeight Declaration property OriginalHeight: Integer; Description Returns the actual height of an image before it was scaled during loading. JPEG and Raw images can be loaded at a reduced size to speed up the loading. This property allows you to access the true size of the image. See also: !!} property OriginalHeight: integer read fOriginalHeight write fOriginalHeight; {!! TIOParams.JPEG_EnableAdjustOrientation Declaration property JPEG_EnableAdjustOrientation: boolean; Description If enabled before loading a file which contains EXIF orientation information, the image will be automatically rotated for display (the actual file is not modified). Orientation information is often found in digital photos from high-end cameras. ImageEn uses the data found in to determine the correct orientation for JPEG images. Default: False See also: Example ImageEnView1.IO.Params.JPEG_EnableAdjustOrientation := True; ImageEnView1.IO.LoadFromFile('C:\input.jpg'); !!} property JPEG_EnableAdjustOrientation: boolean read fJPEG_EnableAdjustOrientation write fJPEG_EnableAdjustOrientation; {!! TIOParams.JPEG_GetExifThumbnail Declaration property JPEG_GetExifThumbnail: Boolean; Description Specifies that the thumbnail for an image will be loaded instead of the full image. A thumbnail is often available for JPEG images from digital cameras (EXIF Thumbnail). If enabled and the file does not contain a thumbnail the full image will be automatically loaded instead. Default: False See also: Example // Load only the thumbnail ImageEnView1.IO.Params.JPEG_GetExifThumbnail := True; ImageEnView1.IO.LoadFromFile('C:\input.jpg'); !!} property JPEG_GetExifThumbnail: Boolean read fJPEG_GetExifThumbnail write SetJPEG_GetExifThumbnail; // JPEG2000 {$IFDEF IEINCLUDEJPEG2000} {!! TIOParams.J2000_ColorSpace Declaration property J2000_ColorSpace: ; Description Specifies the currently loaded/saved color space. Default: ioJ2000_RGB !!} property J2000_ColorSpace: TIOJ2000ColorSpace read fJ2000_ColorSpace write fJ2000_ColorSpace; {!! TIOParams.J2000_Rate Declaration property J2000_Rate : Double; Description Specifies the compression rate to use when saving a JPEG2000 image. Allowed values are from 0 to 1, where 1 is no compression (lossless mode). Default: 0.07 Example // Save without quality loss ImageEnIO.Params.J2000_Rate := 1; ImageEnIO.SaveToFile('D:\output.jp2'); // Save with lossy compression ImageEnView1.IO.Params.J2000_Rate := 0.015 ImageEnView1.IO.SaveToFile('D:\output.jp2'); !!} property J2000_Rate: double read fJ2000_Rate write fJ2000_Rate; {!! TIOParams.J2000_ScalableBy Declaration property J2000_ScalableBy: ; Description Specifies the JPEG2000 progression order. Default: ioJ2000_Rate !!} property J2000_ScalableBy: TIOJ2000ScalableBy read fJ2000_ScalableBy write fJ2000_ScalableBy; {$ENDIF} // PCX {!! TIOParams.PCX_Version Declaration property PCX_Version: integer; Description Returns the PCX Version. Default: 5 !!} property PCX_Version: integer read fPCX_Version write fPCX_Version; {!! TIOParams.PCX_Compression Declaration property PCX_Compression: ; Description Specifies the compression type for a PCX image. Default: ioPCX_RLE !!} property PCX_Compression: TIOPCXCompression read fPCX_Compression write fPCX_Compression; // BMP {!! TIOParams.BMP_Version Declaration property BMP_Version: ; Description Returns the version of the BMP file. Default: ioBMP_BM3 Example // Save a Windows 3.x bitmap ImageEnView1.IO.Params.BMP_Version := ioBMP_BM3; ImageEnView1.IO.SaveToFile('D:\alfa.bmp'); !!} property BMP_Version: TIOBMPVersion read fBMP_Version write fBMP_Version; {!! TIOParams.BMP_Compression Declaration property BMP_Compression: ; Description Specifies the compression method when saving a BMP image. Default: ioBMP_UNCOMPRESSED Note: Only 16 or 256 color bitmap can be saved with RLE compression. Example // Save a compressed bitmap ImageEnView1.IO.Params.BMP_Compression := ioBMP_RLE; ImageEnView1.IO.SaveToFile('D:\alfa.bmp'); !!} property BMP_Compression: TIOBMPCompression read fBMP_Compression write fBMP_Compression; {!! TIOParams.BMP_HandleTransparency Declaration property BMP_HandleTransparency: Boolean; Description BMP files can have up to 32 bits per pixel. This property controls how to interpret the extra byte in the 32 bit word. When BMP_HandleTransparency is true the extra byte is interpreted as an alpha channel, otherwise it is just ignored. So if BMP_HandleTransparency = True the image will be displayed in ImageEn with transparency. Whereas if BMP_HandleTransparency = False the transparent color will not be used. Default: False Example // if BMP_HandleTransparency = true then display with transparency ImageENVect1.IO.Params.BMP_HandleTransparency := chkBMPHandleTransparency.Checked; ImageENVect1.IO.LoadFromFile( FilePath ); See Also - !!} property BMP_HandleTransparency: boolean read fBMP_HandleTransparency write fBMP_HandleTransparency; // ICO {!! TIOParams.ICO_ImageIndex Declaration property ICO_ImageIndex: Integer; Description The index (zero-based) of the current image of the current icon file. An icon file can contain multiple images of varying sizes and color depths. Use to return the number of images the file contains. Note: You can use for generic access to the ImageIndex (not specific to an image format). See Also - - Example // Load the second image inside 'alfa.ico' ImageEnView1.IO.Params.ICO_ImageIndex := 1; ImageEnView1.IO.LoadFromFile('C:\alfa.ico'); !!} property ICO_ImageIndex: integer read fICO_ImageIndex write SetImageIndex; {!! TIOParams.ICO_Background Declaration property ICO_background: ; Description Specifies the color that is used for transparency (i.e. becomes the image background) when loading icon files. Default: (255, 255, 255), i.e. white Note: This property must be set before loading. It is not used when saving because only the image's alpha channel is used for transparency. To make a color transparent you use before saving. Example // Reading ImageEnView1.IO.Params.ICO_Background := CreateRGB(255, 255, 255); ImageEnView1.IO.LoadFromFileICO('D:\myicon.ico'); // Writing example ImageEnView1.Proc.SetTransparentColors(transparent_color, transparent_color, 0); ImageEnView1.IO.SaveToFileICO('D:\myicon.ico'); See Also - - - !!} property ICO_Background: TRGB read fICO_Background write fICO_Background; // CUR {!! TIOParams.CUR_ImageIndex Declaration property CUR_ImageIndex: Integer; Description The index (zero-based) of the current image/cursor of the current cursor file (CUR files can contain multiple images). Use to return the number of images the file contains. Example // Load the second cursor inside 'alfa.cur' ImageEnView1.IO.Params.CUR_ImageIndex := 1; ImageEnView1.IO.LoadFromFile('C:\alfa.cur'); !!} property CUR_ImageIndex: integer read fCUR_ImageIndex write SetImageIndex; {!! TIOParams.CUR_XHotSpot Declaration property CUR_XHotSpot: Integer; Description Specifies the horizontal position of the "hot spot". The hot spot is the point of the cursor that activates a click. Default: 0 See also: !!} property CUR_XHotSpot: integer read fCUR_XHotSpot write fCUR_XHotSpot; {!! TIOParams.CUR_YHotSpot Declaration property CUR_YHotSpot: Integer; Description Specifies the vertical position of the "hot spot". The hot spot is the point of the cursor that activates a click Default: 0. See also: !!} property CUR_YHotSpot: integer read fCUR_YHotSpot write fCUR_YHotSpot; {!! TIOParams.CUR_Background Declaration property CUR_Background: ; Description Specifies the color that is used for transparency (i.e. becomes the image background) when loading cursor files. Default: (255, 255, 255), i.e. white Note: This property must be set before loading. Example ImageEnView1.IO.Params.CUR_Background := CreateRGB(255, 255, 255); ImageEnView1.IO.LoadFromFileCUR('C:\myicon.cur'); See Also - - - !!} property CUR_Background: TRGB read fCUR_Background write fCUR_Background; {$ifdef IEINCLUDEDICOM} // DICOM {!! TIOParams.DICOM_Tags Declaration property DICOM_Tags: ; Description Provides access to the object which contains all the informational tags within a DICOM file. You can view a list of tags at: Dicom Tag List Demo Demos\InputOutput\Dicom\Dicom.dpr Example ImageType := ImageEnView1.IO.Params.DICOM_Tags.GetTagString( tags.IndexOf($0008, $0008) ); PatientName := ImageEnView1.IO.Params.DICOM_Tags.GetTagString( tags.IndexOf($0010, $0010) ); !!} property DICOM_Tags: TIEDicomTags read fDICOM_Tags; {!! TIOParams.DICOM_WindowCenterOffset Declaration property DICOM_WindowCenterOffset: Double; Description Returns the calculated offset of the window center. !!} property DICOM_WindowCenterOffset: Double read fDICOM_WindowCenterOffset write fDICOM_WindowCenterOffset; property DICOM_RescaleIntercept: Double read fDICOM_RescaleIntercept write fDICOM_RescaleIntercept; property DICOM_RescaleSlope: Double read fDICOM_RescaleSlope write fDICOM_RescaleSlope; property DICOM_WindowCenter: Double read fDICOM_WindowCenter write fDICOM_WindowCenter; property DICOM_WindowWidth: Double read fDICOM_WindowWidth write fDICOM_WindowWidth; {!! TIOParams.DICOM_Range Declaration property DICOM_Range: ; Description Specifies how to handle the pixel visibility range. Default: iedrAdjust !!} property DICOM_Range: TIEDicomRange read fDICOM_Range write fDICOM_Range; {!! TIOParams.DICOM_Compression Declaration property DICOM_Compression: ; Description The compression used for a DICOM file. Default: iedcUncompressed !!} property DICOM_Compression: TIEDicomCompression read GetDICOM_Compression write SetDICOM_Compression; {!! TIOParams.DICOM_JPEGQuality Declaration property DICOM_JPEGQuality: integer; Description Specifies the quality factor (ranging from 1 to 100) to use when saving a DICOM file as a lossy JPEG. Higher values improve image quality but require more disk space. Default: 80 !!} property DICOM_JPEGQuality: integer read fDICOM_JPEGQuality write fDICOM_JPEGQuality; {!! TIOParams.DICOM_J2000Rate Declaration property DICOM_J2000Rate: double; Description Specifies the compression rate to use when saving a DICOM file as JPEG 2000. Allowed values are from 0 to 1, where 1 is no compression (lossless mode). Default: 0.07 !!} property DICOM_J2000Rate: double read fDICOM_J2000Rate write fDICOM_J2000Rate; {$endif} // PNG {!! TIOParams.PNG_Interlaced Declaration property PNG_Interlaced: Boolean; Description Returns true if the current PNG image is interlaced. !!} property PNG_Interlaced: boolean read fPNG_Interlaced write fPNG_Interlaced; {!! TIOParams.PNG_Background Declaration property PNG_Background: ; Description Specifies the background color of the image. Default: (0, 0, 0), i.e. Black See Also - - - !!} property PNG_Background: TRGB read fPNG_Background write fPNG_Background; {!! TIOParams.PNG_Filter Declaration property PNG_Filter: ; Description Specifies the filter to use when saving a PNG file. PNG filters can have a significant impact on the file size and encoding (i.e. saving) speed, though, generally the effect on the decoding/loading speed is minimal. Default: ioPNG_FILTER_NONE Example // Set best compression ImageEnView1.IO.Params.PNG_Filter := ioPNG_FILTER_PAETH; ImageEnView1.IO.Params.PNG_Compression := 9; // Save PNG ImageEnView1.IO.SaveToFilePNG('D:\max.png'); !!} property PNG_Filter: TIOPNGFilter read fPNG_Filter write fPNG_Filter; {!! TIOParams.PNG_Compression Declaration property PNG_Compression: Integer; Description Determines how much time the PNG compressor will spend trying to compress image data when saving a PNG. Allowed values are from 0 (no compression) to 9 (best compression). Default: 5 Example // Set best compression ImageEnView1.IO.Params.PNG_Filter := ioPNG_FILTER_PAETH; ImageEnView1.IO.Params.PNG_Compression := 9; // Save PNG ImageEnView1.IO.SaveToFilePNG('max.png'); !!} property PNG_Compression: integer read fPNG_Compression write fPNG_Compression; {!! TIOParams.PNG_TextKeys Declaration property PNG_TextKeys: TStringList; Description Contains the keys associated with the list of values ( property). Note: PNG_TextKeys and must contain the same number of entries. Only uncompressed text is supported. Examples // Add author and other text info to a PNG file ImageEnView1.IO.Params.PNG_TextKeys.Add('Author'); ImageEnView1.IO.Params.PNG_TextValues.Add('Letizia'); ImageEnView1.IO.Params.PNG_TextKeys.Add('Subject'); ImageEnView1.IO.Params.PNG_TextValues.Add('Colosseo'); ImageEnView1.IO.SaveToFile('D:\output.png'); // read all text info from a PNG for i := 0 to ImageEnView1.IO.Params.PNG_TextKeys.Count - 1 do begin key := ImageEnView1.IO.Params.PNG_TextKeys[i]; value := ImageEnView1.IO.Params.PNG_TextValues[I]; end; !!} property PNG_TextKeys: TStringList read fPNG_TextKeys; {!! TIOParams.PNG_TextValues Declaration property PNG_TextValues: TStringList; Description Contains the values associated with a list of keys ( property). Note: and PNG_TextValues must contain the same number of entries. Only uncompressed text is supported. Example Examples // Add author and other text info to a PNG file ImageEnView1.IO.Params.PNG_TextKeys.Add('Author'); ImageEnView1.IO.Params.PNG_TextValues.Add('Letizia'); ImageEnView1.IO.Params.PNG_TextKeys.Add('Subject'); ImageEnView1.IO.Params.PNG_TextValues.Add('Colosseo'); ImageEnView1.IO.SaveToFile('D:\output.png'); // read all text info from a PNG for i := 0 to ImageEnView1.IO.Params.PNG_TextKeys.Count - 1 do begin key := ImageEnView1.IO.Params.PNG_TextKeys[i]; value := ImageEnView1.IO.Params.PNG_TextValues[I]; end; !!} property PNG_TextValues: TStringList read fPNG_TextValues; //// PSD/PSB //// {!! TIOParams.PSD_LoadLayers Declaration property PSD_LoadLayers: Boolean; Description When enabled, ImageEn will load the separated layers of a PSD file. If False, only the merged image is loaded (flattened layers). Default: False About Adobe PhotoShop Layers PSD files are unique among the file types supported by ImageEnIO because the file stores layer information inside of the file including layer positions, layer names, layer dimensions and other unique information along with a merged image containing all the layers flattened onto a background. When opening PSD files with ImageEnIO the layers can be loaded automatically by setting ImageEnView1.IO.Params.PSD_LoadLayers to true (before loading). If PSD_LoadLayers is True then the merged image is ignored and only the layers are loaded. If PSD_LoadLayers is False then only the merged image is loaded. You can replace the layers automatically by setting ImageEnView1.IO.Params.PSD_ReplaceLayers to true before loading the file. If PSD_LoadLayers is True then the layers in the PSD file replace any layers already in ImageEnView. If PSD_ReplaceLayers is False then all layers in the PSD file will be added to the layers in ImageEnView. When PSD_ReplaceLayers is True, the content of the PSD file replaces the content of the ImageEnView. For example, assume a PSD file has three layers, and ImageEnView has two layers. This is the situation before loading the PSD file: ImageEnView, Layer 0: image X ImageEnView, Layer 1: image Y Now, you load the PSD file with PSD_ReplaceLayers = True: The result will be: ImageEnView, Layer 0 : PSD layer 0 ImageEnView, Layer 1 : PSD layer 1 ImageEnView, Layer 2 : PSD layer 2 If PSD_ReplaceLayers was False, the result will be: ImageEnView, Layer 0: image X ImageEnView, Layer 1: image Y ImageEnView, Layer 2 : PSD layer 0 ImageEnView, Layer 3 : PSD layer 1 ImageEnView, Layer 4 : PSD layer 2 ImageEn usually has a Layer 0 so when you load a PSD file, PSD_LoadLayers should be True and PSD_ReplaceLayers should be True: ImageEnView1.IO.Params.PSD_LoadLayers := True; ImageEnView1.IO.Params.PSD_ReplaceLayers := True; ImageEnView1.IO.LoadFromFilePSD(iFilename); ImageEnView1.Update; If both PSD_LoadLayers and PSD_ReplaceLayers is true then the layers displayed by ImageEnView after the file is loaded will be the same as the layers that are in the PSD file. Generally, both of these params should be set to true before opening a PSD file. If you do not set PSD_ReplaceLayers to True before loading the PSD file, ImageEnView will contain an empty layer 0 after the PSD file is opened. Example // loads a multilayer PSD and allow user to move and resize layers ImageEnView1.IO.Params.PSD_LoadLayers := True; ImageEnView1.IO.LoadFromFile('C:\input.psd'); ImageEnView1.MouseInteract := [miMoveLayers, miResizeLayers]; See Also - !!} property PSD_LoadLayers: Boolean read fPSD_LoadLayers write fPSD_LoadLayers; {!! TIOParams.PSD_ReplaceLayers Declaration property PSD_ReplaceLayers: Boolean; Description If enabled, the layers of the current image are replaced by the content of the PSD file, otherwise the PSD file content is appended to the existing layers. Default: False Note: See detail on PSD layer support at: See Also - !!} property PSD_ReplaceLayers: Boolean read fPSD_ReplaceLayers write fPSD_ReplaceLayers; {!! TIOParams.PSD_HasPremultipliedAlpha Declaration property PSD_HasPremultipliedAlpha: Boolean; Description Returns true if the alpha channel is premultiplied. !!} property PSD_HasPremultipliedAlpha: Boolean read fPSD_HasPremultipliedAlpha; {!! TIOParams.PSD_LargeDocumentFormat Declaration property PSD_LargeDocumentFormat: Boolean; Description Returns true if the loaded file is a PSB (Large document format) Photoshop file. Set PSD_LargeDocumentFormat = true before saving to use PSB format instead of PSD (enabled automatically when using '.psb' extension). Default: False !!} property PSD_LargeDocumentFormat: Boolean read fPSD_LargeDocumentFormat write fPSD_LargeDocumentFormat; {!! TIOParams.PSD_SelectLayer Declaration PSD_SelectLayer: AnsiString; Description Specifies name of the layer to load. Specifying an empty string will load all layers. You should set = true. Default: '' Example ImageEnView1.IO.Params.PSD_LoadLayers := true; ImageEnView1.IO.Params.PSD_SelectLayer := 'upperlayer'; ImageEnView1.IO.LoadFromFile('input.psd'); !!} property PSD_SelectLayer: AnsiString read fPSD_SelectLayer write fPSD_SelectLayer; //// HDP //// {!! TIOParams.HDP_ImageQuality Declaration property HDP_ImageQuality: Double; Description Specifies the quality to use when saving an HDP file. 0.0 produces the lowest possible quality, and 1.0 produces the highest quality, which for Microsoft HD Photo results in mathematically lossless compression. Default: 0.9 See also: !!} property HDP_ImageQuality: Double read fHDP_ImageQuality write fHDP_ImageQuality; {!! TIOParams.HDP_Lossless Declaration property HDP_Lossless: Boolean; Description Enabling this property will create an HDP file with mathematically lossless compression (overriding the property). Default: False !!} property HDP_Lossless: Boolean read fHDP_Lossless write fHDP_Lossless; //// TGA //// {!! TIOParams.TGA_XPos Declaration property TGA_XPos: Integer; Description Specifies the X coordinate where the top-left of the image will be shown (not used by ImageEn). !!} property TGA_XPos: integer read fTGA_XPos write fTGA_XPos; {!! TIOParams.TGA_YPos Declaration property TGA_YPos: Integer; Description Specifies the Y coordinate where the top-left of the image will be shown (not used by ImageEn). !!} property TGA_YPos: integer read fTGA_YPos write fTGA_YPos; {!! TIOParams.TGA_Compressed Declaration property TGA_Compressed: Boolean; Description Set to True to compress a TGA image (using RLE compression). Default: True !!} property TGA_Compressed: boolean read fTGA_Compressed write fTGA_Compressed; {!! TIOParams.TGA_Descriptor Declaration property TGA_Descriptor: AnsiString; Description Specifies the description of the current TGA file. !!} property TGA_Descriptor: AnsiString read fTGA_Descriptor write fTGA_Descriptor; {!! TIOParams.TGA_Author Declaration property TGA_Author: AnsiString; Description Specifies the author name of the current TGA file. !!} property TGA_Author: AnsiString read fTGA_Author write fTGA_Author; {!! TIOParams.TGA_Date Declaration property TGA_Date: TDateTime; Description Specifies the creation date and time of the current TGA file. !!} property TGA_Date: TDateTime read fTGA_Date write fTGA_Date; {!! TIOParams.TGA_ImageName Declaration property TGA_ImageName: AnsiString; Description Specifies the image name of the current TGA file. !!} property TGA_ImageName: AnsiString read fTGA_ImageName write fTGA_ImageName; {!! TIOParams.TGA_Background Declaration property TGA_Background: ; Description Specifies the background (or transparency) color of the current TGA image. Default: (0, 0, 0), i.e. Black See Also - - - !!} property TGA_Background: TRGB read fTGA_Background write fTGA_Background; {!! TIOParams.TGA_AspectRatio Declaration property TGA_AspectRatio: Double; Description Returns the pixel aspect ratio (pixel width/height) of the current TGA image. !!} property TGA_AspectRatio: double read fTGA_AspectRatio write fTGA_AspectRatio; {!! TIOParams.TGA_Gamma Declaration property TGA_Gamma: Double; Description Returns the gamma value of the current TGA image. Default: 2.2 !!} property TGA_Gamma: double read fTGA_Gamma write fTGA_Gamma; {!! TIOParams.TGA_GrayLevel Declaration property TGA_GrayLevel: Boolean; Description When set to True, the image will be saved in gray-scale (i.e. without color). Default: False !!} property TGA_GrayLevel: boolean read fTGA_GrayLevel write fTGA_GrayLevel; // AVI {!! TIOParams.AVI_FrameCount Declaration property AVI_FrameCount: Integer; Description Returns the number of frames contained in the current AVI file. See Also - - !!} property AVI_FrameCount: integer read fAVI_FrameCount write SetImageCount; {!! TIOParams.AVI_FrameDelayTime Declaration property AVI_FrameDelayTime: Double; Description Specifies the time (in milliseconds) that the current frame will be shown when animated/playing. !!} property AVI_FrameDelayTime: double read fAVI_FrameDelayTime write fAVI_FrameDelayTime; // MEDIAFILE {$ifdef IEINCLUDEDIRECTSHOW} {!! TIOParams.MEDIAFILE_FrameCount Declaration property MEDIAFILE_FrameCount: integer; Description Returns the number of frames of the current media file (using ). See Also - - !!} property MEDIAFILE_FrameCount: integer read fMEDIAFILE_FrameCount write SetImageCount; {!! TIOParams.MEDIAFILE_FrameDelayTime Declaration property MEDIAFILE_FrameDelayTime: double; Description Specifies the time (in milliseconds) that the current frame will be shown when animated/playing. !!} property MEDIAFILE_FrameDelayTime: double read fMEDIAFILE_FrameDelayTime write fMEDIAFILE_FrameDelayTime; {$endif} // PXM {!! TIOParams.PXM_Comments Declaration property PXM_Comments: TStringList; Description Contains a list of the comments in a PPM, PBM or PGM file. !!} property PXM_Comments: TStringList read fPXM_Comments; // PostScript (PS) {!! TIOParams.PS_PaperWidth Declaration property PS_PaperWidth: Integer Description Specifies the width of the page in "PostScript points" (1 point = 1/72 of inch). Default values are width: 595 and height: 842 (A4 format). Alternatively, you can use . Common values: Paper Size PS_PaperWidth PS_PaperHeight A0 2380 3368 A1 1684 2380 A2 1190 1684 A3 842 1190 A4 595 842 A5 421 595 A6 297 421 B5 501 709 US Letter (8.5 x 11") 612 792 US Legal (8.5 x 14") 612 1008 US Ledger (17 x 11") 1224 792 US Tabloid (11 x 17") 792 1224
Example // Save using "US Letter" paper size ImageEnView1.IO.Params.PS_PaperWidth := 612; ImageEnView1.IO.Params.PS_PaperHeight := 792; ImageEnView1.IO.SaveToFile('D:\output.ps'); !!} property PS_PaperWidth: integer read fPS_PaperWidth write fPS_PaperWidth; {!! TIOParams.PS_PaperHeight Declaration property PS_PaperHeight: Integer Description Specifies the height of the page in "PostScript points" (1 point = 1/72 of inch). Default values are width: 595 and height: 842 (A4 format). Alternatively, you can use
. Common values: Paper Size PS_PaperWidth PS_PaperHeight A0 2380 3368 A1 1684 2380 A2 1190 1684 A3 842 1190 A4 595 842 A5 421 595 A6 297 421 B5 501 709 US Letter (8.5 x 11") 612 792 US Legal (8.5 x 14") 612 1008 US Ledger (17 x 11") 1224 792 US Tabloid (11 x 17") 792 1224
Example // Save using "US Letter" paper size ImageEnView1.IO.Params.PS_PaperWidth := 612; ImageEnView1.IO.Params.PS_PaperHeight := 792; ImageEnView1.IO.SaveToFile('D:\output.ps'); !!} property PS_PaperHeight: integer read fPS_paperHeight write fPS_PaperHeight; property PS_PaperSize : TIOPDFPaperSize read GetPS_PaperSize write SetPS_PaperSize; {!! TIOParams.PS_Compression Declaration property PS_Compression:
; Description Specifies the compression filter for a PostScript file. Default: ioPS_G4FAX Example ImageEnView1.IO.LoadFromFile('D:\input.tif'); ImageEnView1.IO.Params.PS_Compression := ioPS_G4FAX; ImageEnView1.IO.SaveToFile('D:\output.ps'); !!} property PS_Compression: TIOPSCompression read fPS_Compression write fPS_Compression; {!! TIOParams.PS_Title Declaration property PS_Title: AnsiString; Description Specifies the title of the PostScript file. Default: 'No Title' !!} property PS_Title: AnsiString read fPS_Title write fPS_Title; // PDF {!! TIOParams.PDF_PaperWidth Declaration property PDF_PaperWidth: Integer Description Specifies the width of the page in Adobe PDF points (1 point = 1/72 of inch). Default values are width: 595 and height: 842 (A4 format). Alternatively, you can use . Note: If you set PDF_PaperWidth and to 0 the page will be output at the size of the image. Note: This may create huge pages! Common values: Paper Size PDF_PaperWidth PDF_PaperHeight A0 2380 3368 A1 1684 2380 A2 1190 1684 A3 842 1190 A4 595 842 A5 421 595 A6 297 421 B5 501 709 US Letter (8.5 x 11") 612 792 US Legal (8.5 x 14") 612 1008 US Ledger (17 x 11") 1224 792 US Tabloid (11 x 17") 792 1224
Example // Save using "US Letter" paper size ImageEnView1.IO.Params.PDF_PaperWidth := 612; ImageEnView1.IO.Params.PDF_PaperHeight := 792; ImageEnView1.IO.SaveToFile('D:\output.pdf'); !!} property PDF_PaperWidth: integer read fPDF_PaperWidth write fPDF_PaperWidth; {!! TIOParams.PDF_PaperHeight Declaration property PDF_PaperHeight: Integer Description Specifies the height of the page in Adobe PDF points (1 point = 1/72 of inch). Default values are width: 595 and height: 842 (A4 format). Alternatively, you can use
. Note: If you set and PDF_PaperHeight to 0 the page will be output at the size of the image. Note: This may create huge pages! Common values: Paper Size PDF_PaperWidth PDF_PaperHeight A0 2380 3368 A1 1684 2380 A2 1190 1684 A3 842 1190 A4 595 842 A5 421 595 A6 297 421 B5 501 709 US Letter (8.5 x 11") 612 792 US Legal (8.5 x 14") 612 1008 US Ledger (17 x 11") 1224 792 US Tabloid (11 x 17") 792 1224
Example // Save using "US Letter" paper size ImageEnView1.IO.Params.PDF_PaperWidth := 612; ImageEnView1.IO.Params.PDF_PaperHeight := 792; ImageEnView1.IO.SaveToFile('D:\output.pdf'); !!} property PDF_PaperHeight: integer read fPDF_paperHeight write fPDF_PaperHeight; property PDF_PaperSize : TIOPDFPaperSize read GetPDF_PaperSize write SetPDF_PaperSize; {!! TIOParams.PDF_Compression Declaration property PDF_Compression:
; Description Specifies the compression filter for an Adobe PDF file. Default: ioPDF_G4FAX Example ImageEnView1.IO.LoadFromFile('D:\input.tif'); ImageEnView1.IO.Params.PDF_Compression := ioPDF_G4FAX; ImageEnView1.IO.SaveToFile('D:\output.pdf'); !!} property PDF_Compression: TIOPDFCompression read fPDF_Compression write fPDF_Compression; {!! TIOParams.PDF_Title Declaration property PDF_Title: AnsiString; Description Specifies the title of a PDF document. !!} property PDF_Title: AnsiString read fPDF_Title write fPDF_Title; {!! TIOParams.PDF_Author Declaration property PDF_Author: AnsiString; Description Specifies the name of the person who created the document. !!} property PDF_Author: AnsiString read fPDF_Author write fPDF_Author; {!! TIOParams.PDF_Subject Declaration property PDF_Subject: AnsiString; Description Specifies the subject of the PDF document. !!} property PDF_Subject: AnsiString read fPDF_Subject write fPDF_Subject; {!! TIOParams.PDF_Keywords Declaration property PDF_Keywords: AnsiString; Description Specifies the keywords associated with a PDF document. !!} property PDF_Keywords: AnsiString read fPDF_Keywords write fPDF_Keywords; {!! TIOParams.PDF_Creator Declaration property PDF_Creator: AnsiString; Description Specifies the application that created the original document. !!} property PDF_Creator: AnsiString read fPDF_Creator write fPDF_Creator; {!! TIOParams.PDF_Producer Declaration property PDF_Producer: AnsiString; Description Specifies the application that converted the image to PDF. !!} property PDF_Producer: AnsiString read fPDF_Producer write fPDF_Producer; //// EXIF //// property EXIF_Tags: TList read fEXIF_Tags; {!! TIOParams.EXIF_HasEXIFData Declaration property EXIF_HasEXIFData: Boolean; Description If True, the loaded image contains EXIF information tags. EXIF data is commonly added by digital cameras to provide meta data on a photo. Note: If you do not wish to maintain the original EXIF info, set EXIF_HasEXIFData to False before saving. Important Note: If an image is assigned from a to another, the EXIF tags is NOT automatically assigned. To maintain EXIF data in the second or , you must also assign the EXIF Data. This applies to all ImageEn "Display" components including TImageEnView and TImageEnVect. Typical situations: 1) You want to maintain the EXIF data untouched: Do nothing... (default behavior) 2) You want to set some EXIF fields, e.g. Params.EXIF_Software := 'ImageEn'; Params.EXIF_HasEXIFData := true; 3) You want to remove all EXIF data: Params.ResetInfo; Demo Demos\InputOutput\EXIF\EXIF.dpr Example // In this example, a form named DlgEXIF has a TImageEnView (ImageEnView1) and another form has a TImageEnView (ImageEnView). Both the image and its EXIF data are passed from one to another via assign. // Assign the image to DlgEXIF DlgEXIF.ImageEnView1.Assign ( ImageEnView ); // Assign EXIF data to DlgEXIF.ImageEnView1 DlgEXIF.ImageEnView1.IO.Params.Assign ( ImageEnView.IO.Params ); !!} property EXIF_HasEXIFData: boolean read fEXIF_HasEXIFData write fEXIF_HasEXIFData; {!! TIOParams.EXIF_Bitmap Declaration property EXIF_Bitmap: ; Description Contains a thumbnail of the image, if available. If you modify the image, you can use to update the thumbnail. Note: EXIF_Bitmap is supported by JPEG, TIFF, RAW and PSP files, though files of these types will not always include thumbnails. !!} property EXIF_Bitmap: TIEBitmap read fEXIF_Bitmap write fEXIF_Bitmap; {!! TIOParams.EXIF_ImageDescription Declaration property EXIF_ImageDescription: AnsiString; Description Returns a description of the image. !!} property EXIF_ImageDescription: AnsiString read fEXIF_ImageDescription write fEXIF_ImageDescription; {!! TIOParams.EXIF_Make Declaration property EXIF_Make: AnsiString; Description The manufacturer of the recording equipment (camera, scanner, video digitizer, etc.) that generated the image. !!} property EXIF_Make: AnsiString read fEXIF_Make write fEXIF_Make; {!! TIOParams.EXIF_Model Declaration property EXIF_Model: AnsiString; Description Returns the model number of the camera !!} property EXIF_Model: AnsiString read fEXIF_Model write fEXIF_Model; {!! TIOParams.EXIF_Orientation Declaration property EXIF_Orientation: Integer; Description The orientation of the camera relative to the scene, when the image was captured Value Description _exoCorrectOrientation (1) Image is Orientated Correctly (top left side) _exoNeedsHorizontalFlip (2) Image is Horizontally Flipped (top right side) _exoNeeds180Rotate (3) Image is Offset by 180º (bottom right side) _exoNeedsVerticalFlip (4) Image is Vertically Flipped (bottom left side) _exoNeedsHorzAndVertFlip (5) Image is Flipped Horiz. and Offset 90º CCW (left side top) _exoNeeds90RotateCW (6) Image is Offset by 90º CCW (right side top) _exoNeedsFlipHorzAnd90Rotate (7) Image is Flipped Horiz. and offset 90º CW (right side bottom) _exoNeeds270RotateCW (8) Image is Offset by 90º clockwise (left side bottom)
See also:
!!} property EXIF_Orientation: integer read fEXIF_Orientation write SetEXIF_Orientation; {!! TIOParams.EXIF_XResolution Declaration property EXIF_XResolution: Double; Description Returns the horizontal resolution of the image. The default value is 1/72 inch (one "point"), but it is largely meaningless as personal computers typicaly don't use this value for display/printing. A string version of EXIF_XResolution (in human-readable format) is available in the iexMetaHelpers.pas EXIF helper unit. See Also - - - Example // Get as string value sExifXResolution := DoubleToFraction( ImageEnView1.IO.Params.EXIF_XResolution ); // Write string value // Note: Assumes a value formatted as a fraction, e.g. '1/72' ImageEnView1.IO.Params.EXIF_XResolution := FractionToDouble( sExifXResolution ); // Note: DoubleToFraction() and FractionToDouble() are in the iexMetaHelpers unit !!} property EXIF_XResolution: double read fEXIF_XResolution write SetEXIF_XResolution; {!! TIOParams.EXIF_YResolution Declaration property EXIF_YResolution: Double; Description Returns the vertical resolution of the image. The default value is 1/72 inch (one "point"), but it is largely meaningless as personal computers typicaly don't use this value for display/printing. A string version of EXIF_YResolution (in human-readable format) is available in the iexMetaHelpers.pas EXIF helper unit. See Also - - - Example // Get as string value sExifYResolution := DoubleToFraction( ImageEnView1.IO.Params.EXIF_YResolution ); // Write string value // Note: Assumes a value formatted as a fraction, e.g. '1/72' ImageEnView1.IO.Params.EXIF_YResolution := FractionToDouble( sExifYResolution ); // Note: DoubleToFraction() and FractionToDouble() are in the iexMetaHelpers unit !!} property EXIF_YResolution: double read fEXIF_YResolution write SetEXIF_YResolution; {!! TIOParams.EXIF_ResolutionUnit Declaration property EXIF_ResolutionUnit: Integer; Description Returns the units of and : 1: No unit 2: Inches 3: Centimeters Default: 2 (inches) !!} property EXIF_ResolutionUnit: integer read fEXIF_ResolutionUnit write fEXIF_ResolutionUnit; {!! TIOParams.EXIF_Software Declaration property EXIF_Software: AnsiString; Description Returns the version number of the camera firmware (the internal software of the hardware) !!} property EXIF_Software: AnsiString read fEXIF_Software write fEXIF_Software; {!! TIOParams.EXIF_Artist Declaration property EXIF_Artist: AnsiString; Description Specifies the EXIF artist. !!} property EXIF_Artist: AnsiString read fEXIF_Artist write fEXIF_Artist; {!! TIOParams.EXIF_DateTime Declaration property EXIF_DateTime: AnsiString; Description The date and time that the image was last modified. Data format is "YYYY:MM:DD HH:MM:SS"+0x00, total 20 bytes. If the clock has not been set or the camera doesn't have clock, the field may be filled with spaces. Usually this returns the same value as . See Also - - !!} property EXIF_DateTime: AnsiString read fEXIF_DateTime write fEXIF_DateTime; {!! TIOParams.EXIF_DateTime2 Declaration property EXIF_DateTime2 : TDateTime; Description The date and time that the image was last modified. It is a TDateTime variant of . If the clock has not been set or the camera doesn't have clock, a zero result will be returned. Usually this returns the same value as . See Also - - !!} property EXIF_DateTime2: TDateTime read GetEXIF_DateTime2 write SetEXIF_DateTime2; {!! TIOParams.EXIF_WhitePoint Declaration property EXIF_WhitePoint[index: Integer]: Double; Description Defines the chromaticity of white points of the image. index is in the range 0 to 1. If the image uses CIE Standard Illumination D65 (known as international standard of "daylight"), the values are '3127/10000, 3290/10000'. "-1" for both values means "unspecified". !!} property EXIF_WhitePoint[index: integer]: double read GetEXIF_WhitePoint write SetEXIF_WhitePoint; {!! TIOParams.EXIF_PrimaryChromaticities Declaration property EXIF_PrimaryChromaticities[index: Integer]: Double; Description Defines the chromaticity of the primaries of the image. index is in the range 0 to 5. If the image uses CCIR Recommendation 709 primaries, the values are '640/1000,330/1000,300/1000,600/1000,150/1000,0/1000'. "-1" for all values means "unspecified". !!} property EXIF_PrimaryChromaticities[index: integer]: double read GetEXIF_PrimaryChromaticities write SetEXIF_PrimaryChromaticities; {!! TIOParams.EXIF_YCbCrCoefficients Declaration property EXIF_YCbCrCoefficients[index: Integer]: Double; Description When the image format is YCbCr, this value shows a constant to translate it to RGB format. index is in the range 0 to 2. Usually the values are '0.299/0.587/0.114'. "-1" for all values means "unspecified". !!} property EXIF_YCbCrCoefficients[index: integer]: double read GetEXIF_YCbCrCoefficients write SetEXIF_YCbCrCoefficients; {!! TIOParams.EXIF_YCbCrPositioning Declaration property EXIF_YCbCrPositioning: Integer; Description When the image format is YCbCr and uses "Sub-sampling" (cropping of chroma data which is performed by all cameras), this property defines the chroma sample point of the sub-sampling pixel array. 0: Unspecified 1: The center of pixel array. 2: The datum point. !!} property EXIF_YCbCrPositioning: integer read fEXIF_YCbCrPositioning write fEXIF_YCbCrPositioning; {!! TIOParams.EXIF_ReferenceBlackWhite Declaration property EXIF_ReferenceBlackWhite[index: Integer]: Double; Description Returns the reference value of the black point/white point. index is in the range 0 to 5. YCbCr format: The first two values show the black/white of Y, the next two are Cb, and the last two are Cr RGB format: The first two values show the black/white of R, the next two are G, and the last two are B. "-1" for all values means "unspecified". !!} property EXIF_ReferenceBlackWhite[index: integer]: double read GetEXIF_ReferenceBlackWhite write SetEXIF_ReferenceBlackWhite; {!! TIOParams.EXIF_Copyright Declaration property EXIF_Copyright: AnsiString; Description Returns the copyright information. !!} property EXIF_Copyright: AnsiString read fEXIF_Copyright write fEXIF_Copyright; {!! TIOParams.EXIF_ExposureTime Declaration property EXIF_ExposureTime: Double; Description The exposure time of the photo (reciprocal of the shutter speed). Unit is second. A string version of EXIF_ExposureTime (in human-readable format) is available in the iexMetaHelpers.pas EXIF helper unit. Example if ImageEnView1.IO.Params.EXIF_ExposureTime > 1 then // It will be something like 4 i.e. 4 seconds sExifExposureTime := IntToStr( Round( ImageEnView1.IO.Params.EXIF_ExposureTime )) else if ImageEnView1.IO.Params.EXIF_ExposureTime > 0 then // It is something like 0.25, which translates to 1/4 second sExifExposureTime := DoubleToFraction( Round(1 / ImageEnView1.IO.Params.EXIF_ExposureTime )) else sExifExposureTime := ''; // Write the value back to image parameters if pos( '1/', sExifExposureTime ) > 0 then ImageEnView1.IO.Params.EXIF_ExposureTime := 1 / FractionToDouble( sExifExposureTime ) else ImageEnView1.IO.Params.EXIF_ExposureTime := StrToInt( sExifExposureTime ); // Note: DoubleToFraction() and FractionToDouble() are in the iexMetaHelpers unit !!} property EXIF_ExposureTime: double read fEXIF_ExposureTime write SetEXIF_ExposureTime; {!! TIOParams.EXIF_FNumber Declaration property EXIF_FNumber: Double; Description The actual F-number (F-stop) of the lens when the photo was taken. A string version of EXIF_FNumber (in human-readable format) is available in the iexMetaHelpers.pas EXIF helper unit. Example if ( ImageEnView1.IO.Params.EXIF_Fnumber <> 0 ) and ( ImageEnView1.IO.Params.EXIF_Fnumber <> -1 ) then sExifFNumber := 'F' + FloatToStr( ImageEnView1.IO.Params.EXIF_FNumber ) else sExifFNumber := ''; // And write back... if ( sExifFNumber <> '' ) and ( uppercase( sExifFNumber )[ 1 ] = 'F' ) then delete( sExifFNumber , 1, 1 ); ImageEnView1.IO.Params.EXIF_FNumber := StrToFloatDef( sExifFNumber, 0 ); !!} property EXIF_FNumber: double read fEXIF_FNumber write SetEXIF_FNumber; {!! TIOParams.EXIF_ExposureProgram Declaration property EXIF_ExposureProgram: Integer; Description The exposure program used by the camera for the photo: 1: Manual control 2: Program normal 3: Aperture priority 4: Shutter priority 5: Program creative (slow program) 6: Program action (high-speed program) 7: Portrait mode 8: Landscape mode !!} property EXIF_ExposureProgram: integer read fEXIF_ExposureProgram write SetEXIF_ExposureProgram; {!! TIOParams.EXIF_ISOSpeedRatings Declaration property EXIF_ISOSpeedRatings[index: Integer]: Integer; Description CCD sensitivity equivalent to Ag-Hr film speedrate. index is in the range 0 to 1. "0" for all values means "unspecified". !!} property EXIF_ISOSpeedRatings[index: integer]: integer read GetEXIF_ISOSpeedRatings write SetEXIF_ISOSpeedRatings; {!! TIOParams.EXIF_ExifVersion Declaration property EXIF_ExifVersion: AnsiString; Description Returns the EXIF version number. It is stored as 4 bytes of ASCII characters, e.g. if the data is based on Exif V2.1, then the value is "0210". Since the type is "undefined", there is no NULL (0x00) for termination. !!} property EXIF_ExifVersion: AnsiString read fEXIF_ExifVersion write fEXIF_ExifVersion; {!! TIOParams.EXIF_DateTimeOriginal Declaration property EXIF_DateTimeOriginal: AnsiString; Description The date and time that the original image was taken. This value should not be modified by your software. The data format is "YYYY:MM:DD HH:MM:SS"+0x00, total 20 bytes. If the clock has not been set or the camera doesn't have a clock, the field may be filled with spaces. In the Exif standard this tag is optional, but it is mandatory for DCF. See Also - - !!} property EXIF_DateTimeOriginal: AnsiString read fEXIF_DateTimeOriginal write fEXIF_DateTimeOriginal; {!! TIOParams.EXIF_DateTimeOriginal2 Declaration property EXIF_DateTimeOriginal2: TDateTime; Description The date and time that the original image was taken. This property is a TDateTime variant of . This value should not be modified by your software. If the clock has not been set or the camera doesn't have a clock, the property may return zero. In the Exif standard this tag is optional, but it is mandatory for DCF. See Also - - !!} property EXIF_DateTimeOriginal2: TDateTime read GetEXIF_DateTimeOriginal2 write SetEXIF_DateTimeOriginal2; {!! TIOParams.EXIF_DateTimeDigitized Declaration property EXIF_DateTimeDigitized: AnsiString; Description The date and time that the image was digitized. Usually, it will return the same value as . The data format is "YYYY:MM:DD HH:MM:SS"+0x00, total 20 bytes. If the clock has not been set or the camera doesn't have a clock, the field may be filled with spaces. In the Exif standard this tag is optional, but it is mandatory for DCF. See Also - - !!} property EXIF_DateTimeDigitized: AnsiString read fEXIF_DateTimeDigitized write fEXIF_DateTimeDigitized; {!! TIOParams.EXIF_DateTimeDigitized2 Declaration property EXIF_DateTimeDigitized2: TDateTime; Description The date and time that the image was digitized. This property is a TDateTime variant of . Usually, it will return the same value as . If the clock has not been set or the camera doesn't have a clock, the property may return zero. In the Exif standard this tag is optional, but it is mandatory for DCF. See Also - - !!} property EXIF_DateTimeDigitized2: TDateTime read GetEXIF_DateTimeDigitized2 write SetEXIF_DateTimeDigitized2; {!! TIOParams.EXIF_CompressedBitsPerPixel Declaration property EXIF_CompressedBitsPerPixel: Double; Description The average JPEG compression ratio (rough estimate) !!} property EXIF_CompressedBitsPerPixel: double read fEXIF_CompressedBitsPerPixel write SetEXIF_CompressedBitsPerPixel; {!! TIOParams.EXIF_ShutterSpeedValue Declaration property EXIF_ShutterSpeedValue: Double; Description The shutter speed as an APEX value. To convert this value to a human-readable "Shutter Speed" calculate this value's power of 2, then make it a reciprocal. For example, if EXIF_ShutterSpeedValue is 4, then the shutter speed is 1/16 second. A string version of EXIF_ShutterSpeedValue (in human-readable format) is available in the iexMetaHelpers.pas EXIF helper unit. Example sShutterSpeed := ApexToStr( 2, ImageEnView1.IO.Params.EXIF_ShutterSpeedValue, '1/' ); // Write value ImageEnView1.IO.Params.EXIF_ShutterSpeedValue := StrToApex( 2, sShutterSpeed, '1/' ); // Note: ApexToStr() and StrToApex() are the iexMetaHelpers unit !!} property EXIF_ShutterSpeedValue: double read fEXIF_ShutterSpeedValue write SetEXIF_ShutterSpeedValue; {!! TIOParams.EXIF_ApertureValue Declaration property EXIF_ApertureValue: Double; Description The aperture of the lens when the photo was taken. The unit is APEX. To convert EXIF_ApertureValue to a human-readable F-number (F-stop) calculate this value's power of root 2 (=1.4142). For example, if EXIF_ApertureValue is 5, then the F-number is 1.41425 = F5.6. A string version of EXIF_ApertureValue (in human-readable format) is available in the iexMetaHelpers.pas EXIF helper unit. Example sApertureValue := ApexToStr( Sqrt( 2 ), ImageEnView1.IO.Params.EXIF_ApertureValue, 'F' ); if sApertureValue = 'F0' then sApertureValue := ''; // Write value ImageEnView1.IO.Params.EXIF_ApertureValue := StrToApex( Sqrt( 2 ), sApertureValue, 'F' ); // Note: ApexToStr() and StrToApex() are the iexMetaHelpers unit !!} property EXIF_ApertureValue: double read fEXIF_ApertureValue write SetEXIF_ApertureValue; {!! TIOParams.EXIF_BrightnessValue Declaration property EXIF_BrightnessValue: Double; Description The brightness of the photo subject. Unit is APEX. To calculate Exposure (Ev) from BrigtnessValue (Bv), you must add SensitivityValue(Sv). Ev = Bv + Sv Sv = log2(ISOSpeedRating / 3.125) ISO100: Sv = 5, ISO200: Sv = 6, ISO400: Sv = 7, ISO125: Sv = 5.32. !!} property EXIF_BrightnessValue: double read fEXIF_BrightnessValue write SetEXIF_BrightnessValue; {!! TIOParams.EXIF_ExposureBiasValue Declaration property EXIF_ExposureBiasValue: Double; Description The exposure bias (compensation) value of the photo. Unit is APEX (EV). !!} property EXIF_ExposureBiasValue: double read fEXIF_ExposureBiasValue write SetEXIF_ExposureBiasValue; {!! TIOParams.EXIF_MaxApertureValue Declaration property EXIF_MaxApertureValue: Double; Description Returns the maximum aperture value of the lens. Convert to an F-number by calculating the power of root 2 (see the process described for ). A string version of EXIF_MaxApertureValue (in human-readable format) is available in the iexMetaHelpers.pas EXIF helper unit. Example sMaxApertureValue := ApexToStr( Sqrt( 2 ), ImageEnView1.IO.Params.EXIF_MaxApertureValue, 'F' ); if sMaxApertureValue = 'F0' then sMaxApertureValue := ''; // Write value ImageEnView1.IO.Params.EXIF_MaxApertureValue := StrToApex( Sqrt( 2 ), sMaxApertureValue, 'F' ); // Note: ApexToStr() and StrToApex() are the iexMetaHelpers unit !!} property EXIF_MaxApertureValue: double read fEXIF_MaxApertureValue write SetEXIF_MaxApertureValue; {!! TIOParams.EXIF_SubjectDistance Declaration property EXIF_SubjectDistance: Double; Description Distance to the focus point (in meters). !!} property EXIF_SubjectDistance: double read fEXIF_SubjectDistance write SetEXIF_SubjectDistance; {!! TIOParams.EXIF_MeteringMode Declaration property EXIF_MeteringMode: Integer; Description Exposure metering method: 0: Unknown 1: Average 2: Center weighted average 3: Spot 4: Multi-spot 5: Multi-segment 6: Partial 255: Other !!} property EXIF_MeteringMode: integer read fEXIF_MeteringMode write SetEXIF_MeteringMode; {!! TIOParams.EXIF_LightSource Declaration property EXIF_LightSource: Integer; Description The Light source of the photo, though generally this refers to the white balance setting: 0: Unknown 1: Daylight 2: Fluorescent 3: Tungsten 10: Flash 17: Standard light A 18: Standard light B 19: Standard light C 20: D55 21: D65 22: D75 255: Other !!} property EXIF_LightSource: integer read fEXIF_LightSource write SetEXIF_LightSource; {!! TIOParams.EXIF_Flash Declaration property EXIF_Flash: Integer; Description The status of the flash when the photo was taken: 0: Flash did not fire 1: Flash fired 5: Flash fired but strobe return light not detected 7: Flash fired and strobe return light detected !!} property EXIF_Flash: integer read fEXIF_Flash write SetEXIF_Flash; {!! TIOParams.EXIF_FocalLength Declaration property EXIF_FocalLength: Double; Description Returns the focal length of lens used to take image (in millimeters). !!} property EXIF_FocalLength: double read fEXIF_FocalLength write SetEXIF_FocalLength; {!! TIOParams.EXIF_SubsecTime Declaration property EXIF_SubsecTime: AnsiString; Description Some digital cameras can take 2 - 30 pictures per second, but the // tags cannot record a sub-second time, so EXIF_SubsecTime is used to record the detail. For example, if the DateTime = "1996:09:01 09:15:30" and the SubSecTime = "130", then the precise date and time is "1996:09:01 09:15:30.130" !!} property EXIF_SubsecTime: AnsiString read fEXIF_SubsecTime write fEXIF_SubsecTime; {!! TIOParams.EXIF_SubsecTimeOriginal Declaration property EXIF_SubsecTimeOriginal: AnsiString; Description Some digital cameras can take 2 - 30 pictures per second, but the // tags cannot record a sub-second time, so EXIF_SubsecTime is used to record the detail. For example, if the DateTimeOriginal = "1996:09:01 09:15:30" and the SubSecTimeOriginal = "130", then the precise original time is "1996:09:01 09:15:30.130" !!} property EXIF_SubsecTimeOriginal: AnsiString read fEXIF_SubsecTimeOriginal write fEXIF_SubsecTimeOriginal; {!! TIOParams.EXIF_SubsecTimeDigitized Declaration property EXIF_SubsecTimeDigitized: AnsiString; Description Some digital cameras can take 2 - 30 pictures per second, but the // tags cannot record a sub-second time, so EXIF_SubsecTime is used to record the detail. For example, if the DateTimeDigitized = "1996:09:01 09:15:30" and the SubSecTimeDigitized = "130", then the precise digitized time is "1996:09:01 09:15:30.130" !!} property EXIF_SubsecTimeDigitized: AnsiString read fEXIF_SubsecTimeDigitized write fEXIF_SubsecTimeDigitized; {!! TIOParams.EXIF_FlashPixVersion Declaration property EXIF_FlashPixVersion: AnsiString; Description Returns the FlashPix version as 4 character string, e.g. if the image data is based on FlashPix format Ver. 1.0, then the value is "0100". !!} property EXIF_FlashPixVersion: AnsiString read fEXIF_FlashPixVersion write fEXIF_FlashPixVersion; {!! TIOParams.EXIF_ColorSpace Declaration property EXIF_ColorSpace: Integer; Description Defines the Color Space. DCF image must use the sRGB color space so the value is always "1". If the photo uses another color space, the value is "65535": Uncalibrated. !!} property EXIF_ColorSpace: integer read fEXIF_ColorSpace write SetEXIF_ColorSpace; {!! TIOParams.EXIF_ExifImageWidth Declaration property EXIF_ExifImageWidth: Integer; Description Returns the horizontal size of the image (in pixels) !!} property EXIF_ExifImageWidth: integer read fEXIF_ExifImageWidth write SetEXIF_ExifImageWidth; {!! TIOParams.EXIF_ExifImageHeight Declaration property EXIF_ExifImageHeight: Integer; Description Returns the vertical size of the image (in pixels) !!} property EXIF_ExifImageHeight: integer read fEXIF_ExifImageHeight write SetEXIF_ExifImageHeight; {!! TIOParams.EXIF_RelatedSoundFile Declaration property EXIF_RelatedSoundFile: AnsiString; Description Returns an audio filename if the source camera recorded audio with the image. !!} property EXIF_RelatedSoundFile: AnsiString read fEXIF_RelatedSoundFile write fEXIF_RelatedSoundFile; {!! TIOParams.EXIF_FocalPlaneXResolution Declaration property EXIF_FocalPlaneXResolution: Double; Description Returns the pixel density at CCD's position. With megapixel cameras, when a photo is taken at a lower resolution (e.g. VGA mode), this value is re-sampled by the photo resolution. In such a case, FocalPlaneResolution is not the same as CCD's actual resolution. See Also - - !!} property EXIF_FocalPlaneXResolution: double read fEXIF_FocalPlaneXResolution write SetEXIF_FocalPlaneXResolution; {!! TIOParams.EXIF_FocalPlaneYResolution Declaration property EXIF_FocalPlaneYResolution: Double; Description Returns the pixel density at CCD's position. With megapixel cameras, when a photo is taken at a lower resolution (e.g. VGA mode), this value is re-sampled by the photo resolution. In such a case, FocalPlaneResolution is not the same as CCD's actual resolution. See Also - - !!} property EXIF_FocalPlaneYResolution: double read fEXIF_FocalPlaneYResolution write SetEXIF_FocalPlaneYResolution; {!! TIOParams.EXIF_FocalPlaneResolutionUnit Declaration property EXIF_FocalPlaneResolutionUnit: Integer; Description The unit of FocalPlaneXResoluton/FocalPlaneYResolution: 1: No unit 2: Inches 3: Centimeters Note: Some Fujifilm cameras (e.g. FX2700, FX2900, Finepix 4700Z/40i, etc.) return a value of centimeters (3), but the actual resoluion appears to be 8.3mm? (1/3 inch?). This seems to be a bug with Fujifilm cameras. With the Finepix4900Z the value has been changed to inches (2) but it doesn't appear to match an actual value either. See Also - - !!} property EXIF_FocalPlaneResolutionUnit: integer read fEXIF_FocalPlaneResolutionUnit write SetEXIF_FocalPlaneResolutionUnit; {!! TIOParams.EXIF_ExposureIndex Declaration property EXIF_ExposureIndex: Double; Description This is the same as (0x8827) but the data type is an unsigned rational. Only Kodak cameras use this tag in preference to . !!} property EXIF_ExposureIndex: double read fEXIF_ExposureIndex write SetEXIF_ExposureIndex; {!! TIOParams.EXIF_SensingMethod Declaration property EXIF_SensingMethod: Integer; Description Returns the type of image sensor unit. "2" means a one-chip color area sensor. Most digital cameras use this type. !!} property EXIF_SensingMethod: integer read fEXIF_SensingMethod write SetEXIF_SensingMethod; {!! TIOParams.EXIF_FileSource Declaration property EXIF_FileSource: Integer; Description Returns the image source, e.g. a value of "0x03" means the image source is a digital still camera. !!} property EXIF_FileSource: integer read fEXIF_FileSource write SetEXIF_FileSource; {!! TIOParams.EXIF_SceneType Declaration property EXIF_SceneType: Integer; Description Returns the type of scene, e.g. a value of "0x01" means that the image was directly photographed. !!} property EXIF_SceneType: integer read fEXIF_SceneType write SetEXIF_SceneType; {!! TIOParams.EXIF_UserComment Declaration property EXIF_UserComment: WideString Description Provides an alternative tag for storing textual data (keywords, comments, etc) with the image instead of (which has character code limitations). Note: You must specify how the string is coded (ASCII or Unicode) using the property. Example // Write our comment to the file ImageEnView1.IO.LoadFromFile('C:\input.jpg'); ImageEnView1.IO.Params.EXIF_UserComment := 'Hello World!'; ImageEnView1.IO.Params.EXIF_UserCommentCode := IEEXIFUSERCOMMENTCODE_UNICODE; ImageEnView1.IO.Params.EXIF_HasEXIFData := true; ImageEnView1.IO.SaveToFileTIFF('D:\test.tiff'); // Read back the comment ImageEnView1.IO.LoadFromFileTIFF('D:\test.tiff'); ShowMessage( ImageEnView1.IO.Params.EXIF_UserComment ); !!} property EXIF_UserComment: WideString read fEXIF_UserComment write fEXIF_UserComment; {!! TIOParams.EXIF_UserCommentCode Declaration property EXIF_UserCommentCode: AnsiString; Description Specifies the character code (8 bytes) for the property. Allowed values: Description ImageEn Const Character Code Desgination (8 bytes) References IEExifUserCommentCode_Unicode Unicode #$55#$4E#$49#$43#$4F#$44#$45#$00 Unicode Standard IEExifUserCommentCode_ASCII ASCII #$41#$53#$43#$49#$49#$00#$00#$00 ITU-T T.50 IA5 IEExifUserCommentCode_JIS JIS #$4A#$49#$53#$00#$00#$00#$00#$00 JIS X0208-1990 IEExifUserCommentCode_Undefined Undefined #$00#$00#$00#$00#$00#$00#$00#$00 Undefined
Note: All consts are defined in ImageEnIO.pas Example // Write a comment to file ImageEnView1.IO.LoadFromFile('C:\input.jpg'); ImageEnView1.IO.Params.EXIF_UserComment := 'Hello World!'; ImageEnView1.IO.Params.EXIF_UserCommentCode := IEEXIFUSERCOMMENTCODE_UNICODE; ImageEnView1.IO.Params.EXIF_HasEXIFData := true; ImageEnView1.IO.SaveToFileTIFF('D:\test.tiff'); !!} property EXIF_UserCommentCode: AnsiString read fEXIF_UserCommentCode write fEXIF_UserCommentCode; {!! TIOParams.EXIF_MakerNote Declaration property EXIF_MakerNote:
; Description Contains custom tags that are added by camera manufacturers. Unfortunately there is not a standard for this tag, so ImageEn offers a general handler which will read the IFD (if present) of the maker note. See the InputOutput/EXIF demo for more details. Example // Read the ISO value for a Canon camera photo case ImageEnView1.IO.Params.EXIF_MakerNote.GetIntegerIndexed(1, 16) of 15: ShowMessage('Auto'); 16: ShowMessage ('50'); 17: ShowMessage ('100'); 18: ShowMessage ('200'); 19: ShowMessage ('400'); end; Demo Demos\InputOutput\EXIF\EXIF.dpr !!} property EXIF_MakerNote: TIETagsHandler read fEXIF_MakerNote; {!! TIOParams.EXIF_XPTitle Declaration property EXIF_XPTitle: WideString; Description Specifies the Windows image title. This is shown in the properties dialog for JPEG and TIFF files. It is still read on newer versions of Windows, but only if a relevant XMP field cannot be found. !!} property EXIF_XPTitle: WideString read fEXIF_XPTitle write fEXIF_XPTitle; {!! TIOParams.EXIF_XPRating Declaration property EXIF_XPRating: Integer; Description Specifies the Windows image rating. This is shown in the properties dialog for JPEG and TIFF files. It is still read on newer versions of Windows, but only if a relevant XMP field cannot be found. Allowed values from 0 up to 5. -1 is returned when not available. !!} property EXIF_XPRating: Integer read fEXIF_XPRating write fEXIF_XPRating; {!! TIOParams.EXIF_XPComment Declaration property EXIF_XPComment: WideString; Description Specifies the Windows image comment. This is shown in the properties dialog for JPEG and TIFF files. It is still read on newer versions of Windows, but only if a relevant XMP field cannot be found. !!} property EXIF_XPComment: WideString read fEXIF_XPComment write fEXIF_XPComment; {!! TIOParams.EXIF_XPAuthor Declaration property EXIF_XPAuthor: WideString; Description Specifies the Windows image author. This is shown in the properties dialog for JPEG and TIFF files. It is still read on newer versions of Windows, but only if a relevant XMP field cannot be found. !!} property EXIF_XPAuthor: WideString read fEXIF_XPAuthor write fEXIF_XPAuthor; {!! TIOParams.EXIF_XPKeywords Declaration property EXIF_XPKeywords: WideString; Description Specifies the Windows image keywords. This is shown in the properties dialog for JPEG and TIFF files. It is still read on newer versions of Windows, but only if a relevant XMP field cannot be found. !!} property EXIF_XPKeywords: WideString read fEXIF_XPKeywords write fEXIF_XPKeywords; {!! TIOParams.EXIF_XPSubject Declaration property EXIF_XPSubject: WideString; Description Specifies the Windows image subject. This is shown in the properties dialog for JPEG and TIFF files. It is still read on newer versions of Windows, but only if a relevant XMP field cannot be found. !!} property EXIF_XPSubject: WideString read fEXIF_XPSubject write fEXIF_XPSubject; {!! TIOParams.EXIF_ExposureMode Declaration property EXIF_ExposureMode: Integer; Description Returns the exposure mode that was set when the photo was taken. In auto-bracketing mode, the camera shoots a series of frames of the same scene at different exposure settings. 0: Auto exposure 1: Manual exposure 2: Auto bracketing !!} property EXIF_ExposureMode: Integer read fEXIF_ExposureMode write fEXIF_ExposureMode; {!! TIOParams.EXIF_WhiteBalance Declaration property EXIF_WhiteBalance: Integer; Description Returns the white balance mode selected when the photo was taken: 0: Auto white balance 1: Manual white balance !!} property EXIF_WhiteBalance: Integer read fEXIF_WhiteBalance write fEXIF_WhiteBalance; {!! TIOParams.EXIF_DigitalZoomRatio Declaration property EXIF_DigitalZoomRatio: Double; Description Returns the digital zoom ratio when the photo was taken. Note: If the numerator of the recorded value is 0, this indicates that digital zoom was not used. !!} property EXIF_DigitalZoomRatio: Double read fEXIF_DigitalZoomRatio write fEXIF_DigitalZoomRatio; {!! TIOParams.EXIF_FocalLengthIn35mmFilm Declaration property EXIF_FocalLengthIn35mmFilm: Integer; Description Returns the equivalent focal length assuming a 35mm film camera, in mm. A value of 0 means the focal length is unknown. Note: This property differs from the tag. !!} property EXIF_FocalLengthIn35mmFilm: Integer read fEXIF_FocalLengthIn35mmFilm write fEXIF_FocalLengthIn35mmFilm; {!! TIOParams.EXIF_SceneCaptureType Declaration property EXIF_SceneCaptureType: Integer; Description Returns the type of scene that was shot. It may also be used to record the mode in which the photo was taken. Allowed values: 0: Standard 1: Landscape 2: Portrait 3: Night scene Note: This property differs from the tag. !!} property EXIF_SceneCaptureType: Integer read fEXIF_SceneCaptureType write fEXIF_SceneCaptureType; {!! TIOParams.EXIF_GainControl Declaration property EXIF_GainControl: Integer; Description Returns the degree of overall image gain adjustment: 0: None 1: Low gain up 2: High gain up 3: Low gain down 4: High gain down !!} property EXIF_GainControl: Integer read fEXIF_GainControl write fEXIF_GainControl; {!! TIOParams.EXIF_Contrast Declaration property EXIF_Contrast: Integer; Description Returns the direction of contrast processing applied by the camera when the photo was taken: 0: Normal 1: Soft 2: Hard !!} property EXIF_Contrast: Integer read fEXIF_Contrast write fEXIF_Contrast; {!! TIOParams.EXIF_Saturation Declaration property EXIF_Saturation: Integer; Description Returns the direction of saturation processing applied by the camera when the photo was taken: 0: Normal 1: Low saturation 2: High saturation !!} property EXIF_Saturation: Integer read fEXIF_Saturation write fEXIF_Saturation; {!! TIOParams.EXIF_Sharpness Declaration property EXIF_Sharpness: Integer; Description Returns the direction of sharpness processing applied by the camera when the photo was taken: 0: Normal 1: Soft 2: Hard !!} property EXIF_Sharpness: Integer read fEXIF_Sharpness write fEXIF_Sharpness; {!! TIOParams.EXIF_SubjectDistanceRange Declaration property EXIF_SubjectDistanceRange: Integer; Description Returns the distance to the subject: 0: Unknown 1: Macro 2: Close view 3: Distant view !!} property EXIF_SubjectDistanceRange: Integer read fEXIF_SubjectDistanceRange write fEXIF_SubjectDistanceRange; {!! TIOParams.EXIF_ImageUniqueID Declaration property EXIF_ImageUniqueID: AnsiString; Description Returns an identifier assigned uniquely to each image. It is recorded as an ASCII string equivalent of hexadecimal notation with a 128-bit fixed length. !!} property EXIF_ImageUniqueID: AnsiString read fEXIF_ImageUniqueID write fEXIF_ImageUniqueID; {!! TIOParams.EXIF_CameraOwnerName Declaration property EXIF_CameraOwnerName: AnsiString; Description Returns the owner of a camera used in photography as an ASCII string. !!} property EXIF_CameraOwnerName: AnsiString read fEXIF_CameraOwnerName write fEXIF_CameraOwnerName; {!! TIOParams.EXIF_BodySerialNumber Declaration property EXIF_BodySerialNumber: AnsiString; Description Returns the serial number of the body of the camera that was used in photography as an ASCII string. !!} property EXIF_BodySerialNumber: AnsiString read fEXIF_BodySerialNumber write fEXIF_BodySerialNumber; {!! TIOParams.EXIF_LensMake Declaration property EXIF_LensMake: AnsiString; Description Returns the lens manufacturer as an ASCII string. !!} property EXIF_LensMake: AnsiString read fEXIF_LensMake write fEXIF_LensMake; {!! TIOParams.EXIF_LensModel Declaration property EXIF_LensModel: AnsiString; Description Returns the lens model name and number as an ASCII string. !!} property EXIF_LensModel: AnsiString read fEXIF_LensModel write fEXIF_LensModel; {!! TIOParams.EXIF_LensSerialNumber Declaration property EXIF_LensSerialNumber: AnsiString; Description Returns the serial number of the interchangeable lens that was used in photography as an ASCII string. !!} property EXIF_LensSerialNumber: AnsiString read fEXIF_LensSerialNumber write fEXIF_LensSerialNumber; {!! TIOParams.EXIF_Gamma Declaration property EXIF_Gamma: Double; Description Specifies the coefficient gamma. The formula of transfer function used for image reproduction is expressed as follows: Value = Power( InputValue, Gamma ); Range: 0 to 1 !!} property EXIF_Gamma: double read fEXIF_Gamma write SetEXIF_Gamma; {!! TIOParams.EXIF_SubjectArea Declaration property EXIF_SubjectArea[Index: Integer]: Integer; Description Specifies the location and area of the main subject in the overall scene. EXIF_SubjectArea has either 2, 3, or 4 values, so Index can be 0 to 3. The subject location and area are defined by Count values as follows: Count = 2: Indicates the location of the main subject as coordinates. The first value is the X coordinate and the second is the Y coordinate. Count = 3: The area of the main subject is given as a circle. The circular area is expressed as center coordinates and diameter. The first value is the center X coordinate, the second is the center Y coordinate, and the third is the diameter. Count = 4: The area of the main subject is given as a rectangle. The rectangular area is expressed as center coordinates and area dimensions. The first value is the center X coordinate, the second is the center Y coordinate, the third is the width of the area, and the fourth is the height of the area. Notes: - Count = 2 would mean EXIF_SubjectArea[2] and EXIF_SubjectArea[3] are both -1, for example - Coordinate values, width, and height are expressed in relation to the upper left as origin, prior to rotation processing as per the Rotation tag. - A string version of EXIF_SubjectArea is available in the iexMetaHelpers.pas EXIF helper unit. See Also - !!} property EXIF_SubjectArea[Index: Integer]: integer read GetEXIF_SubjectArea write SetEXIF_SubjectArea; {!! TIOParams.EXIF_SubjectLocationX Declaration property EXIF_SubjectLocationX: Integer; Description Indicates the X and location of the main subject in the scene. The value of this tag represents the pixel at the center of the main subject relative to the left edge, prior to rotation processing as per the Rotation tag. When a camera records the main subject location, it is recommended that the tag be used instead of this tag. See Also - - !!} property EXIF_SubjectLocationX: integer read fEXIF_SubjectLocationX write SetEXIF_SubjectLocationX; {!! TIOParams.EXIF_SubjectLocationY Declaration property EXIF_SubjectLocationY: Integer; Description Indicates the and Y location of the main subject in the scene. The value of this tag represents the pixel at the center of the main subject relative to the left edge, prior to rotation processing as per the Rotation tag. When a camera records the main subject location, it is recommended that the tag be used instead of this tag. See Also - - !!} property EXIF_SubjectLocationY: integer read fEXIF_SubjectLocationY write SetEXIF_SubjectLocationY; {!! TIOParams.EXIF_GPSVersionID Declaration property EXIF_GPSVersionID: AnsiString; Description Indicates the version of the GPSInfoIFD tag. To save GPS info fill this property with '2.2.0.0' string. !!} property EXIF_GPSVersionID: AnsiString read fEXIF_GPSVersionID write fEXIF_GPSVersionID; {!! TIOParams.EXIF_GPSLatitude Declaration property EXIF_GPSLatitude: Double; Description Returns the latitude in decimal degrees where the photo was taken (if the camera supports GPS). Note: This uses the following EXIF properties: , , and See Also - - !!} property EXIF_GPSLatitude: Double read GetEXIF_GPSLatitude write SetEXIF_GPSLatitude; {!! TIOParams.EXIF_GPSLatitude_Str Declaration property EXIF_GPSLatitude_Str : string; (Read-only) Description Returns a human-readable representation of . Returns '' if the image does not contain EXIF GPS data. Note: This uses the following EXIF properties: , , and See Also - - !!} property EXIF_GPSLatitude_Str : string read GetEXIF_GPSLatitude_Str; {!! TIOParams.EXIF_GPSLatitudeRef Declaration property EXIF_GPSLatitudeRef: AnsiString; Description Indicates whether the latitude is North or South. The ASCII value "N" indicates North latitude, whereas "S" is South latitude. Default value is empty string, which means "unknown". An unknown value is not written when saving EXIF values. See Also - - !!} property EXIF_GPSLatitudeRef: AnsiString read fEXIF_GPSLatitudeRef write fEXIF_GPSLatitudeRef; {!! TIOParams.EXIF_GPSLatitudeDegrees Declaration property EXIF_GPSLatitudeDegrees: Double; Description Returns the latitude degrees where the photo was taken (if the camera supports GPS). See Also - - !!} property EXIF_GPSLatitudeDegrees: Double read fEXIF_GPSLatitudeDegrees write fEXIF_GPSLatitudeDegrees; {!! TIOParams.EXIF_GPSLatitudeMinutes Declaration property EXIF_GPSLatitudeMinutes: Double; Description Returns the latitude minutes where the photo was taken (if the camera supports GPS). See Also - - !!} property EXIF_GPSLatitudeMinutes: Double read fEXIF_GPSLatitudeMinutes write fEXIF_GPSLatitudeMinutes; {!! TIOParams.EXIF_GPSLatitudeSeconds Declaration property EXIF_GPSLatitudeSeconds: Double; Description Returns the latitude seconds where the photo was taken (if the camera supports GPS). See Also - - !!} property EXIF_GPSLatitudeSeconds: Double read fEXIF_GPSLatitudeSeconds write fEXIF_GPSLatitudeSeconds; {!! TIOParams.EXIF_GPSLongitude Declaration property EXIF_GPSLongitude: Double; Description Returns the longitude in decimal degrees where the photo was taken (if the camera supports GPS). Note: This uses the following EXIF properties: , , and See Also - - !!} property EXIF_GPSLongitude: Double read GetEXIF_GPSLongitude write SetEXIF_GPSLongitude; {!! TIOParams.EXIF_GPSLongitude_Str Declaration property EXIF_GPSLongitude_Str : string; (Read-only) Description Returns a human-readable representation of . Returns '' if the image does not contain EXIF GPS data. Note: This uses the following EXIF properties: , , and See Also - - !!} property EXIF_GPSLongitude_Str : string read GetEXIF_GPSLongitude_Str; {!! TIOParams.EXIF_GPSLongitudeRef Declaration property EXIF_GPSLongitudeRef: AnsiString; Description Indicates whether the longitude is East or West. An ASCII value of "E" indicates East longitude, whereas "W" is West longitude. Default value is empty string, which means "unknown". An unknown value is not written when saving EXIF values. See Also - - !!} property EXIF_GPSLongitudeRef: AnsiString read fEXIF_GPSLongitudeRef write fEXIF_GPSLongitudeRef; {!! TIOParams.EXIF_GPSLongitudeDegrees Declaration property EXIF_GPSLongitudeDegrees: Double; Description Returns the longitude degrees where the photo was taken (if the camera supports GPS). See Also - - !!} property EXIF_GPSLongitudeDegrees: Double read fEXIF_GPSLongitudeDegrees write fEXIF_GPSLongitudeDegrees; {!! TIOParams.EXIF_GPSLongitudeMinutes Declaration property EXIF_GPSLongitudeMinutes: Double; Description Returns the longitude minutes where the photo was taken (if the camera supports GPS). See Also - - !!} property EXIF_GPSLongitudeMinutes: Double read fEXIF_GPSLongitudeMinutes write fEXIF_GPSLongitudeMinutes; {!! TIOParams.EXIF_GPSLongitudeSeconds Declaration property EXIF_GPSLongitudeSeconds: Double; Description Returns the longitude seconds where the photo was taken (if the camera supports GPS). See Also - - !!} property EXIF_GPSLongitudeSeconds: Double read fEXIF_GPSLongitudeSeconds write fEXIF_GPSLongitudeSeconds; {!! TIOParams.EXIF_GPSAltitudeRef Declaration property EXIF_GPSAltitudeRef: AnsiString; Description Returns the altitude used as a reference: - If the reference is sea level and the altitude is above sea level, "0" is returned. - If the altitude is below sea level, a value of "1" is returned and the altitude is indicated as an absolute value in the tag. The reference unit is meters. Default value is empty string, which means "unknown". An unknown value is not written when saving EXIF values. !!} property EXIF_GPSAltitudeRef: AnsiString read fEXIF_GPSAltitudeRef write fEXIF_GPSAltitudeRef; {!! TIOParams.EXIF_GPSAltitude Declaration property EXIF_GPSAltitude: Double; Description Returns the altitude (in meters) based on the reference in . !!} property EXIF_GPSAltitude: Double read fEXIF_GPSAltitude write fEXIF_GPSAltitude; {!! TIOParams.EXIF_GPSTimeStampHour Declaration property EXIF_GPSTimeStampHour: Double; Description Returns the hour portion of the GPS time as UTC (Coordinated Universal Time). !!} property EXIF_GPSTimeStampHour: Double read fEXIF_GPSTimeStampHour write fEXIF_GPSTimeStampHour; {!! TIOParams.EXIF_GPSTimeStampMinute Declaration property EXIF_GPSTimeStampMinute: Double; Description Returns the minutes portion of the GPS time as UTC (Coordinated Universal Time). !!} property EXIF_GPSTimeStampMinute: Double read fEXIF_GPSTimeStampMinute write fEXIF_GPSTimeStampMinute; {!! TIOParams.EXIF_GPSTimeStampSecond Declaration property EXIF_GPSTimeStampSecond: Double; Description Returns the second portion of the GPS time as UTC (Coordinated Universal Time). !!} property EXIF_GPSTimeStampSecond: Double read fEXIF_GPSTimeStampSecond write fEXIF_GPSTimeStampSecond; {!! TIOParams.EXIF_GPSSatellites Declaration property EXIF_GPSSatellites: AnsiString Description Returns the GPS satellites used for measurement. This tag can be used to describe the number of satellites, their ID number, angle of elevation, azimuth, SNR and other information in ASCII notation. The format is not defined. !!} property EXIF_GPSSatellites: AnsiString read fEXIF_GPSSatellites write fEXIF_GPSSatellites; {!! TIOParams.EXIF_GPSStatus Declaration property EXIF_GPSStatus: AnsiString; Description Returns the status of the GPS receiver when the image was recorded. "A" means measurement is in progress, and "V" means the measurement is interoperability. !!} property EXIF_GPSStatus: AnsiString read fEXIF_GPSStatus write fEXIF_GPSStatus; {!! TIOParams.EXIF_GPSMeasureMode Declaration property EXIF_GPSMeasureMode: AnsiString; Description Returns the GPS measurement mode. "2" means two-dimensional measurement and "3" means three-dimensional measurement is in progress. !!} property EXIF_GPSMeasureMode: AnsiString read fEXIF_GPSMeasureMode write fEXIF_GPSMeasureMode; {!! TIOParams.EXIF_GPSDOP Declaration property EXIF_GPSDOP: Double; Description Returns the GPS DOP (data degree of precision). An HDOP value is written during two-dimensional measurement, and PDOP during three-dimensional measurement. !!} property EXIF_GPSDOP: Double read fEXIF_GPSDOP write fEXIF_GPSDOP; {!! TIOParams.EXIF_GPSSpeedRef Declaration property EXIF_GPSSpeedRef: AnsiString; Description Returns the unit used to express the GPS receiver speed of movement: K: Kilometers per hour M: Miles per hour N: Knots Default value is empty string, which means "unknown". An unknown value is not written when saving EXIF values. !!} property EXIF_GPSSpeedRef: AnsiString read fEXIF_GPSSpeedRef write fEXIF_GPSSpeedRef; {!! TIOParams.EXIF_GPSSpeed Declaration property EXIF_GPSSpeed: Double; Description Returns the speed of GPS receiver movement. See also: !!} property EXIF_GPSSpeed: Double read fEXIF_GPSSpeed write fEXIF_GPSSpeed; {!! TIOParams.EXIF_GPSTrackRef Declaration property EXIF_GPSTrackRef: AnsiString; Description Returns the reference for the direction of GPS receiver movement. "T" denotes true direction and "M" is magnetic direction. Default value is empty string, which means "unknown". An unknown value is not written when saving EXIF values. !!} property EXIF_GPSTrackRef: AnsiString read fEXIF_GPSTrackRef write fEXIF_GPSTrackRef; {!! TIOParams.EXIF_GPSTrack Declaration property EXIF_GPSTrack: Double; Description Returns the direction of GPS receiver movement. The range of values is from 0.00 to 359.99. See also: !!} property EXIF_GPSTrack: Double read fEXIF_GPSTrack write fEXIF_GPSTrack; {!! TIOParams.EXIF_GPSImgDirectionRef Declaration property EXIF_GPSImgDirectionRef: AnsiString; Description Returns the reference for the direction of the image when it was captured. "T" denotes true direction and "M" is magnetic direction. The default value is an empty string, which means "unknown". An unknown value is not written when saving EXIF values. !!} property EXIF_GPSImgDirectionRef: AnsiString read fEXIF_GPSImgDirectionRef write fEXIF_GPSImgDirectionRef; {!! TIOParams.EXIF_GPSImgDirection Declaration property EXIF_GPSImgDirection: Double; Description Returns the direction of the image when it was captured. The range of values is from 0.00 to 359.99. See also: !!} property EXIF_GPSImgDirection: Double read fEXIF_GPSImgDirection write fEXIF_GPSImgDirection; {!! TIOParams.EXIF_GPSMapDatum Declaration property EXIF_GPSMapDatum: AnsiString; Description Returns the geodetic survey data used by the GPS receiver. If the survey data is restricted to Japan, the value of this tag is "TOKYO" or "WGS-84". !!} property EXIF_GPSMapDatum: AnsiString read fEXIF_GPSMapDatum write fEXIF_GPSMapDatum; {!! TIOParams.EXIF_GPSDestLatitudeRef Declaration property EXIF_GPSDestLatitudeRef: AnsiString; Description Indicates whether the latitude of the destination point is North or South latitude. The ASCII value "N" indicates North latitude, whereas "S" is South latitude. The default value is an empty string, which means "unknown". An unknown value is not written when saving EXIF values. See Also - - - !!} property EXIF_GPSDestLatitudeRef: AnsiString read fEXIF_GPSDestLatitudeRef write fEXIF_GPSDestLatitudeRef; {!! TIOParams.EXIF_GPSDestLatitudeDegrees Declaration property EXIF_GPSDestLatitudeDegrees: Double; Description Returns the latitude degrees of the destination point. See Also - - - !!} property EXIF_GPSDestLatitudeDegrees: Double read fEXIF_GPSDestLatitudeDegrees write fEXIF_GPSDestLatitudeDegrees; {!! TIOParams.EXIF_GPSDestLatitudeMinutes Declaration property EXIF_GPSDestLatitudeMinutes: Double; Description Returns the latitude minutes of the destination point. See Also - - - !!} property EXIF_GPSDestLatitudeMinutes: Double read fEXIF_GPSDestLatitudeMinutes write fEXIF_GPSDestLatitudeMinutes; {!! TIOParams.EXIF_GPSDestLatitudeSeconds Declaration property EXIF_GPSDestLatitudeSeconds: Double; Description Returns the latitude seconds of the destination point. See Also - - - !!} property EXIF_GPSDestLatitudeSeconds: Double read fEXIF_GPSDestLatitudeSeconds write fEXIF_GPSDestLatitudeSeconds; {!! TIOParams.EXIF_GPSDestLongitudeRef Declaration property EXIF_GPSDestLongitudeRef: AnsiString; Description Indicates whether the longitude of the destination point is East or West longitude. An ASCII value of "E" indicates East longitude, whereas "W" is West longitude. The default value is an empty string, which means "unknown". An unknown value is not written when saving EXIF values. See Also - - - !!} property EXIF_GPSDestLongitudeRef: AnsiString read fEXIF_GPSDestLongitudeRef write fEXIF_GPSDestLatitudeRef; {!! TIOParams.EXIF_GPSDestLongitudeDegrees Declaration property EXIF_GPSDestLongitudeDegrees: Double; Description Returns the longitude degrees of the destination point. See Also - - - !!} property EXIF_GPSDestLongitudeDegrees: Double read fEXIF_GPSDestLongitudeDegrees write fEXIF_GPSDestLongitudeDegrees; {!! TIOParams.EXIF_GPSDestLongitudeMinutes Declaration property EXIF_GPSDestLongitudeMinutes: Double; Description Returns the longitude minutes of the destination point. See Also - - - !!} property EXIF_GPSDestLongitudeMinutes: Double read fEXIF_GPSDestLongitudeMinutes write fEXIF_GPSDestLongitudeMinutes; {!! TIOParams.EXIF_GPSDestLongitudeSeconds Declaration property EXIF_GPSDestLongitudeSeconds: Double; Description Returns the longitude seconds of the destination point. See Also - - - !!} property EXIF_GPSDestLongitudeSeconds: Double read fEXIF_GPSDestLongitudeSeconds write fEXIF_GPSDestLongitudeSeconds; {!! TIOParams.EXIF_GPSDestBearingRef Declaration property EXIF_GPSDestBearingRef: AnsiString; Description Returns the reference used for the bearing to the destination point. "T" denotes true direction, whereas "M" is magnetic direction. The default value is an empty string, which means "unknown". An unknown value is not written when saving EXIF values. !!} property EXIF_GPSDestBearingRef: AnsiString read fEXIF_GPSDestBearingRef write fEXIF_GPSDestBearingRef; {!! TIOParams.EXIF_GPSDestBearing Declaration property EXIF_GPSDestBearing: Double; Description Returns the bearing to the destination point. The range of values is from 0.00 to 359.99. See also: !!} property EXIF_GPSDestBearing: Double read fEXIF_GPSDestBearing write fEXIF_GPSDestBearing; {!! TIOParams.EXIF_GPSDestDistanceRef Declaration property EXIF_GPSDestDistanceRef: AnsiString; Description Returns the unit used to express the distance to the destination point: K: Kilometers M: Miles N: Knots The default value is an empty string, which means "unknown". An unknown value is not written when saving EXIF values. !!} property EXIF_GPSDestDistanceRef: AnsiString read fEXIF_GPSDestDistanceRef write fEXIF_GPSDestDistanceRef; {!! TIOParams.EXIF_GPSDestDistance Declaration property EXIF_GPSDestDistance: Double; Description Returns the distance to destination. See also: !!} property EXIF_GPSDestDistance: Double read fEXIF_GPSDestDistance write fEXIF_GPSDestDistance; {!! TIOParams.EXIF_GPSDateStamp Declaration property EXIF_GPSDateStamp: AnsiString; Description Returns the GPS date. !!} property EXIF_GPSDateStamp: AnsiString read fEXIF_GPSDateStamp write fEXIF_GPSDateStamp; //// Exif-interoperability //// {!! TIOParams.EXIF_InteropIndex Declaration property EXIF_InteropIndex: AnsiString; Description Returns the EXIF interoperability index. !!} property EXIF_InteropIndex: AnsiString read fEXIF_InteropIndex write fEXIF_InteropIndex; {!! TIOParams.EXIF_InteropVersion Declaration property EXIF_InteropVersion: AnsiString; Description Returns the EXIF interoperability version. !!} property EXIF_InteropVersion: AnsiString read fEXIF_InteropVersion write fEXIF_InteropVersion; //// XMP //// {!! TIOParams.XMP_Info Declaration property XMP_Info: AnsiString; Description Returns the Adobe XMP info loaded from Jpeg, TIFF and PSD file formats. Adobe XMP is an XML coded string defined by the Adobe XMP Specification (updated to January 2004). XMP_Info is also saved back to Jpeg, TIFF and PSD file formats. You can read parsed values using dictionary, under "XMP" key: xmp := ImageEnView1.IO.Params.Dict.GetDictionary('XMP'); sDescription := xmp.GetString('dc:description', True); You can also use the XMP helper functions in !!} property XMP_Info: AnsiString read fXMP_Info write SetXMP_Info; // RAW Cameras {$ifdef IEINCLUDERAWFORMATS} {!! TIOParams.RAW_HalfSize Declaration property RAW_HalfSize: Boolean; Description Set to True before loading to retrieve only a half-size image of a Raw image. This will speed up loading. Default: False Example ImageEnView1.IO.Params.RAW_HalfSize := True; ImageEnView1.IO.LoadFromFile('C:\CRW_0001.CRW'); !!} property RAW_HalfSize: Boolean read fRAW_HalfSize write fRAW_HalfSize; {!! TIOParams.RAW_Gamma Declaration property RAW_Gamma: Double; Description Specifies the gamma used when loading a RAW image. Default: 2.222 Example ImageEnView1.IO.Params.RAW_Gamma := 1; ImageEnView1.IO.LoadFromFile('C:\CRW_0001.CRW'); !!} property RAW_Gamma: Double read fRAW_Gamma write fRAW_Gamma; {!! TIOParams.RAW_Bright Declaration property RAW_Bright: Double Description Specifies the brightness value used when loading a RAW image. Default: 1.0 Example ImageEnView1.IO.Params.RAW_Bright := 1.5; ImageEnView1.IO.LoadFromFile('C:\CRW_0001.CRW'); !!} property RAW_Bright: Double read fRAW_Bright write fRAW_Bright; {!! TIOParams.RAW_RedScale Declaration property RAW_RedScale: Double Description Specifies the red multiplier used when loading a RAW image. Default: 1.0 (Daylight) Example ImageEnView1.IO.Params.RAW_RedScale := 0.8; ImageEnView1.IO.LoadFromFile('C:\CRW_0001.CRW'); !!} property RAW_RedScale: Double read fRAW_RedScale write fRAW_RedScale; {!! TIOParams.RAW_BlueScale Declaration property RAW_BlueScale: Double Description Specifies the blue multiplier used when loading a RAW image. Default: 1.0 (Daylight) Example ImageEnView1.IO.Params.RAW_BlueScale := 0.8; ImageEnView1.IO.LoadFromFile('C:\CRW_0001.CRW'); !!} property RAW_BlueScale: Double read fRAW_BlueScale write fRAW_BlueScale; {!! TIOParams.RAW_QuickInterpolate Declaration property RAW_QuickInterpolate: Boolean; Description If True, a quick, low-quality color interpolation is performed. Default: True Example ImageEnView1.IO.Params.RAW_QuickInterpolate := False; ImageEnView1.IO.LoadFromFile('C:\CRW_0001.CRW'); !!} property RAW_QuickInterpolate: Boolean read fRAW_QuickInterpolate write fRAW_QuickInterpolate; {!! TIOParams.RAW_UseAutoWB Declaration property RAW_UseAutoWB: Boolean; Description If True, automatic white balance is performed. By default, Raw images are given a fixed white balance based on a color chart illuminated with a standard D65 lamp. When RAW_UseAutoWB is enabled, the white balance is calculated by averaging the entire image. Default: False Example ImageEnView1.IO.Params.RAW_UseAutoWB := True; ImageEnView1.IO.LoadFromFile('C:\CRW_0001.CRW'); See Also - - !!} property RAW_UseAutoWB: Boolean read fRAW_UseAutoWB write fRAW_UseAutoWB; {!! TIOParams.RAW_ExtraParams Declaration property RAW_ExtraParams: AnsiString; Description Specifies extra parameters for the raw plug-in (based on Dcraw). Example ImageEnView1.IO.Params.RAW_ExtraParams := '-H 0 -j'; ImageEnView1.IO.LoadFromFile('C:\CRW_0001.CRW'); !!} property RAW_ExtraParams: AnsiString read fRAW_ExtraParams write fRAW_ExtraParams; {!! TIOParams.RAW_UseCameraWB Declaration property RAW_UseCameraWB: Boolean Description If True, The camera's white balance is used if possible. By default, Raw images are given a fixed white balance based on a color chart illuminated with a standard D65 lamp. When RAW_UseCameraWB is enabled, the white balance specified by the camera is used (if it exists). This has preference over . Default: False Example ImageEnView1.IO.Params.RAW_UseCameraWB := True; ImageEnView1.IO.LoadFromFile('C:\CRW_0001.CRW'); See Also - - !!} property RAW_UseCameraWB: Boolean read fRAW_UseCameraWB write fRAW_UseCameraWB; {!! TIOParams.RAW_FourColorRGB Declaration property RAW_FourColorRGB: Boolean Description If True, ImageEn interpolates RGBG as four colors. Default: False Example ImageEnView1.IO.Params.RAW_FourColorRGB := True; ImageEnView1.IO.LoadFromFile('C:\CRW_0001.CRW'); !!} property RAW_FourColorRGB: Boolean read fRAW_FourColorRGB write fRAW_FourColorRGB; {!! TIOParams.RAW_Camera Declaration property RAW_Camera: AnsiString; Description Returns the camera description. Example ImageEnView1.IO.LoadFromFile('C:\CRW_0001.CRW'); Cameraname := ImageEnView1.IO.Params.RAW_Camera; !!} property RAW_Camera: AnsiString read fRAW_Camera write fRAW_Camera; {!! TIOParams.RAW_GetExifThumbnail Declaration property RAW_GetExifThumbnail: Boolean; Description Specifies that the thumbnail for an image will be loaded instead of the full image. A thumbnail is often available for Raw images (EXIF Thumbnail). If enabled and the file does not contain a thumbnail the full image will be automatically loaded instead. See also: Example // Load only the thumbnail ImageEnView1.IO.Params.RAW_GetExifThumbnail := True; ImageEnView1.IO.LoadFromFile('C:\input.crw'); !!} property RAW_GetExifThumbnail: Boolean read fRAW_GetExifThumbnail write SetRAW_GetExifThumbnail; {!! TIOParams.RAW_AutoAdjustColors Declaration property RAW_AutoAdjustColors: Boolean; Description If True, ImageEn applies an algorithm to adjust image colors. Note: This works only when the RAW file contains an EXIF thumbnail with correct colors, as it used to calculate image colors. Example ImageEnView.IO.Params.RAW_AutoAdjustColors := True; ImageEnView.IO.LoadFromFile('C:\input.crw'); See Also - - !!} property RAW_AutoAdjustColors: Boolean read fRAW_AutoAdjustColors write fRAW_AutoAdjustColors; {$endif} // Real RAWs {!! TIOParams.BMPRAW_ChannelOrder Declaration property BMPRAW_ChannelOrder: ; Description Specifies the channels order for a BmpRaw file (a true "raw" format, not the same as a digital camera Raw file). It can be coRGB or coBGR and it is valid only for color images. Default: coRGB Demo Demos\InputOutput\RealRAW\RealRaw.dpr Examples // load a RAW image, RGB, interleaved, 8 bit aligned, 1024x768 ImageEnView1.LegacyBitmap := False; ImageEnView1.IEBitmap.Allocate(1024, 768, ie24RGB); ImageEnView1.IO.Params.BMPRAW_ChannelOrder := coRGB; ImageEnView1.IO.Params.BMPRAW_Planes := plInterleaved; ImageEnView1.IO.Params.BMPRAW_RowAlign := 8; ImageEnView1.IO.Params.BMPRAW_HeaderSize := 0; ImageEnView1.IO.LoadFromFileBMPRAW('C:\input.dat'); // load a RAW image, CMYK, interleaved, 8 bit aligned, 1024x768 ImageEnView1.LegacyBitmap := False; ImageEnView1.IEBitmap.Allocate(1024, 768, ieCMYK); ImageEnView1.IO.Params.BMPRAW_ChannelOrder := coRGB; ImageEnView1.IO.Params.BMPRAW_Planes := plInterleaved; ImageEnView1.IO.Params.BMPRAW_RowAlign := 8; ImageEnView1.IO.Params.BMPRAW_HeaderSize := 0; ImageEnView1.IO.LoadFromFileBMPRAW('C:\input.dat'); // saves current image as RAW image ImageEnView1.IO.Params.BMPRAW_ChannelOrder := coRGB; ImageEnView1.IO.Params.BMPRAW_Planes := plPlanar; ImageEnView1.IO.Params.BMPRAW_RowAlign := 8; ImageEnView1.IO.SaveToFileBMPRAW('C:\output.dat'); !!} property BMPRAW_ChannelOrder: TIOBMPRAWChannelOrder read fBMPRAW_ChannelOrder write fBMPRAW_ChannelOrder; {!! TIOParams.BMPRAW_Planes Declaration property BMPRAW_Planes: ; Description Specifies how channels of a BmpRaw file are disposed. Default: plInterleaved Demo Demos\InputOutput\RealRAW\RealRaw.dpr Example See example at !!} property BMPRAW_Planes: TIOBMPRAWPlanes read fBMPRAW_Planes write fBMPRAW_Planes; {!! TIOParams.BMPRAW_RowAlign Declaration property BMPRAW_RowAlign: Integer; Description Specifies the row alignment in bits. Default: 8 Demo Demos\InputOutput\RealRAW\RealRaw.dpr Example See example at !!} property BMPRAW_RowAlign: Integer read fBMPRAW_RowAlign write fBMPRAW_RowAlign; {!! TIOParams.BMPRAW_HeaderSize Declaration property BMPRAW_HeaderSize: Integer; Description Specifies the header size in bytes. The header will be bypassed. Default: 0 Demo Demos\InputOutput\RealRAW\RealRaw.dpr Example See example at !!} property BMPRAW_HeaderSize: Integer read fBMPRAW_HeaderSize write fBMPRAW_HeaderSize; {!! TIOParams.BMPRAW_DataFormat Declaration property BMPRAW_DataFormat: ; Description Specifies the next input/output data format. ASCII text values must be separated by one or more non-alpha characters (#13, #10, #32...). Default: dfBinary Demo Demos\InputOutput\RealRAW\RealRaw.dpr Examples // load a RAW image, 16 bit gray scale, ascii-text ImageEnView1.LegacyBitmap := false; ImageEnView1.IEBitmap.Allocate(1024, 768, ie16g); ImageEnView1.IO.Params.BMPRAW_RowAlign := 8; ImageEnView1.IO.Params.BMPRAW_HeaderSize := 0; ImageEnView1.IO.Params.BMPRAW_DataFormat := dfTextDecimal; ImageEnView1.IO.LoadFromFileBMPRAW('input.dat'); !!} property BMPRAW_DataFormat: TIOBMPRAWDataFormat read fBMPRAW_DataFormat write fBMPRAW_DataFormat; {!! TIOParams.IEN_Compression Declaration property IEN_Compression: ; Description Specifies the format to save an ImageEn layer file. If CompressionFormat is -1, an internal lossless compressed format is used. Pixel format and alpha channel are preserved. If CompressionFormat is -2, an internal non-compressed format is used. Pixel format and alpha channel are preserved. Otherwise any standard image format can be used , except ioTIFF. Note: Even if a standard compression format, such as ioJPEG is used, the file will only be readable by ImageEn. Default: -1 !!} property IEN_Compression: Integer read fIEN_Compression write fIEN_Compression; {!! TIOParams.IEN_Description Declaration property IEN_Description: Widestring; Description A description you can specify for the file. !!} property IEN_Description: Widestring read fIEN_Description write fIEN_Description; {!! TIOParams.IEN_LayerCount Declaration property IEN_LayerCount: Integer; Description Returns the number of layers in the file. Read-only See Also - - !!} property IEN_LayerCount: Integer read fIEN_LayerCount; {!! TIOParams.IEN_Version Declaration property IEN_Version: Integer; Description Returns the version of this IEN file. Read-only !!} property IEN_Version: Integer read fIEN_Version; {!! TIOParams.IEN_GetThumbnail Declaration property IEN_GetThumbnail: Boolean; Description Specifies that the thumbnail for an IEN image will be loaded instead of the full image. Thumbnails are saved for IEN images when is specified. If enabled and the file does not contain a thumbnail, the full image is automatically loaded instead. See also: Example // Load only the thumbnail ImageEnView1.IO.Params.IEN_GetThumbnail := True; ImageEnView1.IO.LoadFromFile('C:\input.ien'); !!} property IEN_GetThumbnail: Boolean read fIEN_GetThumbnail write fIEN_GetThumbnail; {!! TIOParams.SVG_ImageCompression Declaration property SVG_ImageCompression: ; Description Specifies the format that is used when saving raster images within an SVG file. Notes: - SVG_ImageCompression should be a web-safe image format, such as ioPNG or ioJPEG - If SVG_ImageCompression is ioJPEG, then the quality will be specified by Default: ioPNG Example // Save current layers (compress image layers as jpeg) ImageEnView1.IO.Params.SVG_ImageCompression := ioJPEG; ImageEnView1.IO.Params.JPEG_Quality := 80; ImageEnView1.IO.SaveToFileSVG( 'D:\layers.SVG' ); !!} property SVG_ImageCompression: Integer read fSVG_ImageCompression write fSVG_ImageCompression; ///// constructor Create(AttachTo: TObject = nil); destructor Destroy; override; procedure SetDefaultParams; procedure Assign(Source: TIOParams); procedure AssignCompressionInfo(Source: TIOParams); procedure SaveToFile(const FileName: WideString); procedure SaveToStream(Stream: TStream); procedure LoadFromFile(const FileName: WideString; CheckMagicString: Boolean = true); procedure LoadFromStream(Stream: TStream; CheckMagicString: Boolean = true); property ImageEnIO: TObject read GetImageEnIO; procedure ResetInfo; procedure ResetEXIF; function GetProperty(const Prop: WideString): WideString; procedure SetProperty(Prop, Value: WideString); procedure UpdateEXIFThumbnail(Width: integer = 160; Height: integer = -1; ResampleFilter: TResampleFilter = rfTriangle); procedure FreeColorMap; procedure AdjustGPSCoordinates(); function ReadIPTCField(iRecNo, iFieldIndex: Integer) : string; overload; procedure ReadIPTCField(iRecNo, iFieldIndex: Integer; Dest : TStrings); overload; procedure WriteIPTCField(iRecNo, iFieldIndex: Integer; const Value : string); overload; procedure WriteIPTCField(iRecNo, iFieldIndex: Integer; ssValues : TStrings); overload; procedure ClearIPTCField(iRecNo, iFieldIndex: Integer); function Read(const FileName: WideString; Format: TIOFileType = ioUnknown): Boolean; overload; function Read(const FileName: WideString; bUseExtension: Boolean): Boolean; overload; function Read(Stream: TStream; Format: TIOFileType = ioUnknown): Boolean; overload; function Read(Buffer: Pointer; BufferSize: Integer; Format: TIOFileType = ioUnknown): Boolean; overload; end; {$ifdef IEIncludeDeprecatedInV6} // Deprecated in v6.2.0 (2015-06-08) TIOParamsVals = TIOParams; {$ENDIF} /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // TIOMultiParams {$IFDEF IEINCLUDEMULTIVIEW} {!! TIOMultiParams Description A list of for handling images with multiple frames, such as AVI, TIFF, GIF and DICOM. It is used by and . See Also - Methods and Properties General !!} TIOMultiParams = class private fParamsList: TList; // list of TIOParams function GetCount: integer; function GetParams(idx: integer): TIOParams; procedure RemoveParam(idx: integer); procedure InsertParam(idx: integer); procedure MoveParam(idx: integer; Destination: integer); procedure MoveParams(IndexGroup: TIEArrayOfInteger; Destination: integer); procedure SwapParams(idx1, idx2: integer); procedure CheckAllocated(idx: integer); public constructor Create; destructor Destroy; override; procedure UpdateEx(Operation: integer; Idx: integer; ExtraParam: Integer); overload; procedure UpdateEx(Operation: integer; Idx: integer; ExtraParam: Integer; IndexGroup: TIEArrayOfInteger); overload; // setting IndexGroup default value (nil) generates incorrect C++ headers procedure Allocate(Count : Integer); procedure Clear; procedure Assign(Source: TObject); procedure DuplicateCompressionInfo; property Count: integer read GetCount; property Params[idx: integer]: TIOParams read GetParams; function Read(const FileName: WideString; Format: TIOFileType = ioUnknown): Boolean; overload; function Read(const FileName: WideString; bUseExtension: Boolean): Boolean; overload; function Read(Stream: TStream; Format: TIOFileType = ioUnknown): Boolean; overload; function Read(Buffer: Pointer; BufferSize: Integer; Format: TIOFileType = ioUnknown): Boolean; overload; end; {$ENDIF} // IEINCLUDEMULTIVIEW /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // DICOM TAGS {$ifdef IEINCLUDEDICOM} //type {!! TIEDicomTagSource Declaration TIEDicomTagSource = (dsStandard, dsDeprecated, dsProprietary); Description The source of Dicom tags: Type Description dsStandard A tag that is listed in the NEMA DICOM Standard dsDeprecated A tag listed in the NEMA standard, but marked as "Retired" dsProprietary Other tags that are vendor specific
!!} TIEDicomTagSource = (dsStandard, dsDeprecated, dsProprietary); {!! TIEDicomTagType Declaration TIEDicomTagType = (dvAE, dvAS, dvAT, dvCS, dvDA, dvDS, dvDT, dvFD, dvFL, dvIS, dvLO, dvLT, dvOB, dvOF, dvOW, dvPN, dvSH, dvSL, dvSQ, dvSS, dvST, dvTM, dvUI, dvUL, dvUS, dvUT, dvUSorSS, dvUnknown); Description The variable type for Dicom tags: Type Description Detail dvAE Application Entity A string of characters that identifies an Application Entity with leading and trailing spaces (20H) being non-significant dvAS Age String A string of characters with one of the following formats -- nnnD, nnnW, nnnM, nnnY; where nnn shall contain the number of days for D, weeks for W, months for M, or years for Y dvAT Attribute Tag Ordered pair of 16-bit unsigned integers that is the value of a Data Element Tag dvCS Code String A string of characters with leading or trailing spaces (20H) being non-significant dvDA Date A string of characters of the format yyyymmdd; where yyyy shall contain year, mm shall contain the month, and dd shall contain the day dvDS Decimal String A string of characters representing either a fixed point number or a floating point number dvDT Date Time The Date Time common data type. Indicates a concatenated date-time ASCII string in the format: YYYYMMDDHHMMSS.FFFFFF&ZZZZ dvFL Floating Point Single Single precision binary floating point number represented in IEEE 754:1985 32-bit Floating Point Number Format dvFD Floating Point Double Double precision binary floating point number represented in IEEE 754:1985 64-bit Floating Point Number Format dvIS Integer String A string of characters representing an Integer in base-10 (decimal), shall contain only the characters 0 - 9, with an optional leading "+" or "-" dvLO Long String A character string that may be padded with leading and/or trailing spaces dvLT Long Text A character string that may contain one or more paragraphs dvOB Other Byte String A string of bytes where the encoding of the contents is specified by the negotiated Transfer Syntax dvOF Other Float String A string of 32-bit IEEE 754:1985 floating point words dvOW Other Word String A string of 16-bit words where the encoding of the contents is specified by the negotiated Transfer Syntax dvPN Person Name A character string encoded using a 5 component convention dvSH Short String A character string that may be padded with leading and/or trailing spaces dvSL Signed Long Signed binary integer 32 bits long in 2's complement form dvSQ Sequence of Items Value is a Sequence of zero or more Items, as defined in NEMA Documentation, Section 7.5 dvSS Signed Short Signed binary integer 16 bits long in 2's complement form dvST Short Text A character string that may contain one or more paragraphs dvTM Time A string of characters of the format hhmmss.frac; dvUI Unique Identifier A character string containing a UID that is used to uniquely identify a wide variety of items dvUL Unsigned Long Unsigned binary integer 32 bits long dvUN Unknown A string of bytes where the encoding of the contents is unknown (see NEMA Documentation, Section 6.2.2) dvUR Universal Resource Identifier or Universal Resource Locator (URI/URL) A string of characters that identifies a URI or a URL as defined in [RFC 3986]. Leading spaces are not allowed. Trailing spaces shall be ignored. Data Elements with this VR shall not be multi-valued dvUS Unsigned Short Unsigned binary integer 16 bits long dvUT Unlimited Text A character string that may contain one or more paragraphs dvUSorSS Signed or unsigned Short ImageEn type: Could be either dvUS or dvSS dvUnknown Unsupported ImageEn type: An unsupported type
Source: http://medical.nema.org/medical/dicom/current/output/html/part05.html#sect_6.2 !!} TIEDicomTagType = (dvAE, dvAS, dvAT, dvCS, dvDA, dvDS, dvDT, dvFD, dvFL, dvIS, dvLO, dvLT, dvOB, dvOF, dvOW, dvPN, dvSH, dvSL, dvSQ, dvSS, dvST, dvTM, dvUI, dvUL, dvUN, dvUR, dvUS, dvUT, dvUSorSS, dvUnknown); {!! TIEDicomTag Declaration type TIEDicomTag = record Group : Word; Element : Word; DataType :
; Data : Pointer; DataLen : Integer; Children : TObjectList; // Each item must be a . If defined then Data = nil and DataLen = 0 end; !!} TIEDicomTag = record Group : Word; Element : Word; DataType : TIEDicomTagType; Data : Pointer; DataLen : Integer; Children : TObjectList; // each item must be TIEDicomTags. If defined then Data = nil and DataLen = 0 end; {!! PIEDicomTag Declaration PIEDicomTag = ^; !!} PIEDicomTag = ^TIEDicomTag; {!! TIEDicomTags Description Metadata within the Dicom file. You can view a list of tags at: Dicom Tag List Methods and Properties Demo Demos\InputOutput\Dicom\Dicom.dpr !!} TIEDicomTags = class private fTags: TList; fSorted: boolean; function GetCount: integer; procedure FreeTag(Index: integer); function SetTag(Tag: PIEDicomTag; ReplaceIfExist: boolean): integer; public constructor Create; destructor Destroy; override; procedure Clear; procedure SaveToStream(Stream: TStream); procedure LoadFromStream(Stream: TStream); procedure Assign(Source: TIEDicomTags); function AddTag(Group: word; Element: word; DataType: TIEDicomTagType; Data: pointer; DataLen: integer; Children: TObjectList = nil): integer; function IndexOf(Group: Word; Element: Word): integer; overload; function GetTag(Index: integer): PIEDicomTag; overload; function GetTag(Group: Word; Element: Word): PIEDicomTag; overload; function GetTagString(Index: integer): AnsiString; overload; function GetTagString(Group: Word; Element: Word): AnsiString; overload; function GetTagNumeric(Index: integer; Default: double = 0.0): double; overload; function GetTagNumeric(Group: Word; Element: Word; Default: double = 0.0): double; overload; function GetTagChildren(Group: Word; Element: Word): TObjectList; overload; function GetTagChildren(Index: integer): TObjectList; overload; function GetTagDescription(Index: integer): string; overload; function GetTagDescription(Index: integer; out TagSource : TIEDicomTagSource): string; overload; class function GetTagDescription(Group: Word; Element: Word): string; overload; class function GetTagDescription(Group: Word; Element: Word; out TagSource : TIEDicomTagSource): string; overload; procedure SetTagNumeric(Group: Word; Element: Word; Value: double; ReplaceIfExist: Boolean = True); procedure SetTagString(Group: Word; Element: Word; Value: AnsiString; ReplaceIfExist: Boolean = True); procedure SetTagByteBuffer(Group: Word; Element: Word; Buffer: pbyte; Length: integer; ReplaceIfExist: Boolean = True); procedure DeleteTag(Index: integer); overload; procedure DeleteTag(Group: Word; Element: Word; DeleteAllInstances: boolean = false); overload; procedure DeleteGroup(Group: Word); function FindNestedTag(Group: Word; Element: Word; out Index: integer; StartFrom: TIEDicomTags = nil): TIEDicomTags; overload; function FindNestedTag(Group: Word; Element: Word; out Index: integer; StartFrom: TObjectList): TIEDicomTags; overload; property Count: integer read GetCount; {!! TIEDicomTags.Sorted Declaration property Sorted: boolean; Description If true, the Dicom tags are sorted by group and element IDs. Default: True Set Sorted to false when adding tags if you want to maintain a tag sequence. Example Children := TObjectList.Create(); SubTags := TIEDicomTags.Create(); SubTags.Sorted := false; SubTags.SetTagNumeric( $4, $1400, 0, False ); SubTags.SetTagNumeric( $4, $1410, 65535, False ); SubTags.SetTagNumeric( $4, $1420, 0, False ); SubTags.SetTagString( $4, $1430, 'PATIENT', False ); SubTags.SetTagNumeric( $4, $1400, 0, False ); SubTags.SetTagNumeric( $4, $1410, 65535, False ); SubTags.SetTagNumeric( $4, $1420, 0, False ); SubTags.SetTagString( $4, $1430, 'STUDY', False ); SubTags.SetTagNumeric( $4, $1400, 0, False ); SubTags.SetTagNumeric( $4, $1410, 65535, False ); SubTags.SetTagNumeric( $4, $1420, 0, False ); SubTags.SetTagString( $4, $1430, 'SERIES', False ); SubTags.SetTagNumeric( $4, $1400, 0, False ); SubTags.SetTagNumeric( $4, $1410, 65535, False ); SubTags.SetTagNumeric( $4, $1420, 0, False ); SubTags.SetTagString( $4, $1430, 'IMAGE', False ); SubTags.SetTagString( $4, $1500, 'C:\FileName.jpg', False ); Children.Add( SubTags ); ImageEnMView1.MIO.Params[0].DICOM_Tags.AddTag( 4, $1220, dvSQ, nil, -1, Children ); !!} property Sorted: boolean read fSorted write fSorted; end; {$endif} ///////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIETIFTagsReader {!! TIETIFTagsReader Description TIETIFTagsReader allows reading of single tags from a TIFF file or stream. See also: for a more powerful TIFF handling class. Methods and Properties - - - - - - - - - - - - - - Example Var Tags: TIETIFTagsReader; ... Tags := TIETIFTagsReader.CreateFromFile('input.tif', 0); // read tags of the first image (page) If Tags.TagExists(269) then DocumentName := Tags.GetString(269); // 269 is the document name If Tags.TagExists(285) then Pagename := Tags.GetString(285); // 285 is the page name Tags.free; !!} TIETIFTagsReader = class private fFileStream: TStream; fStream: TStream; fIFD: TIETIFFIFDReader; fNumi: integer; public constructor CreateFromFile(const FileName: string; ImageIndex: integer); constructor CreateFromStream(Stream: TStream; ImageIndex: integer); constructor CreateFromIFD(tagReader: TIETIFTagsReader; IFDTag: integer); destructor Destroy; override; {!! TIETIFTagsReader.ImageCount Declaration property ImageCount: integer; Description Returns the number of pages in the TIFF. !!} property ImageCount: integer read fNumi; function TagExists(Tag: integer): boolean; function TagLength(Tag: integer): integer; function GetInteger(Tag: integer): int64; function GetIntegerIndexed(Tag: integer; index: integer): integer; function GetRational(Tag: integer; defaultValue: double = 0): double; function GetRationalIndexed(Tag: integer; index: integer; defVal: double=0.0): double; function GetIntegerArray(Tag: integer; var ar: pint64array): integer; function GetRawData(Tag: integer): pointer; function GetString(Tag: integer): AnsiString; function GetMiniString(Tag: integer): AnsiString; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIETagsHandler TIEEXIFMakerNoteDeviceInfo = record signature: AnsiString; sigbypass: integer; base: (iemnAbsolute, iemnTIFFHeader, iemnEXIFSegment); headerType: (iemnNONE, iemnTIFF, iemnIFDOFFSET); TIFFHeader: TTIFFHeader; // in case of iemnTIFF byteOrder: (ieboFromEXIF, ieboFromTIFFHeader, ieboLittleEndian, ieboBigEndian); end; TIETagsHandlerAddTagFunc = procedure(tagPosition: integer; littleEndian: boolean; var tag: TTIFFTAG) of object; {!! TIETagsHandler Description This class allows reading of EXIF maker note tags, which are not in IFD format (such as Canon). Methods and Properties !!} TIETagsHandler = class private fUnparsedData: pointer; fUnparsedDataLength: integer; fEXIFMakerInfo: TIEEXIFMakerNoteDeviceInfo; fData: TMemoryStream; fIFD: TIETIFFIFDReader; procedure SetUnparsedData(value: pointer); function CheckHeader(buffer: pointer; bufferLen: integer): TIEEXIFMakerNoteDeviceInfo; public constructor Create; destructor Destroy; override; property Data: TMemoryStream read fData; procedure Update; // synch fIFD with fData content procedure Assign(source: TIETagsHandler); procedure Clear; function TagExists(Tag: integer): boolean; function TagLength(Tag: integer): integer; function GetInteger(Tag: integer): integer; function GetIntegerIndexed(Tag: integer; index: integer): integer; function GetRational(Tag: integer; defaultValue: double = 0): double; function GetRationalIndexed(Tag: integer; index: integer; defVal: double = 0.0): double; function GetIntegerArray(Tag: integer; var ar: pint64array): integer; function GetRawData(Tag: integer): pointer; function GetString(Tag: integer): AnsiString; function GetMiniString(Tag: integer): AnsiString; function GetDataType(Tag: integer): integer; property UnparsedData: pointer read fUnparsedData write SetUnparsedData; property UnparsedDataLength: integer read fUnparsedDataLength write fUnparsedDataLength; procedure ReadFromStreamUnparse(stream: TStream; size: integer); procedure ReadFromStream(stream: TStream; size: integer; littleEndian: boolean; exifSegmentPos: int64; clearOnFail: boolean; addTagFunc: TIETagsHandlerAddTagFunc = nil); function WriteToStream(stream: TStream; exifSegmentPos: int64): integer; end; // TIETagsHandler ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIETagsHandlerRelocator //type TIETagsHandlerRelocator = class private Stream: TStream; Position: int64; Offset: int64; LittleEndian: boolean; TagsHandler: TIETagsHandler; procedure AddTagFunc(tagPosition: integer; littleEndian: boolean; var tag: TTIFFTAG); public constructor Create(Stream_: TStream; Position_: int64; Offset_: int64; LittleEndian_: boolean); destructor Destroy(); override; procedure Relocate(); end; // TIETagsHandlerRelocator ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {!! TIETagType Declaration } TIETagType = (ttUnknown, ttByte, ttAscii, ttShort, ttLong, ttRational, ttSByte, ttUndefined, ttSShort, ttSLong, ttSRational, ttFloat, ttDouble, ttLongOffset); {!!} ///////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIETIFFHandler {$ifdef IEINCLUDETIFFHANDLER} {!! TIETIFFHandler Description This class allows you to read all TIFF tags, edit/add tags and pages, delete pages, and finally save back the modified TIFF. Note: This class is unable to work with some OLD-JPEG tiff files. OLD-JPEG compression is no longer supported by the TIFF standard. Examples Demo Demos\InputOutput\TiffHandler\TiffHandler.dpr Methods and Properties Input/output Meta Information Tag Information Tag Reading Tag Writing Tag Copying Page Handling !!} {!! TIETIFFHandler Examples // add a custom tag (65000 with 'Hello World') at page 0 mytif := TIETIFFHandler.Create('input.tif'); mytif.SetValue(0, 65000, ttAscii, 'Hello World!'); mytif.WriteFile('output.tif'); mytif.free; // delete second page (indexed 1) of a multipage tiff mytif := TIETIFFHandler.Create('input.tif'); mytif.DeletePage(1); mytif.WriteFile('output.tif'); mytif.free; // insert a new page from an external file mytif := TIETIFFHandler.Create('input.tif'); mytif.InsertPageAsFile('external.jpg', 0); mytif.WriteFile('output.tif'); mytif.free; // merge two tiff (even they are multipage files..) mytif := TIETIFFHandler.Create('input-1.tif'); mytif.InsertTIFFFile('input-2.tif', mytif.PagesCount-1); mytif.WriteFile('output.tif'); mytif.free; // read tag 305 ('software') mytif := TIETIFFHandler.Create('input-1.tif'); software := mytif.GetString(0, mytif.FindTag(0, 305)); mytif.free; !!} TIETIFFHandler = class private fBigEndian: boolean; // BigEndian (Motorola) vs LittleEndian (Intel) fVersion: word; fPages: TList; // each item contain another TList which contains pointers to TTIFFTAG fBuffers: TList; // list of allocated buffers (indices stores in DataPos of TTIFFTAG) function ReadHeader(Stream: TStream): boolean; function xword(value: word): word; function xdword(value: dword): dword; function GetIntegerByCode(page: integer; tagcode: integer; idx: integer): integer; overload; function GetIntegerByCode(ifd: TList; tagcode: integer; idx: integer): integer; overload; procedure SortTags(pageIndex: integer); overload; procedure SortTags(ifd: TList); overload; function GetValueRAWEx(pageIndex: integer; tagIndex: integer; arrayIndex: integer; var tagType: integer): pointer; overload; function GetValueRAWEx(tag: PTIFFTAG; arrayIndex: integer): pointer; overload; function GetLittleEndian: boolean; procedure CheckPairTag(tagCode: integer; var tgpos: integer; var tglen: integer); overload; function CheckPairTag(tagCode: integer): boolean; overload; function CheckIFD(tagCode: integer): boolean; function ReadIFD(Stream: TStream; Pages: TList; ifd: TList; insertPos: integer): boolean; function FindTag(ifd: TList; tagCode: integer): integer; overload; procedure DeleteTag(pageIndex: integer; tagIndex: integer; checkOffsetTags: boolean); overload; procedure DeleteTag(ifd: TList; tagIndex: integer; checkOffsetTags: boolean); overload; procedure WriteIFD(Stream: TStream; ifd: TList; var dataPos: int64); function GetInteger(ifd: TList; tagIndex: integer; arrayIndex: integer): integer; overload; procedure SetValue(ifd: TList; tagCode: integer; tagType: TIETagType; value: variant); overload; procedure SetValueRAW(ifd: TList; tagCode: integer; tagType: TIETagType; dataNum: integer; buffer: pointer); overload; procedure CopyTag(src_ifd: TList; srcTagIndex: integer; source: TIETIFFHandler; dst_ifd: TList); overload; procedure init(); public constructor Create(); overload; constructor Create(const FileName: string); overload; constructor Create(Stream: TStream); overload; destructor Destroy(); override; // input/output function ReadFile(const FileName: string): boolean; function ReadStream(Stream: TStream): boolean; function InsertTIFFStream(Stream: TStream; pageIndex: integer): boolean; function InsertTIFFFile(const FileName: string; pageIndex: integer): boolean; function InsertPageAsFile(const FileName: string; pageIndex: integer): boolean; function InsertPageAsStream(Stream: TStream; pageIndex: integer): boolean; function InsertPageAsImage(viewer: TObject; pageIndex: integer): boolean; procedure WriteFile(const FileName: string; page: integer = -1); procedure WriteStream(Stream: TStream; page: integer = -1); procedure FreeData(); // tag info/handling function GetTagsCount(pageIndex: integer): integer; function GetPagesCount: integer; function GetTagCode(pageIndex: integer; tagIndex: integer): integer; function GetTagType(pageIndex: integer; tagIndex: integer): TIETagType; function GetTagLength(pageIndex: integer; tagIndex: integer): integer; function GetTagLengthInBytes(pageIndex: integer; tagIndex: integer): integer; function FindTag(pageIndex: integer; tagCode: integer): integer; overload; procedure DeleteTag(pageIndex: integer; tagIndex: integer); overload; function GetTagDescription(pageIndex: integer; tagIndex: integer): AnsiString; procedure ChangeTagCode(pageIndex: integer; tagIndex: integer; newCode: integer); // tag read function GetInteger(pageIndex: integer; tagIndex: integer; arrayIndex: integer): integer; overload; function GetString(pageIndex: integer; tagIndex: integer): AnsiString; function GetFloat(pageIndex: integer; tagIndex: integer; arrayIndex: integer): double; function GetValue(pageIndex: integer; tagIndex: integer; arrayIndex: integer): variant; procedure SaveTagToFile(pageIndex: integer; tagIndex: integer; const fileName: string); function GetValueRAW(pageIndex: integer; tagIndex: integer; arrayIndex: integer): pointer; // tag write procedure SetValue(pageIndex: integer; tagCode: integer; tagType: TIETagType; value: variant); overload; procedure SetValueRAW(pageIndex: integer; tagCode: integer; tagType: TIETagType; dataNum: integer; buffer: pointer); overload; // tag copy procedure CopyTag(srcPageIndex: integer; srcTagIndex: integer; source: TIETIFFHandler; dstPageIndex: integer); overload; // pages handling procedure DeletePage(pageIndex: integer); procedure ExchangePage(Index1, Index2: integer); procedure MovePage(CurIndex, NewIndex: integer); function InsertPage(pageIndex: integer = -1): integer; overload; function InsertPage(pageIndex: integer; sourceHandler: TIETIFFHandler; sourcePage: integer): integer; overload; // informational property LittleEndian: boolean read GetLittleEndian; {!! TIETIFFHandler.Version Declaration property Version: word; Description Returns file version. TIFF ver.6 will return $2A, while Microsoft HD Photo will return $1BC. !!} property Version: word read fVersion write fVersion; end; {$endif} // TIETIFFHandler ///////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// TIEGraphicBase = class(TGraphic) private fio: TObject; // TImageEnIO bmp: TIEBitmap; fFiletype: integer; fResampleFilter: TResampleFilter; protected procedure Draw(ACanvas: TCanvas; const Rect: TRect); override; function GetEmpty: Boolean; override; function GetHeight: Integer; override; function GetWidth: Integer; override; procedure SetHeight(Value: Integer); override; procedure SetWidth(Value: Integer); override; procedure WriteData(Stream: TStream); override; procedure ReadData(Stream: TStream); override; public constructor Create; override; destructor Destroy; override; procedure LoadFromStream(Stream: TStream); override; procedure SaveToStream(Stream: TStream); override; procedure LoadFromClipboardFormat(AFormat: Word; AData: THandle; APalette: HPALETTE); {$ifndef FPC} override; {$endif} procedure SaveToClipboardFormat(var AFormat: Word; var AData: THandle; var APalette: HPALETTE); {$ifndef FPC} override; {$endif} procedure Assign(Source: TPersistent); override; property IO: TObject read fio; property ResampleFilter: TResampleFilter read fResampleFilter write fResampleFilter; property IEBitmap: TIEBitmap read bmp; procedure AssignTo(Dest: TPersistent); override; end; {$ifdef IEINCLUDENEURALNET} tdoublepdoublearray = array [0..maxint div 8] of pdoublearray; pdoublepdoublearray = ^tdoublepdoublearray; TLAYER = record Units: integer; // - number of units in this layer Output: pdoublearray; // - output of ith unit Error: pdoublearray; // - error term of ith unit Weight: pdoublepdoublearray; // - connection weights to ith unit WeightSave: pdoublepdoublearray; // - saved weights for stopped training dWeight: pdoublepdoublearray; // - last weight deltas for momentum end; PTLAYER = ^TLAYER; TLAYERARRAY = array [0..maxint div 32] of TLAYER; PTLAYERARRAY = ^TLAYERARRAY; // multilayer backpropagation neural network TIENeurNet = class private LayersDef: pintegerarray; // number of units for each layer LayersDefCount: integer; // layers count Layer: PTLAYERARRAY; // - layers of this net InputLayer: PTLAYER; // - input layer OutputLayer: PTLAYER; // - output layer Alpha: double; // - momentum factor Eta: double; // - learning rate Gain: double; // - gain of sigmoid function Error: double; // - total net error procedure GenerateNetwork; procedure RandomWeights; procedure PropagateLayer(Lower, Upper: PTLAYER); procedure BackpropagateLayer(Upper, Lower: PTLAYER); procedure BackpropagateNet; procedure AdjustWeights; public constructor Create(layerUnits: array of integer); destructor Destroy; override; property Momentum: double read Alpha write Alpha; property LearnRate: double read Eta write Eta; property SigmoidGain: double read Gain write Gain; property NetError: double read Error write Error; procedure SetInput(idx: integer; value: double); overload; procedure SetInput(fromIdx: integer; Input: pdoublearray); overload; procedure SetInput(fromIdx: integer; bitmap: TIEBitmap; colorSpace: integer; srcX, srcY, srcWidth, srcHeight: integer; dstWidth, dstHeight: integer); overload; procedure SetInputAsHist(fromIdx: integer; bitmap: TIEBitmap); overload; function GetOutput(idx: integer): double; overload; procedure GetOutput(Output: pdoublearray); overload; procedure GetOutput(Bitmap: TIEBitmap; w, h: integer); overload; procedure Run; procedure Train(bitmap: TIEBitmap; srcX, srcY, srcWidth, srcHeight: integer; dstWidth, dstHeight: integer; DoTrain: boolean); overload; procedure Train(Target: array of double; DoTrain: boolean); overload; procedure SaveWeights; procedure RestoreWeights; procedure SaveToStream(Stream: TStream); procedure SaveToFile(const FileName: string); procedure LoadFromStream(Stream: TStream); procedure LoadFromFile(const FileName: string); end; {$endif} {$ifdef IEUSEBUFFEREDSTREAM} TIEBufferedReadStream = class(TStream) private fStream: TStream; fBufferSize: integer; fMemory: array of byte; fPosition: int64; fPositionBuf: integer; fSize: int64; fRelativePosition: int64; fOverPosition: boolean; procedure AllocBufferSize(BufferSize: integer); procedure LoadData(); public constructor Create(InputStream: TStream; BufferSize: integer; UseRelativePosition: boolean=true); destructor Destroy; override; function Read(var Buffer; Count: longint): Longint; override; function Write(const Buffer; Count: longint): Longint; override; {$ifdef IEOLDSEEKDEF} function Seek(Offset: longint; Origin: word): longint; override; {$else} function Seek(const Offset: int64; Origin: TSeekOrigin): int64; override; {$endif} property OverPosition: boolean read fOverPosition; end; TIEBufferedWriteStream = class(TStream) private fStream: TStream; fMemory: pbytearray; fBufferSize: integer; fBufferPos: integer; procedure FlushData; public constructor Create(InputStream: TStream; BufferSize: integer); destructor Destroy; override; function Read(var Buffer; Count: longint): Longint; override; function Write(const Buffer; Count: longint): Longint; override; {$ifdef IEOLDSEEKDEF} function Seek(Offset: longint; Origin: word): longint; override; {$else} function Seek(const Offset: int64; Origin: TSeekOrigin): int64; override; {$endif} end; {$else} TIEBufferedReadStream = class(TStream) private fStream: TStream; public constructor Create(InputStream: TStream; BufferSize: integer; UseRelativePosition: boolean=true); destructor Destroy; override; function Read(var Buffer; Count: longint): Longint; override; function Write(const Buffer; Count: longint): Longint; override; {$ifdef IEOLDSEEKDEF} function Seek(Offset: longint; Origin: word): longint; override; {$else} function Seek(const Offset: int64; Origin: TSeekOrigin): int64; override; {$endif} end; TIEBufferedWriteStream = class(TStream) private fStream: TStream; public constructor Create(InputStream: TStream; BufferSize: integer); destructor Destroy; override; function Read(var Buffer; Count: longint): Longint; override; function Write(const Buffer; Count: longint): Longint; override; {$ifdef IEOLDSEEKDEF} function Seek(Offset: longint; Origin: word): longint; override; {$else} function Seek(const Offset: int64; Origin: TSeekOrigin): int64; override; {$endif} end; {$endif} {$IFDEF IEINCLUDEMULTIVIEW} {!! TIESourceType Declaration type TIESourceType = (iestDefault, iestFileIcon, iestFolderIcon, iestCustomImage); Description Returns the method used to fill the content of a frame/thumbnail. Value Description iestDefault The frame is a supported image (or video) type which was loaded normally iestFileIcon The frame is for a file or unsupported image type and was filled by loading the system icon for that file type iestFolderIcon The frame displays a system folder. The system icon for folders will be displayed iestCustomImage The frame is for an unsupported image type and was filled using
!!} TIESourceType = ( // Normal loading iestDefault, // Unsupported type: System icon loaded iestFileIcon, // Unsupported type: a folder, so the icon will be loaded iestFolderIcon, // Unsupported type: Filled with image using OnWrongImage iestCustomImage ); // Contains all info for a single image (except the bitmap) TIEImageInfo = class // the parent TImageEnMView object parent: TObject; // the TImageEnMView parent object // image contained in fImageList // if image is nil the image is not handled by component image: pointer; // image contained in fCacheList // if nil we need to repaint the image cacheImage: pointer; // top/left position X, Y: integer; // row/col position (calculated by UpdateCoords) row, col: integer; // image background color Background: TColor; // File name to load ('' = none) Filename: WideString; // Image ID (-1=none). ID: integer; // Delay time, display time for this image (in millisecs) DTime: Double; // Text TopText: WideString; BottomText: WideString; InfoText: WideString; // last painted internal rect (this the internal image when there is a shadow) internalrect: TRect; // user tag tag: Integer; // user pointer userPointer: pointer; // user dictionary userDict: TIEDictionary; // Generally iestDefault. For unsupported images will be iestFileIcon, iestFolderIcon or iesCustomImage SourceType : TIESourceType; // Checked status of image Checked : Boolean; // File data CreateDate : TDateTime; EditDate : TDateTime; FileSize : Int64; FileTypeIndex : Integer; // Used only for sorting // MD5 Hash of image Hash : AnsiString; constructor Create(Parent_: TObject); destructor Destroy(); override; class function CreateFromStream(Parent: TObject; Stream: TStream; StreamVersion: Byte; LoadCache: Boolean; Images: TIEVirtualImageList; Caches: TIEVirtualImageList): TIEImageInfo; procedure SaveToStream(Stream: TStream; SaveCache: Boolean; Images: TIEVirtualImageList; Caches: TIEVirtualImageList); end; type TIEOnUpdateParams = procedure(Sender : TObject; Operation: Integer; idx : integer; ExtraParam: Integer) of object; {!! TIESaveSnapshotOptions Declaration } TIESaveSnapshotOptions = set of (iessoCompressed, iessoSaveIOParams); {!!} {!! TIEImageNotifyEvent Declaration type TIEImageNotifyEvent = procedure(Sender: TObject; idx: integer) of object; Description Used by . idx is the index of the relevant image. !!} TIEImageNotifyEvent = procedure(Sender: TObject; idx: integer) of object; {!! TIECustomMultiBitmap Description TIECustomMultiBitmap is the ancestor class of and . You should not use it directly. !!} TIECustomMultiBitmap = class private fImageCacheSize: integer; // stored in fImageList.MaxImagesInMemory fImageCacheUseDisk: boolean; // stored in fImageList.UseDisk fOnUpdateParams: TIEOnUpdateParams; fParamsList: TIOMultiParams; // Params of all images if ParamsEnabled has been set to true fLockUpdate: integer; // 0 = Update unlocked fOnChanged: TIEImageNotifyEvent; // Occurs on editing of the image fModified: Boolean; // True if the file has changed since loading function GetImageBitCount(idx: integer): integer; function GetImageCount: integer; function GetImageHash(idx: integer): AnsiString; function GetImageHeight(idx: integer): integer; function GetImageOriginalHeight(idx: integer): integer; function GetImageOriginalWidth(idx: integer): integer; function GetImageTag(idx: integer): integer; function GetImageUserPointer(idx: Integer): pointer; function GetImageWidth(idx: integer): integer; procedure SetImageCacheSize(v: integer); procedure SetImageCacheUseDisk(v: boolean); procedure SetImageOriginalHeight(idx: integer; Value: integer); procedure SetImageOriginalWidth(idx: integer; Value: integer); procedure SetImageTag(idx, v: integer); procedure SetImageUserPointer(idx: Integer; v: pointer); function GetImageBackground(idx: integer): TColor; procedure SetImageBackground(idx: integer; v: TColor); function GetImageDelayTime(idx: integer): Double; procedure SetImageDelayTime(idx: integer; v: Double); function GetParams(idx: integer): TIOParams; function GetParamsEnabled: Boolean; procedure SetParamsEnabled(const Value: Boolean); procedure UpdateParams(Operation: integer; Idx: integer; ExtraParam: Integer); procedure FreeImageInfo(idx: integer); procedure SetImageEx(idx: Integer; srcImage: TIEBaseBitmap); procedure CheckImageLoaded(idx: Integer); function GetImageFileName(idx: integer): WideString; function GetImageDictionary(idx: integer): TIEDictionary; procedure SetImageFileName(idx: integer; v: WideString); procedure SetModified(Value: Boolean); protected fUpdatePending: Boolean; // True when we require update to be called procedure CheckAllocated(idx: integer); virtual; procedure AllocateVirtual(Count: integer); function ValidateIndex(idx: integer): Boolean; procedure Changed(idx: integer); public fBackground: TColor; fImageList: TIEVirtualImageList; fImageInfo: TList; // contains TIEImageInfo structures fOwner: TComponent; // The TImageEnMView this is attached to constructor Create; overload; virtual; constructor Create(bCacheToDisk: Boolean); overload; destructor Destroy; override; function GetImageInfo(idx: integer): TIEImageInfo; function AppendImage(): integer; overload; virtual; function AppendImage(Stream: TStream): integer; overload; virtual; function AppendImage(Bitmap: TIEBitmap): integer; overload; virtual; function AppendImage(MBitmap: TIECustomMultiBitmap): integer; overload; virtual; function AppendImage(Bitmap : TBitmap): integer; overload; virtual; function AppendImage(Width, Height: Integer; PixelFormat: TIEPixelFormat = ie24RGB): Integer; overload; virtual; function AppendImage(const FileName: String): integer; overload; virtual; procedure InsertImage(Idx : integer); overload; virtual; procedure InsertImage(Idx : integer; Stream : TStream); overload; virtual; procedure InsertImage(Idx : integer; Bitmap : TIEBitmap); overload; virtual; procedure InsertImage(Idx : integer; MBitmap : TIECustomMultiBitmap); overload; virtual; procedure InsertImage(Idx : integer; Bitmap : TBitmap); overload; virtual; procedure InsertImage(Idx : integer; Width, Height : integer; PixelFormat : TIEPixelFormat = ie24RGB); overload; virtual; procedure InsertImage(Idx : integer; const FileName : string); overload; virtual; function IndexOf(const Hash: AnsiString): Integer; overload; function IndexOf(Bitmap: TIEBitmap): Integer; overload; procedure GetImageToFile(idx: Integer; const FileName: WideString; IOParams: TIOParams = nil); procedure GetImageToStream(idx: Integer; Stream: TStream; ImageFormat: TIOFileType; IOParams: TIOParams = nil); function GetBitmap(idx: integer): TBitmap; function GetTIEBitmap(idx: integer): TIEBitmap; procedure ReleaseBitmap(idx: Integer; SaveChanges: Boolean); virtual; procedure CopyToIEBitmap(idx: integer; bmp: TIEBitmap); procedure DeleteImage(idx: integer); virtual; procedure PrepareSpaceFor(Width, Height: integer; Bitcount: integer; ImageCount: integer); procedure SetImage(idx: Integer; srcImage: TBitmap); overload; virtual; procedure SetImage(idx: integer; srcImage: TIEBaseBitmap); overload; virtual; procedure SetImage(idx: Integer; width, height: Integer; PixelFormat: TIEPixelFormat); overload; virtual; function SetImage(idx: integer; const FileName: WideString; SourceImageIndex: Integer = 0; FileFormat: TIOFileType = ioUnknown): boolean; overload; virtual; function SetImage(idx: integer; Stream: TStream; SourceImageIndex: Integer = 0; FileFormat: TIOFileType = ioUnknown): boolean; overload; virtual; procedure SaveSnapshot(Stream: TStream; Options: TIESaveSnapshotOptions = [iessoCompressed, iessoSaveIOParams]); overload; procedure SaveSnapshot(const FileName: WideString; Options: TIESaveSnapshotOptions = [iessoCompressed, iessoSaveIOParams]); overload; function LoadSnapshot(Stream: TStream): Boolean; overload; function LoadSnapshot(const FileName: WideString): Boolean; overload; property ImageCacheUseDisk: Boolean read fImageCacheUseDisk write SetImageCacheUseDisk; property ImageCacheSize: integer read fImageCacheSize write SetImageCacheSize default 10; property Count: integer read GetImageCount; property ImageWidth[idx: integer]: integer read GetImageWidth; property ImageHash[idx: integer]: AnsiString read GetImageHash; property ImageHeight[idx: integer]: integer read GetImageHeight; property ImageOriginalWidth[idx: integer]: integer read GetImageOriginalWidth write SetImageOriginalWidth; property ImageOriginalHeight[idx: integer]: integer read GetImageOriginalHeight write SetImageOriginalHeight; property ImageBitCount[idx: integer]: integer read GetImageBitCount; property ImageTag[idx: integer]: integer read GetImageTag write SetImageTag; property ImageUserPointer[idx: Integer]: pointer read GetImageUserPointer write SetImageUserPointer; property ImageFilename[idx: integer]: WideString read GetImageFilename write SetImageFilename; property ImageDictionary[idx: integer]: TIEDictionary read GetImageDictionary; property ParamsEnabled: Boolean read GetParamsEnabled write SetParamsEnabled; property Params[idx: integer]: TIOParams read GetParams; procedure Flip(idx: integer; Dir: TFlipDir); virtual; procedure Rotate(idx: integer; Angle: double; AntialiasMode: TIEAntialiasMode = ierFast; BackgroundColor: TColor = clWhite); virtual; procedure Resample(idx: integer; ScaleBy: Double; FilterType: TResampleFilter = rfNone); virtual; procedure FlipAll(Dir: TFlipDir); procedure RotateAll(Angle: double; AntialiasMode: TIEAntialiasMode = ierFast; BackgroundColor: TColor = clWhite); procedure ResampleAll(ScaleBy: Double; FilterType: TResampleFilter = rfNone); // NOTE: UNDOCUMENTED property ImageBackground[idx: integer]: TColor read GetImageBackground write SetImageBackground; // NOTE: UNDOCUMENTED property ImageDelayTime[idx: integer]: Double read GetImageDelayTime write SetimageDelayTime; // Used by TImageEnMIO to re-align the params when images are moved // NOTE: UNDOCUMENTED property OnUpdateParams : TIEOnUpdateParams read fOnUpdateParams write fOnUpdateParams; // Not documented: List of all params property ParamsList: TIOMultiParams read fParamsList; procedure Clear; procedure LockUpdate; function UnlockUpdate: Integer; procedure Update; virtual; procedure UpdateEx(bFullUpdate: Boolean = true); virtual; {!! TIECustomMultiBitmap.LockUpdateCount Declaration property LockUpdateCount: Integer; Description Returns the current state of update locking. A value of 0 means no locking. A value greater than zero means locking is in place (i.e. updating is disabled). Calling increments , decrements it. !!} property LockUpdateCount: integer read fLockUpdate; // Internal use only function SetImageFromStreamOrFile(idx: integer; Stream: TStream; const FileName: WideString; SourceImageIndex: Integer; FileFormat: TIOFileType; MIO: TObject = nil): Boolean; virtual; procedure SetActiveImage(idx: integer); virtual; function InternalLoadImageByID_Assigned(): Boolean; virtual; procedure InternalLoadImageByID(Sender: TObject; Index, ID: Integer; var Bitmap: TIEBitmap; var IOParams: TIOParams); virtual; {!! TIECustomMultiBitmap.OnChanged Declaration property OnChanged: ; Description Occurs whenever the TIEMultiBitmap is modified, e.g. by appending, inserting or deleting frames, or maniputation of individual frames (e.g. by ). Note: If an image is modified then idx with a valid index. For frame addition, removal and movement, idx will be -1. See Also - !!} property OnChanged: TIEImageNotifyEvent read fOnChanged write fOnChanged; {!! TIECustomMultiBitmap.Modified Declaration property Modified: Boolean; Description Returns true if the image has changed since loading. See Also - !!} property Modified: Boolean read fModified write SetModified; end; {!! TIEMultiBitmap Description TIEMultiBitmap is an array of images. It allows you to work with multiple-frame images in memory, such as GIF, TIFF, AVI, etc. It is also used by to store images within the grid. Methods and Properties General Page Editing Image Access Image Information Input/Output (Load from file/stream) (Save to file/stream) Input/Output Parameters (Meta-Data) Animation and Effects Image Manipulation See Also - !!} TIEMultiBitmap = class( TIECustomMultiBitmap ) private protected public constructor Create(ImageWidth, ImageHeight: integer; PageCount: integer; ImagePixelFormat: TIEPixelFormat = ie24RGB); overload; constructor Create(MBitmap: TIECustomMultiBitmap); overload; constructor Create(const FileName: string); overload; procedure Assign(Source: TObject); // for TIEMultiBitmap, TImageEnMView, TIEBitmap and TBitmap function AppendSplit(SourceGrid: TIEBitmap; cellWidth: Integer; cellHeight: Integer; maxCount: Integer = 0): Integer; procedure MoveImage(idx: integer; destination: integer); procedure SwapImages(idx1, idx2: Integer); procedure InsertTransitionFrames(Idx : integer; iFrameCount : Integer; Effect : TIETransitionType; iWidth : Integer = -1; iHeight : Integer = -1; BackgroundColor : TColor = clBlack; ResamplingFilter: TResampleFilter = rfFastLinear); procedure InsertTransitionFramesEx(Idx : integer; iFrameCount : Integer; Effect : TIETransitionType; StartRect, EndRect : TRect; RectMaintainAspectRatio : boolean = True; iWidth : Integer = -1; iHeight : Integer = -1; bStretchSmall : Boolean = False; BackgroundColor : TColor = clBlack; ResamplingFilter: TResampleFilter = rfFastLinear; Smoothing: Integer = 96; Timing : TIETransitionTiming = iettLinear); function RemoveBlankPages(Tolerance: Double = 0; Complete: boolean = true; LeftToRight: boolean = true): Integer; function RemoveDuplicates(): Integer; procedure SetImageRect(idx: integer; srcImage: TBitmap; x1, y1, x2, y2: integer); overload; procedure SetImageRect(idx: integer; srcImage: TIEBitmap; x1, y1, x2, y2: integer); overload; function Read(const FileName: string; IOParams: TIOMultiParams = nil; bCheckUnknown: Boolean = False): boolean; overload; function Read(Stream: TStream; FileType: TIOFileType = 0; IOParams: TIOMultiParams = nil): boolean; overload; function Read(Buffer: pointer; BufferSize: integer; FileType: TIOFileType = 0; IOParams: TIOMultiParams = nil): boolean; overload; function Write(const FileName: string; IOParams: TIOMultiParams = nil): boolean; overload; function Write(Stream: TStream; FileType: TIOFileType; IOParams: TIOMultiParams = nil): boolean; overload; procedure DuplicateCompressionInfo; procedure FillFromDirectory(const Directory: WideString; Limit : integer = -1; AllowUnknownFormats : boolean = false; const ExcludeExtensions : WideString = ''; DetectFileFormat : boolean = false; const FilterMask : WideString = ''; bGetHiddenFiles : Boolean = False); end; {$ENDIF} // IEINCLUDEMULTIVIEW // TIEMultiBitmap /////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////// TIETIFFImage = class(TIEGraphicBase) end; TIEGIFImage = class(TIEGraphicBase) end; TIEJpegImage = class(TIEGraphicBase) end; TIEPCXImage = class(TIEGraphicBase) end; TIEBMPImage = class(TIEGraphicBase) end; TIEICOImage = class(TIEGraphicBase) end; {$IFDEF IEINCLUDEPNG} TIEPNGImage = class(TIEGraphicBase) end; {$ENDIF} TIETGAImage = class(TIEGraphicBase) end; TIEPXMImage = class(TIEGraphicBase) end; {$IFDEF IEINCLUDEJPEG2000} TIEJP2Image = class(TIEGraphicBase) end; TIEJ2KImage = class(TIEGraphicBase) end; {$ENDIF} TIEPSDImage = class(TIEGraphicBase) end; {$ifdef IEINCLUDEPDFWRITING} ////////////////////////////////////////////////////////////////////////////// // PDF support // base class for all objects( direct and indirect ) // for indirect object: // ObjectNumber is not included because it always starts at 1 // GenerationNumber is not included because it is always 0 TIEPDFObject = class Index: integer; Position: integer; // position inside the start of stream (wrote when we save the objects to the stream) DontFree: boolean; // if True the parent doesn't free this object constructor Create; destructor Destroy; override; procedure Write(Stream: TStream); virtual; abstract; end; // object reference TIEPDFRefObject = class(TIEPDFObject) ObjectNumber: integer; GenerationNumber: integer; constructor Create(ObjNumber: integer; GenNumber: integer); procedure Write(Stream: TStream); override; end; // boolean object TIEPDFBooleanObject = class(TIEPDFObject) Value: boolean; constructor Create(vv: boolean); procedure Write(Stream: TStream); override; end; // numeric object TIEPDFNumericObject = class(TIEPDFObject) Value: double; constructor Create(vv: double); procedure Write(Stream: TStream); override; end; // string object TIEPDFStringObject = class(TIEPDFObject) Value: AnsiString; constructor Create(vv: AnsiString); procedure Write(Stream: TStream); override; end; // name object TIEPDFNameObject = class(TIEPDFObject) Value: AnsiString; constructor Create(vv: AnsiString); // do not specify '\' procedure Write(Stream: TStream); override; end; // array object TIEPDFArrayObject = class(TIEPDFObject) Items: TList; constructor Create; destructor Destroy; override; procedure Write(Stream: TStream); override; end; // dictionary object TIEPDFDictionaryObject = class(TIEPDFObject) items: TStringList; // Items[] for key (without '/') and Objects[] for values constructor Create; destructor Destroy; override; procedure Write(Stream: TStream); override; end; // stream object TIEPDFStreamObject = class(TIEPDFObject) data: pointer; length: integer; dict: TIEPDFDictionaryObject; cache: TIETemporaryFileStream; constructor Create; constructor CreateCopy(copydata: pointer; copylength: integer); destructor Destroy; override; procedure Write(Stream: TStream); override; procedure FlushToCache(); end; procedure iepdf_WriteHeader(Stream: TStream); procedure iepdf_WriteFooter(Stream: TStream; IndirectObjects: TList; info: TIEPDFObject); procedure iepdf_WriteIndirectObjects(Stream: TStream; IndirectObjects: TList); function iepdf_AddCatalog(IndirectObjects: TList): TIEPDFDictionaryObject; function iepdf_AddPageTree(IndirectObjects: TList; pages: TList): TIEPDFDictionaryObject; procedure iepdf_AddPage(IndirectObjects: TList; pages: TList; Resources: TIEPDFDictionaryObject; MediaBox: TIEPDFArrayObject; Content: integer); procedure iepdf_AddIndirectObject(IndirectObjects: TList; obj: TIEPDFObject); procedure iepdf_WriteLn(Stream: TStream; line: AnsiString); procedure iepdf_Write(Stream: TStream; line: AnsiString); {$endif} // IEINCLUDEPDFWRITING function IEPDFFrameCount(const Filename: WideString): integer; overload; function IEPDFFrameCount(Stream: TStream): integer; overload; // End of PDF support ////////////////////////////////////////////////////////////////////////////// type EIERFBError = class(Exception); {$ifdef IERFBPROTOCOL} {!! TIERFBClipboardTextEvent Declaration TIERFBClipboardTextEvent = procedure(Sender: TObject; Text: AnsiString) of object; Description Declaration for clipboard messages from RFB server. !!} TIERFBClipboardTextEvent = procedure(Sender: TObject; Text: AnsiString) of object; {!! TIERFBUpdateRectEvent Declaration TIERFBUpdateRectEvent = procedure(Sender: TObject; Rect: TRect) of object; Description Declaration for update rectangle messages from RFB server. !!} TIERFBUpdateRectEvent = procedure(Sender: TObject; Rect: TRect) of object; {!! EIERFBError Declaration EIERFBError = class(Exception); Description Generic RFB exception. !!} TIERFBClient = class; TIERFBMessageThread = class(TThread) private m_client: TIERFBClient; m_clipboardText: AnsiString; m_updatedRect: TRect; procedure CopyRawRow(var src: pbyte; dst: pbyte; columns: integer); procedure msg_FrameBufferUpdate; procedure msg_SetColourMapEntries; procedure msg_Bell; procedure msg_ServerCutText; procedure DoOnUpdate; procedure DoOnUpdateNonSync; procedure DoOnUpdateRect; procedure DoOnBell; procedure DoOnClipboardText; procedure DoOnUpdateScreenSize; procedure UpdateCursorShape; public constructor Create(Client: TIERFBClient); destructor Destroy(); override; procedure Execute; override; end; {!! TIERFBPixelFormat Declaration TIERFBPixelFormat = (ierfbPalette256, ierfbRGB16, ierfbRGB32); Description Specifies the connection pixel format (this is not the framebuffer pixelformat, which is always 24 bit RGB). Value Description ierfbPalette256 256 colors palette. ierfbRGB16 RGB packed inside words of 16 bits. ierfbRGB32 RGB, 8 bit per channel. Last byte discarded.
!!} TIERFBPixelFormat = (ierfbPalette256, ierfbRGB16, ierfbRGB32); {!! TIERFBClient Description TIERFBClient implements a RFB (Remote Frame Buffer) client. It can connect to any RFB compatible server like RealVNC, TightVNC, VMWare virtual machines or Macintosh remote desktop. Currently implemented features: Protocol 3.3, 3.7 and 3.8 Authentication No authentication or VNC (DES) authentication Pixel format 8 bit with RGB palette, 16 bit RGB, 32 bit RGB Client messages SetPixelFormat, SetEncodings, FrameBufferUpdateRequest, KeyEvent, PointerEvent, ClientCutText Server messages FrameBufferUpdate, SetColorMapEntries, Bell, ServerCutText Keyboard Limited support (CTRL-?, ALT-? could require more code by application) Encodings Raw, CopyRect, RRE, Cursor, DesktopSize Cursor Cursor shape and drawing local handled
Notes: - Keysending doesn't support all key combinations (like CTRL-?, ALT-?, etc...), so applications should handle these combination manually. - Requires at least Windows 2000. Demos Demos\VideoCapture\RFB_VNCViewer1\VNCViewer1.dpr Demos\VideoCapture\RFB_VNCViewer2\VNCViewer2.dpr Methods and properties
Connect/Disconnect Server Properties Commands Framebuffer Access (accessing frame buffer or cursor) Frame Buffer and Cursor Bitmaps Events !!} TIERFBClient = class private m_socket: TIEClientSocket; m_frameBufferSize: TSize; m_bitsPerPixel: byte; m_depth: byte; m_bigEndianFlag: byte; m_trueColorFlag: byte; m_redMax: word; m_greenMax: word; m_blueMax: word; m_redShift: byte; m_greenShift: byte; m_blueShift: byte; m_name: AnsiString; m_frameBuffer: TIEBitmap; m_freeFrameBuffer: boolean; m_OnUpdateRect: TIERFBUpdateRectEvent; m_OnUpdate: TNotifyEvent; m_OnUpdateNonSync: TNotifyEvent; m_OnBell: TNotifyEvent; m_OnClipboardText: TIERFBClipboardTextEvent; m_OnCursorShapeUpdated: TNotifyEvent; m_OnUpdateScreenSize: TNotifyEvent; m_msgThread: TIERFBMessageThread; m_colorMap: array of TRGB48; m_pixelFormat: TIERFBPixelFormat; m_cursor: TIEBitmap; m_cursorPos: TPoint; m_cursorHotSpot: TPoint; m_savedCursorArea: TIEBitmap; m_savedCursorPos: TPoint; m_frameBufferLock: TCriticalSection; m_socketSendLock: TCriticalSection; m_suspended: boolean; // bypass framebuffer updates procedure SendSetPixelFormat(pixelFormat: TIERFBPixelFormat); // call it only inside "Connect", otherwise we con't know if a msg_FrameBufferUpdate message has the new pixel format function GetConnected: boolean; procedure PaintCursor; procedure RemoveCursor; procedure SetSuspended(value: boolean); public constructor Create(FrameBuffer: TIEBitmap = nil); destructor Destroy; override; // connect/disconnect procedure Connect(const Address: string; Port: word = 5900; const Password: AnsiString = ''); procedure Disconnect(); {!! TIERFBClient.Connected Declaration property Connected: boolean; Description Returns true when connection is active. See Also - - !!} property Connected: boolean read GetConnected; {!! TIERFBClient.Suspended Declaration property Suspended: boolean; Description Setting this property you can suspend frame buffer updates. This is useful when applications need to do some processing on the framebuffer (like save it). When suspended TIERFBClient continues to receive messages and updates from the server, but they do not update the frame buffer. Events like and are disabled when connection is in suspended state. Example rfb.Suspended := true; try ImageEnView.IO.SaveToFile('curentframe.jpg'); finally rfb.Suspended := false; end; !!} property Suspended: boolean read m_suspended write SetSuspended; // server properties {!! TIERFBClient.ScreenSize Declaration property ScreenSize: TSize; Description Returns the server screen size (width and height in pixels). This may change after event. !!} property ScreenSize: TSize read m_frameBufferSize; {!! TIERFBClient.ScreenName Declaration property ScreenName: AnsiString; Description Returns the server screen name. !!} property ScreenName: AnsiString read m_name; {!! TIERFBClient.ScreenPixelFormat Declaration property ScreenPixelFormat: ; Description Specifies connection pixel format (this is not the framebuffer pixelformat, which is always 24 bit RGB). Applications must set this property before start the connection. Default: ierfbRGB32 Example with TIERFBClient.Create do begin rfb.ScreenPixelFormat := ierfbPalette256; rfb.Connect('A_VNC_Server'); ... end; !!} property ScreenPixelFormat: TIERFBPixelFormat read m_pixelFormat write m_pixelFormat default ierfbRGB32; // commands procedure SendRequestUpdate(x, y, width, height: word; incremental: boolean); overload; procedure SendRequestUpdate(incremental: boolean = true); overload; procedure SendPointerEvent(x, y: integer; LeftButton: boolean; MiddleButton: boolean; RightButton: boolean); procedure SendKeyEvent(xkey: dword; down: boolean); overload; procedure SendKeyEvent(VirtualKey: dword; KeyData: dword; down: boolean); overload; procedure SendClipboard(const Text: AnsiString); // framebuffer access (to access frame buffer or cursor) procedure LockFrameBuffer; procedure UnlockFrameBuffer; // frame buffer and cursor bitmaps {!! TIERFBClient.FrameBuffer Declaration property FrameBuffer: ; Description Contains the bitmap where TIERFBClient will paint the server screen. This bitmap could be external (for instance a TImageEnView.IEBitmap) or internal (created and owned by TIERFBClient object). See Also - - - - !!} property FrameBuffer: TIEBitmap read m_frameBuffer; {!! TIERFBClient.Cursor Declaration property Cursor: ; Description Returns last cursor shape sent by the server. See Also - - !!} property Cursor: TIEBitmap read m_cursor; // events {!! TIERFBClient.OnUpdateRect Declaration property OnUpdateRect: ; Description Occurs whenever server updates a single frame buffer rectangle. Because multiple rectangle updates can be sent in a single message so is also sent after a sequence of OnUpdateRect messages. !!} property OnUpdateRect: TIERFBUpdateRectEvent read m_OnUpdateRect write m_OnUpdateRect; {!! TIERFBClient.OnUpdate Declaration property OnUpdate: TNotifyEvent; Description Occurs after a sequence of rectangles has been updated (see . Example // this is the common way to handle OnUpdate events using ImageEnView1.IEBitmap has framebuffer procedure TForm.OnRFBUpdate(Sender: TObject); begin ImageEnView1.Update; end; // this is the common way to handle OnUpdate events using TIERFBClient owned frame buffer procedure TForm.OnRFBUpdate(Sender: TObject); begin rfb.LockFrameBuffer; ImageEnView1.IEBitmap.Assign( rfb.FrameBuffer ); rfb.UnlockFrameBuffer; ImageEnView1.Update; end; !!} property OnUpdate: TNotifyEvent read m_OnUpdate write m_OnUpdate; property OnUpdateNonSync: TNotifyEvent read m_OnUpdateNonSync write m_OnUpdateNonSync; {!! TIERFBClient.OnBell Declaration property OnBell: TNotifyEvent; Description Occurs whenever the server sends "bell" message. !!} property OnBell: TNotifyEvent read m_OnBell write m_OnBell; {!! TIERFBClient.OnClipboardText Declaration property OnClipboardText: ; Description Occurs whenever the server sends clipboard text (user on the server Copies or Cuts some text). !!} property OnClipboardText: TIERFBClipboardTextEvent read m_OnClipboardText write m_OnClipboardText; {!! TIERFBClient.OnCursorShapeUpdated Declaration property OnCursorShapeUpdated: TNotifyEvent; Description Occurs whenever the cursor shape () is updated. Cursor is painted automatically, so you don't need to handle this event or to read Cursor bitmap. !!} property OnCursorShapeUpdated: TNotifyEvent read m_OnCursorShapeUpdated write m_OnCursorShapeUpdated; {!! TIERFBClient.OnUpdateScreenSize Declaration property OnUpdateScreenSize: TNotifyEvent; Description Occurs whenever server changes desktop size. The framebuffer will be automatically resized. !!} property OnUpdateScreenSize: TNotifyEvent read m_OnUpdateScreenSize write m_OnUpdateScreenSize; end; TIE3DESMode = (ie3desENCRYPT, ie3desDECRYPT); TIE3DES = class private KnL: array [0..31] of dword; procedure scrunch(outof: pbyte; into: pdword); procedure unscrun(outof: pdword; into: pbyte); procedure desfunc(block: pdwordarray; keys: pdword); procedure cookey(raw1: pdword); procedure usekey(from: pdword); procedure deskey(key: pbytearray; edf: TIE3DESMode); procedure des(inblock: pbyte; outblock: pbyte); public constructor Create(); overload; constructor Create(const Password: AnsiString; Mode: TIE3DESMode); overload; destructor Destroy; override; procedure Reset(const Password: AnsiString; Mode: TIE3DESMode); overload; procedure Reset(Password: int64; Mode: TIE3DESMode); overload; procedure Transform(InBlock: pbyte; OutBlock: pbyte; Length: integer); end; {$endif} /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // TIEImageList TIEImageListItem = class public image: TIEBitmap; filename: WideString; constructor Create(image_: TIEBitmap; filename_: WideString); end; {!! TIEImageList Declaration TIEImageList = class; Description A simple in-memory list of images. Methods and Properties Demo Demos\Display\ManualFlow\ManualFlow.dpr !!} TIEImageList = class private m_images: TList; function GetImageCount(): integer; function GetImage(idx: integer): TIEBitmap; procedure SetImage(idx: integer; value: TIEBitmap); function GetFilename(idx: integer): WideString; procedure SetFilename(idx: integer; value: WideString); public constructor Create(); destructor Destroy(); override; procedure Clear(); procedure FillFromDirectory(const Directory: WideString; Limit : integer = -1; AllowUnknownFormats : boolean = false; const ExcludeExtensions : WideString = ''; DetectFileFormat : boolean = false; const FilterMask : WideString = ''; IncludeVideoFiles : Boolean = False); function AppendImageRef(image: TIEBitmap; filename: WideString): integer; procedure Remove(imageIndex: integer); property ImageCount: integer read GetImageCount; property Image[idx: integer]: TIEBitmap read GetImage write SetImage; default; property Filename[idx: integer]: WideString read GetFilename write SetFilename; end; /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // TIEEquirectangularRenderer {$ifdef IEINCLUDEEQUIRECTANGULARRENDERER} {!! TIEEquirectangularRendererQuality Declaration } TIEEquirectangularRendererQuality = (ierqLow, ierqHigh); {!!} {!! TIEEquirectangularRenderer Declaration TIEEquirectangularRenderer = class(); Description Use TIEEquirectangularRenderer as bitmap provider for property to display equirectangular images (Google Android PhotoSphere 360° panoramic images). Methods and Properties Demo Demos\Other\Photosphere\Photosphere.dpr Example ImageEnViewContainer.IO.LoadFromFile('panoimage.jpg'); ImageEnViewDisplayer.LegacyBitmap := false; ImageEnViewDisplayer.IEBitmap.VirtualBitmapProvider := TIEEquirectangularRenderer.Create(ImageEnViewContainer.IEBitmap, ImageEnViewContainer.IO.Params, false); ImageEnViewDisplayer.Update(); !!} TIEEquirectangularRenderer = class(TIEVirtualBitmapProvider) private m_segmentBuffer: TIEBitmap; // buffer for GetSegement implementation m_source: TIEBitmap; m_ownSource: boolean; m_arccos_tab: array [-10000..10000] of double; m_cam_heading: double; m_cam_pitch: double; m_cam_fov: double; m_quality: TIEEquirectangularRendererQuality; procedure Init(Source: TIEBitmap; IOParams: TObject; OwnSource: boolean); procedure RenderLowQuality(Container: TIEBitmap; DestBitmap: TIEBitmap; DestWidth: integer; DestHeight: integer; DestX1, DestY1, DestX2, DestY2: integer; SrcCols, SrcRows: PInteger; Transparency: integer; RenderOperation: TIERenderOperation; Opacity: double); procedure RenderHighQuality(Container: TIEBitmap; DestBitmap: TIEBitmap; DestWidth: integer; DestHeight: integer; DestX1, DestY1, DestX2, DestY2: integer; SrcCols, SrcRows: PInteger; Transparency: integer; RenderOperation: TIERenderOperation; Opacity: double); public constructor Create(Source: TIEBitmap; IOParams: TObject; OwnSource: boolean); overload; // IOParams must be TIOParams constructor Create(SourceView: TObject); overload; // SourceView must be TImageEnView destructor Destroy(); override; // TIEVirtualBitmapRenderer implementation procedure Render(Container: TIEBitmap; DestBitmap: TIEBitmap; DestWidth: integer; DestHeight: integer; DestX1, DestY1, DestX2, DestY2: integer; SrcCols, SrcRows: PInteger; Transparency: integer; RenderOperation: TIERenderOperation; Opacity: double); override; function GetSegment(Container: TIEBitmap; Row: integer; Col: integer; Width: integer): pointer; override; {!! TIEEquirectangularRenderer.Quality Declaration property Quality: ; Description Specifies the rendering quality. Lowest quality speedup rendering. Default: ierqLow !!} property Quality: TIEEquirectangularRendererQuality read m_quality write m_quality; {!! TIEEquirectangularRenderer.CamHeading Declaration property CamHeading: double; Description Specifies the camera heading (horizontal movement) in degrees. Range: 0 to 360 degrees !!} property CamHeading: double read m_cam_heading write m_cam_heading; {!! TIEEquirectangularRenderer.CamPitch Declaration property CamPitch: double; Description Specifies the camera pitch (vertical movement) in degrees. Range: 0 (looking straight up) to 180 (looking straight down). !!} property CamPitch: double read m_cam_pitch write m_cam_pitch; {!! TIEEquirectangularRenderer.CamFov Declaration property CamFov: double; Description Specifies the camera FOV (Field Of View) in degrees, from 0 up to 90. Default: 90 !!} property CamFov: double read m_cam_fov write m_cam_fov; end; {$endif} /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // IIELoadPicture IIELoadPicture = interface ['{A7CC5606-1E6C-4A7D-972C-6464A392A278}'] procedure LoadPicture(); end; /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // TIESlippyMap {$ifdef IEINCLUDESLIPPYMAP} {!! TIESlippyMapProvider Declaration TIESlippyMapProvider = (iesmpOSM_Mapnik, iesmpOpenCycleMap, iesmpOpenCycleMapTransport, iesmpCloudMadeWebStyle, iesmpCloudMadeFineLineStyle, iesmpCloudMadeNoNamesStyle, iesmpMapQuest, iesmpMapQuestOpenAerial, iesmpMigurskisTerrain); Description Specifies the slippy-map source. See this link for more details: wiki.openstreetmap.org/wiki/Slippy_map_tilenames Map Provider Zoom range Description iesmpOSM_Mapnik 0-18 OSM Mapnik iesmpOpenCycleMap 0.16 OpenCycleMap iesmpOpenCycleMapTransport 0-18 OpenCycleMap Transport iesmpCloudMadeWebStyle 0-18 CloudMade (Web style). Requires registration at cloudmade.com and setting of . iesmpCloudMadeFineLineStyle 0-18 CloudMade (Fine line style). Requires registration at cloudmade.com and setting of . iesmpCloudMadeNoNamesStyle 0-18 CloudMade (NoNames style). Requires registration at cloudmade.com and setting of . iesmpMapQuest Discontinued! MapQuest iesmpMapQuestOpenAerial Discontinued! MapQuest Open Aerial iesmpMigurskisTerrain 4-18, US-only (for now) Migurski's Terrain
!!} TIESlippyMapProvider = (iesmpOSM_Mapnik, iesmpOpenCycleMap, iesmpOpenCycleMapTransport, iesmpCloudMadeWebStyle, iesmpCloudMadeFineLineStyle, iesmpCloudMadeNoNamesStyle, iesmpMapQuest, iesmpMapQuestOpenAerial, iesmpMigurskisTerrain); TIESlippyMapQueueItem = class public tile: TPoint; zoom: integer; bmp: TIEBitmap; destBitmap: TIEBitmap; destPos: TPoint; io: TObject; // running TImageEnIO, nil = waiting state: (iesmqWAIT, iesmqLOAD, iesmqSAVE, iesmqEND); constructor Create(tile_: TPoint; zoom_: integer; destBitmap_: TIEBitmap; destPos_: TPoint); destructor Destroy(); override; end; {!! TIESlippyMap Declaration TIESlippyMap = class(); Description Slippy Map is a term referring to the main openstreetmap.org map display, a web interface for browsing rendered OpenStreetMap data (from openstreetmap wiki). See this link for more details: wiki.openstreetmap.org/wiki/Slippy_Map TIESlippyMap is a virtual image provider for objects. Selecting a position using Latitude and Longitude a map (an image) will be loaded and handled as TIEBitmap content. Local caching is provided to speed up re-loading tiles and to support off-line jobs. Example ImageEnView1.LegacyBitmap := false; ImageEnView1.IEBitmap.VirtualBitmapProvider := TIESlippyMap.Create(); with TIESlippyMap(ImageEnView1.IEBitmap.VirtualBitmapProvider) do begin // move to London Latitude := 51.503614574056016; Longitude := -0.12774750793460043; // location at bitmap center PointPosition := Point(ImageEnView1.IEBitmap.Width div 2, ImageEnView1.IEBitmap.Height div 2); // zoom Zoom := 14; end; ImageEnView1.Update(); Methods and Properties Constructor Generic Rendering TIEVirtualBitmapProvider rendering Multithreading and Cache Map Coordinates and Zooming Coordinates Conversion Others Demo Demos\Other\GeoMaps\GeoMaps.dpr !!} TIESlippyMap = class(TIEVirtualBitmapProvider) private m_providerURL: string; m_providerURLIndex: integer; m_loadQueue: TList; // a list of TIESlippyMapQueueItem m_maxThreads: integer; // 0 = number of provider servers count (default) m_cachePath: string; // path of local cache (ex: "C:\myprog\cache"). Empty string is "no cache" m_segmentBuffer: TIEBitmap; // buffer for GetSegement implementation m_latitude: double; // current latitude in decimal degrees m_longitude: double; // current longitude in decimal degrees m_pointPosition: TPoint; // where specified (Latitude, longitude) are located inside rendered bitmap m_zoom: integer; // current zoom (1..) m_memoryCacheSize: integer; // max number of items in memory cache m_memoryCache: TList; // memory cache m_userKey: string; // user key. $0 tag in provider URL m_missingTileColor: TColor; // missing tile color m_OnBeginWork: TNotifyEvent; // Before download/loading m_OnFinishWork: TNotifyEvent; // After download/loading procedure init(const providerURL: string; const cachePath: string); procedure SetLatitude(value: double); procedure SetLongitude(value: double); protected class function LongitudeToTileX(longitude: double; zoom: integer): integer; class function LatitudeToTileY(latitude: double; zoom: integer): integer; class function TileXToLongitude(tileX: integer; zoom: integer): double; class function TileYToLatitude(tileY: integer; zoom: integer): double; class function CoordXToLongitude(coordX: integer; tileX: integer; zoom: integer): double; class function CoordYToLatitude(coordY: integer; tileY: integer; zoom: integer): double; class function LongitudeToCoordX(longitude: double; zoom: integer): integer; class function LatitudeToCoordY(latitude: double; zoom: integer): integer; function GetProviderURL(): string; function GetProviderURLCount(): integer; function GetFileURL(tileX: integer; tileY: integer): string; function GetCachedFileName(tileX: integer; tileY: integer): string; function ProcessQueue(): boolean; procedure AddTileToLoadQueue(tile: TPoint; destBitmap: TIEBitmap; destPos: TPoint); procedure WaitLoadQueue(); procedure ClearLoadQueue(); procedure ClearMemoryCache(); procedure AddItemToMemoryCache(item: TIESlippyMapQueueItem); procedure CalcTopLeftTileAndPos(var startTile: TPoint; var startPos: TPoint); function WrapHorizTile(tileX: integer): integer; public constructor Create(const providerURL: string; const cachePath: string = ''); overload; constructor Create(provider: TIESlippyMapProvider = iesmpMapQuest; const cachePath: string = ''); overload; destructor Destroy(); override; procedure DrawTo(destBitmap: TIEBitmap); // TIEVirtualBitmapProvider implementation procedure Render(Container: TIEBitmap; DestBitmap: TIEBitmap; DestWidth: integer; DestHeight: integer; DestX1, DestY1, DestX2, DestY2: integer; SrcCols, SrcRows: PInteger; Transparency: integer; RenderOperation: TIERenderOperation; Opacity: double); override; function GetSegment(Container: TIEBitmap; Row: integer; Col: integer; Width: integer): pointer; override; {!! TIESlippyMap.MaxThreads Declaration property MaxThreads: integer; Description Specifies the maximum number of loading threads. Each thread loads and caches a single map tile (256x256). If MaxThreads is zero then as many threads will be created as the number of online provider mirrors. Default: 0 !!} property MaxThreads: integer read m_maxThreads write m_maxThreads; {!! TIESlippyMap.CachePath Declaration property CachePath: string; Description Defines a path where cached map tiles are stored. Local caching is provided to speed up re-loading tiles and to support off-line jobs. Example TIESlippyMap(ImageEnView1.IEBitmap.VirtualBitmapProvider).CachePath := 'C:\mapcache'; !!} property CachePath: string read m_cachePath write m_cachePath; {!! TIESlippyMap.MemoryCacheSize Declaration property MemoryCacheSize: integer; Description Specifies how many tiles to maintain in memory. Each tile requires about 192KB. Default: 50 !!} property MemoryCacheSize: integer read m_MemoryCacheSize write m_MemoryCacheSize; {!! TIESlippyMap.Latitude Declaration property Latitude: double; Description Specifies the latitude of point position () in decimal degrees. Allowed range is between -85 and 85 degrees. See Also - - - Example // move to London with TIESlippyMap(ImageEnView1.IEBitmap.VirtualBitmapProvider) do begin Latitude := 51.503614574056016; Longitude := -0.12774750793460043; end; ImageEnView1.Update(); !!} property Latitude: double read m_latitude write SetLatitude; {!! TIESlippyMap.Longitude Declaration property Longitude: double; Description Specifies the longitude of point position () in decimal degrees. Allowed range is between -180 and 180 degrees. See Also - - - Example // move to London with TIESlippyMap(ImageEnView1.IEBitmap.VirtualBitmapProvider) do begin Latitude := 51.503614574056016; Longitude := -0.12774750793460043; end; ImageEnView1.Update(); !!} property Longitude: double read m_longitude write SetLongitude; {!! TIESlippyMap.Zoom Declaration property Zoom: integer; Description Specifies the zoom level (0-...). Level 0 is the minimum zoom, supported by all map 1providers. Maximum zoom is map provider specific. See for maximum value for each map provider. This property has nothing to do with which specifies the image zoom, while TIESlippyMap.Zoom specifies the map source zoom. Example TIESlippyMap(ImageEnView1.IEBitmap.VirtualBitmapProvider).Zoom := 14; ImageEnView1.Update(); !!} property Zoom: integer read m_zoom write m_zoom; {!! TIESlippyMap.PointPosition Declaration property PointPosition: TPoint; Description Specifies where the map point at and is located within the object. Example // show point 51.503614574056016, -0.12774750793460043 at the center of bitmap with TIESlippyMap(ImageEnView1.IEBitmap.VirtualBitmapProvider) do begin PointPosition := Point(ImageEnView1.IEBitmap.Width div 2, ImageEnView1.IEBitmap.Height div 2); Latitude := 51.503614574056016; Longitude := -0.12774750793460043; end; ImageEnView1.Update(); !!} property PointPosition: TPoint read m_pointPosition write m_pointPosition; {!! TIESlippyMap.UserKey Declaration property UserKey: string; Description Specifies the user key for map providers that requires registration (like cloudmade.com). !!} property UserKey: string read m_userKey write m_userKey; {!! TIESlippyMap.MissingTileColor Declaration property MissingTileColor: TColor; Description Specifies a fill color when a tile is unavailable (ie upper/bottom boundaries of the map) !!} property MissingTileColor: TColor read m_missingTileColor write m_missingTileColor; // Coordinates conversions function BmpXToLongitude(X: integer): double; function BmpYToLatitude(Y: integer): double; function LongitudeToBmpX(lon: double): integer; function LatitudeToBmpY(lat: double): integer; {!! TIESlippyMap.OnBeginWork Declaration property OnBeginWork: TNotifyEvent; Description Occurs before downloading map tiles. Useful for displaying a hourglass cursor. See Also - !!} property OnBeginWork: TNotifyEvent read m_OnBeginWork write m_OnBeginWork; {!! TIESlippyMap.OnFinishWork Declaration property OnFinishWork: TNotifyEvent; Description Occurs after downloading map tiles. Useful for resetting the cursor. See Also - !!} property OnFinishWork: TNotifyEvent read m_OnFinishWork write m_OnFinishWork; end; {$endif} type {!! TIEFindFormatMethod Declaration type TIEFindFormatMethod = (ffContentOnly, ffVerifyByExtension, ffFallbackToExtension); Description Methods used by to determine the type of an image: Value Description ffContentOnly Only the content of the file is examined. The filename is ignored (No extension checking) ffVerifyByExtension The content is examined to determine the type. This is then compared to the file extension and ioUnknown is returned if the type does not match (Strict extension checking) ffFallbackToExtension The content is examined to determine the type. If it cannot be determined (which can happen with some Dicom and Raw formats), then the type is guessed by the file extension (Optimistic extension checking)
Example // Determine the file type only by examining the file header/content if FindFileFormat( sFilename, ffContentOnly ) = ioJPEG then ShowMessage( 'File content is JPEG' ); // Determine the file type by examining the file header/content, check it has the correct file extension if FindFileFormat( sFilename, ffVerifyByExtension ) = ioJPEG then ShowMessage( 'File content is JPEG and it has a JPEG extension' ); // Determine the file type by examining the file header/content. If that fails use the correct file extension if FindFileFormat( sFilename, ffFallbackToExtension ) = ioDICOM then ShowMessage( 'File appears to be a DICOM' ); !!} TIEFindFormatMethod = (ffContentOnly, ffVerifyByExtension, ffFallbackToExtension); /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // TIEVCLStreamProvider {$ifdef IEVISION} type TIEVCLStreamProvider = class(TInterfacedObject, TIEVisionCustomStreamProvider) private m_stream: TStream; public constructor Create(Stream: TStream); destructor Destroy; override; function size(): int64; safecall; procedure seek(offset: int64; whence: TIEVisionSeekOffset); safecall; function tell(): int64; safecall; function silent_read(ptr: pointer; size: int64): int64; safecall; function silent_write(ptr: pointer; size: int64): int64; safecall; function silent_getc(): int32_t; safecall; function eof(): bool32; safecall; end; {$endif} // IEVISION function IETIFFCalcTagSize(tagType: integer): word; // EXIF SUPPORT FUNCTIONS function LoadEXIFFromStandardBuffer(Buffer: pointer; BufferLength: integer; params: TObject): boolean; procedure SaveEXIFToStandardBuffer(params: TObject; var Buffer: pointer; var BufferLength: integer; savePreamble: boolean); function IESearchEXIFInfo(Stream: TStream): int64; function IELoadEXIFFromTIFF(Stream: TStream; params: TObject; loadXMP: boolean): boolean; overload; function IELoadParamsFromTIFF(Stream: TStream; params: TObject; page: integer): boolean; overload; procedure IEAdjustEXIFOrientation(Bitmap: TIEBitmap; Orientation: integer); function CheckEXIFFromStandardBuffer(Buffer: pointer; BufferLength: integer): boolean; procedure IECopyEXIF(source_, dest_: TObject; copyBitmap: boolean); function EXIFDateToDateTime(const sEXIFDate: string): TDateTime; function DateTimeToEXIFDate(ADateTime: TDateTime): string; function IEReadEXIFFromMOV(Stream: TStream; OutParams: TObject): boolean; overload; function IEReadEXIFFromMOV(const FileName: WideString; OutParams: TObject): boolean; overload; // XMP support functions function IELoadXMPFromJpegTag(Buffer: pointer; BufferLength: integer; params: TObject): boolean; procedure IESaveXMPToJpegTag(params: TObject; var Buffer: pointer; var BufferLength: integer); function IEFindXMPFromJpegTag(Buffer: pointer; BufferLength: integer): pbyte; // DICOM Functions {$ifdef IEINCLUDEDICOM} function DicomTagToStr(dt : TIEDicomTagType) : AnsiString; function DicomStrToTag(s: AnsiString): TIEDicomTagType; {$endif} function IEPaperSizeToStr(const aSize : TIOPDFPaperSize) : string; function IEStrToPaperSize(const sSize : string; aDefault : TIOPDFPaperSize = iepUnknown) : TIOPDFPaperSize; function IEPointsToPaperSize(const Width, Height : Integer) : TIOPDFPaperSize; function IECalcPaperSize(const Width, Height : Double; Metric: Boolean) : TIOPDFPaperSize; function TidyIPTCStr(const Value: string): string; procedure IESwapIEBitmaps(var a: TIEBitmap; var b: TIEBitmap); function IECreateGrayPalette(): HPALETTE; procedure IESetGrayPalette(Bitmap: TBitmap); function IEIsGrayPalette(Bitmap: TBitmap): boolean; procedure IECopyTBitmapPaletteToTIEBitmap(source: TBitmap; dest: TIEBitmap); // IIF functions function IEIFI(cond: boolean; val1, val2: integer): integer; function IEIFD(cond: boolean; val1, val2: double): double; function IEIFB(cond: boolean; val1, val2: TIEBitmap): TIEBitmap; function IECSwapWord(i: word; sc: boolean): word; function IECSwapDWord(i: integer; sc: boolean): integer; function IECSwapInt64(i: int64; sc: boolean): int64; function IEStreamReadWord(Stream: TStream; bigEndian: boolean): word; function IEStreamReadDWord(Stream: TStream; bigEndian: boolean): dword; function IEStreamReadInt64(Stream: TStream; bigEndian: boolean): int64; function IEStreamWordAlign(Stream: TStream; var Aborting: boolean): integer; procedure IEStreamWriteLn(Stream: TStream; Text: AnsiString); procedure IEStreamWriteByte(Stream: TStream; Value: byte); function IsKnownFormat(const FileName: WideString; bIncludeVideoFiles : Boolean = False): boolean; function IsKnownSaveFormat(const FileName: WideString): boolean; function FindFileFormat(const FileName: WideString; FindMethod: TIEFindFormatMethod = ffContentOnly): TIOFileType; {$ifdef IEIncludeDeprecatedInV6} overload; {$endif} {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 6.3.1 (2015-06-16) function FindFileFormat(const FileName: WideString; VerifyExtension: boolean): TIOFileType; overload; {$ifdef IEWarningForDeprecated} deprecated {$ifdef IESupportDeprecatedDescription} 'Use newer FindFileFormat overload - http://imageen.com/help/Compatibility.html' {$endif}; {$endif} {$endif} function FindStreamFormat(Stream: TStream): TIOFileType; function DeleteGIFIm(const FileName: WideString; idx: integer): integer; procedure DeleteDCXIm(const FileName: WideString; idx: integer); function DeleteTIFFIm(const FileName: WideString; idx: integer): integer; function DeleteTIFFImGroup(const FileName: WideString; Indexes: array of integer): integer; function EnumGIFIm(const FileName: WideString): integer; function EnumTIFFIm(const FileName: WideString): integer; function EnumTIFFStream(Stream: TStream): integer; function EnumICOIm(const FileName: WideString): integer; function EnumDCXIm(const FileName: WideString): integer; function CheckAniGIF(const FileName: WideString): boolean; procedure IEWriteICOImages(const fileName: WideString; images: array of TObject); type {!! TIEJpegTransform Declaration TIEJpegTransform = (jtNone, jtCut, jtHorizFlip, jtVertFlip, jtTranspose, jtTransverse, jtRotate90, jtRotate180, jtRotate270); Description Lossless JPEG transformation functions: Value Description jtNone No transformation jtCut Crops the image (i.e. only a portion of the image is kept) jtHorizFlip Mirrors the image horizontally (left-right) jtVertFlip Mirrors the image vertically (top-bottom) jtTranspose Transposes the image (across UL-to-LR axis) jtTransverse Transverse transpose (across UR-to-LL axis) jtRotate90 Rotates the image 90 degrees clockwise jtRotate180 Rotates the image 180 degrees jtRotate270 Rotates the image 270 degrees clockwise (i.e. 90° CCW)
!!} TIEJpegTransform = (jtNone, jtCut, jtHorizFlip, jtVertFlip, jtTranspose, jtTransverse, jtRotate90, jtRotate180, jtRotate270); {!! TIEJpegCopyMarkers Declaration TIEJpegCopyMarkers = (jcCopyNone, jcCopyComments, jcCopyAll); Description Specify how the extra markers in a source file should be transfered to the destination file: Value Description jcCopyNone Copy no extra markers from the source file. This setting suppresses all comments and other excess data present in the source file jcCopyComments Copy only comment markers. This setting copies only the comments from the source file, discarding all other inessential data jcCopyAll Copy all extra markers. This setting preserves miscellaneous markers found in the source file, such as JFIF thumbnails and Photoshop settings. In some files these extra markers can be sizable
!!} TIEJpegCopyMarkers = (jcCopyNone, jcCopyComments, jcCopyAll); function JpegLosslessTransform(const SourceFile, DestFile: WideString; Transform: TIEJpegTransform; GrayScale: boolean; CopyMarkers: TIEJpegCopyMarkers; CutRect: TRect; UpdateEXIF: Boolean = False): boolean; overload; function JpegLosslessTransform(const SourceFile, DestFile: WideString; Transform: TIEJpegTransform): boolean; overload; function JpegLosslessTransform2(const FileName: WideString; Transform: TIEJpegTransform; GrayScale: boolean; CopyMarkers: TIEJpegCopyMarkers; CutRect: TRect; UpdateEXIF: Boolean = False): boolean; overload; function JpegLosslessTransform2(const FileName: WideString; Transform: TIEJpegTransform): boolean; overload; function JpegLosslessTransformStream(SourceStream, DestStream: TStream; Transform: TIEJpegTransform; GrayScale: boolean; CopyMarkers: TIEJpegCopyMarkers; CutRect: TRect; UpdateEXIF: Boolean = False): boolean; procedure ExtractTIFFImageStream(SourceStream, OutStream: TStream; idx: integer); procedure ExtractTIFFImageFile(const SourceFileName, OutFileName: WideString; idx: integer); procedure InsertTIFFImageStream(SourceStream, InsertingStream, OutStream: TStream; idx: integer); procedure InsertTIFFImageFile(const SourceFileName, InsertingFileName, OutFileName: WideString; idx: integer); function IEAdjustDPI(bmp: TIEBitmap; Params: TIOParams; FilteredAdjustDPI: boolean): TIEBitmap; function IEGetFileFramesCount(const FileName: WideString): Integer; function IEFindNumberWithKnownFormat( const Directory: WideString ): integer; function IEAVISelectCodec(): AnsiString; function IEAVIGetCodecs: TStringList; function IEAVIGetCodecsDescription: TStringList; function IEGetFromURL(const URL: WideString; OutStream: TStream; const ProxyAddress: WideString; const ProxyUser: WideString; const ProxyPassword: WideString; OnProgress: TIEProgressEvent; Sender: TObject; Aborting: pboolean; var FileExt: String): Boolean; // others procedure IEUpdateGIFStatus; function IECalcJpegFileQuality(const FileName: WideString): integer; function IECalcJpegStreamQuality(Stream: TStream): integer; procedure IEOptimizeGIF(const InputFile, OutputFile: WideString); {!! IERegisterFormats Declaration procedure IERegisterFormats; Description Register/unregister following classes inside the VCL class framework. This allows use of standard VCL open/save dialogs and TPicture objects with ImageEn file formats. TIETiffImage, TIEGifImage, TIEJpegImage, TIEPCXImage, TIEBMPImage, TIEICOImage, TIEPNGImage, TIETGAImage, TIEPXMImage, TIEJP2Image, TIEJ2Kimage Each of above classes inherits from TIEGraphicBase. To get input/output parameters use the “IO” property, which is the same as the ImageEnIO.Params property. !!} procedure IERegisterFormats; {!! IEUnregisterFormats Declaration procedure IEUnregisterFormats; Description Unregisters ImageEn file formats from the VCL. !!} procedure IEUnregisterFormats; type {!! TIEReadImageStream Declaration TIEReadImageStream = procedure(Stream: TStream; Bitmap:
; var IOParams: ; var Progress: ; Preview: boolean); Description The procedure to load the image in Stream into Bitmap and fill IOParams with metadata. Use Progress to return progress information (e.g. for 35% progress Progress.val := 35 and Progress.tot := 100) and notify of load failure (Progress.Aborting^ := True). When Preview is true, ImageEn is only seeking to fill IOParams, not load the image (i.e. you can skip Bitmap as it will be ignored. You will need to reset the stream position. !!} TIEReadImageStream = procedure(Stream: TStream; Bitmap: TIEBitmap; var IOParams: TIOParams; var Progress: TProgressRec; Preview: boolean); {!! TIEWriteImageStream Declaration TIEWriteImageStream = procedure(Stream: TStream; Bitmap: ; var IOParams: ; var Progress: ); Description The procedure to save the image in Bitmap to a Stream. Use Progress to return progress information (e.g. for 35% progress Progress.val := 35 and Progress.tot := 100) and notify of save failure (Progress.Aborting^ := True). !!} TIEWriteImageStream = procedure(Stream: TStream; Bitmap: TIEBitmap; var IOParams: TIOParams; var Progress: TProgressRec); {!! TIETryImageStream Declaration TIETryImageStream = function(Stream: TStream; TryingFormat: ): boolean; Description Return True if Stream matches our custom file type. !!} TIETryImageStream = function(Stream: TStream; TryingFormat: TIOFileType): boolean; {!! TIEFileFormatInfo Declarations TIEFileFormatInfo=class FileType : ; FullName : string; Extensions : string; SuitableExtension : string; InternalFormat : boolean; DialogPage : ; ReadFunction : ; WriteFunction : ; TryFunction : ; end; Description Value Description FileType The file type class, e.g. ioJPEG FullName A description of the file type, e.g. 'JPEG Bitmap' Extensions All extensions of this format WITHOUT the period, e.g. 'jpg;jpeg;jpe' SuitableExtension A single extension that is suitable for this format WITHOUT the period, e.g. 'jpeg' InternalFormat True for native ImageEn formats, false for custom formats DialogPage The page that is used to display properties for this type in ReadFunction The function used for reading this file type (nil if it cannot be read) WriteFunction The function used for saving this file type (nil if it is read-only) TryFunction The function used to determine if a file is of this type (used only when ImageEn is checking for the image type without considering its file extension)
!!} TIEFileFormatInfo = class FileType: TIOFileType; FullName: string; // ex 'JPEG Bitmap' Extensions: string; // extensions without '.' ex 'jpg' (ex 'jpg;jpeg;jpe') SuitableExtension : string; InternalFormat: Boolean; DialogPage: TPreviewParams; ReadFunction: TIEReadImageStream; WriteFunction: TIEWriteImageStream; TryFunction: TIETryImageStream; constructor Create(); overload; constructor Create(FileType: TIOFileType; FullName: string; Extensions: string; SuitableExtension : string; InternalFormat: Boolean; DialogPage: TPreviewParams; ReadFunction: TIEReadImageStream; WriteFunction: TIEWriteImageStream; TryFunction: TIETryImageStream); overload; end; // custom file formats registration functions function IEFileFormatGetInfo(FileType: TIOFileType): TIEFileFormatInfo; function IEFileFormatGetInfo2(Extension: string): TIEFileFormatInfo; function IEFileFormatGetExt(FileType: TIOFileType; idx: integer): string; function IEFileFormatGetExtCount(FileType: TIOFileType): integer; procedure IEFileFormatAdd(FileFormatInfo: TIEFileFormatInfo); procedure IEFileFormatRemove(FileType: TIOFileType); function GetAllSupportedFileExtensions(bLoadFormats, bSaveFormats : Boolean; bVideoFormats: Boolean = True) : string; function GetFileExtensionsOfType(FileType: TIOFileType) : string; function IEExtToFileFormat(const ext: String): TIOFileType; function IEFilenameToFileFormat(const FileName: String): TIOFileType; function IEFileIsOfFormat(const sFilename : string; aFormat : TIOFileType) : Boolean; function IEIsInternalFormat(ex: String): Boolean; // External dll plugins function IEAutoLoadIOPlugins : Integer; function IEAddExtIOPlugin(const FileName : string) : Integer; function IEIsExtIOPluginLoaded(const FileName : string) : boolean; function IECMYK2RGB(cmyk: TCMYK): TRGB; function IECMYK2RGBROW(inrow: PCMYK; outrow: PRGB; width: Integer; alphaRow: pinteger = nil): TRGB; overload; function IECMYK2RGBROW(inrow: PCMYK; outrow: PRGB; width: Integer; alphaRow: pinteger; colorProfile: TIEICC): TRGB; overload; function IERGB2CMYK(const rgb: TRGB): TCMYK; type {!! TIEConvertColorFunction Declaration TIEConvertColorFunction = procedure(InputScanline: pointer; InputColorSpace: ; OutputScanline: pointer; OutputColorSpace: ; ImageWidth: integer; IOParams: ); Description Specifies the function used to convert from one color space to another. !!} TIEConvertColorFunction = procedure(InputScanline: pointer; InputColorSpace: TIEColorSpace; OutputScanline: pointer; OutputColorSpace: TIEColorSpace; ImageWidth: integer; IOParams: TIOParams); procedure IEDefaultConvertColorFunction(InputScanline: pointer; InputColorSpace: TIEColorSpace; OutputScanline: pointer; OutputColorSpace: TIEColorSpace; ImageWidth: integer; IOParams: TIOParams); procedure IEInitialize_iexBitmaps; procedure IEFinalize_iexBitmaps; const iebitmask1: array[0..7] of byte = ($80, $40, $20, $10, $08, $04, $02, $01); // $80 shr index // table for 1bpp images reversing bits in bytes - bits in DIB bytes are reversed ierevertbyte: array[0..255] of byte = ( 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255); implementation uses math, {$ifdef DelphiXE4orNewer} AnsiStrings, {$endif} {$ifdef DelphiXE5orNewer}System.Types,{$endif} imageenview, imageenproc, imageenio, ieview, neurquant, tiffilt, ievect, printers, ielcms, iexLayers, iej2000, tifccitt, ietextc, iewia, iewic, iepresetim, iesettings, iedicom, iemiscplugins, iemview, iemio {$ifdef IEUSEVCLZLIB}, zlib{$else}, iezlib{$endif} {$ifdef IEINCLUDEFLATSB}, flatsb{$endif} , IEVfw, iepsd, giflzw, tiflzw, ieraw, jpegfilt, giffilter, pcxfilter, bmpfilt, pngfilt, ietgafil, ietwain; {$R-} const ANNOT_CREATION_SCALE: integer = 7500; const IEIOPARAMSMAGIC: AnsiString = 'IEIOPARAMSMAGIC'; // Standard Paper Sizes to Adobe point conversion // Used by TIOParams.PS_PaperSize, TIOParams.PDF_PaperSize, IEStrToPaperSize() and IEPaperSizeToStr() type TIOPDFPaperSizeRec = record Size : TIOPDFPaperSize; Name : String; // Display name for the paper size Width : Integer; // Width of the page in Adobe PDF points (1 point = 1/72 of inch). Height : Integer; // Hidth of the page in Adobe PDF points (1 point = 1/72 of inch). end; const IOPDFPaperSizes : array[0 .. 12] of TIOPDFPaperSizeRec = ( (Size: iepA0; Name: 'A0'; Width: 2380; Height: 3368), (Size: iepA1; Name: 'A1'; Width: 1684; Height: 2380), (Size: iepA2; Name: 'A2'; Width: 1190; Height: 1684), (Size: iepA3; Name: 'A3'; Width: 842; Height: 1190), (Size: iepA4; Name: 'A4'; Width: 595; Height: 842), (Size: iepA5; Name: 'A5'; Width: 421; Height: 595), (Size: iepA6; Name: 'A6'; Width: 297; Height: 421), (Size: iepB5; Name: 'B5'; Width: 501; Height: 709), (Size: iepLetter; Name: 'US Letter'; Width: 612; Height: 792), (Size: iepLegal; Name: 'US Legal'; Width: 612; Height: 1008), (Size: iepLedger; Name: 'US Ledger'; Width: 1224; Height: 792), (Size: iepTabloid; Name: 'US Tabloid'; Width: 792; Height: 1224), (Size: iepAuto; Name: 'Auto'; Width: 0; Height: 0) ); ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // generic inline functions. Must be not moved out of this unit function GetPixelbw_inline(row: pbyte; pix: integer): integer; {$ifdef IESUPPORTINLINE} inline; {$endif} begin result := pbytearray(row)^[pix shr 3] and iebitmask1[pix and $7]; end; procedure SetPixelbw_inline(row: pbyte; pix: integer; vv: integer); {$ifdef IESUPPORTINLINE} inline; {$endif} var bp: pbyte; begin bp := pbyte(uint64(row) + (uint64(pix) shr 3)); if vv <> 0 then bp^ := bp^ or iebitmask1[pix and 7] else bp^ := bp^ and not iebitmask1[pix and 7]; end; ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// // TIEMarkerList constructor TIEMarkerList.Create; begin inherited; fData := TList.Create; fType := TList.Create; end; destructor TIEMarkerList.Destroy; begin Clear; FreeAndNil(fData); FreeAndNil(fType); inherited Destroy; end; {!! TIEMarkerList.Count Declaration property Count: integer; Description Returns the markers count. !!} function TIEMarkerList.GetCount: integer; begin result := fData.Count; end; {!! TIEMarkerList.MarkerStream Declaration property MarkerStream[idx: integer]: TStream; Description Get data stream of marker, idx. !!} function TIEMarkerList.GetMarkerStream(idx: integer): TStream; begin result := TStream(fData.Items[idx]); result.Position := 0; end; {!! TIEMarkerList.MarkerData Declaration property MarkerData[idx: integer]: PAnsiChar; Description Get data buffer pointer of marker, idx. !!} function TIEMarkerList.GetMarkerData(idx: integer): PAnsiChar; begin result := PAnsiChar(TMemoryStream(fData.Items[idx]).memory); end; {!! TIEMarkerList.MarkerType Declaration property MarkerType[idx: integer]: byte; Description Get marker type (JPEG_APP0 to JPEG_APP15 and JPEG_COM). !!} function TIEMarkerList.GetMarkerType(idx: integer): byte; begin result := byte(integer(fType.Items[idx])); end; {!! TIEMarkerList.MarkerLength Declaration property MarkerLength[idx: integer]: word; Description Get marker length (65,535 bytes max). !!} function TIEMarkerList.GetMarkerLength(idx: integer): word; begin result := TMemoryStream(fData.Items[idx]).size; end; {!! TIEMarkerList.IndexOf Declaration function IndexOf(marker: byte): integer; Description Finds the first marker and return its index. If a marker is not in the list, IndexOf returns -1. !!} function TIEMarkerList.IndexOf(marker: byte): integer; begin for result := 0 to fType.Count - 1 do if byte(integer(fType.Items[result])) = marker then exit; result := -1; end; {!! TIEMarkerList.AddMarker Declaration function AddMarker(marker: byte; data: PAnsiChar; datalen: word): integer; Description Adds a new marker to the list. Marker can be from JPEG_APP0 to JPEG_APP15 and JPEG_COM. AddMarker returns the index of the new marker, where the first marker in the list has an index of 0. A single JPEG file can contains multiple instances of the same marker. !!} function TIEMarkerList.AddMarker(marker: byte; data: PAnsiChar; datalen: word): integer; var ms: TMemoryStream; i: integer; begin ms := TMemoryStream.Create; ms.Write(data^, datalen); fData.Add(ms); i := marker; result := fType.Add(pointer(i)); end; {!! TIEMarkerList.InsertMarker Declaration procedure InsertMarker(idx: integer; data: PAnsiChar; marker: byte; datalen: word); Description Call InsertMarker to add a marker to the middle of the marker array. The idx parameter is a zero-based index. !!} procedure TIEMarkerList.InsertMarker(idx: integer; data: PAnsiChar; marker: byte; datalen: word); var ms: TMemoryStream; i: integer; begin ms := TMemoryStream.Create; ms.Write(data^, datalen); fData.Insert(idx, ms); i := marker; fType.Insert(idx, pointer(i)); end; {!! TIEMarkerList.SetMarker Declaration procedure SetMarker(idx: integer; marker: byte; data: PAnsiChar; datalen: word); Description Replace the marker, idx. !!} procedure TIEMarkerList.SetMarker(idx: integer; marker: byte; data: PAnsiChar; datalen: word); var ms: TMemoryStream; i: integer; begin TMemoryStream(fData.Items[idx]).Free; fData.Items[idx] := nil; ms := TMemoryStream.Create; ms.Write(data^, datalen); fData.Items[idx] := ms; i := marker; fType.Items[idx] := pointer(i); end; {!! TIEMarkerList.Clear Declaration procedure Clear; Description Remove all markers. !!} procedure TIEMarkerList.Clear; var i: integer; begin for i := 0 to fData.Count-1 do TMemoryStream(fData.Items[i]).free; fData.Clear; fType.Clear; end; {!! TIEMarkerList.SaveToStream Declaration procedure SaveToStream(Stream: TStream); Description Saves all markers in the stream. Only can reload data. !!} procedure TIEMarkerList.SaveToStream(Stream: TStream); var bb: byte; ii, w: integer; begin bb := 0; Stream.Write(bb, 1); // version ii := fData.Count; Stream.Write(ii, sizeof(integer)); // markers count for ii := 0 to fData.Count - 1 do begin bb := byte(integer(fType.Items[ii])); Stream.Write(bb, 1); // marker type w := TMemoryStream(fData.Items[ii]).Size; Stream.Write(w, sizeof(integer)); // marker length TMemoryStream(fData.Items[ii]).Position := 0; TMemoryStream(fData.Items[ii]).SaveToStream(Stream); // data end; end; {!! TIEMarkerList.LoadFromStream Declaration procedure LoadFromStream(Stream: TStream); Description Load all markers from stream. !!} procedure TIEMarkerList.LoadFromStream(Stream: TStream); var bb: byte; ii, q, w, l: integer; ms: TMemoryStream; begin Clear; Stream.Read(bb, 1); Stream.Read(ii, sizeof(integer)); for q := 0 to ii - 1 do begin Stream.Read(bb, 1); w := bb; fType.Add(pointer(w)); Stream.Read(l, sizeof(integer)); ms := TMemoryStream.Create; ms.SetSize(l); Stream.Read(PAnsiChar(ms.memory)^, l); fData.Add(ms); end; end; {!! TIEMarkerList.DeleteMarker Declaration procedure DeleteMarker(idx: integer); Description Remove marker, idx. !!} procedure TIEMarkerList.DeleteMarker(idx: integer); begin TMemoryStream(fData.Items[idx]).free; fData.Delete(idx); fType.Delete(idx); end; {!! TIEMarkerList.DeleteMarkerInstances Declaration procedure DeleteMarkerInstances(markerType: byte); Description Remove all markers of the specified marker type. Example // removes ICC jpeg profile (APP2 markers) ImageEnView.IO.Params.JPEG_MarkerList.DeleteMarkerInstances(M_APP2); !!} procedure TIEMarkerList.DeleteMarkerInstances(markerType: byte); var i: integer; begin while true do begin i := IndexOf(markerType); if i = -1 then break; DeleteMarker(i); end; end; {!! TIEMarkerList.Assign Declaration procedure Assign(Source: ); Description Assign all markers from Source. !!} procedure TIEMarkerList.Assign(Source: TIEMarkerList); var q: integer; begin if assigned(Source) then begin Clear; for q := 0 to Source.Count - 1 do AddMarker(Source.MarkerType[q], Source.MarkerData[q], Source.MarkerLength[q]); end; end; function TIEMarkerList.SortCompare(Index1, Index2: integer): integer; var p1, p2: PAnsiChar; begin result := integer(fType[Index1])-integer(fType[Index2]); if (integer(fType[Index1])=JPEG_APP2) and (integer(fType[Index2])=JPEG_APP2) and (MarkerLength[Index1]>13) and (MarkerLength[Index2]>13) then begin // compare ICC tags (2.3.1) p1 := MarkerData[Index1]; p2 := MarkerData[Index2]; if (p1='ICC_PROFILE') and (p2='ICC_PROFILE') then begin result := ord(p1[12])-ord(p2[12]); end; end; end; procedure TIEMarkerList.SortSwap(Index1, Index2: integer); var t: pointer; begin t := fType[Index1]; fType[Index1] := fType[Index2]; fType[Index2] := t; t := fData[Index1]; fData[Index1] := fData[Index2]; fData[Index2] := t; end; procedure TIEMarkerList.Sort; var i, j: integer; begin IEQuickSort(fType.Count, SortCompare, SortSwap); // put APP1 with EXIF before other APP1 // APP1-EXIF must be the first one, even they are other APP1 tags (i.e. Photoshop adds a custom APP1 tag) for i := 0 to fType.Count-1 do if integer(fType[i])=JPEG_APP1 then begin for j := i+1 to fType.Count-1 do if (GetMarkerType(j)=JPEG_APP1) and CheckEXIFFromStandardBuffer(GetMarkerData(j), GetMarkerLength(j)) then SortSwap(i, j); break; end; end; ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// // PIEIPTCInfoList {!! TIEIPTCInfoList.StringItem Declaration property StringItem[idx: integer]: string; Description Returns the string associated with item, idx. The item must be of string type. !!} function TIEIPTCInfoList.GetStrings(idx: integer): string; var r: AnsiString; begin if (idx >= 0) and (idx < fInfo.Count) then begin SetLength(r, PIPTCInfo(fInfo[idx])^.fLength); move(pbyte(fBuffer[idx])^, r[1], PIPTCInfo(fInfo[idx])^.fLength); end else r := ''; result := string(r); end; procedure TIEIPTCInfoList.SetStrings(idx: integer; Value: string); var v: AnsiString; begin v := AnsiString(Value); freemem(fBuffer[idx]); fBuffer[idx] := allocmem(length(v)); CopyMemory(fBuffer[idx], PAnsiChar(v), length(v)); PIPTCInfo(fInfo[idx])^.fLength := length(v); fUserChanged := true; end; {!! TIEIPTCInfoList.GetItemData Declaration function GetItemData(idx: integer): pointer; Description Returns the raw data associated with the item, idx. !!} function TIEIPTCInfoList.GetItemData(idx: integer): pointer; begin if (idx >= 0) and (idx < fInfo.Count) then result := fBuffer[idx] else result := nil; end; {!! TIEIPTCInfoList.GetItemLength Declaration function GetItemLength(idx: integer): integer; Description Returns the raw data length associated with the item, idx. !!} function TIEIPTCInfoList.GetItemLength(idx: integer): integer; begin if (idx >= 0) and (idx < fInfo.Count) then result := PIPTCInfo(fInfo[idx])^.fLength else result := 0; end; {!! TIEIPTCInfoList.RecordNumber Declaration property RecordNumber[idx: integer]: integer; Description Returns the record number associated with the item, idx. !!} function TIEIPTCInfoList.GetRecordNumber(idx: integer): integer; begin result := PIPTCInfo(fInfo[idx])^.fRecord; end; procedure TIEIPTCInfoList.SetRecordNumber(idx: integer; Value: integer); begin PIPTCInfo(fInfo[idx])^.fRecord := Value; fUserChanged := true; end; {!! TIEIPTCInfoList.DataSet Declaration property DataSet[idx: integer]: integer; Description Returns the dataset number associated with the item, idx. !!} function TIEIPTCInfoList.GetDataSet(idx: integer): integer; begin result := PIPTCInfo(fInfo[idx])^.fDataSet; end; procedure TIEIPTCInfoList.SetDataSet(idx: integer; Value: integer); begin PIPTCInfo(fInfo[idx])^.fDataSet := Value; fUserChanged := true; end; {!! TIEIPTCInfoList.Count Declaration property Count: integer; Description Returns the item count. !!} function TIEIPTCInfoList.GetCount: integer; begin result := fInfo.Count; end; constructor TIEIPTCInfoList.Create; begin inherited Create; fInfo := TList.Create; fBuffer := TList.Create; fUserChanged := false; end; destructor TIEIPTCInfoList.Destroy; begin Clear; FreeAndNil(fInfo); FreeAndNil(fBuffer); inherited Destroy; end; {!! TIEIPTCInfoList.AddStringItem Declaration function AddStringItem(RecordNumber: integer; DataSet: integer; Value: AnsiString): integer; Description Adds a string (textual information) with the specified RecordNumber and DataSet. Result is the index of the new item, where the first item in the list has an index of 0. !!} function TIEIPTCInfoList.AddStringItem(ARecordNumber: integer; ADataSet: integer; Value: AnsiString): integer; var pinfo: PIPTCInfo; xbuffer: PAnsiChar; begin getmem(xbuffer, length(Value)); copymemory(xbuffer, PAnsiChar(Value), length(Value)); result := fBuffer.Add(xbuffer); new(pinfo); pinfo^.fRecord := ARecordNumber; pinfo^.fDataSet := ADataSet; pinfo^.fLength := length(Value); fInfo.Add(pinfo); fUserChanged := true; end; {!! TIEIPTCInfoList.AddBufferItem Declaration function AddBufferItem(RecordNumber: integer; DataSet: integer; Buffer: pointer; BufferLength: integer): integer; Description Adds a memory buffer (non-textual information) with the specified RecordNumber and DataSet. Result is the index of the new item, where the first item in the list has an index of 0. !!} function TIEIPTCInfoList.AddBufferItem(ARecordNumber: integer; ADataSet: integer; Buffer: pointer; BufferLength: integer): integer; var pinfo: PIPTCInfo; xbuffer: pointer; begin getmem(xbuffer, BufferLength); copymemory(xbuffer, Buffer, BufferLength); result := fBuffer.Add(xbuffer); new(pinfo); pinfo^.fRecord := ARecordNumber; pinfo^.fDataSet := ADataSet; pinfo^.fLength := BufferLength; fInfo.Add(pinfo); fUserChanged := true; end; {!! TIEIPTCInfoList.InsertStringItem Declaration procedure InsertStringItem(idx: integer; RecordNumber: integer; DataSet: integer; Value: AnsiString); Description Add an item to the middle of the item array. The idx parameter is a zero-based index. !!} procedure TIEIPTCInfoList.InsertStringItem(idx: integer; ARecordNumber: integer; ADataSet: integer; Value: AnsiString); var pinfo: PIPTCInfo; xbuffer: pointer; begin getmem(xbuffer, length(Value)); copymemory(xbuffer, PAnsiChar(Value), length(Value)); fBuffer.Insert(idx, xbuffer); new(pinfo); pinfo^.fRecord := ARecordNumber; pinfo^.fDataSet := ADataSet; pinfo^.fLength := length(Value); fInfo.Insert(idx, pinfo); fUserChanged := true; end; {!! TIEIPTCInfoList.Clear Declaration procedure Clear; Description Remove all items from the array. !!} procedure TIEIPTCInfoList.Clear; var i: integer; begin for i := 0 to fInfo.Count-1 do begin dispose(PIPTCInfo(fInfo[i])); freemem(fBuffer[i]); end; fInfo.Clear; fBuffer.Clear; fUserChanged := true; end; {!! TIEIPTCInfoList.IndexOf Declaration function IndexOf(RecordNumber: integer; DataSet: integer): integer; Description Finds the first item that matches the RecordNumber and DataSet parameters and return its index. Result is -1 if the item is not in the list. !!} function TIEIPTCInfoList.IndexOf(ARecordNumber: integer; ADataSet: integer): integer; begin for result := 0 to fInfo.Count - 1 do with PIPTCInfo(fInfo[result])^ do if (fRecord = ARecordNumber) and (fDataSet = ADataSet) then exit; result := -1; end; {!! TIEIPTCInfoList.DeleteItem Declaration procedure DeleteItem(idx: integer); Description Remove the item, idx. !!} procedure TIEIPTCInfoList.DeleteItem(idx: integer); begin dispose(PIPTCInfo(fInfo[idx])); fInfo.Delete(idx); freemem(fBuffer[idx]); fBuffer.Delete(idx); fUserChanged := true; end; {!! TIEIPTCInfoList.Assign Declaration procedure Assign(Source: ); Description Copy all items from Source. !!} procedure TIEIPTCInfoList.Assign(Source: TIEIPTCInfoList); var q: integer; begin if assigned(Source) then begin Clear; for q := 0 to Source.Count - 1 do AddBufferItem(Source.RecordNumber[q], Source.DataSet[q], Source.fBuffer[q], PIPTCInfo(Source.fInfo[q])^.fLength); fUserChanged := true; end; end; {!! TIEIPTCInfoList.SaveToStream Declaration procedure SaveToStream(Stream: TStream); Description Save IPTC info in the Stream. Note: Do not use this method to embed IPTC data in image files, use . !!} procedure TIEIPTCInfoList.SaveToStream(Stream: TStream); var q, v: integer; begin v := 0; Stream.Write(v, sizeof(integer)); // version v := fInfo.Count; Stream.Write(v, sizeof(integer)); // count for q := 0 to fInfo.Count - 1 do begin Stream.Write(PIPTCInfo(fInfo[q])^, sizeof(TIPTCInfo)); Stream.Write(pbyte(fBuffer[q])^, PIPTCInfo(fInfo[q])^.fLength); end; end; {!! TIEIPTCInfoList.LoadFromStream Declaration procedure LoadFromStream(Stream: TStream); Description Loads all IPTC info from stream. Note: This method cannot load IPTC data from an image files, use . !!} procedure TIEIPTCInfoList.LoadFromStream(Stream: TStream); var q, v: integer; info: TIPTCInfo; xbuffer: pbyte; begin Clear; Stream.Read(v, sizeof(integer)); // version Stream.Read(v, sizeof(integer)); // count for q := 0 to v - 1 do begin Stream.Read(info, sizeof(TIPTCInfo)); getmem(xbuffer, info.fLength); Stream.Read(xbuffer^, info.fLength); AddBufferItem(info.fRecord, info.fDataSet, xbuffer, info.fLength); freemem(xbuffer); end; fUserChanged := true; end; {!! TIEIPTCInfoList.SaveToStandardBuffer Declaration procedure SaveToStandardBuffer(var Buffer: pointer; var BufferLength: integer; WriteHeader: boolean); Description Saves IPTC in a buffer. You must free the buffer. This method is used to embed IPTC data in an image file. !!} // Buffer is allocated by SaveToStandardBuffer procedure TIEIPTCInfoList.SaveToStandardBuffer(var Buffer: pointer; var BufferLength: integer; WriteHeader: boolean); const psheader: PAnsiChar = (*0*) 'Photoshop 3.0' + #0 + (*14*) '8BIM' + (*18*) #4#4 + (*20*) #0#0 + (*22*) #0#0#0#0; psheader2: PAnsiChar = #28#2#0#0#2#0#2; var q: integer; ms: TMemoryStream; l, tl: dword; b: byte; begin if fInfo.Count = 0 then begin Buffer := nil; BufferLength := 0; end else begin ms := TMemoryStream.Create; if WriteHeader then // good for Jpegs ms.Write(psheader^, 26) // PhotoShop 3.0 marker else // good for TIFF ms.Write(psheader2^, 7); // marker for TIFFs tl := 0; for q := 0 to fInfo.Count - 1 do begin with PIPTCInfo(fInfo[q])^ do begin if ((fRecord = 2) and (fDataSet = 0)) or (fLength = 0) then continue; b := $1C; ms.Write(b, 1); // tag marker b := fRecord; ms.Write(b, 1); // recnum b := fDataSet; ms.Write(b, 1); // dataset l := fLength; if l > 32767 then begin // long b := 0; ms.Write(b, 1); // length of data field count field (hi) b := 4; ms.Write(b, 1); // length of data field count field (lo) b := (l and $FF000000) shr 24; ms.Write(b, 1); // data length b := (l and $00FF0000) shr 16; ms.Write(b, 1); b := (l and $0000FF00) shr 8; ms.Write(b, 1); b := (l and $000000FF); ms.Write(b, 1); inc(tl, 3 + 6 + l); end else begin // short b := (l and $0000FF00) shr 8; ms.Write(b, 1); // data length b := (l and $000000FF); ms.Write(b, 1); inc(tl, 3 + 2 + l); end; ms.Write(pbyte(fBuffer[q])^, l); end; end; BufferLength := ms.Size; if (BufferLength and $1) <> 0 then begin inc(BufferLength); b := 0; ms.Write(b, 1); end; getmem(Buffer, BufferLength); copymemory(Buffer, ms.Memory, BufferLength); if WriteHeader then begin pbytearray(Buffer)^[22] := (tl and $FF000000) shr 24; pbytearray(Buffer)^[23] := (tl and $00FF0000) shr 16; pbytearray(Buffer)^[24] := (tl and $0000FF00) shr 8; pbytearray(Buffer)^[25] := (tl and $000000FF); end; FreeAndNil(ms); end; end; {!! TIEIPTCInfoList.LoadFromStandardBuffer Declaration function LoadFromStandardBuffer(Buffer: pointer; BufferLength: integer): boolean; Description Loads IPTC from the specified buffer. Use to extract IPTC data from an image file. !!} function TIEIPTCInfoList.LoadFromStandardBuffer(Buffer: pointer; BufferLength: integer): boolean; var pc: PAnsiChar; ps: integer; dataset, recnum: integer; len: integer; begin result := false; Clear; if BufferLength=0 then exit; pc := PAnsiChar(Buffer); ps := 0; if CompareMem(pc, PAnsiChar('Photoshop 3.0'), 13) then while (ps AnsiChar($1C)) then break else inc(ps); repeat if pc[ps] <> AnsiChar($1C) then break; inc(ps); if (ps + 4) >= BufferLength then break; recnum := NativeInt(pc[ps]); inc(ps); dataset := NativeInt(pc[ps]); inc(ps); if (byte(pc[ps]) and $80) <> 0 then begin // long tag len := (NativeInt(pc[ps + 2]) shl 24) + (NativeInt(pc[ps + 3]) shl 16) + (NativeInt(pc[ps + 4]) shl 8) + (NativeInt(pc[ps + 5])); inc(ps, 6); end else begin // short tag len := (NativeInt(pc[ps]) shl 8) or NativeInt(pc[ps + 1]); inc(ps, 2); end; len := abs(len); if (ps + len) > BufferLength then break; AddBufferItem(recnum, dataset, @(pc[ps]), len); inc(ps, len); result := true; // at least one tag loaded until ps >= BufferLength; fUserChanged := false; // the user should not call LoadFromStandardBuffer, then this is not an user changement end; //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // TIEVirtualRotatedBitmap constructor TIEVirtualRotatedBitmap.Create(Source: TIEBitmap; Rotation: Double; Background: TColor; FreeSourceOnDestroy: Boolean); var tsin, tcos: Double; cxSrc, cySrc: Double; cxDest, cyDest: Double; i: Integer; begin inherited Create(); OnRenderVirtualPixel := RenderVirtualPixel; fSource := Source; fSourceWidth := Source.Width; fSourceHeight := Source.Height; fSourcePixelFormat := Source.PixelFormat; fFreeSourceOnDestroy := FreeSourceOnDestroy; fRotation := Rotation; fRotationRad := fRotation * PI / 180.0; Width := round(abs(fSourceWidth * cos(fRotationRad)) + abs(fSourceHeight * sin(fRotationRad))); Height := round(abs(fSourceWidth * sin(fRotationRad)) + abs(fSourceHeight * cos(fRotationRad))); IsAlpha := Source.IsAlpha; if IsAlpha then PixelFormat := ie8g else PixelFormat := ie24RGB; BitCount := IEPixelFormat2BitCount(PixelFormat); RowLen := IEBitmapRowLen(Width, BitCount, 8); ChannelCount := IEPixelFormat2ChannelCount(PixelFormat); fBackgroundRGB := TColor2TRGB(Background); fBackgroundGray := trunc(Background); Contrast := Source.Contrast; for i := 0 to IEMAXCHANNELS - 1 do ChannelOffset[i] := Source.ChannelOffset[i]; BlackValue := Source.BlackValue; WhiteValue := Source.WhiteValue; tsin := sin(fRotationRad); tcos := cos(fRotationRad); cxSrc := (Source.Width - 1) / 2; cySrc := (Source.Height - 1) / 2; cxDest := (Width - 1) / 2; cyDest := (Height - 1) / 2; SetLength(fArx1, Width); SetLength(fArx2, Width); for i := 0 to Width - 1 do begin fArx1[i] := round( cxSrc + (i - cxDest) * tcos ); fArx2[i] := round( cySrc + (i - cxDest) * tsin ); end; SetLength(fAry1, Height); SetLength(fAry2, Height); for i := 0 to Height - 1 do begin fAry1[i] := round( (i - cyDest) * tsin ); fAry2[i] := round( (i - cyDest) * tcos ); end; end; destructor TIEVirtualRotatedBitmap.Destroy(); begin if fFreeSourceOnDestroy then fSource.Free(); inherited; end; procedure TIEVirtualRotatedBitmap.RenderVirtualPixel(Sender: TObject; SrcX, SrcY: integer; var outval); var fx, fy: Integer; p_rgb: PRGB; p_byte: pbyte; begin fx := fArx1[SrcX] - fAry1[SrcY]; fy := fArx2[SrcX] + fAry2[SrcY]; if (fy < fSourceHeight) and (fy >= 0) and (fx < fSourceWidth) and (fx >= 0) then begin if fSourcePixelFormat = ie24RGB then begin p_rgb := fSource.ScanLine[fy]; inc(p_rgb, fx); TRGB(outval) := p_rgb^; end else if (fSourcePixelFormat = ie8g) and IsAlpha then // ie8g allowed only for alpha channel (because Render_ieVirtualXX supports only ie24RGB as main image) begin p_byte := fSource.ScanLine[fy]; inc(p_byte, fx); byte(outval) := p_byte^; end else TRGB(outval) := fSource.Pixels[fx, fy]; end else begin case PixelFormat of ie8g: byte(outval) := fBackgroundGray; ie24RGB: TRGB(outval) := fBackgroundRGB; end; end; end; //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // TIEVirtualClippedBitmap constructor TIEVirtualClippedBitmap.Create(Source: TIEBitmap; Rect: TRect; FreeSourceOnDestroy: Boolean); var i: Integer; begin inherited Create(); OnRenderVirtualPixel := RenderVirtualPixel; fSource := Source; fRect := Rect; fAlphaChannel := nil; Width := Rect.Right - Rect.Left + 1; Height := Rect.Bottom - Rect.Top + 1; PixelFormat := Source.PixelFormat; IsAlpha := Source.IsAlpha; BitCount := Source.BitCount; RowLen := IEBitmapRowLen(Width, BitCount, Source.BitAlignment); ChannelCount := Source.ChannelCount; Contrast := Source.Contrast; for i := 0 to IEMAXCHANNELS - 1 do ChannelOffset[i] := Source.ChannelOffset[i]; BlackValue := Source.BlackValue; WhiteValue := Source.WhiteValue; end; destructor TIEVirtualClippedBitmap.Destroy(); begin if fFreeSourceOnDestroy then fSource.Free(); FreeAndNil(fAlphaChannel); inherited; end; function TIEVirtualClippedBitmap.GetAlphaChannel(): TIEBitmap; begin if not assigned(fAlphaChannel) then fAlphaChannel := TIEVirtualClippedBitmap.Create(fSource.AlphaChannel, fRect, false); result := fAlphaChannel; end; function TIEVirtualClippedBitmap.GetAlphaChannelOpt: TIEBitmap; begin result := fAlphaChannel; end; function TIEVirtualClippedBitmap.GetScanLine(Row: integer): pointer; var pb: pbyte; begin pb := pbyte(fSource.ScanLine[fRect.Top + Row]); inc(pb, BitCount div 8 * fRect.Left); result := pb; end; function TIEVirtualClippedBitmap.GetPalette(index: integer): TRGB; begin result := fSource.GetPalette(index); end; function TIEVirtualClippedBitmap.GetPaletteBuffer(): pointer; begin result := fSource.GetPaletteBuffer(); end; function TIEVirtualClippedBitmap.GetPaletteLen(): integer; begin result := fSource.GetPaletteLen(); end; function TIEVirtualClippedBitmap.GetPaletteUsed(): integer; begin result := fSource.GetPaletteUsed(); end; function TIEVirtualClippedBitmap.GetSegment(Row: integer; Col: integer; Width: integer): pointer; begin result := fSource.GetSegment(fRect.Top + Row, fRect.Left + Col, Width); end; function TIEVirtualClippedBitmap.GetRow(Row: integer): pointer; begin result := fSource.GetRow(fRect.Top + Row); end; procedure TIEVirtualClippedBitmap.FreeRow(Row: integer); begin fSource.FreeRow(fRect.Top + Row); end; procedure TIEVirtualClippedBitmap.RenderVirtualPixel(Sender: TObject; SrcX, SrcY: integer; var outval); begin end; //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // TIEMask class constructor TIEMask.Create; begin inherited; fFull := false; fWidth := 0; fHeight := 0; fBitsperpixel := 0; fRowlen := 0; fBits := nil; fX1 := 2147483647; fY1 := 2147483647; fX2 := 0; fY2 := 0; // ZeroMemory(@fBitmapInfoHeader1, sizeof(TBitmapInfoHeader256)); with fBitmapInfoHeader1 do begin biSize := sizeof(TBitmapInfoHeader); biPlanes := 1; biBitCount := 1; Palette[1].rgbRed := 255; Palette[1].rgbGreen := 255; Palette[1].rgbBlue := 255; biCompression := BI_RGB; end; fTmpBmp := nil; fTmpBmpScanline := nil; fTmpBmpWidth := 0; fTmpBmpHeight := 0; fDrawPixelBitmap := TBitmap.Create(); fDrawPixelBitmap.Width := 1; fDrawPixelBitmap.Height := 1; fDrawPixelBitmap.PixelFormat := pf24bit; fDrawPixelPtr := PRGB(fDrawPixelBitmap.Scanline[0]); end; destructor TIEMask.Destroy; begin fDrawPixelBitmap.Free(); FreeBits(); inherited; end; function TIEMask.CreateResampledMask(NewWidth, NewHeight: integer): TIEMask; var x, y, sx: integer; zx, zy: double; sxarr: array of integer; d_g, s_g, bp: pbyte; s_ga: pbytearray; begin CheckMemoryAllocation(); result := TIEMask.Create(); result.AllocateBits(NewWidth, NewHeight, fBitsperpixel); zx := Width / NewWidth; zy := Height / NewHeight; SetLength(sxarr, NewWidth); for x := 0 to NewWidth - 1 do sxarr[x] := trunc(x * zx); case fBitsperpixel of 1: for y := 0 to NewHeight - 1 do begin s_g := Scanline[trunc(y * zy)]; d_g := result.Scanline[y]; for x := 0 to NewWidth - 1 do begin sx := sxarr[x]; bp := pbyte(uint64(d_g) + (uint64(x) shr 3)); if (pbytearray(s_g)^[sx shr 3] and iebitmask1[sx and $7]) <> 0 then bp^ := bp^ or iebitmask1[x and 7] else bp^ := bp^ and not iebitmask1[x and 7]; end; end; 8: for y := 0 to NewHeight - 1 do begin s_ga := Scanline[trunc(y * zy)]; d_g := result.Scanline[y]; for x := 0 to NewWidth - 1 do begin d_g^ := s_ga[sxarr[x]]; inc(d_g); end; end; end; if not IsEmpty then begin result.fX1 := trunc(fX1/zx); result.fY1 := trunc(fY1/zy); result.fX2 := trunc(fX2/zx); result.fY2 := trunc(fY2/zy); end; result.fFull := fFull; end; {!! TIEMask.Assign Declaration procedure Assign(Source: ); overload; procedure Assign(Source: ); overload; Description Assigns Source mask or creates a mask from a TIEBitmap. Note: When creating a mask from a TIEBitmap, the image is reduced to 8bit gray scale and the intensity of each pixel determining the selection mask value. Example // Select the non-alpha areas of an image // Same as TImageEnView.SelectNonAlpha ImageEnView1.SelectionMask.Assign( ImageEnView1.AlphaChannel ); ImageEnView1.SelectCustom(); !!} procedure TIEMask.Assign(Source: TIEMask); begin if not assigned(Source) then exit; AllocateBits(Source.fWidth, Source.fHeight, Source.fBitsPerPixel); if Source.fBits <> nil then begin // allocate and copy only if actually necessary CheckMemoryAllocation(); CopyMemory(fBits, Source.fBits, fRowlen * fHeight); end; fX1 := Source.fX1; fY1 := Source.fY1; fX2 := Source.fX2; fY2 := Source.fY2; fFull := Source.fFull; end; procedure TIEMask.Assign(Source: TIEBitmap); var bmp: TIEBitmap; x, y: Integer; pSel, pBmp: pbyte; begin if not assigned(Source) then exit; bmp := TIEBitmap.create; try bmp.Assign( Source ); // Ensure it is the same size as our mask bmp.Resample( fWidth, fHeight, rfNone ); bmp.PixelFormat := ie8g; CheckMemoryAllocation(); fFull := True; for y := 0 to Height - 1 do begin pSel := ScanLine[ y ]; pBmp := bmp.ScanLine[ y ]; case BitsPerPixel of 1: for x := 0 to Width - 1 do begin // 1 Bit mask (values are 0 or 1) if pBmp^ <> 0 then SetPixelbw_inline( pSel, x, 1 ) else begin SetPixelbw_inline( pSel, x, 0 ); fFull := False; end; inc( pBmp ); end; 8: for x := 0 to Width - 1 do begin // 8 Bit mask (values are 0 to 255) if pBmp^ < 255 then fFull := false; pSel^ := pBmp^; inc( pSel ); inc( pBmp ); end; end; end; fX1 := 0; fX2 := fWidth - 1; fY1 := 0; fY2 := fHeight - 1; finally bmp.free; end; end; {!! TIEMask.SetPixel Declaration procedure SetPixel(x, y: integer; Alpha: integer); Description Set a single pixel selection at x, y coordinates. A pixel with mask 1 or >0 is selected. !!} // set mask pixel // supported bitsperpixel: 1, 8 // Alpha for 1bpp: // 1 = over image is fully visible (for selections: the region is selected) // 0 = over image is not visible (for selections: the region is not selected) // Alpha for 8bpp: // 255 = over image is fully visible // ... // 0 = over image is not visible procedure TIEMask.SetPixel(x, y: integer; Alpha: integer); var px: pbyte; begin if (x >= fWidth) or (y >= fHeight) or (x < 0) or (y < 0) then exit; CheckMemoryAllocation(); if Alpha <> 0 then begin if x < fX1 then fX1 := x; if x > fX2 then fX2 := x; if y < fY1 then fY1 := y; if y > fY2 then fY2 := y; if fX1 < 0 then fX1 := 0; if fX2 >= fWidth then fX2 := fWidth - 1; if fY1 < 0 then fY1 := 0; if fY2 >= fHeight then fY2 := fHeight - 1; end; if fFull then fFull := not ((fBitsPerPixel = 8) and (Alpha <> 255)) or ((fBitsPerPixel = 1) and (Alpha = 0)); px := fBits; inc(px, (fHeight - y - 1) * fRowlen); case fBitsperpixel of 1: begin // 1 bit per pixel SetPixelbw_inline(px, x, Alpha); end; 8: begin // 8 bits per pixel inc(px, x); px^ := Alpha; end; end; end; {!! TIEMask.SetRectangle Declaration procedure SetRectangle(Rect: TRect; Alpha: integer); procedure SetRectangle(x1, y1, x2, y2: integer; Alpha: integer); Description Set a rectanglular selection. A pixel with mask 1 or >0 is selected. Parameter Description Rect Rectangle to select. Alpha Alpha value (0 = not selected, >0 selected).
Example // Select rectangle (10, 10 - 14, 14) ImageEnView1.SelectionMask.SetRectangle(Rect(10, 10, 14, 14), 1); ImageEnView1.SelectCustom(); !!} procedure TIEMask.SetRectangle(Rect: TRect; Alpha: integer); var i: integer; begin for i := Rect.Top to Rect.Bottom do DrawHorizontalLine(Alpha, Rect.Left, Rect.Right, i); if Rect.Left < fX1 then fX1 := imax(0, Rect.Left); if Rect.Right > fX2 then fX2 := imin(fWidth - 1, Rect.Right); if Rect.Top < fY1 then fY1 := imax(0, Rect.Top); if Rect.Bottom > fY2 then fY2 := imin(fHeight - 1, Rect.Bottom); end; procedure TIEMask.SetRectangle(x1, y1, x2, y2: integer; Alpha: integer); begin SetRectangle(Rect(x1, y1, x2, y2), Alpha); end; {!! TIEMask.SetEllipse Declaration procedure SetEllipse(CenterX, CenterY, Width, Height: integer; Alpha: integer); Description Set an elliptical selection. A pixel with mask 1 or >0 is selected. Parameter Description CenterX Ellipse horizontal center. CenterY Ellipse vertical center. Width Ellipse width. Height Ellipse height. Alpha Alpha value (0 = not selected, >0 selected).
Example // Select an ellipse (10, 10 - 14, 14) ImageEnView1.SelectionMask.SetEllipse(10, 10, 14, 14); ImageEnView1.SelectCustom(); !!} procedure TIEMask.SetEllipse(CenterX, CenterY, Width, Height: integer; Alpha: integer); var X, Y: integer; err: integer; endx, endy: integer; radX, radY: integer; xsqr, ysqr: integer; xoffset, yoffset: integer; begin radX := Width div 2; radY := Height div 2; // don't need to adjust also CenterX, Y... because DrawHorizontalLine already does this check fX1 := imax(0, imin(CenterX - radX, fX1)); fX2 := imin(fWidth - 1, imax(CenterX + radX, fX2)); fY1 := imax(0, imin(CenterY - radY, fY1)); fY2 := imin(fHeight - 1, imax(CenterY + radY, fY2)); xsqr := 2 * radX * radX; ysqr := 2 * radY * radY; X := radX; Y := 0; xoffset := radY * radY * (1 - (2 * radX)); yoffset := radX * radX; err := 0; endx := ysqr * radX; endy := 0; while endx >= endy do begin DrawHorizontalLine(Alpha, CenterX - X, CenterX + X, CenterY + Y); DrawHorizontalLine(Alpha, CenterX - X, CenterX + X, CenterY - Y); inc(Y); inc(endy, xsqr); inc(err, yoffset); inc(yoffset, xsqr); if (2 * err) + xoffset > 0 then begin dec(X); dec(endx, ysqr); inc(err, xoffset); inc(xoffset, ysqr); End; end; X := 0; Y := radY; xoffset := radY * radY; yoffset := radX * radX * (1 - (2 * radY)); err := 0; endx := 0; endy := xsqr * radY; while endx <= endy do begin DrawHorizontalLine(Alpha, CenterX - X, CenterX + X, CenterY + Y); DrawHorizontalLine(Alpha, CenterX - X, CenterX + X, CenterY - Y); inc(X); inc(endx, ysqr); inc(err, xoffset); inc(xoffset, ysqr); if (2 * err) + yoffset > 0 then begin dec(Y); dec(endy, xsqr); inc(err, yoffset); inc(yoffset, xsqr); End; end; end; {!! TIEMask.SyncRect Declaration procedure SyncRect; Description Adjusts
, , and to enclose the bounding box of the selected pixels. !!} procedure TIEMask.SyncRect; procedure SetRect(x, y: integer; var fX1, fY1, fX2, fY2: integer; fWidth, fHeight: integer); {$ifdef IESUPPORTINLINE} inline; {$endif} begin if x < fX1 then fX1 := x; if x > fX2 then fX2 := x; if y < fY1 then fY1 := y; if y > fY2 then fY2 := y; if fX1 < 0 then fX1 := 0; if fX2 >= fWidth then fX2 := fWidth - 1; if fY1 < 0 then fY1 := 0; if fY2 >= fHeight then fY2 := fHeight - 1; end; var y, x: integer; px: pbyte; begin CheckMemoryAllocation(); fX1 := 2147483647; fY1 := 2147483647; fX2 := 0; fY2 := 0; for y := 0 to fHeight - 1 do begin case fBitsPerPixel of 1: begin px := fBits; inc(px, (fHeight - y - 1) * fRowlen); for x := 0 to fWidth - 1 do begin if GetPixelbw_inline(px, x) <> 0 then SetRect(x, y, fX1, fY1, fX2, fY2, fWidth, fHeight); end; end; 8: begin px := Scanline[y]; for x := 0 to fWidth - 1 do begin if px^ <> 0 then SetRect(x, y, fX1, fY1, fX2, fY2, fWidth, fHeight); inc(px); end; end; end; end; end; {!! TIEMask.GetPixel Declaration function GetPixel(x, y: integer): integer; Description Return the value of the pixel at x, y coordinates. !!} // get mask pixel // supported bitsperpixel: 1, 8 // Value for 1bpp: // 1 = over image is fully visible (for selections: the region is selected) // 0 = over image is not visible (for selections: the region is not selected) // Value for 8bpp: // 255 = over image si fully visible // ... // 0 = over image is not visible function TIEMask.GetPixel(x, y: integer): integer; var px: pbyte; begin if (x >= fWidth) or (y >= fHeight) or (x < 0) or (y < 0) then result := 0 else begin CheckMemoryAllocation(); px := fBits; inc(px, (fHeight - y - 1) * fRowlen); case fBitsperpixel of 1: begin // 1 bit per pixel result := GetPixelbw_inline(px, x); end; 8: begin // 8 bits per pixel inc(px, x); result := px^; end; else result := 0; end; end; end; {!! TIEMask.IsPointInside Declaration function IsPointInside(x, y: integer): boolean; Description Return true if the x, y pixel is not 0. !!} // return true if the x, y point is inside non zero mask function TIEMask.IsPointInside(x, y: integer): boolean; begin result := (fBits <> nil) and (GetPixel(x, y) <> 0); end; {!! TIEMask.AllocateBits Declaration procedure AllocateBits(width, height: integer; bitsperpixel: integer); Description Allocates memory for the map. Memory is zero filled. bitsperpixel can be 1 or 8. !!} // allocate Mask (and free previous) // memory is initialized to zero procedure TIEMask.AllocateBits(width, height: integer; bitsperpixel: integer); begin FreeBits; fWidth := width; fHeight := height; fBitsperpixel := bitsperpixel; fRowlen := IEBitmapRowLen(width, fBitsPerPixel, 32); fBits := nil; // CheckMemoryAllocation() will allocate it fX1 := 2147483647; fY1 := 2147483647; fX2 := 0; fY2 := 0; fFull := false; end; // Check if actual memory allocation is necessary // AllocateBits doesn't allocate memory, so TIEMask will allocate memory only if necessary. procedure TIEMask.CheckMemoryAllocation(); begin if fBits = nil then fBits := AllocMem(fHeight * fRowlen); end; function TIEMask.GetBits(): pbyte; begin CheckMemoryAllocation(); result := fBits; end; {!! TIEMask.Resize Declaration procedure Resize(NewWidth, NewHeight: integer); Description Resizes this selection map. !!} procedure TIEMask.Resize(NewWidth, NewHeight: integer); var lBits, ps, pd: pbyte; lRowLen, y, rl: integer; h: integer; begin if (NewWidth <> fWidth) or (NewHeight <> fHeight) then begin if fBits <> nil then begin lBits := fBits; lRowLen := fRowLen; fRowLen := IEBitmapRowLen(NewWidth, fBitsPerPixel, 32); fBits := AllocMem(NewHeight * fRowlen); rl := imin(lRowLen, fRowLen); ps := lBits; inc(ps, (fHeight - 1) * lRowLen); pd := fBits; inc(pd, (NewHeight - 1) * fRowLen); h := imin(fHeight, NewHeight); for y := 0 to h - 1 do begin CopyMemory(pd, ps, rl); dec(ps, lRowLen); dec(pd, fRowLen); end; freemem(lBits); end else begin // no memory still allocated, resize don't necessary fRowLen := IEBitmapRowLen(NewWidth, fBitsPerPixel, 32); end; fWidth := NewWidth; fHeight := NewHeight; if fX1 < fX2 then begin fX1 := imin(fX1, fWidth - 1); fY1 := imin(fY1, fHeight - 1); fX2 := imin(fX2, fWidth - 1); fY2 := imin(fY2, fHeight - 1); end; end; end; {!! TIEMask.FreeBits Declaration procedure FreeBits; Description Free the allocated mask. !!} procedure TIEMask.FreeBits; begin if fTmpBmp <> nil then begin freemem(fTmpBmp); freemem(fTmpBmpScanline); end; fTmpBmp := nil; fTmpBmpScanline := nil; fTmpBmpWidth := 0; fTmpBmpHeight := 0; if fBits <> nil then freemem(fBits); fBits := nil; fWidth := 0; fHeight := 0; fBitsperpixel := 0; fRowlen := 0; end; {!! TIEMask.InvertCanvas Declaration procedure InvertCanvas(Dest: TCanvas; xDst, yDst, dxDst, dyDst: integer; xMask, yMask, dxMask, dyMask: integer); Description For internal use only. !!} // Inverts pixels of Dest rect, stretching mask rect // Only with fBitsPerPixel=1 procedure TIEMask.InvertCanvas(Dest: TCanvas; xDst, yDst, dxDst, dyDst: integer; xMask, yMask, dxMask, dyMask: integer); var bi: ^TBitmapInfo; begin if (fX1 = 2147483647) or (fY1 = 2147483647) or (fBitsPerPixel <> 1) then exit; CheckMemoryAllocation(); with fBitmapInfoHeader1 do begin biWidth := fWidth; biHeight := fHeight; end; bi := @fBitmapInfoHeader1; StretchDIBits(Dest.Handle, xDst, yDst, dxDst, dyDst, xMask, (fheight - dyMask - yMask), dxMask, dyMask, fBits, bi^, DIB_RGB_COLORS, SRCINVERT); end; procedure Stretch(BitsPerPixel: integer; dest: pbyte; dxDst, dyDst, xSrc, ySrc, dxSrc, dySrc: integer; src: pbyte; srcWidth, srcHeight: integer; fx1, fy1, fx2, fy2: integer); var rx, ry, sy: integer; y2, x2: integer; x, y: integer; px1, px2, px3: pbyte; destRowlen, srcRowLen: integer; ffx1, ffy1, ffx2, ffy2: integer; zx, zy: double; arx: array of integer; arxp: pinteger; begin if (dxDst < 1) or (dyDst < 1) then exit; destRowlen := IEBitmapRowLen(dxDst, BitsPerPixel, 32); zeromemory(dest, destRowlen * dyDst); srcRowLen := IEBitmapRowLen(srcWidth, BitsPerPixel, 32); ry := trunc((dySrc / dyDst) * 16384); // 2^14 rx := trunc((dxSrc / dxDst) * 16384); y2 := dyDst - 1; x2 := dxDst - 1; zx := dxDst / dxSrc; zy := dyDst / dySrc; ffy1 := imax(trunc(zy * (fy1 - ySrc)), 0); ffx1 := imax(trunc(zx * (fx1 - xSrc)), 0); ffy2 := imin(trunc(zy * (fy2 - ySrc + 1)), y2); ffx2 := imin(trunc(zx * (fx2 - xSrc + 1)), x2); if (ffx2-ffx1+1)<=0 then exit; zeromemory(dest, IEBitmapRowLen(dxDst, BitsPerPixel, 32) * dyDst); SetLength(arx, (ffx2 - ffx1 + 1)); arxp := @arx[0]; for x := ffx1 to ffx2 do begin arxp^ := ((rx * x) shr 14) + xSrc; inc(arxp); end; for y := ffy1 to ffy2 do begin px2 := dest; inc(px2, (dyDst - y - 1) * destRowlen); sy := imin( SrcHeight-1, ((ry * y) shr 14) + ySrc ); // 3.0.1 px1 := src; inc(px1, (srcHeight - sy - 1) * srcRowlen); arxp := @arx[0]; case BitsPerPixel of 1: begin for x := ffx1 to ffx2 do begin if (pbytearray(px1)^[arxp^ shr 3] and iebitmask1[arxp^ and $7]) <> 0 then begin px3 := @(pbytearray(px2)^[x shr 3]); px3^ := px3^ or iebitmask1[x and 7]; // to 1 end; inc(arxp); end; end; 8: begin for x := ffx1 to ffx2 do begin pbytearray(px2)^[x] := pbytearray(px1)^[arxp^]; inc(arxp); end; end; end; end; end; {!! TIEMask.DrawOutline Declaration procedure DrawOutline(Dest: TCanvas; xDst, yDst, dxDst, dyDst: integer; xMask, yMask, dxMask, dyMask: integer; AniCounter: integer; Color1, Color2: TColor; actualRect: PRect = nil); Description For internal use only. !!} procedure TIEMask.DrawOutline(Dest: TCanvas; xDst, yDst, dxDst, dyDst: integer; xMask, yMask, dxMask, dyMask: integer; AniCounter: integer; Color1, Color2: TColor; actualRect: PRect); var row, col, x, y: integer; px, px2, pb: pbyte; rowlo, rowhi, collo, colhi: integer; zx, zy: integer; c1, c2: integer; crgb: array[false..true] of TRGB; rgb: TRGB; xx, yy: integer; row1, row2: integer; // procedure DrawPix; var y: integer; begin xx := col + xDst; rgb := crgb[(((xx + yy + AniCounter) and 7) < 4)]; if col = 0 then begin x := ((col * zx) shr 14) + xMask; if (x <= fX1) then begin fDrawPixelPtr^ := rgb; Dest.Draw(xx, yy, fDrawPixelBitmap); end; end else if col = colhi then begin x := ((col * zx) shr 14) + xMask; if (x >= fX2) or (dxMask = Width) then begin fDrawPixelPtr^ := rgb; Dest.Draw(xx, yy, fDrawPixelBitmap); end; end else if row = 0 then begin y := ((row * zy) shr 14) + yMask; if (y <= fY1) then begin fDrawPixelPtr^ := rgb; Dest.Draw(xx, yy, fDrawPixelBitmap); end; end else if row = rowhi then begin y := ((row * zy) shr 14) + yMask; if (y >= fY2) or (dyMask = Height) then begin fDrawPixelPtr^ := rgb; Dest.Draw(xx, yy, fDrawPixelBitmap); end; end else begin case fBitsPerPixel of 1: begin c1 := 13 - ((col - 1) and 7); c2 := (col - 1) shr 3; for y := row1 to row2 do begin // read 3 pixels at the time px2 := pbyte(uint64(fTmpBmpScanline[y]) + uint64(c2)); if ((IESwapWord(pword(px2)^) shr c1) and 7) < 7 then begin fDrawPixelPtr^ := rgb; Dest.Draw(xx, yy, fDrawPixelBitmap); break; end; end; end; 8: for y := row1 to row2 do begin px2 := pbyte(uint64(fTmpBmpScanline[y]) + uint64(col - 1)); if px2^ = 0 then begin fDrawPixelPtr^ := rgb; Dest.Draw(xx, yy, fDrawPixelBitmap); end; inc(px2); if px2^ = 0 then begin fDrawPixelPtr^ := rgb; Dest.Draw(xx, yy, fDrawPixelBitmap); end; inc(px2); if px2^ = 0 then begin fDrawPixelPtr^ := rgb; Dest.Draw(xx, yy, fDrawPixelBitmap); end; end; end; end; end; // begin if (dxDst < 1) or (dyDst < 1) or (fX1 = 2147483647) or (fY1 = 2147483647) then exit; CheckMemoryAllocation(); crgb[false] := TColor2TRGB(Color1); crgb[true] := TColor2TRGB(Color2); if (fTmpBmpWidth <> dxDst) or (fTmpBmpHeight <> dyDst) then begin fTmpBmpWidth := dxDst; fTmpBmpHeight := dyDst; row := IEBitmaprowlen(dxDst, fBitsPerPixel, 32); if fTmpBmp <> nil then begin freemem(fTmpBmp); freemem(fTmpBmpScanline); end; getmem(fTmpBmp, row * dyDst); getmem(fTmpBmpScanline, sizeof(pointer) * dyDst); for y := 0 to dyDst - 1 do begin pb := fTmpBmp; inc(pb, (dyDst - y - 1) * row); fTmpBmpScanline[y] := pb; end; end; Stretch(fBitsPerPixel, fTmpBmp, dxDst, dyDst, xMask, yMask, dxMask, dyMask, fBits, fWidth, fHeight, fx1, fy1, fx2, fy2); zx := trunc((dxMask / dxDst) * 16384); zy := trunc((dyMask / dyDst) * 16384); rowlo := imax(((fY1 - yMask) * 16384 div zy), 0); rowhi := imin(((fY2 - yMask + 1) * 16384 div zy) + 1, (dyDst - 1)); collo := imax(((fX1 - xMask) * 16384 div zx), 0); colhi := imin(((fX2 - xMask + 1) * 16384 div zx) + 1, (dxDst - 1)); if assigned(actualRect) then actualRect^ := Rect(xDst+collo+1, yDst+rowlo+1, xDst+colhi-1, yDst+rowhi-1); // draw outline of the mask Dest.Pen.Style := psSolid; Dest.Pen.Mode := pmCopy; for row := rowlo to rowhi do begin px := fTmpBmpScanline[row]; yy := row + yDst; row1 := imax(row - 1, 0); row2 := imin(row + 1, dyDst - 1); case fBitsPerPixel of 1: for col := collo to colhi do begin if (pbytearray(px)^[col shr 3] and iebitmask1[col and $7]) <> 0 then DrawPix; end; 8: for col := collo to colhi do begin if pbytearray(px)^[col] <> 0 then DrawPix; end; end; end; end; {!! TIEMask.DrawOuter Declaration procedure DrawOuter(Dest: TBitmap; xDst, yDst, dxDst, dyDst: integer; xMask, yMask, dxMask, dyMask: integer; AlphaBlend: integer; Color: TColor); Description For internal use only. !!} procedure TIEMask.DrawOuter(Dest: TBitmap; xDst, yDst, dxDst, dyDst: integer; xMask, yMask, dxMask, dyMask: integer; AlphaBlend: integer; Color: TColor); var row, col, y, dw, dh: integer; px, pb: pbyte; rowlo, rowhi, collo, colhi: integer; zx, zy: integer; dzx, dzy: double; pxd: PRGB; clr: TRGB; alp: double; begin if (dxDst < 1) or (dyDst < 1) or (fX1 = 2147483647) or (fY1 = 2147483647) then exit; CheckMemoryAllocation(); if yDst<0 then begin dzy := dyMask/dyDst; dyDst := dyDst-yDst; dyMask := dyMask-round(yDst*dzy); yMask := yMask-round(yDst*dzy); yDst := 0; end; if xDst<0 then begin dzx := dxMask/dxDst; dxDst := dxDst-xDst; dxMask := dxMask-round(xDst*dzx); xMask := xMask-round(xDst*dzx); xDst := 0; end; if (fTmpBmpWidth <> dxDst) or (fTmpBmpHeight <> dyDst) then begin fTmpBmpWidth := dxDst; fTmpBmpHeight := dyDst; row := IEBitmaprowlen(dxDst, fBitsPerPixel, 32); if fTmpBmp <> nil then begin freemem(fTmpBmp); freemem(fTmpBmpScanline); end; getmem(fTmpBmp, row * dyDst); getmem(fTmpBmpScanline, sizeof(pointer) * dyDst); for y := 0 to dyDst - 1 do begin pb := fTmpBmp; inc(pb, (dyDst - y - 1) * row); fTmpBmpScanline[y] := pb; end; end; Stretch(fBitsPerPixel, fTmpBmp, dxDst, dyDst, xMask, yMask, dxMask, dyMask, fBits, fWidth, fHeight, fx1, fy1, fx2, fy2); zx := trunc((dxMask / dxDst) * 16384); zy := trunc((dyMask / dyDst) * 16384); dw := Dest.Width; dh := Dest.Height; rowlo := imax(((-yMask) * 16384 div zy), 0); rowhi := imin(((Height - yMask) * 16384 div zy) + 1, (dyDst - 1)); rowhi := imin(rowhi, dh - 1); collo := imax(((0 - xMask) * 16384 div zx), 0); colhi := imin(((Width - xMask) * 16384 div zx) + 1, (dxDst - 1)); colhi := imin(colhi, dw - 1); clr := TColor2TRGB(Color); alp := AlphaBlend / 255; for row := rowlo to rowhi do begin px := fTmpBmpScanline[row]; pxd := Dest.Scanline[row + yDst]; inc(pxd, collo + xDst); if row+yDst >= Dest.Height then break; if AlphaBlend=-1 then begin // just set fixed values case fBitsPerPixel of 1: for col := collo to colhi do begin if collo + xDst + col >= dw then break; if (pbytearray(px)^[col shr 3] and iebitmask1[col and $7]) = 0 then if (((row and 1) = 0) and ((col and 1) = 0)) or (((row and 1) = 1) and ((col and 1) = 1)) then with pxd^ do begin r := 97; g := 97; b := 97; end; inc(pxd); end; 8: for col := collo to colhi do begin if collo + xDst + col >= dw then break; if (pbytearray(px)^[col]) = 0 then if (((row and 1) = 0) and ((col and 1) = 0)) or (((row and 1) = 1) and ((col and 1) = 1)) then with pxd^ do begin r := 97; g := 97; b := 97; end; inc(pxd); end; end; end else begin // use alpha blend case fBitsPerPixel of 1: for col := collo to colhi do begin if collo + xDst + col >= dw then break; if (pbytearray(px)^[col shr 3] and iebitmask1[col and $7]) = 0 then with pxd^ do begin r := trunc(clr.r*alp+r*(1-alp)); g := trunc(clr.g*alp+g*(1-alp)); b := trunc(clr.b*alp+b*(1-alp)); end; inc(pxd); end; 8: for col := collo to colhi do begin if collo + xDst + col >= dw then break; if (pbytearray(px)^[col]) = 0 then with pxd^ do begin r := trunc(clr.r*alp+r*(1-alp)); g := trunc(clr.g*alp+g*(1-alp)); b := trunc(clr.b*alp+b*(1-alp)); end; inc(pxd); end; end; end; end; end; {!! TIEMask.CopyBitmap Declaration procedure CopyBitmap(Dest, Source: TBitmap; dstonlymask, srconlymask: boolean); Description For internal use only. !!} // copy Source in Dest applying mask // Source and Dest can be pf24bit or pf1bit (must be Source.PixelFormat=Dest.PixelFormat) // when dstonlymask is false the entire source bitmap is copied to dest // when dstonlymask is true only the effective mask region is copied to dest // when srconlymask is false the source has some size of the mask // when srconlymask is true the source has size of real used mask procedure TIEMask.CopyBitmap(Dest, Source: TBitmap; dstonlymask, srconlymask: boolean); var row, col: integer; px1, px2: PRGB; a: integer; pb: pbyte; pii: pbyte; ox, oy, sx, sy: integer; begin if (fX1 > fX2) and (fY1 > fY2) then exit; CheckMemoryAllocation(); if dstonlymask then begin ox := fX1; oy := fY1; end else begin ox := 0; oy := 0; end; if srconlymask then begin sx := fX1; sy := fY1; end else begin sx := 0; sy := 0; end; case fBitsperpixel of 1: begin // 1 bit per pixel (copy if mask is 1) if (Source.PixelFormat = pf24bit) and (Dest.PixelFormat = pf24bit) then begin // pf24bit for row := fY1 to fY2 do begin px1 := Source.ScanLine[row - sy]; inc(px1, fX1 - sx); px2 := Dest.ScanLine[row - oy]; inc(px2, fX1 - ox); pb := fBits; inc(pb, (fHeight - row - 1) * fRowlen); for col := fX1 to fX2 do begin if GetPixelbw_inline(pb, col) <> 0 then px2^ := px1^; inc(px2); inc(px1); end; end; end else if (Source.PixelFormat = pf1bit) and (Dest.PixelFormat = pf1bit) then begin // pf1bit for row := fY1 to fY2 do begin px1 := Source.ScanLine[row - sy]; px2 := Dest.ScanLine[row - oy]; pb := fBits; inc(pb, (fHeight - row - 1) * fRowlen); for col := fX1 to fX2 do begin if GetPixelbw_inline(pb, col) <> 0 then SetPixelbw_inline(pbyte(px2), col - ox, GetPixelbw_inline(pbyte(px1), col - sx)); end; end; end; end; 8: begin // 8 bits per pixel (alpha blend) if (Source.PixelFormat = pf24bit) and (Dest.PixelFormat = pf24bit) then begin // pf24bit for row := fY1 to fY2 do begin px1 := Source.ScanLine[row - sy]; inc(px1, fX1 - sx); px2 := Dest.ScanLine[row - oy]; inc(px2, fX1 - ox); pii := fBits; inc(pii, (fHeight - row - 1) * fRowlen); for col := fX1 to fX2 do begin pb := pii; inc(pb, col); a := pb^ shl 10; px2^.r := (a * (px1^.r - px2^.r) shr 18 + px2^.r); px2^.g := (a * (px1^.g - px2^.g) shr 18 + px2^.g); px2^.b := (a * (px1^.b - px2^.b) shr 18 + px2^.b); inc(px2); inc(px1); end; end; end else if (Source.PixelFormat = pf1bit) and (Dest.PixelFormat = pf1bit) then begin // pf1bit for row := fY1 to fY2 do begin px1 := Source.ScanLine[row - sy]; px2 := Dest.ScanLine[row - oy]; pii := fBits; inc(pii, (fHeight - row - 1) * fRowlen); for col := fX1 to fX2 do begin pb := pii; inc(pb, col); a := pb^; if a <> 0 then SetPixelbw_inline(pbyte(px2), col - ox, GetPixelbw_inline(pbyte(px1), col - sx)); end; end; end; end; end; end; {!! TIEMask.CopyIEBitmap Declaration procedure CopyIEBitmap(Dest, Source: ; dstonlymask, srconlymask: boolean; UseAlphaChannel: boolean); Description For internal use only. !!} // copy Source in Dest applying mask (using TIEBItmap instead of TBitmap) // Source and Dest can be ie24RGB or ie1g (must be Source.PixelFormat=Dest.PixelFormat) // when dstonlymask is false the entire source bitmap is copied to dest // when dstonlymask is true only the actual mask region is copied to dest // when srconlymask is false the source has same size of the mask // when srconlymask is true the source has size of actual used mask // If UseAlphaChannel is true then calls CopyIEBitmapAlpha when Dest or Source (or both) has alpha channel procedure TIEMask.CopyIEBitmap(Dest, Source: TIEBitmap; dstonlymask, srconlymask: boolean; UseAlphaChannel: boolean); var row, col: integer; px1, px2: PRGB; a: integer; pb, pb1, pb2: pbyte; pii: pbyte; ox, oy, sx, sy: integer; nX2, nY2: integer; begin CheckMemoryAllocation(); if srconlymask then begin nX2 := imin(fX1 + imin(fX2 - fX1, Source.Width - 1), Dest.Width - 1); nY2 := imin(fY1 + imin(fY2 - fY1, Source.Height - 1), Dest.height - 1); end else begin nX2 := fX2; nY2 := fY2; end; if (fX1 > nX2) and (fY1 > nY2) then exit; if dstonlymask then begin ox := fX1; oy := fY1; end else begin ox := 0; oy := 0; end; if srconlymask then begin sx := fX1; sy := fY1; end else begin sx := 0; sy := 0; end; case fBitsperpixel of 1: begin // 1 bit per pixel (copy if mask is 1) if (Source.PixelFormat = ie24RGB) and (Dest.PixelFormat = ie24RGB) then begin // ie24RGB for row := fY1 to nY2 do begin px1 := Source.ScanLine[row - sy]; inc(px1, fX1 - sx); px2 := Dest.ScanLine[row - oy]; inc(px2, fX1 - ox); pb := fBits; inc(pb, (fHeight - row - 1) * fRowlen); for col := fX1 to nX2 do begin if GetPixelbw_inline(pb, col) <> 0 then px2^ := px1^; inc(px2); inc(px1); end; end; end else if ((Source.PixelFormat = ie8g) and (Dest.PixelFormat = ie8g)) or ((Source.PixelFormat = ie8p) and (Dest.PixelFormat = ie8p)) then begin // ie8g or ie8p for row := fY1 to nY2 do begin pb1 := Source.ScanLine[row - sy]; inc(pb1, fX1 - sx); pb2 := Dest.ScanLine[row - oy]; inc(pb2, fX1 - ox); pb := fBits; inc(pb, (fHeight - row - 1) * fRowlen); for col := fX1 to nX2 do begin if GetPixelbw_inline(pb, col) <> 0 then pb2^ := pb1^; inc(pb2); inc(pb1); end; end; end else if (Source.PixelFormat = ie1g) and (Dest.PixelFormat = ie1g) then begin // ie1g for row := fY1 to nY2 do begin px1 := Source.ScanLine[row - sy]; px2 := Dest.ScanLine[row - oy]; pb := fBits; inc(pb, (fHeight - row - 1) * fRowlen); for col := fX1 to nX2 do begin if GetPixelbw_inline(pb, col) <> 0 then SetPixelbw_inline(pbyte(px2), col - ox, GetPixelbw_inline(pbyte(px1), col - sx)); end; end; end else if (Source.PixelFormat = Dest.PixelFormat) then begin for row := fY1 to nY2 do begin pb := fBits; inc(pb, (fHeight - row - 1) * fRowlen); case Source.PixelFormat of ie16g: for col := fX1 to nX2 do if GetPixelbw_inline(pb, col) <> 0 then Dest.Pixels_ie16g[col - ox, row - oy] := Source.Pixels_ie16g[col - sx, row - sy]; ie32f: for col := fX1 to nX2 do if GetPixelbw_inline(pb, col) <> 0 then Dest.Pixels_ie32f[col - ox, row - oy] := Source.Pixels_ie32f[col - sx, row - sy]; ie32RGB: for col := fX1 to nX2 do if GetPixelbw_inline(pb, col) <> 0 then Dest.Pixels_ie32RGB[col - ox, row - oy] := Source.Pixels_ie32RGB[col - sx, row - sy]; ieCMYK: for col := fX1 to nX2 do if GetPixelbw_inline(pb, col) <> 0 then Dest.Pixels_ieCMYK[col - ox, row - oy] := Source.Pixels_ieCMYK[col - sx, row - sy]; ieCIELab: for col := fX1 to nX2 do if GetPixelbw_inline(pb, col) <> 0 then Dest.Pixels_ieCIELab[col - ox, row - oy] := Source.Pixels_ieCIELab[col - sx, row - sy]; ie48RGB: for col := fX1 to nX2 do if GetPixelbw_inline(pb, col) <> 0 then Dest.Pixels_ie48RGB[col - ox, row - oy] := Source.Pixels_ie48RGB[col - sx, row - sy]; end; end; end; end; 8: begin // 8 bits per pixel (alpha blend) if (Source.PixelFormat = ie24RGB) and (Dest.PixelFormat = ie24RGB) then begin // ie24RGB for row := fY1 to nY2 do begin px1 := Source.ScanLine[row - sy]; inc(px1, fX1 - sx); px2 := Dest.ScanLine[row - oy]; inc(px2, fX1 - ox); pii := fBits; inc(pii, (fHeight - row - 1) * fRowlen); for col := fX1 to nX2 do begin pb := pii; inc(pb, col); a := pb^ shl 10; px2^.r := (a * (px1^.r - px2^.r) shr 18 + px2^.r); px2^.g := (a * (px1^.g - px2^.g) shr 18 + px2^.g); px2^.b := (a * (px1^.b - px2^.b) shr 18 + px2^.b); inc(px2); inc(px1); end; end; end else if ((Source.PixelFormat = ie8g) and (Dest.PixelFormat = ie8g)) or ((Source.PixelFormat = ie8p) and (Dest.PixelFormat = ie8p)) then begin // ie8g or ie8p for row := fY1 to nY2 do begin pb1 := Source.ScanLine[row - sy]; inc(pb1, fX1 - sx); pb2 := Dest.ScanLine[row - oy]; inc(pb2, fX1 - ox); pii := fBits; inc(pii, (fHeight - row - 1) * fRowlen); for col := fX1 to nX2 do begin pb := pii; inc(pb, col); a := pb^ shl 10; pb2^ := (a * (pb1^ - pb2^) shr 18 + pb2^); inc(pb2); inc(pb1); end; end; end else if (Source.PixelFormat = ie1g) and (Dest.PixelFormat = ie1g) then begin // ie1g for row := fY1 to nY2 do begin px1 := Source.ScanLine[row - sy]; px2 := Dest.ScanLine[row - oy]; pii := fBits; inc(pii, (fHeight - row - 1) * fRowlen); for col := fX1 to nX2 do begin pb := pii; inc(pb, col); a := pb^; if a <> 0 then SetPixelbw_inline(pbyte(px2), col - ox, GetPixelbw_inline(pbyte(px1), col - sx)); end; end; end; end; end; if UseAlphaChannel and (Dest.HasAlphaChannel or Source.HasAlphaChannel) then CopyIEBitmapAlpha(Dest, Source, dstonlymask, srconlymask); end; {!! TIEMask.CopyIEBitmapAlpha Declaration procedure CopyIEBitmapAlpha(Dest, Source: ; dstonlymask, srconlymask: boolean); Description For internal use only. !!} // Like CopyIEBitmap, but sets the alpha channel in Dest (0=no selection, 255=selection, if Source is 255, otherwise set Source.Alpha) procedure TIEMask.CopyIEBitmapAlpha(Dest, Source: TIEBitmap; dstonlymask, srconlymask: boolean); var row, col: integer; px1, px2: pbyte; pb: pbyte; ox, oy, sx, sy, ii: integer; al255: array of byte; nX2, nY2: integer; begin CheckMemoryAllocation(); if srconlymask then begin nX2 := imin( fX1 + imin( fX2 - fX1, Source.Width - 1), Dest.Width - 1 ); nY2 := imin( fY1 + imin( fY2 - fY1, Source.Height - 1), Dest.height - 1 ); end else begin nX2 := fX2; nY2 := fY2; end; if (fX1 > nX2) and (fY1 > nY2) then exit; if dstonlymask then begin ox := fX1; oy := fY1; end else begin ox := 0; oy := 0; end; if srconlymask then begin sx := fX1; sy := fY1; end else begin sx := 0; sy := 0; end; if not Source.HasAlphaChannel then begin SetLength(al255, Source.Width); fillchar(al255[0], Source.Width, 255); end; for row := fY1 to nY2 do begin if Source.HasAlphaChannel then px1 := Source.AlphaChannel.ScanLine[row - sy] else px1 := @al255[0]; inc(px1, fX1 - sx); px2 := Dest.AlphaChannel.ScanLine[row - oy]; inc(px2, fX1 - ox); pb := fBits; inc(pb, (fHeight - row - 1) * fRowlen); case fBitsPerPixel of 1: for col := fX1 to nX2 do begin if GetPixelbw_inline(pb, col) <> 0 then // selected px2^ := imin(px1^, 255) else // not selected px2^ := 0; inc(px2); inc(px1); end; 8: for col := fX1 to nX2 do begin ii := pbytearray(pb)^[col]; if ii <> 0 then // selected px2^ := imin(px1^, ii) else // not selected px2^ := 0; inc(px2); inc(px1); end; end; end; Dest.AlphaChannel.Full := false; end; // draw an horizontal line, associating Alpha value to the set pixels // return number of pixel written function TIEMask.DrawHorizontalLine(Alpha: integer; xleft, xright, y: integer): integer; var x: integer; pb: pbyte; pp: pbytearray; begin CheckMemoryAllocation(); result := 0; if xleft < 0 then xleft := 0; if xright >= fWidth then xright := fWidth - 1; if y < 0 then y := 0; if y >= fHeight then y := fHeight - 1; if fFull then fFull := not ((fBitsPerPixel = 8) and (Alpha <> 255)) or ((fBitsPerPixel = 1) and (Alpha = 0)); case fBitsperpixel of 1: begin // 1 bit per pixel, Alpha must be 1 pb := fBits; inc(pb, (fHeight - y - 1) * fRowlen); pp := pbytearray(pb); if Alpha=1 then begin for x := xleft to xright do begin pb := @(pp^[x shr 3]); pb^ := pb^ or iebitmask1[x and 7]; inc(result); end; end else begin for x := xleft to xright do begin pb := @(pp^[x shr 3]); pb^ := pb^ and not iebitmask1[x and 7]; inc(result); end; end; end; 8: begin // 8 bits per pixel pb := fBits; inc(pb, (fHeight - y - 1) * fRowlen + xleft); FillChar(pb^, xright - xleft + 1, Alpha); inc(result, xright - xleft + 1); end; end; end; {!! TIEMask.ScanLine Declaration property ScanLine[row: integer]: pointer; Description This is equivalent to the Scanline property of TBitmap. It allows you to get/set the mask by hand. Example // Set all pixels within selection as red // Same as ImageEnView1.SetSelectedPixelsColor var x, y: Integer; pSel: pbyte; pPix: PRGB; begin if ImageEnView1.SelectionMask.IsEmpty then raise Exception.create( 'Nothing selected' ); if ImageEnView1.IEBitmap.PixelFormat <> ie24RGB then raise Exception.create( 'Not 24bit' ); // Process selected area for y := 0 to ImageEnView1.SelectionMask.Height - 1 do begin pSel := ImageEnView1.SelectionMask.ScanLine[ y ]; pPix := ImageEnView1.IEBitmap.ScanLine[ y ]; case ImageEnView1.SelectionMask.BitsPerPixel of 1: for x := 0 to ImageEnView1.SelectionMask.Width - 1 do begin // 1 Bit mask (values are 0 or 1) if (pbytearray(pSel)^[x shr 3] and iebitmask1[x and $7]) <> 0 then begin pPix^.R := 255; pPix^.G := 0; pPix^.B := 0; end; inc( pPix ); end; 8: for x := 0 to ImageEnView1.SelectionMask.Width - 1 do begin // 8 Bit mask (values are 0 to 255) if pSel^ <> 0 then begin pPix^.R := 255; pPix^.G := 0; pPix^.B := 0; end; inc( pSel ); inc( pPix ); end; end; end; ImageEnView1.Update(); end; !!} function TIEMask.GetScanLine(Row: integer): pointer; var pb: pbyte; begin CheckMemoryAllocation(); pb := fBits; inc(pb, (fHeight - Row - 1) * fRowlen); result := pb; end; {!! TIEMask.Fill Declaration procedure Fill(Alpha: integer = 255); Description Fills the entire mask using the Alpha value. Valid range 0 (fully transparent) to 255 (fully opaque). !!} procedure TIEMask.Fill(Alpha: integer); begin CheckMemoryAllocation(); fillchar(fBits^, fRowLen * fHeight, Alpha); fFull := not ((fBitsPerPixel = 8) and (Alpha <> 255)) or ((fBitsPerPixel = 1) and (Alpha = 0)); end; {!! TIEMask.IsEmpty Declaration function IsEmpty: boolean; Description Returns True if the mask contains all zeros. !!} function TIEMask.IsEmpty: boolean; begin result := fX1 = 2147483647; end; {!! TIEMask.Empty Declaration procedure Empty; Description Fills the entire mask with zeros. !!} procedure TIEMask.Empty; begin if fBits <> nil then begin Fill(0); end; fX1 := 2147483647; fY1 := 2147483647; fX2 := 0; fY2 := 0; end; {!! TIEMask.DrawPolygon Declaration procedure DrawPolygon(Alpha: integer; SelPoly: ; SelPolyCount: integer); Description Draw specified polygon in the mask, using Alpha value for all pixels. Valid range 0 (fully transparent) to 255 (fully opaque). !!} // draw multi polygons separated by IESELBREAK, using DrawSinglePolygon procedure TIEMask.DrawPolygon(Alpha: integer; SelPoly: PPointArray; SelPolyCount: integer); var p1, p2, q: integer; begin CheckMemoryAllocation(); if SelPolyCount > 0 then begin p1 := 0; for q := 0 to SelPolyCount do if (q = SelPolyCount) or (SelPoly^[q].x = IESELBREAK) then begin p2 := q - p1; DrawSinglePolygon(Alpha, PPointArray(@(SelPoly^[p1])), p2); p1 := q + 1; end; end; SyncFull; end; // draw a filled polygon in the mask, associating Alpha value to the set pixels procedure TIEMask.DrawSinglePolygon(Alpha: integer; SelPoly: PPointArray; SelPolyCount: integer); type eltptr = ^element; element = record xP, yQ, dx, dy, E: integer; next: eltptr; end; var x, y, i, ymin, ymax, j, ny, i1, xP, yP, xQ, yQ, temp, dx, dy, m, dyQ, E, xleft, xright: integer; table: array of eltptr; p, start, _end, p0, q: eltptr; pw: integer; // pixel written begin CheckMemoryAllocation(); ymin := 2147483647; ymax := 0; for i := 0 to SelPolyCount - 1 do begin x := selpoly^[i].x; y := selpoly^[i].y; if y < ymin then ymin := y; if y > ymax then ymax := y; if Alpha <> 0 then begin if x < fX1 then fX1 := x; if x > fX2 then fX2 := x - 1; if y < fY1 then fY1 := y; if y > fY2 then fY2 := y - 1; end; end; if fX1 < 0 then fX1 := 0; if fX2 >= fWidth then fX2 := fWidth - 1; if fY1 < 0 then fY1 := 0; if fY2 >= fHeight then fY2 := fHeight - 1; ny := ymax - ymin + 1; SetLength(table, ny); for j := 0 to ny - 1 do table[j] := nil; for i := 0 to SelPolyCount - 1 do begin i1 := i + 1; if i1 = SelPolyCount then i1 := 0; xP := selpoly^[i].x; yP := selpoly^[i].y; xQ := selpoly^[i1].x; yQ := selpoly^[i1].y; if yP = yQ then continue; if yQ < yP then begin temp := xP; xP := xQ; xQ := temp; temp := yP; yP := yQ; yQ := temp; end; getmem(p, sizeof(element)); p^.xP := xP; p^.dx := xQ - xP; p^.yQ := yQ; p^.dy := yQ - yP; j := yP - ymin; p^.next := table[j]; table[j] := p; end; getmem(start, sizeof(element)); _end := start; pw := 0; for j := 0 to ny - 1 do begin y := ymin + j; p := start; while p <> _end do begin if p^.yQ = y then begin q := p^.next; if (q = _end) then _end := p else p^ := q^; freemem(q); end else begin dx := p^.dx; if dx <> 0 then begin x := p^.xP; dy := p^.dy; E := p^.E; m := dx div dy; dyQ := 2 * dy; inc(x, m); inc(E, 2 * dx - m * dyQ); if (E > dy) or (E < -dy) then begin if dx > 0 then begin inc(x); dec(E, dyQ); end else begin dec(x); inc(E, dyQ); end; end; p^.xP := x; p^.E := E; end; p := p^.next; end; end; p := table[j]; while p <> nil do begin _end^.xP := p^.xP; x := _end^.xP; yQ := p^.yQ; dx := p^.dx; dy := p^.dy; q := start; while (q^.xP < x) or (q^.xP = x) and (q <> _end) and (q^.dx * dy < dx * q^.dy) do q := q^.next; p0 := p; p := p^.next; if q = _end then _end := p0 else p0^ := q^; q^.xP := x; q^.yQ := yQ; q^.dx := dx; q^.dy := dy; q^.E := 0; q^.next := p0; end; p := start; while p <> _end do begin xleft := p^.xP; p := p^.next; xright := p^.xP - 1; if xleft <= xright then inc(pw, DrawHorizontalLine(Alpha, xleft, xright, y)); p := p^.next; end; end; p := start; while p <> _end do begin p0 := p; p := p^.next; freemem(p0); end; freemem(start); if pw = 0 then begin // empty selection fX1 := 2147483647; fY1 := 2147483647; fX2 := 0; fY2 := 0; end; end; {!! TIEMask.TranslateBitmap Declaration procedure TranslateBitmap(var ox, oy: integer; CutSel: boolean); Description Translates (moves) the mask of ox, oy pixels. Set CutSel to true if the mask can go out of mask margins. !!} // adjust ox, oy procedure TIEMask.TranslateBitmap(var ox, oy: integer; CutSel: boolean); var xbits: array of byte; ps, pd: pbyte; x, y: integer; xx, yy: integer; dx, dy, slen: integer; begin CheckMemoryAllocation(); if IsEmpty then SyncRect; if IsEmpty then exit; if CutSel then begin if (ox + fX1) < 0 then inc(fX1, abs(ox + fX1)); if (oy + fY1) < 0 then inc(fY1, abs(oy + fY1)); if (ox + fX2) >= fWidth then dec(fX2, 1 + abs(fWidth - (ox + fX2))); if (oy + fY2) >= fHeight then dec(fY2, 1 + abs(fHeight - (oy + fY2))); end else begin if (ox + fX1) < 0 then dec(ox, (ox + fX1)); if (ox + fX2) >= fWidth then dec(ox, (ox + fX2 - fWidth + 1)); if (oy + fY1) < 0 then dec(oy, (oy + fY1)); if (oy + fY2) >= fHeight then dec(oy, (oy + fY2 - fHeight + 1)); end; if (ox = 0) and (oy = 0) then exit; case fBitsperpixel of 1: begin // 1 bit per pixel dx := fX2 - fX1 + 1; dy := fY2 - fY1 + 1; if (dx<=0) or (dy<=0) then begin Empty; exit; end; slen := IEBitmapRowLen(dx, fBitsPerPixel, 32); SetLength(xbits, slen * dy); ZeroMemory(@xbits[0], slen * dy); ps := fBits; inc(ps, (fHeight - fY1 - 1) * fRowlen); pd := @xBits[0]; inc(pd, (dy - 1) * slen); for y := 0 to dy - 1 do begin IECopyBits_large(pd, ps, 0, fX1, dx, fRowLen); dec(ps, fRowlen); dec(pd, slen); end; ZeroMemory(fbits, frowlen * fheight); ps := @xBits[0]; inc(ps, (dy - 1) * slen); pd := fBits; inc(pd, (fHeight - fY1 - oy - 1) * fRowlen); for y := 0 to dy - 1 do begin IECopyBits_large(pd, ps, fX1 + ox, 0, dx, slen); dec(pd, fRowlen); dec(ps, slen); end; end; 8: begin // 8 bits per pixel SetLength(xbits, frowlen * fheight); CopyMemory(@xbits[0], fbits, frowlen * fheight); ZeroMemory(fbits, frowlen * fheight); for y := fY1 to fY2 do begin yy := y + oy; if (yy < fHeight) and (yy >= 0) then begin for x := fX1 to fX2 do begin xx := x + ox; if (xx < fWidth) and (xx >= 0) then begin ps := @xBits[0]; inc(ps, (fHeight - y - 1) * fRowlen + x); pd := fBits; inc(pd, (fHeight - yy - 1) * fRowlen + xx); pd^ := ps^; end; end; end; end; end; end; inc(fX1, ox); if fX1 < 0 then fX1 := 0; if fX1 >= fWidth then fX1 := fWidth - 1; inc(fY1, oy); if fY1 < 0 then fY1 := 0; if fY1 >= fHeight then fY1 := fHeight - 1; inc(fX2, ox); if fX2 < 0 then fX2 := 0; if fX2 >= fWidth then fX2 := fWidth - 1; inc(fY2, oy); if fY2 < 0 then fY2 := 0; if fY2 >= fHeight then fY2 := fHeight - 1; end; {!! TIEMask.Negative Declaration procedure Negative(MaxVal: integer); Description For internal use only. !!} procedure TIEMask.Negative(MaxVal: integer); var x, y: integer; begin if (fX1 = 2147483647) or (fY1 = 2147483647) then exit; CheckMemoryAllocation(); fFull := false; fX1 := 2147483647; fY1 := 2147483647; fX2 := 0; fY2 := 0; for y := 0 to fHeight - 1 do begin for x := 0 to fWidth - 1 do begin if GetPixel(x, y) = 0 then begin SetPixel(x, y, MaxVal); if x < fX1 then fX1 := x; if x > fX2 then fX2 := x; if y < fY1 then fY1 := y; if y > fY2 then fY2 := y; end else SetPixel(x, y, 0); end; end; end; {!! TIEMask.SyncFull Declaration procedure SyncFull; Description Sets to True if all values are 255. !!} // set Full to True if all values are 255 // works both 1 and 8 bitsperpixel procedure TIEMask.SyncFull; var px: pbyte; y, x, l: integer; begin CheckMemoryAllocation(); case fBitsperpixel of 1: begin l := fWidth div 8; for y := 0 to fHeight-1 do begin px := Scanline[y]; for x := 0 to l-1 do begin if px^<$FF then begin fFull := false; exit; end; inc(px); end; if (fWidth and $7)<>0 then begin // check last bits for x := l*8 to fWidth-1 do begin if GetPixel(x, y)=0 then begin fFull := false; exit; end; end; end; end; end; 8: begin for y := 0 to fHeight - 1 do begin px := Scanline[y]; for x := 0 to fWidth - 1 do begin if px^ < $FF then begin fFull := False; exit; end; inc(px); end; end; end; end; fFull := True; end; {!! TIEMask.CombineWithAlpha Declaration procedure CombineWithAlpha(SourceAlpha: ; ox, oy: integer; SynchronizeBoundingRect: boolean); Description Only for internal use. !!} procedure TIEMask.CombineWithAlpha(SourceAlpha: TIEBitmap; ox, oy: integer; SynchronizeBoundingRect: boolean); var x, y: integer; px, pa: pbyte; SourceAlphaWidth, SourceAlphaHeight: integer; begin CheckMemoryAllocation(); if (SourceAlpha.PixelFormat <> ie8g) and (SourceAlpha.PixelFormat <> ie8p) then exit; SourceAlphaWidth := SourceAlpha.Width; SourceAlphaHeight := SourceAlpha.Height; case fBitsperpixel of 1: begin for y := 0 to SourceAlphaHeight - 1 do begin if y + oy >= fHeight then break; px := Scanline[y + oy]; pa := SourceAlpha.Scanline[y]; for x := 0 to SourceAlphaWidth - 1 do begin if x + ox >= fWidth then break; if pa^ = 0 then SetPixelbw_inline(px, x + ox, 0); inc(pa); end; end; end; 8: begin for y := 0 to SourceAlphaHeight - 1 do begin if y + oy >= fHeight then break; px := Scanline[y + oy]; inc(px, ox); pa := SourceAlpha.Scanline[y]; for x := 0 to SourceAlphaWidth - 1 do begin if x + ox >= fWidth then break; px^ := imin(pa^, px^); inc(pa); inc(px); end; end; end; end; if SynchronizeBoundingRect then SyncRect; SyncFull; end; {!! TIEMask.Intersect Declaration procedure Intersect(x1, y1, x2, y2: integer); Description For internal use only. !!} procedure TIEMask.Intersect(x1, y1, x2, y2: integer); var px: pbyte; x, y: integer; begin CheckMemoryAllocation(); case fBitsPerPixel of 1: for y := fY1 to fY2 do begin px := Scanline[y]; for x := fX1 to fX2 do if (xx2) or (yy2) then SetPixelbw_inline(px, x, 0); end; 8: for y := fY1 to fY2 do begin px := Scanline[y]; for x := fX1 to fX2 do begin if (xx2) or (yy2) then px^ := 0; inc(px); end; end; end; SyncRect; SyncFull; end; // copy a bitmap/map to a map/bitmap // dir: 0=map to bitmap // 1=bitmap to map // map and bitmap must have some pixel format: exception for from bitmap (pf1bit) to map (24 bit) procedure IEBitmapMapXCopy(map: pbyte; maprowlen: dword; mapbitcount: dword; bitmap: TBitmap; mapx, mapy, bitmapx, bitmapy, dx, dy: dword; dir: integer); var s1, d1: pbyte; rgb: PRGB; yy, xx: integer; rl: integer; begin case dir of 0: begin // copy from map to bitmap s1 := map; inc(s1, maprowlen * mapy); case bitmap.PixelFormat of pf1bit: begin for yy := bitmapy + dy - 1 downto bitmapy do begin IECopyBits_large(bitmap.Scanline[yy], s1, bitmapx, mapx, dx, maprowlen); inc(s1, maprowlen); end; end; pf8bit: begin inc(s1, mapx); for yy := bitmapy + dy - 1 downto bitmapy do begin d1 := bitmap.Scanline[yy]; inc(d1, bitmapx); CopyMemory(d1, s1, dx); inc(s1, maprowlen); end; end; pf24bit: begin inc(s1, mapx * 3); for yy := bitmapy + dy - 1 downto bitmapy do begin d1 := bitmap.Scanline[yy]; inc(d1, bitmapx * 3); CopyMemory(d1, s1, dx * 3); inc(s1, maprowlen); end; end; end; end; 1: begin // copy from bitmap to map s1 := map; inc(s1, maprowlen * mapy); case bitmap.PixelFormat of pf1bit: begin if mapbitcount = 24 then begin // convert 1bit to 24bit inc(s1, mapx * 3); for yy := bitmapy + dy - 1 downto bitmapy do begin rgb := PRGB(s1); d1 := bitmap.scanline[yy]; for xx := bitmapx to bitmapx + dx - 1 do begin with rgb^ do if GetPixelbw_inline(d1, xx) <> 0 then begin r := 255; g := 255; b := 255; end else begin r := 0; g := 0; b := 0; end; inc(rgb); end; inc(s1, maprowlen); end; end else begin rl := IEVCLPixelFormat2RowLen(bitmap.width, bitmap.pixelformat); for yy := bitmapy + dy - 1 downto bitmapy do begin IECopyBits_large(s1, bitmap.Scanline[yy], mapx, bitmapx, dx, rl); inc(s1, maprowlen); end; end; end; pf8bit: begin inc(s1, mapx); for yy := bitmapy + dy - 1 downto bitmapy do begin d1 := bitmap.Scanline[yy]; inc(d1, bitmapx); CopyMemory(s1, d1, dx); inc(s1, maprowlen); end; end; pf24bit: begin inc(s1, mapx * 3); for yy := bitmapy + dy - 1 downto bitmapy do begin d1 := bitmap.Scanline[yy]; inc(d1, bitmapx * 3); CopyMemory(s1, d1, dx * 3); inc(s1, maprowlen); end; end; end; end; end; end; { // copy a bitmap/map to a map/bitmap // dir: 0=map to bitmap // 1=bitmap to map // map and bitmap must have some pixel format: exception for from bitmap (ie1g) to map (ie24RGB) procedure IEBitmapMapXCopyEx(map: pbyte; maprowlen: dword; mapbitcount: dword; bitmap: TIEBitmap; mapx, mapy, bitmapx, bitmapy, dx, dy: dword; dir: integer); var s1, d1: pbyte; rgb: PRGB; yy, xx: integer; begin case dir of 0: begin // copy from map to bitmap s1 := map; inc(s1, maprowlen * mapy); case bitmap.PixelFormat of ie1g: begin for yy := bitmapy + dy - 1 downto bitmapy do begin IECopyBits_large(bitmap.Scanline[yy], s1, bitmapx, mapx, dx, maprowlen); inc(s1, maprowlen); end; end; ie8g, ie8p: begin inc(s1, mapx); for yy := bitmapy + dy - 1 downto bitmapy do begin d1 := bitmap.Scanline[yy]; inc(d1, bitmapx); CopyMemory(d1, s1, dx); inc(s1, maprowlen); end; end; ie24RGB: begin inc(s1, mapx * 3); for yy := bitmapy + dy - 1 downto bitmapy do begin d1 := bitmap.Scanline[yy]; inc(d1, bitmapx * 3); CopyMemory(d1, s1, dx * 3); inc(s1, maprowlen); end; end; end; end; 1: begin // copy from bitmap to map s1 := map; inc(s1, maprowlen * mapy); case bitmap.PixelFormat of ie1g: begin if mapbitcount = 24 then begin // convert 1bit to 24bit inc(s1, mapx * 3); for yy := bitmapy + dy - 1 downto bitmapy do begin rgb := PRGB(s1); d1 := bitmap.scanline[yy]; for xx := bitmapx to bitmapx + dx - 1 do begin with rgb^ do if GetPixelbw_inline(d1, xx) <> 0 then begin r := 255; g := 255; b := 255; end else begin r := 0; g := 0; b := 0; end; inc(rgb); end; inc(s1, maprowlen); end; end else for yy := bitmapy + dy - 1 downto bitmapy do begin IECopyBits_large(s1, bitmap.Scanline[yy], mapx, bitmapx, dx, bitmap.RowLen); inc(s1, maprowlen); end; end; ie8g, ie8p: begin inc(s1, mapx); for yy := bitmapy + dy - 1 downto bitmapy do begin d1 := bitmap.Scanline[yy]; inc(d1, bitmapx); CopyMemory(s1, d1, dx); inc(s1, maprowlen); end; end; ie24RGB: begin inc(s1, mapx * 3); for yy := bitmapy + dy - 1 downto bitmapy do begin d1 := bitmap.Scanline[yy]; inc(d1, bitmapx * 3); CopyMemory(s1, d1, dx * 3); inc(s1, maprowlen); end; end; end; end; end; end; } //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // TIEVirtualImageList // Location: // ielTempFile : create in a temp directory a new file // TempDirectory: // if empty uses windows temp directory // otherwise must be a full path ending with '\' constructor TIEVirtualImageList.Create(const Descriptor:string; UseDisk:boolean); begin inherited Create; fLock := TCriticalSection.Create(); fDescriptor := Descriptor; fUseDisk := UseDisk; fAllocationBlock := 262144; fMaxImagesInMemory := 10; CreateEx; end; destructor TIEVirtualImageList.Destroy; begin DestroyEx; FreeAndNil(fLock); inherited; end; procedure TIEVirtualImageList.CreateEx; begin fmemmap := TIEFileBuffer.Create; fSize := fAllocationBlock; fInsPos := 0; fImageInfo := TList.Create; fFreeBlocks := TList.Create; fToDiscardList := TList.Create; fImagesInMemory := 0; fBmpToRelease := TList.Create; fLastVImageSize := 0; ReAllocateBits; end; procedure TIEVirtualImageList.DestroyEx; begin FreeBits; FreeAndNil(fmemmap); FreeAndNil(fImageInfo); FreeAndNil(fFreeBlocks); FreeAndNil(fToDiscardList); FreeAndNil(fBmpToRelease); end; procedure TIEVirtualImageList.SaveToStream(Stream: TStream); var i: integer; ii: PIEVirtualImageInfo; ver: byte; begin DiscardAll; // make file consistent // magic IESaveStringToStream(Stream, 'VIRTUALIMAGELIST'); // version ver := 1; Stream.Write(ver, 1); // image count i := fImageInfo.Count; Stream.Write(i, sizeof(integer)); // image info for i := 0 to fImageInfo.Count - 1 do Stream.Write( PIEVirtualImageInfo(fImageInfo[i])^, sizeof(TIEVirtualImageInfo) ); // image data for i := 0 to fImageInfo.Count - 1 do begin ii := PIEVirtualImageInfo(fImageInfo[i]); fmemmap.CopyTo(Stream, ii^.pos, ii^.vsize); // 3.0.0b3 end; end; function TIEVirtualImageList.LoadFromStream(Stream: TStream): boolean; var i: integer; s: AnsiString; ii: PIEVirtualImageInfo; fs: integer; ver: byte; icount: integer; begin result := false; // magic IELoadStringFromStream(Stream, s); if s<>'VIRTUALIMAGELIST' then exit; // version Stream.Read(ver, 1); // image count Stream.Read(icount, sizeof(integer)); if icount>0 then begin DestroyEx; CreateEx; // image info fs := 0; for i := 0 to icount - 1 do begin new(ii); Stream.Read(ii^, sizeof(TIEVirtualImageInfo)); ii^.pos := fs; fImageInfo.Add(ii); inc(fs, ii^.vsize); end; // image data fSize := fs+1; ReallocateBits; fmemmap.fSimFile.Position := 0; if fs>0 then IECopyFrom(fmemmap.fSimFile, Stream, fs); fInsPos := fs; end; result := true; end; // allocate (or re-allocate) bits without memory loss procedure TIEVirtualImageList.ReAllocateBits; var i: integer; begin fLock.Enter(); try // delete free blocks list for i := 0 to fFreeBlocks.Count-1 do dispose(fFreeBlocks[i]); fFreeBlocks.Clear; if not fmemmap.IsAllocated then begin FreeBits; fmemmap.AllocateFile(fSize, fDescriptor, fUseDisk); end else begin DiscardAll; fmemmap.ReAllocateFile(fSize); end; finally fLock.Leave(); end; end; procedure TIEVirtualImageList.FreeBits; var i: integer; begin for i := 0 to fImageInfo.Count - 1 do RemoveImageInfo(i, false); fImageInfo.Clear; fToDiscardList.Clear; // delete free blocks list for i := 0 to fFreeBlocks.Count-1 do dispose(fFreeBlocks[i]); fFreeBlocks.Clear; // bmp to release list for i := 0 to fBmpToRelease.Count-1 do begin FreeAndNil(PIEVirtualToReleaseBmp(fBmpToRelease[i])^.bmp); dispose(fBmpToRelease[i]); end; fBmpToRelease.Clear(); fmemmap.DeAllocate; fInsPos := 0; end; procedure TIEVirtualImageList.RemoveImageInfo(idx: integer; deleteItem: boolean); var qidx: integer; inf: PIEVirtualToReleaseBmp; begin qidx := BmpToReleaseIndexOf(fImageInfo[idx]); if qidx > -1 then begin inf := PIEVirtualToReleaseBmp(fBmpToRelease[qidx]); FreeAndNil(inf^.bmp); dispose(inf); fBmpToRelease.Delete(qidx); end; DiscardImage(fImageInfo[idx]); // discard if needed dispose(fImageInfo[idx]); if deleteItem then fImageInfo.Delete(idx); end; procedure TIEVirtualImageList.DiscardImage(info: PIEVirtualImageInfo); begin with info^ do begin if ptr <> nil then begin fmemmap.UnMap(ptr); fToDiscardList.Remove(info); dec(fImagesInMemory); end; ptr := nil; end; end; procedure TIEVirtualImageList.DiscardOne; begin if fToDiscardList.Count > 0 then DiscardImage(fToDiscardList[0]); end; procedure TIEVirtualImageList.DiscardAll; begin while fToDiscardList.Count > 0 do DiscardImage(fToDiscardList[0]); end; // the opposite of DiscardImage // if the image is already mapped, MapImage brings it at last position of the discard list procedure TIEVirtualImageList.MapImage(image: pointer; access: TIEDataAccess); var pinfo: PIEVirtualImageInfo; begin pinfo := image; with pinfo^ do begin if access <> currentaccess then DiscardImage(pinfo); if ptr = nil then begin while fImagesInMemory > fMaxImagesInMemory do DiscardOne; ptr := fmemmap.Map(pos, vsize, access); if ptr <> nil then begin inc(fImagesInMemory); fToDiscardList.Add(pinfo); end; currentaccess := access; end else begin // move to the end of discard list if pinfo^.ptr <> nil then begin fToDiscardList.Remove(pinfo); fToDiscardList.Add(pinfo); end; end; end; end; procedure TIEVirtualImageList.PrepareSpaceFor(Width, Height: integer; Bitcount: integer; ImageCount: integer); var rowlen, bmplen, vbmplen: int64; begin rowlen := IEBitmapRowLen(Width, Bitcount, 32); bmplen := Height * rowlen; vbmplen := bmplen; fSize := fSize + vbmplen * ImageCount; ReAllocateBits; end; // MapNow = true: maps the image in memory function TIEVirtualImageList.AddBlankImage(Width, Height, Bitcount: integer; PixelFormat: TIEPixelFormat; HasAlpha: boolean; MapNow: boolean): pointer; var ii: PIEVirtualImageInfo; begin fLock.Enter(); try result := nil; new(ii); if AllocImage(ii, Width, Height, Bitcount, PixelFormat, HasAlpha, MapNow) then begin fImageInfo.Add(ii); result := ii; end else dispose(ii); finally fLock.Leave(); end; end; procedure TIEVirtualImageList.MergeConsecutiveBlocks(); var i: integer; fb_cur, fb_next: PIEVirtualFreeBlock; begin i := 0; while i < fFreeBlocks.Count-1 do // -1 avoids to check last block begin fb_cur := PIEVirtualFreeBlock(fFreeBlocks[i]); fb_next := PIEVirtualFreeBlock(fFreeBlocks[i+1]); if fb_cur^.pos + fb_cur^.vsize = fb_next^.pos then begin // do merge inc(fb_cur^.vsize, fb_next^.vsize); fFreeBlocks.Delete(i+1); dispose(fb_next); end else inc(i); end; end; // MapNow = true: maps the image in memory function TIEVirtualImageList.AllocImage(image: pointer; Width, Height, Bitcount: integer; PixelFormat: TIEPixelFormat; HasAlpha: boolean; MapNow: boolean): boolean; var rowlen, vbmplen, alphalen: int64; ne: int64; ii: PIEVirtualImageInfo; fb: PIEVirtualFreeBlock; q: integer; paletteLen: integer; // palette length in bytes begin rowlen := IEBitmapRowLen(Width, Bitcount, 32); alphalen := 0; if HasAlpha then alphalen := sizeof(boolean) + IEBitmapRowLen(Width, 8, 32) * Height; paletteLen := 0; if PixelFormat = ie8p then paletteLen := 256 * sizeof(TRGB); vbmplen := Height * rowlen + alphalen + paletteLen; // look for a free block before last image MergeConsecutiveBlocks(); q := 0; fb := nil; while q < fFreeBlocks.Count do begin fb := PIEVirtualFreeBlock(fFreeBlocks[q]); if vbmplen <= fb^.vsize then break else fb := nil; inc(q); end; if fb <> nil then begin // found a free block ne := fInsPos; fInsPos := fb^.pos; // split or remove free block if fb^.vsize = vbmplen then begin // remove free block dispose(fb); fFreeBlocks.Delete(q); end else begin // split to a new free block inc(fb^.pos, vbmplen); dec(fb^.vsize, vbmplen); end; end else begin // no free blocks found, allocate new if fAllocationBlock < vbmplen then fAllocationBlock := fLastVImageSize + vbmplen; fLastVImageSize := vbmplen; ne := fInsPos + vbmplen; if ne > fSize then begin // expand file (of fAllocationBlock bytes) fSize := fSize + fAllocationBlock; ReAllocateBits; end; end; ii := image; with ii^ do begin pos := fInsPos; vsize := vbmplen; ptr := nil; bitmapped := false; orig_width := Width; orig_height := Height; HasAlphaChannel := HasAlpha; currentaccess := [iedWrite]; ImWidth := Width; ImHeight := Height; ImBitCount := BitCount; ImPixelFormat := PixelFormat; Identifier := 0; end; if MapNow then begin MapImage(ii, ii^.currentaccess); if ii^.ptr <> nil then fInsPos := ne; end else fInsPos := ne; result := true; end; function TIEVirtualImageList.AddBitmap(bitmap: TBitmap): pointer; var tbmp: TIEBitmap; begin fLock.Enter(); tbmp := TIEBitmap.Create(); try tbmp.EncapsulateTBitmap(bitmap, true); result := AddIEBitmap(tbmp); finally FreeAndNil(tbmp); fLock.Leave(); end; end; // the image stays mapped function TIEVirtualImageList.AddIEBitmap(bitmap: TIEBaseBitmap): pointer; var row: integer; pbmp: pbyte; ii: PIEVirtualImageInfo; rowlen: integer; bitcount: integer; iebmp: TIEBitmap; HasAlpha: boolean; begin fLock.Enter(); try bitcount := bitmap.BitCount; HasAlpha := (bitmap is TIEBitmap) and ((bitmap as TIEBitmap).HasAlphaChannel); result := AddBlankImage(bitmap.Width, bitmap.Height, bitcount, bitmap.PixelFormat, HasAlpha, true); ii := result; if (ii <> nil) and (ii^.ptr <> nil) then begin pbmp := ii^.ptr; rowlen := IEBitmapRowLen(bitmap.Width, bitcount, 32); // write bitmap for row := 0 to bitmap.height - 1 do begin CopyMemory(pbmp, bitmap.Scanline[bitmap.height - row - 1], rowlen); inc(pbmp, rowlen); end; // write palette (if present) if bitmap.PixelFormat = ie8p then begin CopyMemory(pbmp, bitmap.PaletteBuffer, 256*sizeof(TRGB)); inc(pbmp, 256*sizeof(TRGB)); end; // write alpha channel (if present) if HasAlpha then begin // copy alpha channel rowlen := IEBitmapRowLen(bitmap.Width, 8, 32); iebmp := bitmap as TIEBitmap; pboolean(pbmp)^ := iebmp.AlphaChannel.Full; inc(pbmp, sizeof(boolean)); for row := 0 to bitmap.height - 1 do begin CopyMemory(pbmp, iebmp.AlphaChannel.Scanline[bitmap.height - row - 1], rowlen); inc(pbmp, rowlen); end; end; end; finally fLock.Leave(); end; end; // Direct copy to disk. Image is not mapped function TIEVirtualImageList.AddIEBitmapNoMap(bitmap: TIEBaseBitmap): pointer; var row: integer; ii: PIEVirtualImageInfo; rowlen: integer; bitcount: integer; iebmp: TIEBitmap; HasAlpha: boolean; dpos: int64; bool: boolean; begin fLock.Enter(); try bitcount := bitmap.BitCount; HasAlpha := (bitmap is TIEBitmap) and ((bitmap as TIEBitmap).HasAlphaChannel); result := AddBlankImage(bitmap.Width, bitmap.Height, bitcount, bitmap.PixelFormat, HasAlpha, false); ii := result; if (ii <> nil) then begin dpos := ii^.pos; rowlen := IEBitmapRowLen(bitmap.Width, bitcount, 32); // write bitmap for row := 0 to bitmap.Height - 1 do begin fmemmap.CopyFrom(dpos, bitmap.Scanline[bitmap.Height - row - 1], rowlen); inc(dpos, rowlen); end; // write palette (if present) if bitmap.PixelFormat = ie8p then begin fmemmap.CopyFrom(dpos, bitmap.PaletteBuffer, 256 * sizeof(TRGB)); inc(dpos, 256 * sizeof(TRGB)); end; // write alpha channel (if present) if HasAlpha then begin // copy alpha channel rowlen := IEBitmapRowLen(bitmap.Width, 8, 32); iebmp := bitmap as TIEBitmap; bool := iebmp.AlphaChannel.Full; fmemmap.CopyFrom(dpos, @bool, sizeof(boolean)); inc(dpos, sizeof(boolean)); for row := 0 to bitmap.Height - 1 do begin fmemmap.CopyFrom(dpos, iebmp.AlphaChannel.Scanline[bitmap.Height - row - 1], rowlen); inc(dpos, rowlen); end; end; end; finally fLock.Leave(); end; end; // the image remains mapped function TIEVirtualImageList.AddBitmapRect(bitmap: TBitmap; xsrc, ysrc, dxsrc, dysrc: integer): pointer; var pbmp: pbyte; ii: PIEVirtualImageInfo; rowlen: integer; bitcount: integer; begin fLock.Enter(); try bitcount := IEVCLPixelFormat2BitCount(bitmap.PixelFormat); result := AddBlankImage(dxsrc, dysrc, bitcount, IEVCLPixelFormat2ImageEnPixelFormat(bitmap.PixelFormat), false, true); if result <> nil then begin ii := result; pbmp := ii^.ptr; rowlen := IEBitmapRowLen(dxsrc, bitcount, 32); IEBitmapMapXCopy(pbmp, rowlen, bitcount, bitmap, 0, 0, xsrc, ysrc, dxsrc, dysrc, 1); end; finally fLock.Leave(); end; end; // get the image from the memory mapped file (NOT FROM BmpToRelease!!) procedure TIEVirtualImageList.DirectCopyToBitmap(image: pointer; bitmap: TIEBitmap); var pbmp: pbyte; rowlen: dword; width, height, bitcount: integer; row: integer; ii: PIEVirtualImageInfo; begin ii := image; MapImage(ii, [iedRead]); if ii^.ptr <> nil then begin pbmp := ii^.ptr; width := ii^.ImWidth; height := ii^.ImHeight; bitcount := ii^.ImBitCount; rowlen := IEBitmapRowLen(width, bitcount, 32); if (bitmap.PixelFormat <> ii^.ImPixelFormat) or (bitmap.width <> width) or (bitmap.height <> height) then bitmap.Allocate(width, height, ii^.ImPixelFormat); // copy bitmap for row := 0 to height - 1 do begin copymemory(bitmap.ScanLine[height - row - 1], pbmp, rowlen); inc(pbmp, rowlen); end; // copy palette if bitmap.PixelFormat = ie8p then begin CopyMemory(bitmap.PaletteBuffer, pbmp, 256*sizeof(TRGB)); inc(pbmp, 256*sizeof(TRGB)); end; // copy alpha channel if (not ii^.HasAlphaChannel) or pboolean(pbmp)^ then bitmap.RemoveAlphaChannel else begin // load alpha bitmap.AlphaChannel.Full := pboolean(pbmp)^; inc(pbmp, sizeof(boolean)); rowlen := IEBitmapRowLen(width, 8, 32); for row := 0 to height - 1 do begin copymemory(bitmap.AlphaChannel.Scanline[height - row - 1], pbmp, rowlen); inc(pbmp, rowlen); end; end; end; end; // can get the image from memory mapped or from BmpToRelease procedure TIEVirtualImageList.CopyToIEBitmap(image: pointer; bitmap: TIEBitmap); var pbmp: pbyte; rowlen: dword; width, height, bitcount: integer; row: integer; ii: PIEVirtualImageInfo; qidx: integer; begin fLock.Enter(); try ii := image; MapImage(ii, [iedRead]); if ii^.ptr <> nil then begin qidx := BmpToReleaseIndexOf(image); if qidx < 0 then begin pbmp := ii^.ptr; width := ii^.ImWidth; height := ii^.ImHeight; bitcount := ii^.ImBitCount; rowlen := IEBitmapRowLen(width, bitcount, 32); bitmap.Allocate(width, height, ii^.ImPixelFormat); // copy bitmap for row := 0 to height - 1 do begin copymemory(bitmap.scanline[height - row - 1], pbmp, rowlen); inc(pbmp, rowlen); end; // copy palette if bitmap.PixelFormat = ie8p then begin CopyMemory(bitmap.PaletteBuffer, pbmp, 256*sizeof(TRGB)); inc(pbmp, 256*sizeof(TRGB)); end; // copy alpha channel if (not ii^.HasAlphaChannel) or pboolean(pbmp)^ then bitmap.RemoveAlphaChannel else begin // load alpha bitmap.AlphaChannel.Full := pboolean(pbmp)^; inc(pbmp, sizeof(boolean)); rowlen := IEBitmapRowLen(width, 8, 32); for row := 0 to height - 1 do begin copymemory(bitmap.AlphaChannel.Scanline[height - row - 1], pbmp, rowlen); inc(pbmp, rowlen); end; end; end else begin // stored in TBitmap bitmap.Assign(PIEVirtualToReleaseBmp(fBmpToRelease[qidx]).bmp); end; end; finally fLock.Leave(); end; end; procedure TIEVirtualImageList.CopyFromIEBitmap(image: pointer; bitmap: TIEBitmap); var pbmp: pbyte; rowlen: dword; width, height, bitcount: integer; row: integer; ii: PIEVirtualImageInfo; bmpbitcount: integer; begin fLock.Enter(); try ii := image; MapImage(ii, [iedRead, iedWrite]); if ii^.ptr <> nil then begin width := ii^.ImWidth; height := ii^.ImHeight; bitcount := ii^.ImBitCount; bmpbitcount := bitmap.BitCount; if (width <> bitmap.width) or (height <> bitmap.height) or (bmpbitcount <> bitcount) or (bitmap.HasAlphaChannel <> ii^.HasAlphaChannel) then begin width := bitmap.width; height := bitmap.height; bitcount := bmpbitcount; DiscardImage(ii); AllocImage(ii, width, height, bitcount, bitmap.PixelFormat, bitmap.HasAlphaChannel, true); // changes ii^.ptr end; pbmp := ii^.ptr; rowlen := IEBitmapRowLen(width, bitcount, 32); // copy bitmap for row := 0 to height - 1 do begin copymemory(pbmp, bitmap.scanline[height - row - 1], rowlen); inc(pbmp, rowlen); end; // copy palette if bitmap.PixelFormat = ie8p then begin CopyMemory(pbmp, bitmap.PaletteBuffer, 256*sizeof(TRGB)); inc(pbmp, 256*sizeof(TRGB)); end; // alpha channel rowlen := IEBitmapRowLen(bitmap.Width, 8, 32); if bitmap.HasAlphaChannel then begin // copy alpha channel pboolean(pbmp)^ := bitmap.AlphaChannel.Full; inc(pbmp, sizeof(boolean)); for row := 0 to bitmap.height - 1 do begin copymemory(pbmp, bitmap.AlphaChannel.Scanline[bitmap.height - row - 1], rowlen); inc(pbmp, rowlen); end; end; end; finally fLock.Leave(); end; end; function TIEVirtualImageList.BmpToReleaseIndexOf(image: pointer): integer; var q: integer; begin result := -1; for q := 0 to fBmpToRelease.Count - 1 do if PIEVirtualToReleaseBmp(fBmpToRelease[q])^.info = image then begin result := q; break; end; end; // create a bitmap (must be released with ReleaseBitmap) function TIEVirtualImageList.GetBitmap(image: pointer): TIEBitmap; var inf: PIEVirtualToReleaseBmp; qidx: integer; begin fLock.Enter(); try result := nil; MapImage(image, [iedRead]); if PIEVirtualImageInfo(image)^.ptr <> nil then begin qidx := BmpToReleaseIndexOf(image); if qidx < 0 then begin result := TIEBitmap.Create(); new(inf); inf^.info := image; inf^.bmp := result; inf^.refcount := 1; fBmpToRelease.Add(inf); DirectCopyToBitmap(image, result); end else begin // already got inf := PIEVirtualToReleaseBmp(fBmpToRelease[qidx]); inc(inf^.refcount); result := inf^.bmp; end; PIEVirtualImageInfo(image)^.bitmapped := true; end; finally fLock.Leave(); end; end; // release a bitmap created by GetBitmap // if changed is true copy the bitmap back to internal image // warning: changed with refcount>1 should make changes lost procedure TIEVirtualImageList.ReleaseBitmap(bitmap: TIEBitmap; changed: boolean); var q, idx: integer; inf: PIEVirtualToReleaseBmp; begin fLock.Enter(); try if bitmap <> nil then begin if (bitmap.Location = ieTBitmap) then bitmap.UpdateFromTBitmap; // idx := -1; for q := 0 to fBmpToRelease.Count - 1 do if PIEVirtualToReleaseBmp(fBmpToRelease[q])^.bmp = bitmap then begin idx := q; break; end; if idx < 0 then exit; inf := PIEVirtualToReleaseBmp(fBmpToRelease[idx]); dec(inf^.refcount); if changed then begin // copy back CopyFromIEBitmap(inf^.info, bitmap); end; if inf^.refcount = 0 then begin // free memory PIEVirtualImageInfo(inf^.info)^.bitmapped := false; bitmap.Free(); dispose(inf); fBmpToRelease.Delete(idx); end; end; finally fLock.Leave(); end; end; // release a bitmap created by GetBitmap // if changed is true copy the bitmap back to internal image // warning: changed with refcount>1 should make changes lost procedure TIEVirtualImageList.ReleaseBitmapByImage(image: pointer; changed: boolean); var q, idx: integer; begin fLock.Enter(); try idx := -1; for q := 0 to fBmpToRelease.Count - 1 do if PIEVirtualToReleaseBmp(fBmpToRelease[q])^.info = image then begin idx := q; break; end; if idx < 0 then exit; ReleaseBitmap(PIEVirtualToReleaseBmp(fBmpToRelease[idx])^.bmp, changed); finally fLock.Leave(); end; end; function TIEVirtualImageList.GetImageCount: integer; begin fLock.Enter(); try result := fImageInfo.Count; finally fLock.Leave(); end; end; function TIEVirtualImageList.GetImageWidth(image: pointer): integer; var ii: PIEVirtualImageInfo; qidx: integer; inf: PIEVirtualToReleaseBmp; begin fLock.Enter(); try ii := image; if ii^.bitmapped then begin qidx := BmpToReleaseIndexOf(image); inf := PIEVirtualToReleaseBmp(fBmpToRelease[qidx]); result := inf^.bmp.Width; end else result := ii^.ImWidth; finally fLock.Leave(); end; end; function TIEVirtualImageList.GetImageHeight(image: pointer): integer; var ii: PIEVirtualImageInfo; qidx: integer; inf: PIEVirtualToReleaseBmp; begin fLock.Enter(); try ii := image; if ii^.bitmapped then begin qidx := BmpToReleaseIndexOf(image); inf := PIEVirtualToReleaseBmp(fBmpToRelease[qidx]); result := inf^.bmp.Height; end else result := ii^.ImHeight; finally fLock.Leave(); end; end; function TIEVirtualImageList.GetImageOriginalWidth(image: pointer): integer; begin result := PIEVirtualImageInfo(image)^.orig_width; end; function TIEVirtualImageList.GetImageOriginalHeight(image: pointer): integer; begin result := PIEVirtualImageInfo(image)^.orig_height; end; procedure TIEVirtualImageList.SetImageOriginalWidth(image: pointer; Value: integer); begin PIEVirtualImageInfo(image)^.orig_width := Value; end; procedure TIEVirtualImageList.SetImageOriginalHeight(image: pointer; Value: integer); begin PIEVirtualImageInfo(image)^.orig_height := Value; end; procedure TIEVirtualImageList.SetImageIdentifier(image: pointer; const Value: WideString); var Iden: cardinal; begin Iden := 0; if Value <> '' then Iden := IE_MMHash( Value ); PIEVirtualImageInfo(image)^.identifier := Iden; end; function TIEVirtualImageList.GetImageBitCount(image: pointer): integer; var ii: PIEVirtualImageInfo; qidx: integer; inf: PIEVirtualToReleaseBmp; begin fLock.Enter(); try ii := image; if ii^.bitmapped then begin qidx := BmpToReleaseIndexOf(image); inf := PIEVirtualToReleaseBmp(fBmpToRelease[qidx]); result := inf^.bmp.Bitcount; end else result := ii^.ImBitCount; finally fLock.Leave(); end; end; function TIEVirtualImageList.GetImagePixelFormat(image: pointer): TIEPixelFormat; var ii: PIEVirtualImageInfo; qidx: integer; inf: PIEVirtualToReleaseBmp; begin fLock.Enter(); try ii := image; if ii^.bitmapped then begin qidx := BmpToReleaseIndexOf(image); inf := PIEVirtualToReleaseBmp(fBmpToRelease[qidx]); result := inf^.bmp.PixelFormat; end else result := ii^.imPixelFormat; finally fLock.Leave(); end; end; function TIEVirtualImageList.GetImageFilePos(image: pointer): int64; var ii: PIEVirtualImageInfo; begin ii := image; result := ii^.pos; end; function TIEVirtualImageList.GetImageFromIndex(index: integer): pointer; begin fLock.Enter(); try if index = -1 then result := nil else result := PIEVirtualImageInfo(fImageInfo[index]); finally fLock.Leave(); end; end; function TIEVirtualImageList.GetImageByIdentifier(const Value: string): pointer; var i: Integer; Iden: Cardinal; begin Result := nil; if Value = '' then exit; Iden := IE_MMHash( Value ); fLock.Enter(); try for i := 0 to fImageInfo.Count - 1 do begin if PIEVirtualImageInfo( fImageInfo[ i ])^.Identifier = Iden then begin Result := fImageInfo[ i ]; exit; end; end; finally fLock.Leave(); end; end; function TIEVirtualImageList.FindImageIndex(image: pointer): integer; begin fLock.Enter(); try result := fImageInfo.IndexOf(image); finally fLock.Leave(); end; end; // returned pointer is valid until next call to TIEVirtualDBList class function TIEVirtualImageList.GetImageBits(image: pointer): pointer; var ii: PIEVirtualImageInfo; pbmp: pbyte; qidx: integer; inf: PIEVirtualToReleaseBmp; begin fLock.Enter(); try result := nil; ii := image; if ii^.bitmapped then begin qidx := BmpToReleaseIndexOf(image); if qidx >= 0 then begin inf := PIEVirtualToReleaseBmp(fBmpToRelease[qidx]); result := inf^.bmp.scanline[inf^.bmp.height - 1]; end; end else begin MapImage(ii, [iedRead]); if ii^.ptr <> nil then begin pbmp := ii^.ptr; result := pbmp; end; end; finally fLock.Leave(); end; end; function TIEVirtualImageList.GetImagePalette(image: pointer): pointer; var ii: PIEVirtualImageInfo; pbmp: pbyte; qidx: integer; inf: PIEVirtualToReleaseBmp; begin fLock.Enter(); try result := nil; ii := image; if ii^.bitmapped then begin qidx := BmpToReleaseIndexOf(image); if qidx >= 0 then begin inf := PIEVirtualToReleaseBmp(fBmpToRelease[qidx]); result := inf^.bmp.PaletteBuffer; end; end else begin MapImage(ii, [iedRead]); if ii^.ptr <> nil then begin pbmp := ii^.ptr; inc(pbmp, IEBitmapRowLen(ii^.ImWidth, ii^.ImBitCount, 32) * ii^.ImHeight); result := pbmp; end; end; finally fLock.Leave(); end; end; // returned pointer is valid until next call to TIEVirtualDBList class function TIEVirtualImageList.GetAlphaBits(image: pointer): pointer; var ii: PIEVirtualImageInfo; pbmp: pbyte; qidx: integer; inf: PIEVirtualToReleaseBmp; begin fLock.Enter(); try result := nil; ii := image; if ii^.HasAlphaChannel then begin if ii^.bitmapped then begin qidx := BmpToReleaseIndexOf(image); if qidx >= 0 then begin inf := PIEVirtualToReleaseBmp(fBmpToRelease[qidx]); if inf^.bmp.HasAlphaChannel then result := inf^.bmp.AlphaChannel.ScanLine[inf^.bmp.height - 1] else result := nil; end; end else begin MapImage(ii, [iedRead]); if ii^.ptr <> nil then begin pbmp := ii^.ptr; inc(pbmp, IEBitmapRowLen(ii^.ImWidth, ii^.ImBitCount, 32) * ii^.ImHeight); if ii^.ImPixelFormat = ie8p then inc(pbmp, 256 * sizeof(TRGB)); if pboolean(pbmp)^ then result := nil else begin inc(pbmp, sizeof(boolean)); result := pbmp; end; end; end; end; finally fLock.Leave(); end; end; procedure TIEVirtualImageList.Delete(image: pointer); var fb: PIEVirtualFreeBlock; ii: PIEVirtualImageInfo; begin fLock.Enter(); try // make a new entry in the free blocks list (fFreeBlocks) ii := image; new(fb); fb^.pos := ii^.pos; fb^.vsize := ii^.vsize; fFreeBlocks.Add(fb); RemoveImageInfo(fImageInfo.IndexOf(image), true); if fImageInfo.Count = 0 then begin fSize := fAllocationBlock; fInsPos := 0; ReAllocateBits; end; finally fLock.Leave(); end; end; // end of TIEVirtualImageList. //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // TIEDibBitmap constructor TIEDibBitmap.Create; begin inherited; fWidth := 0; fHeight := 0; fBitCount := 0; fHDC := 0; fDIB := 0; fBits := nil; ZeroMemory(@fBitmapInfoHeader1, sizeof(TBitmapInfoHeader256)); with fBitmapInfoHeader1 do begin biSize := sizeof(TBitmapInfoHeader); biPlanes := 1; Palette[1].rgbRed := 255; Palette[1].rgbGreen := 255; Palette[1].rgbBlue := 255; biCompression := BI_RGB; end; end; destructor TIEDibBitmap.Destroy; begin FreeBits; inherited; end; function TIEDibBitmap.GetBitCount: integer; begin result := fBitCount; end; function TIEDibBitmap.GetWidth: integer; begin result := fWidth; end; function TIEDibBitmap.GetHeight: integer; begin result := fHeight; end; procedure TIEDibBitmap.SetWidth(Value: integer); begin raise EIEException.create('Cannot resize TIEDibBitmap'); end; procedure TIEDibBitmap.SetHeight(Value: integer); begin raise EIEException.create('Cannot resize TIEDibBitmap'); end; {!! TIEDibBitmap.PixelFormat Declaration property PixelFormat: Description Specifies the pixel format. !!} function TIEDibBitmap.GetPixelFormat: TIEPixelFormat; begin case fBitCount of 1: result := ie1g; 24: result := ie24RGB; else result := ienull; end; end; function TIEDibBitmap.GetRowLen: integer; begin result := fRowLen; end; {!! TIEDibBitmap.Allocate Declaration function Allocate(ImageWidth, ImageHeight: integer; ImagePixelFormat: TIEPixelFormat): boolean; Description Allocates a new windows DIB section of the specified size and pixel format. ImagePixelFormat can be ie1g or ie24RGB. Returns True on success. !!} function TIEDibBitmap.Allocate(ImageWidth, ImageHeight: integer; ImagePixelFormat: TIEPixelFormat): boolean; begin result := false; if ImagePixelFormat = ie1g then result := AllocateBits(ImageWidth, ImageHeight, 1) else if ImagePixelFormat = ie24RGB then result := AllocateBits(ImageWidth, ImageHeight, 24); end; {!! TIEDibBitmap.AllocateBits Declaration function AllocateBits(BmpWidth, BmpHeight, BmpBitCount: dword): boolean; Description Allocates a new windows DIB section of the specified size and bitcount. BmpBitCount can be 1 or 24. Returns True on success. !!} function TIEDibBitmap.AllocateBits(BmpWidth, BmpHeight, BmpBitCount: dword): boolean; begin result := false; if (BmpWidth > 0) and (BmpHeight > 0) then begin FreeBits; fBitCount := BmpBitCount; fWidth := BmpWidth; fHeight := BmpHeight; fRowLen := IEBitmapRowLen(fWidth, BmpBitCount, 32); fHDC := CreateCompatibleDC(0); if fHDC=0 then exit; with fBitmapInfoHeader1 do begin biBitCount := BmpBitCount; biWidth := BmpWidth; biHeight := BmpHeight; biSizeImage := fRowLen * fHeight; end; fDIB := CreateDIBSection(fHDC, PBITMAPINFO(@fBitmapInfoHeader1)^, DIB_RGB_COLORS, fBits, 0, 0); if fDIB=0 then exit; SelectObject(fHDC, fDIB); result := true; end; end; {!! TIEDibBitmap.FreeBits Declaration procedure FreeBits; Description Frees the allocated DIB section. !!} procedure TIEDibBitmap.FreeBits; begin if fDIB <> 0 then DeleteObject(fDIB); fDIB := 0; if fHDC <> 0 then DeleteDC(fHDC); fHDC := 0; fBits := nil; fWidth := 0; fHeight := 0; fBitCount := 0; end; function TIEDibBitmap.GetScanline(row: integer): pointer; begin result := pointer(uint64(fBits) + (fHeight - uint64(row) - 1) * fRowlen); end; {!! TIEDibBitmap.CopyToTBitmap Declaration procedure CopyToTBitmap(Dest: TBitmap); Description Copies the DIB bitmap to a TBitmap object. !!} procedure TIEDibBitmap.CopyToTBitmap(Dest: TBitmap); var row: integer; begin Dest.Width := 1; Dest.Height := 1; case fBitCount of 1: Dest.PixelFormat := pf1bit; 24: Dest.PixelFormat := pf24bit; 32: Dest.PixelFormat := pf32bit; end; Dest.Width := fWidth; Dest.Height := fHeight; for row := 0 to fHeight - 1 do CopyMemory(Dest.Scanline[row], Scanline[row], fRowLen); end; {!! TIEDibBitmap.Assign Declaration procedure Assign(Source: TObject); Description Copies the DIB bitmap from a Source TIEDibBitmap object. !!} // only for TIEDibBitmap procedure TIEDibBitmap.Assign(Source: TObject); var src: TIEDibBitmap; begin if Source is TIEDibBitmap then begin src := Source as TIEDibBitmap; AllocateBits(src.Width, src.Height, src.BitCount); CopyMemory(fBits, src.fBits, fRowlen * fHeight); end; end; procedure TIEDibBitmap.AssignImage(Source: TIEBaseBitmap); begin Assign(Source); end; function TIEDibBitmap.GetPalette(index: integer): TRGB; begin // not supported result := CreateRGB(0, 0, 0); end; function TIEDibBitmap.GetPaletteBuffer: pointer; begin // not supported; result := nil; end; procedure TIEDibBitmap.SetPalette(index: integer; Value: TRGB); begin // not supported end; function TIEDibBitmap.GetPaletteLen: integer; begin // not supported result := 0; end; function TIEDibBitmap.GetPaletteUsed(): integer; begin // not supported result := 0; end; procedure TIEDibBitmap.SetPaletteUsed(Value: integer); begin // not supported end; procedure TIEDibBitmap.CopyPaletteTo(Dest: TIEBaseBitmap); begin // not supported end; // end of TIEDibBitmap //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // TIEWorkBitmap // can raise out of memory exception constructor TIEWorkBitmap.Create(BmpWidth, BmpHeight, BmpBitCount: integer); begin inherited Create; fRowsPerFragment := 0; fWidth := 0; fHeight := 0; fBitCount := 0; fRowLen := 0; fBits := nil; if (BmpWidth > 0) and (BmpHeight > 0) then AllocateBits(BmpWidth, BmpHeight, BmpBitCount); end; destructor TIEWorkBitmap.Destroy; begin FreeBits; inherited; end; function TIEWorkBitmap.GetScanline(row: integer): pointer; var pb: pbyte; begin if length(fFragments) > 0 then begin pb := fFragments[Row div fRowsPerFragment]; inc(pb, fRowlen * (Row mod fRowsPerFragment)); result := pb; end else begin pb := fBits; inc(pb, (fHeight - row - 1) * fRowlen); result := pb; end; end; function TIEWorkBitmap.GetPByte(row, col: integer): pbyte; begin result := GetScanline(row); inc(result, col); end; function TIEWorkBitmap.GetPWord(row, col: integer): pword; begin result := GetScanline(row); inc(result, col); end; function TIEWorkBitmap.GetPRGB(row, col: integer): PRGB; begin result := GetScanline(row); inc(result, col); end; function TIEWorkBitmap.GetPDouble(row, col: integer): PDouble; begin result := GetScanline(row); inc(result, col); end; function TIEWorkBitmap.GetPSingle(row, col: integer): PSingle; begin result := GetScanline(row); inc(result, col); end; function TIEWorkBitmap.GetPInteger(row, col: integer): pinteger; begin result := GetScanline(row); inc(result, col); end; procedure TIEWorkBitmap.SetBit(row, col: integer; value: integer); var bp: pbyte; begin bp := GetScanline(row); inc(bp, (col shr 3)); if value <> 0 then bp^ := bp^ or iebitmask1[col and 7] else bp^ := bp^ and not iebitmask1[col and 7]; end; procedure TIEWorkBitmap.AllocateBits(BmpWidth, BmpHeight, BmpBitCount: integer); begin if (BmpWidth <> fWidth) or (BmpHeight <> fHeight) or (BmpBitCount <> fBitCount) then begin FreeBits; fBitCount := BmpBitCount; fWidth := BmpWidth; fHeight := BmpHeight; fRowLen := IEBitmapRowLen(fWidth, BmpBitCount, 32); fBits := IEAutoAlloc(fRowLen * fHeight); if fBits = nil then begin FragmentedAlloc(); if length(fFragments) = 0 then OutOfMemoryError(); end; end; end; procedure TIEWorkBitmap.FreeBits(); begin if fBits <> nil then IEAutoFree(fBits); FreeFragments(); fWidth := 0; fHeight := 0; fBitCount := 0; fRowLen := 0; fBits := nil; end; procedure TIEWorkBitmap.FreeFragments(); var i: integer; begin for i := 0 to high(fFragments) do if fFragments[i] <> nil then IESystemFree(fFragments[i]); SetLength(fFragments, 0); fRowsPerFragment := 0; end; // allocates in chunks procedure TIEWorkBitmap.FragmentedAlloc(); const STARTWITH = 4; MINIMUMSIZE = 10*1024*1024; var i: integer; exitLoop: boolean; fc: integer; bufSize: integer; begin FreeFragments(); if not IEGlobalSettings().AutoFragmentBitmap then exit; fc := STARTWITH; // start with 4 blocks (fragments) repeat exitLoop := true; fRowsPerFragment := Ceil( fHeight / fc ); bufSize := fRowLen * fRowsPerFragment; if (bufSize < MINIMUMSIZE) and (fc > STARTWITH) then begin // to avoid excessive framentation we cannot allow framents minor than MINIMUMSIZE FreeFragments(); break; end; SetLength(fFragments, fc); ZeroMemory(@fFragments[0], sizeof(pointer) * fc); for i := 0 to high(fFragments) do begin fFragments[i] := IESystemAlloc(bufSize); if fFragments[i] = nil then begin // FAIL! Reduce block size FreeFragments(); fc := fc * 2; if (fc < fHeight) then exitLoop := false; break; end; end; until exitLoop; end; // TIEWorkBitmap //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // EXIF SUPPORT FUNCTIONS // source and dest must be TIOParams procedure IECopyEXIF(source_, dest_: TObject; copyBitmap: boolean); var q: integer; source, dest: TIOParams; begin source := source_ as TIOParams; dest := dest_ as TIOParams; IECopyTList(source.EXIF_Tags, dest.EXIF_Tags); if copyBitmap then begin if assigned(dest.EXIF_Bitmap) then begin dest.EXIF_Bitmap.Free(); dest.EXIF_Bitmap := nil; end; if assigned(source.EXIF_Bitmap) then dest.EXIF_Bitmap := TIEBitmap.Create(source.EXIF_Bitmap); end; dest.EXIF_HasEXIFData := source.EXIF_HasEXIFData; dest.EXIF_ImageDescription := source.EXIF_ImageDescription; dest.EXIF_Make := source.EXIF_Make; dest.EXIF_Model := source.EXIF_Model; dest.EXIF_Orientation := source.EXIF_Orientation; dest.EXIF_XResolution := source.EXIF_XResolution; dest.EXIF_YResolution := source.EXIF_YResolution; dest.EXIF_ResolutionUnit := source.EXIF_ResolutionUnit; dest.EXIF_Software := source.EXIF_Software; dest.EXIF_XPRating := source.EXIF_XPRating; dest.EXIF_XPTitle := source.EXIF_XPTitle; dest.EXIF_XPComment := source.EXIF_XPComment; dest.EXIF_XPAuthor := source.EXIF_XPAuthor; dest.EXIF_XPKeywords := source.EXIF_XPKeywords; dest.EXIF_XPSubject := source.EXIF_XPSubject; dest.EXIF_Artist := source.EXIF_Artist; dest.EXIF_DateTime := source.EXIF_DateTime; dest.EXIF_WhitePoint[0] := source.EXIF_WhitePoint[0]; dest.EXIF_WhitePoint[1] := source.EXIF_WhitePoint[1]; for q := 0 to 5 do dest.EXIF_PrimaryChromaticities[q] := source.EXIF_PrimaryChromaticities[q]; for q := 0 to 2 do dest.EXIF_YCbCrCoefficients[q] := source.EXIF_YCbCrCoefficients[q]; dest.EXIF_YCbCrPositioning := source.EXIF_YCbCrPositioning; for q := 0 to 5 do dest.EXIF_ReferenceBlackWhite[q] := source.EXIF_ReferenceBlackWhite[q]; dest.EXIF_Copyright := source.EXIF_Copyright; dest.EXIF_ExposureTime := source.EXIF_ExposureTime; dest.EXIF_FNumber := source.EXIF_FNumber; dest.EXIF_ExposureProgram := source.EXIF_ExposureProgram; dest.EXIF_ISOSpeedRatings[0] := source.EXIF_ISOSpeedRatings[0]; dest.EXIF_ISOSpeedRatings[1] := source.EXIF_ISOSpeedRatings[1]; dest.EXIF_ExifVersion := source.EXIF_ExifVersion; dest.EXIF_DateTimeOriginal := source.EXIF_DateTimeOriginal; dest.EXIF_DateTimeDigitized := source.EXIF_DateTimeDigitized; dest.EXIF_CompressedBitsPerPixel := source.EXIF_CompressedBitsPerPixel; dest.EXIF_ShutterSpeedValue := source.EXIF_ShutterSpeedValue; dest.EXIF_ApertureValue := source.EXIF_ApertureValue; dest.EXIF_BrightnessValue := source.EXIF_BrightnessValue; dest.EXIF_ExposureBiasValue := source.EXIF_ExposureBiasValue; dest.EXIF_MaxApertureValue := source.EXIF_MaxApertureValue; dest.EXIF_SubjectDistance := source.EXIF_SubjectDistance; dest.EXIF_MeteringMode := source.EXIF_MeteringMode; dest.EXIF_LightSource := source.EXIF_LightSource; dest.EXIF_Flash := source.EXIF_Flash; dest.EXIF_FocalLength := source.EXIF_FocalLength; dest.EXIF_SubsecTime := source.EXIF_SubsecTime; dest.EXIF_SubsecTimeOriginal := source.EXIF_SubsecTimeOriginal; dest.EXIF_SubsecTimeDigitized := source.EXIF_SubsecTimeDigitized; dest.EXIF_FlashPixVersion := source.EXIF_FlashPixVersion; dest.EXIF_ColorSpace := source.EXIF_ColorSpace; dest.EXIF_ExifImageWidth := source.EXIF_ExifImageWidth; dest.EXIF_ExifImageHeight := source.EXIF_ExifImageHeight; dest.EXIF_RelatedSoundFile := source.EXIF_RelatedSoundFile; dest.EXIF_FocalPlaneXResolution := source.EXIF_FocalPlaneXResolution; dest.EXIF_FocalPlaneYResolution := source.EXIF_FocalPlaneYResolution; dest.EXIF_FocalPlaneResolutionUnit := source.EXIF_FocalPlaneResolutionUnit; dest.EXIF_ExposureIndex := source.EXIF_ExposureIndex; dest.EXIF_SensingMethod := source.EXIF_SensingMethod; dest.EXIF_FileSource := source.EXIF_FileSource; dest.EXIF_SceneType := source.EXIF_SceneType; dest.EXIF_UserComment := source.EXIF_UserComment; dest.EXIF_UserCommentCode := source.EXIF_UserCommentCode; dest.EXIF_MakerNote.Assign(source.EXIF_MakerNote); dest.EXIF_ExposureMode := source.EXIF_ExposureMode; dest.EXIF_WhiteBalance := source.EXIF_WhiteBalance; dest.EXIF_DigitalZoomRatio := source.EXIF_DigitalZoomRatio; dest.EXIF_FocalLengthIn35mmFilm := source.EXIF_FocalLengthIn35mmFilm; dest.EXIF_SceneCaptureType := source.EXIF_SceneCaptureType; dest.EXIF_GainControl := source.EXIF_GainControl; dest.EXIF_Contrast := source.EXIF_Contrast; dest.EXIF_Saturation := source.EXIF_Saturation; dest.EXIF_Sharpness := source.EXIF_Sharpness; dest.EXIF_SubjectDistanceRange := source.EXIF_SubjectDistanceRange; dest.EXIF_ImageUniqueID := source.EXIF_ImageUniqueID; dest.EXIF_GPSVersionID := Source.EXIF_GPSVersionID; dest.EXIF_GPSLatitudeRef := Source.EXIF_GPSLatitudeRef; dest.EXIF_GPSLatitudeDegrees := Source.EXIF_GPSLatitudeDegrees; dest.EXIF_GPSLatitudeMinutes := Source.EXIF_GPSLatitudeMinutes; dest.EXIF_GPSLatitudeSeconds := Source.EXIF_GPSLatitudeSeconds; dest.EXIF_GPSLongitudeRef := Source.EXIF_GPSLongitudeRef; dest.EXIF_GPSLongitudeDegrees := Source.EXIF_GPSLongitudeDegrees; dest.EXIF_GPSLongitudeMinutes := Source.EXIF_GPSLongitudeMinutes; dest.EXIF_GPSLongitudeSeconds := Source.EXIF_GPSLongitudeSeconds; dest.EXIF_GPSAltitudeRef := Source.EXIF_GPSAltitudeRef; dest.EXIF_GPSAltitude := Source.EXIF_GPSAltitude; dest.EXIF_GPSTimeStampHour := Source.EXIF_GPSTimeStampHour; dest.EXIF_GPSTimeStampMinute := Source.EXIF_GPSTimeStampMinute; dest.EXIF_GPSTimeStampSecond := Source.EXIF_GPSTimeStampSecond; dest.EXIF_GPSSatellites := Source.EXIF_GPSSatellites; dest.EXIF_GPSStatus := Source.EXIF_GPSStatus; dest.EXIF_GPSMeasureMode := Source.EXIF_GPSMeasureMode; dest.EXIF_GPSDOP := Source.EXIF_GPSDOP; dest.EXIF_GPSSpeedRef := Source.EXIF_GPSSpeedRef; dest.EXIF_GPSSpeed := Source.EXIF_GPSSpeed; dest.EXIF_GPSTrackRef := Source.EXIF_GPSTrackRef; dest.EXIF_GPSTrack := Source.EXIF_GPSTrack; dest.EXIF_GPSImgDirectionRef := Source.EXIF_GPSImgDirectionRef; dest.EXIF_GPSImgDirection := Source.EXIF_GPSImgDirection; dest.EXIF_GPSMapDatum := Source.EXIF_GPSMapDatum; dest.EXIF_GPSDestLatitudeRef := Source.EXIF_GPSDestLatitudeRef; dest.EXIF_GPSDestLatitudeDegrees := Source.EXIF_GPSDestLatitudeDegrees; dest.EXIF_GPSDestLatitudeMinutes := Source.EXIF_GPSDestLatitudeMinutes; dest.EXIF_GPSDestLatitudeSeconds := Source.EXIF_GPSDestLatitudeSeconds; dest.EXIF_GPSDestLongitudeRef := Source.EXIF_GPSDestLongitudeRef; dest.EXIF_GPSDestLongitudeDegrees := Source.EXIF_GPSDestLongitudeDegrees; dest.EXIF_GPSDestLongitudeMinutes := Source.EXIF_GPSDestLongitudeMinutes; dest.EXIF_GPSDestLongitudeSeconds := Source.EXIF_GPSDestLongitudeSeconds; dest.EXIF_GPSDestBearingRef := Source.EXIF_GPSDestBearingRef; dest.EXIF_GPSDestBearing := Source.EXIF_GPSDestBearing; dest.EXIF_GPSDestDistanceRef := Source.EXIF_GPSDestDistanceRef; dest.EXIF_GPSDestDistance := Source.EXIF_GPSDestDistance; dest.EXIF_GPSDateStamp := Source.EXIF_GPSDateStamp; dest.EXIF_InteropIndex := Source.EXIF_InteropIndex; dest.EXIF_InteropVersion := Source.EXIF_InteropVersion; dest.EXIF_CameraOwnerName := Source.EXIF_CameraOwnerName; dest.EXIF_BodySerialNumber := Source.EXIF_BodySerialNumber; dest.EXIF_LensMake := Source.EXIF_LensMake; dest.EXIF_LensModel := Source.EXIF_LensModel; dest.EXIF_LensSerialNumber := Source.EXIF_LensSerialNumber; dest.EXIF_Gamma := Source.EXIF_Gamma; for q := 0 to 3 do dest.EXIF_SubjectArea[ q ] := Source.EXIF_SubjectArea[ q ]; dest.EXIF_SubjectLocationX := Source.EXIF_SubjectLocationX; dest.EXIF_SubjectLocationY := Source.EXIF_SubjectLocationY; end; // return a pointer (to free!) // if savePreamble=true, will save 'Exif/0/0' before TIFF data procedure SaveEXIFToStandardBuffer(params: TObject; var Buffer: pointer; var BufferLength: integer; savePreamble: boolean); const EXF: AnsiString = 'Exif'#0#0; var ioparams, tempParams: TIOParams; ms: TMemoryStream; NullProgress: TProgressRec; Aborting: boolean; begin Buffer := nil; BufferLength := 0; NullProgress := NullProgressRec( Aborting ); ioparams := TIOParams(Params); ms := TMemoryStream.Create; try TIFFWriteStream(ms, false, nil, ioparams, NullProgress); // EXIF Thumbnail (EXIF_Bitmap) if assigned(ioparams.EXIF_Bitmap) and not ioparams.EXIF_Bitmap.IsEmpty then begin ms.Position := 0; tempParams := TIOParams.Create( nil ); try tempParams.TIFF_ImageIndex := 1; tempParams.TIFF_Compression := ioTIFF_OLDJPEG; TIFFWriteStream(ms, true, ioparams.EXIF_Bitmap, tempParams, NullProgress); finally tempParams.Free; end; end; if savePreamble then begin BufferLength := ms.Size + 6; getmem(Buffer, BufferLength); move(EXF[1], pbyte(Buffer)^, 6); move(pbyte(ms.Memory)^, PAnsiChar(Buffer)[6], BufferLength - 6); end else begin BufferLength := ms.Size; getmem(Buffer, BufferLength); move(pbyte(ms.Memory)^, pbyte(Buffer)^, BufferLength); end; finally FreeAndNil(ms); end; end; function CheckEXIFFromStandardBuffer(Buffer: pointer; BufferLength: integer): boolean; begin result := (BufferLength >= 4) and (PAnsiChar(Buffer) = 'Exif'); end; // usable only when the TIFF contains a single page function LoadEXIFFromStandardBuffer(Buffer: pointer; BufferLength: integer; params: TObject): boolean; var ioparams: TIOParams; tmpio: TIOParams; ms: TMemoryStream; numi: integer; NullProgress: TProgressRec; Aborting: boolean; tempAlphaChannel: TIEMask; begin result := false; if PAnsiChar(Buffer) <> 'Exif' then exit; // ioparams := TIOParams(Params); tmpio := TIOParams.Create( ioparams.ImageEnIO ); ms := TMemoryStream.Create(); try ms.Write(pbytearray(Buffer)[6], BufferLength - 6); ms.position := 0; NullProgress := NullProgressRec( Aborting ); // load data if not assigned(ioparams.EXIF_Bitmap) then ioparams.EXIF_Bitmap := TIEBitmap.Create(); ioparams.EXIF_Bitmap.FreeImage(true); tempAlphaChannel := nil; TIFFReadStream(ioparams.EXIF_Bitmap, ms, numi, tmpio, NullProgress, true, tempAlphaChannel, true, true, false, true); IECopyEXIF(tmpio, ioparams, false); ioparams.EXIF_HasEXIFData := true; // load thumbnail tmpio.TIFF_ImageIndex := 1; ms.position := 0; Aborting := false; tempAlphaChannel := nil; TIFFReadStream(ioparams.EXIF_Bitmap, ms, numi, tmpio, NullProgress, false, tempAlphaChannel, true, true, true, false); if Aborting then ioparams.EXIF_Bitmap.FreeImage(true); IEAdjustEXIFOrientation(ioparams.EXIF_Bitmap, ioparams.TIFF_Orientation); finally FreeAndNil(ms); FreeAndNil(tmpio); end; result := true; end; function IsValidEXIFIFD(Stream: TStream; pos: integer; swap: boolean): boolean; var w: word; lsave: int64; begin // just check number of tags is > 0 and less than 8192 lsave := Stream.Position; Stream.Position := pos; Stream.Read(w, sizeof(word)); w := IECSwapWord(w, swap); result := (w > 0) and (w < 8192); Stream.Position := lsave; end; // returns the position of the first EXIF data block // -1 = not found // saves stream position function IESearchEXIFInfo(Stream: TStream): int64; const BUFBLOCK = 131072; EXIF: dword = $66697845; // 'Exif' var lsave: int64; buf: array of byte; tiffhe: TTIFFHeader; bufpos: integer; StreamSize: int64; bigEndian: boolean; bufferStreamPosition: int64; // -1 = invalid (not found) function CheckPosition(): int64; const LOOKAHEADBYTES = 128; var lpos: int64; cpos: int64; begin // locate 'II' or 'MM' sequences into first LOOKAHEADBYTES bytes lpos := Stream.Position; cpos := lpos; result := -1; try while cpos < lpos + LOOKAHEADBYTES do begin Stream.Position := cpos; Stream.Read(tiffhe, sizeof(TTIFFHeader)); if (tiffhe.Id = $4949) or (tiffhe.Id = $4D4D) then begin bigEndian := (tiffhe.Id = $4D4D); if bigEndian then begin tiffhe.Ver := IESwapWord(tiffhe.Ver); tiffhe.PosIFD := IESwapDWord(tiffhe.PosIFD); end; if (tiffhe.PosIFD < StreamSize) then begin if ((tiffhe.Ver = 42) or (tiffhe.Ver = 20306) or (tiffhe.Ver = 21330)) then begin if IsValidEXIFIFD(Stream, tiffhe.PosIFD, bigEndian) or IsValidEXIFIFD(Stream, cpos + integer(tiffhe.PosIFD), bigEndian) then begin result := cpos; exit; end; end; end; end; inc(cpos); // try next byte end; finally Stream.Position := lpos; end; end; begin lsave := Stream.Position; try StreamSize := Stream.Size; SetLength(buf, BUFBLOCK); // try current position result := CheckPosition(); if result > -1 then exit; // not found, search for "Exif" string while Stream.Position < StreamSize do begin if Stream.Position > 0 then Stream.Seek(-5, soCurrent); // take care of possible 'Exif' overlappinng bufferStreamPosition := Stream.Position; Stream.Read(buf[0], BUFBLOCK); bufpos := 0; while bufpos < BUFBLOCK - 5 do begin if (pdword(@buf[bufpos])^ = EXIF) and (buf[bufpos + 4] = 0) then begin Stream.Position := bufferStreamPosition + bufpos; result := CheckPosition(); if result > -1 then exit; end; inc(bufpos); end; end; finally Stream.Position := lsave; end; end; // usable only when the TIFF contains a single page function IELoadEXIFFromTIFF(Stream: TStream; params: TObject; loadXMP: boolean): boolean; var ioparams: TIOParams; tmpio: TIOParams; numi: integer; NullProgress: TProgressRec; Aborting: boolean; tempAlphaChannel: TIEMask; lsave: int64; bmp1, bmp2: TIEBitmap; begin lsave := Stream.Position; ioparams := TIOParams(Params); tmpio := TIOParams.Create( ioparams.ImageEnIO ); bmp1 := TIEBitmap.Create; bmp2 := TIEBitmap.Create; try NullProgress := NullProgressRec( Aborting ); // load data if not assigned(ioparams.EXIF_Bitmap) then ioparams.EXIF_Bitmap := TIEBitmap.Create; ioparams.EXIF_Bitmap.FreeImage(true); tempAlphaChannel := nil; TIFFReadStream(ioparams.EXIF_Bitmap, Stream, numi, tmpio, NullProgress, true, tempAlphaChannel, true, true, false, true); IECopyEXIF(tmpio, ioparams, false); ioparams.EXIF_HasEXIFData := true; if loadXMP then ioparams.XMP_Info := tmpio.XMP_Info; // load thumbnail, try image 0 tmpio.TIFF_ImageIndex := 0; tempAlphaChannel := nil; Stream.Position := lsave; Aborting := false; TIFFReadStream(bmp1, Stream, numi, tmpio, NullProgress, false, tempAlphaChannel, true, true, true, false); // try image 1 tmpio.TIFF_ImageIndex := 1; tempAlphaChannel := nil; Stream.Position := lsave; Aborting := false; TIFFReadStream(bmp2, Stream, numi, tmpio, NullProgress, false, tempAlphaChannel, true, true, true, false); if (bmp1.Width > 0) and ((bmp1.Width < bmp2.Width) or (bmp2.Width = 0)) and not bmp1.IsAllBlack then ioparams.EXIF_Bitmap.Assign( bmp1 ) else if (bmp2.Width > 0) and ((bmp2.Width < bmp1.Width) or (bmp1.Width = 0)) and not bmp2.IsAllBlack then ioparams.EXIF_Bitmap.Assign( bmp2 ); finally bmp1.free; bmp2.free; FreeAndNil(tmpio); result := true; Stream.Position := lsave; end; end; function IELoadParamsFromTIFF(Stream: TStream; params: TObject; page: integer): boolean; var ioparams: TIOParams; numi: integer; NullProgress: TProgressRec; Aborting: boolean; tempAlphaChannel: TIEMask; lsave: int64; begin lsave := Stream.Position; ioparams := TIOParams(Params); try NullProgress := NullProgressRec( Aborting ); // load data if not assigned(ioparams.EXIF_Bitmap) then ioparams.EXIF_Bitmap := TIEBitmap.Create; ioparams.EXIF_Bitmap.FreeImage(true); tempAlphaChannel := nil; TIFFReadStream(ioparams.EXIF_Bitmap, Stream, numi, ioparams, NullProgress, true, tempAlphaChannel, true, true, false, false); finally result := true; Stream.Position := lsave; end; end; {!! EXIFDateToDateTime Declaration function EXIFDateToDateTime(const sEXIFDate: string): TDateTime; Description Converts an EXIF date string to a TDateTime value (also works with XMP date fields). EXIF dates are formatted as "YYYY:MM:DD HH:MM:SS"+0x00 Examples dtExifDate := EXIFDateToDateTime( '2015-05-03T14:03:08-04:00' ); See Also - !!} function EXIFDateToDateTime(const sEXIFDate: string): TDateTime; begin result := 0; if (length(trim(sEXIFDate)) = 0) or (sEXIFDate = '0000:00:00 00:00:00') then // this avoids design-time exceptions on empty strings exit; try { EXIF_DateTimeOriginal Date/Time of original image taken. This value should not be modified by user program. Data format is "YYYY:MM:DD HH:MM:SS"+0x00, total 20bytes. If clock has not set or digicam doesn't have clock, the field may be filled with spaces. In the Exif standard, this tag is optional, but it is mandatory for DCF. } result := EncodeDate(StrToInt(Copy(sEXIFDate, 1, 4)), // Year StrToInt(Copy(sEXIFDate, 6, 2)), // Month StrToInt(Copy(sEXIFDate, 9, 2))) + // Day EncodeTime(StrToInt(Copy(sEXIFDate, 12, 2)), // Hour StrToInt(Copy(sEXIFDate, 15, 2)), // Min StrToInt(Copy(sEXIFDate, 18, 2)), // Sec 0); // MSec except // no need to set result := 0 (already set on top) end; end; {!! DateTimeToEXIFDate Declaration function DateTimeToEXIFDate(ADateTime: TDateTime): string; Description Converts a TDateTime value to an EXIF string representation (also used by XMP date fields). EXIF dates are formatted as "YYYY:MM:DD HH:MM:SS"+0x00 Examples // Update the Exif date ImageEnView1.IO.Params.EXIF_DateTime := DateTimeToEXIFDate( Now ); See Also - !!} function DateTimeToEXIFDate(ADateTime: TDateTime): string; const // DATE FORMATS (Use with FormatDateTime) EXIF_TIME_FORMAT = 'hh:mm:ss'; EXIF_DATE_FORMAT = 'yyyy:mm:dd'; EXIF_DATE_TIME_FORMAT = EXIF_DATE_FORMAT + ' ' + EXIF_TIME_FORMAT; begin if ADateTime = 0 then Result := '' else result := FormatDateTime(EXIF_DATE_TIME_FORMAT, ADateTime); end; function IEReadEXIFFromMOV(const FileName: WideString; OutParams: TObject): boolean; var fs: TIEWideFileStream; begin fs := TIEWideFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try result := IEReadEXIFFromMOV(fs, OutParams); finally fs.Free(); end; end; // only FujiFilm Exif is supported function IEReadEXIFFromMOV(Stream: TStream; OutParams: TObject): boolean; var ms: TMemoryStream; tp: dword; sz: int64; nm: integer; NullProgress: TProgressRec; aborting: boolean; tempAlphaChannel: TIEMask; TIFFHeader: TTIFFHeader; ioparams: TIOParams; function GetDWord(): dword; begin Stream.Read(result, sizeof(dword)); result := IESwapDWord(result); end; function DWordToStr(dw: dword): string; var i: integer; begin result := ''; for i := 3 downto 0 do result := result + chr(dw shr (i * 8) and $FF); end; function FindTag(tags: array of string): boolean; var i: integer; begin result := false; while Stream.Position < Stream.Size do begin sz := GetDWord(); // get atom size tp := GetDWord(); // get atom type if sz = 0 then sz := Stream.Size - Stream.Position else if sz = 1 then begin // 64 bit size sz := GetDWord(); sz := sz or (GetDWord() shl 32); end; for i := 0 to high(tags) do if DWordToStr(tp) = tags[i] then begin result := true; exit; end; Stream.Seek(sz - 8, soCurrent); end; end; begin result := false; if FindTag(['moov']) and FindTag(['udta']) and FindTag(['MVTG']) then begin ms := TMemoryStream.Create(); try Stream.Seek(16, soCurrent); ms.CopyFrom(Stream, sz - 8); NullProgress := NullProgressRec( Aborting ); tempAlphaChannel := nil; TIFFHeader.Id := $4949; TIFFHeader.Ver := 42; TIFFHeader.PosIFD := 0; ms.Position := 0; ioparams := OutParams as TIOParams; TIFFReadStream(nil, ms, nm, ioparams, NullProgress, true, tempAlphaChannel, true, true, false, true, @TIFFHeader); result := true; finally ms.Free(); end; end; end; //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // TIEBitmap {!! TIEBitmap.Create Declaration constructor Create(); constructor Create(ImageWidth, ImageHeight: integer; ImagePixelFormat: = ie24RGB); constructor Create(const FileName: string; IOParams: = nil); constructor Create(image: ); constructor Create(Buffer: pointer; BufferSize: integer; Format: = ioUnknown); overload; constructor Create(image: ; Rect: TRect); overload; constructor Create(image: TBitmap; Rect: TRect); overload; Description Creates a new TIEBitmap object. The second overload creates the bitmap using specified parameters. Third overload loads image from specified file. IOParams specifies the in/out parameters as objects. Fourth overload creates a clone of source image. Fifth overload creates from memory buffer. Examples // creates an empty image bmp1 := TIEBitmap.Create(); // creates 1000x1000, 24 bit RGB image bmp2 := TIEBitmap.Create(1000, 1000, ie24RGB); // creates an image from file "input.png" bmp2 := TIEBitmap.Create('input.png'); // creates a clone of bmp2 bmp3 := TIEBitmap.Create(bmp2); !!} constructor TIEBitmap.Create(); var fm: int64; i: integer; begin inherited; // fIOParams := nil; fmemmap := TIEFileBuffer.Create(); fOrigin := ieboBOTTOMLEFT; fFragments := nil; fFragmentsCount := 0; fRowsPerFragment := 0; fFullReallocate := true; fWidth := 0; fHeight := 0; fBitCount := 0; fMemoryAllocator := iemaAuto; fChannelCount := 0; fWorkingMap := nil; fPixelFormat := ienull; fRGBPalette := nil; fIsAlpha := false; fAlphaChannel := nil; fRGBPaletteLen := 0; fLocation := ieFile; fMemory := nil; fRealMemory := nil; fBitmap := nil; fBitmapScanlines := nil; fFull := false; fEncapsulatedFromTBitmap := false; fEncapsulatedFromMemory := false; fScanlinesToUnMapPtr := TList.Create(); fScanlinesToUnMapRow := TList.Create(); fDefaultDitherMethod := ieThreshold; fBlackValue := 0; fWhiteValue := 0; fSavedBitmaps := nil; // calculates fMinFileSize fm := IEGetMemory(false); if IEGlobalSettings().DefMinFileSize = -1 then begin if fm = 0 then begin // we cannot know how much memory is free fMinFileSize := 32 * 1024 * 1024; // 32 Mbytes end else begin fMinFileSize := trunc(fm / 1.1); end; end else fMinFileSize := IEGlobalSettings().DefMinFileSize; // channels for i := 0 to IEMAXCHANNELS - 1 do fChannelOffset[i] := 0; fContrast := 0; fAccess := [iedRead, iedWrite]; fPaletteUsed := 256; fBitAlignment := 32; fCanvasCurrentAlpha := -1; fOnRenderVirtualPixel := nil; fVirtualBitmapProvider := nil; fVirtualBitmapRowBuffer := nil; fIECanvas := nil; fROIOriginalBitmap := nil; fROICanvas := nil; fColorProfile := TIEICC.Create(); fRenderColorProfile := TIEICC.Create(); fRenderColorProfile.Assign_sRGBProfile(); fAdjustmentsMask := nil; fOnChanged := nil; fModified := False; end; constructor TIEBitmap.Create(ImageWidth, ImageHeight: integer; ImagePixelFormat: TIEPixelFormat = ie24RGB); begin Create(); Allocate(ImageWidth, ImageHeight, ImagePixelFormat); fModified := False; end; constructor TIEBitmap.Create(const FileName: string; IOParams: TIOParams); begin Create(); Read(FileName, IOParams); fModified := False; end; constructor TIEBitmap.Create(image: TIEBitmap); begin Create(); Assign(image); fModified := False; end; constructor TIEBitmap.Create(image: TIEBitmap; Rect: TRect); begin Create(); Allocate(Rect.Right - Rect.Left + 1, Rect.Bottom - Rect.Top + 1, image.PixelFormat); image.CopyRectTo(self, Rect.Left, Rect.Top, 0, 0, Width, Height, true); fModified := False; end; constructor TIEBitmap.Create(image: TBitmap; Rect: TRect); var bmp: TIEBitmap; begin Create(); Allocate(Rect.Right - Rect.Left + 1, Rect.Bottom - Rect.Top + 1, IEVCLPixelFormat2ImageEnPixelFormat(image.PixelFormat)); bmp := TIEBitmap.Create(); try bmp.EncapsulateTBitmap(image, false); bmp.CopyRectTo(self, Rect.Left, Rect.Top, 0, 0, Width, Height, false); finally bmp.Free(); end; fModified := False; end; constructor TIEBitmap.Create(Buffer: pointer; BufferSize: integer; Format: integer = 0); begin Create; Read(Buffer, BufferSize, Format); fModified := False; end; {!! TIEBitmap.Read Declaration function Read(const FileName: string; IOParams: = nil; bCheckUnknown: Boolean = True): boolean; overload; function Read(Stream: TStream; FileType: = ioUnknown; IOParams: = nil): boolean; overload; function Read(Buffer: pointer; BufferSize: integer; FileType: = ioUnknown; IOParams: = nil): boolean; Description Load an image from file or stream. This method supports all formats supported by class. When reading from a stream you can optionally specify the Format. If it is not specified ImageEn will determine the file type automatically. You can optionally pass an object for the I/O parameters of the file (see also ). If bCheckUnknown is true and the file extension is not known or is incorrect (e.g. a GIF file named MyImage.jpg), then loading will be attempted by analyzing the file content (in the same way as ). Result will be False if the file is not a recognized file type (and will be false). Loading errors due to a file not being available will raise an exception. Examples var bmp: TIEBitmap; begin bmp := TIEBitmap.Create; bmp.Read('input.jpg'); bmp.Write('output.jpg'); bmp.Free; end; Which is the same as... with TIEBitmap.Create('input.jpg') do begin Write('output.jpg'); Free; end; Also, the same as... var bmp: TIEBitmap; io: TImageEnIO; begin bmp := TIEBitmap.Create; io := TImageEnIO.CreateFromBitmap(bmp); io.LoadFromFile('input.jpg'); io.SaveToFile('output.jpg'); io.Free; bmp.Free; end; Compatibility Notes The parameters of TIEBitmap.Read changed for the stream overload in v6.0.0. Code that was: MyBmp.Read(aStream, aIOParams); Should change to: MyBmp.Read(aStream, ioUnknown, aIOParams); !!} function TIEBitmap.Read(const FileName: string; IOParams: TIOParams = nil; bCheckUnknown: Boolean = True): boolean; var io: TImageEnIO; begin io := TImageEnIO.CreateFromBitmap( Self ); try // Assign Params if assigned( IOParams ) then io.fParams.Assign( IOParams ) else if ParamsEnabled then io.fParams.Assign( fIOParams ); io.LoadFromFile( Filename, bCheckUnknown ); result := not io.Aborting; fFilename := Filename; fFileType := io.fParams.FileType; // Restore Params if assigned( IOParams ) then IOParams.Assign( io.fParams ); if ParamsEnabled then fIOParams.Assign( io.fParams ); finally io.Free; end; UpdateOwner; end; function TIEBitmap.Read(Stream: TStream; FileType: TIOFileType = 0; IOParams: TIOParams = nil): boolean; var io: TImageEnIO; begin io := TImageEnIO.CreateFromBitmap( self ); try // Assign Params if assigned( IOParams ) then io.fParams.Assign( IOParams ) else if ParamsEnabled then io.fParams.Assign( fIOParams ); if fIsResource then io.fParams.IsResource := True; io.LoadFromStream(Stream, FileType); result := not io.Aborting; // Restore Params if assigned( IOParams ) then IOParams.Assign( io.fParams ); if ParamsEnabled then fIOParams.Assign( io.fParams ); finally io.Free; end; UpdateOwner; end; function TIEBitmap.Read(Buffer: pointer; BufferSize: integer; FileType: TIOFileType = 0; IOParams: TIOParams = nil): boolean; var io: TImageEnIO; begin io := TImageEnIO.CreateFromBitmap( self ); try // Assign Params if assigned( IOParams ) then io.fParams.Assign( IOParams ) else if ParamsEnabled then io.fParams.Assign( fIOParams ); io.LoadFromBuffer(Buffer, BufferSize, FileType); result := not io.Aborting; // Restore Params if assigned( IOParams ) then IOParams.Assign( io.fParams ); if ParamsEnabled then fIOParams.Assign( io.fParams ); finally io.Free; end; UpdateOwner; end; // Refresh the TImageEnView that this control belongs to procedure TIEBitmap.UpdateOwner(); begin if assigned( fOwner ) and ( fOwner is TImageEnView ) then begin TImageEnView( fOwner ).Update; TImageEnView( fOwner ).ImageChange; end; end; {!! TIEBitmap.Write Declaration function Write(const FileName: string; IOParams: = nil): boolean; overload; function Write(Stream: TStream; FileType: ; IOParams: = nil): boolean; overload; Description Writes image to file or stream. This method supports all formats supported by class. If saving to a stream you must specify the FileType. You can optionally specify an object containing the I/O parameters of the file (see also ). Returns true on success. Examples var bmp: TIEBitmap; begin bmp := TIEBitmap.Create; bmp.Read('input.jpg'); bmp.Write('output.jpg'); bmp.Free; end; Which is the same as... with TIEBitmap.Create('input.jpg') do begin Write('output.jpg'); Free; end; Also the same as... var bmp: TIEBitmap; io: TImageEnIO; begin bmp := TIEBitmap.Create; io := TImageEnIO.CreateFromBitmap(bmp); io.LoadFromFile('input.jpg'); io.SaveToFile('output.jpg'); io.Free; bmp.Free; end; !!} function TIEBitmap.Write(const FileName: string; IOParams: TIOParams = nil): boolean; var io: TImageEnIO; iBitsPerSample, iSamplesPerPixel: Integer; begin io := TImageEnIO.CreateFromBitmap( Self ); try // Assign Params if assigned( IOParams ) then io.fParams.Assign( IOParams ) else if ParamsEnabled then io.fParams.Assign( fIOParams ) else begin // Assign some minimum params if PixelFormat = ie8g then begin iBitsPerSample := 8; iSamplesPerPixel := 1; io.fParams.JPEG_ColorSpace := ioJPEG_GRAYLEV; end else IEPixelFormatToBPSAndSPP( PixelFormat, iBitsPerSample, iSamplesPerPixel ); io.fParams.BitsPerSample := iBitsPerSample; io.fParams.SamplesPerPixel := iSamplesPerPixel; end; io.SaveToFile(FileName); result := not io.Aborting; fFilename := Filename; fFileType := io.fParams.FileType; finally io.Free; end; end; function TIEBitmap.Write(Stream: TStream; FileType: TIOFileType; IOParams: TIOParams = nil): boolean; var io: TImageEnIO; begin io := TImageEnIO.CreateFromBitmap( self ); try // Assign Params if assigned( IOParams ) then io.fParams.Assign( IOParams ) else if ParamsEnabled then io.fParams.Assign( fIOParams ); io.SaveToStream(Stream, FileType); result := not io.Aborting; finally io.Free; end; end; {!! TIEBitmap.CreateROIBitmap Declaration function CreateROIBitmap(Rect: TRect; ROIPixelFormat: ; PerformAlphaCompositing: boolean = false): ; Description Creates a TIEBitmap object containing a copy of the specified area. When the returned object is destroyed the content is copied back to the original bitmap. If PerformAlphaCompositing is True then the resulting bitmap is black and fully transparent. An alpha compose will be performed when bitmap is released. ROIPixelFormat is ignored when PerformAlphaCompositing is True (it is always ie32RGB). !!} function TIEBitmap.CreateROIBitmap(Rect: TRect; ROIPixelFormat: TIEPixelFormat; PerformAlphaCompositing: boolean): TIEBitmap; begin OrdCor(Rect.Left, Rect.Top, Rect.Right, Rect.Bottom); if PerformAlphaCompositing then begin result := TIEBitmap.Create(Rect.Right - Rect.Left + 1, Rect.Bottom - Rect.Top + 1, ie32RGB); result.Fill(0); // set color and alpha to 0 end else begin result := TIEBitmap.Create(self, Rect); if ROIPixelFormat <> ienull then result.PixelFormat := ROIPixelFormat; end; result.fROIOriginalBitmap := self; result.fROIOriginalRect := Rect; end; procedure TIEBitmap.DestroyMe(Sender: TObject); begin (Sender as TIECanvas).ResetTransform(); Free(); end; {!! TIEBitmap.CreateROICanvas Declaration function CreateROICanvas(Rect: TRect; AntiAlias: boolean = true; UseGDIPlus: boolean = true; PerformAlphaCompositing: boolean = false): TIECanvas; function CreateROICanvas(AntiAlias: boolean = true; UseGDIPlus: boolean = true; PerformAlphaCompositing: boolean = false): TIECanvas; Description Creates a TIECanvas object representing a copy of specified bitmap area. The canvas pixel format will be temporally 24 bit RGB (or 32 bit RGB when PerformAlphaCompositing is True) and has coordinates translated to the top-left of the specified rectangle. When the returned object is destroyed the content is copied back to the original bitmap. Example // create a layer on a TImageEnView with shadow text var compositingCanvas: TIECanvas; begin ImageEnView1.LayersAdd; // Area that is larger than what we need ImageEnView1.IEBitmap.Allocate(500, 500); ImageEnView1.AlphaChannel.Fill(0); // Rect(0,0,500,100) is just the estimated required area compositingCanvas := ImageEnView1.IEBitmap.CreateROICanvas(Rect(0, 0, 500, 100), true, true, true); compositingCanvas.Brush.Color := clRed; compositingCanvas.Font.Name := 'Tahoma'; compositingCanvas.Font.Height := 72; compositingCanvas.DrawText('Hello World!', Rect(0, 0, 500, 300)); // use DrawText instead of TextOut // This will also copy the content back to the IEBitmap compositingCanvas.Free(); // Add a Soft Shadow ImageEnView1.Proc.AddSoftShadow(5, 5, 1); // Remove excess transparent area ImageEnView1.Proc.CropTransparentBorder; ImageEnView1.Update(); end; Example 2 // make area outside ellipse transparent ImageEnView1.IO.LoadFromFile('test.jpg'); ImageEnView1.IEBitmap.AlphaChannel.Fill(0); with ImageEnView1.IEBitmap.AlphaChannel.CreateROICanvas() do begin Brush.Style := bsSolid; Brush.Color := RGB(255, 255, 255); Ellipse(0, 0, ImageEnView1.IEBitmap.Width - 1, ImageEnView1.IEBitmap.Height - 1); Free(); end; ImageEnView1.Update(); !!} function TIEBitmap.CreateROICanvas(Rect: TRect; AntiAlias: boolean; UseGDIPlus: boolean; PerformAlphaCompositing: boolean): TIECanvas; var ROIBitmap: TIEBitmap; begin OrdCor(Rect.Left, Rect.Top, Rect.Right, Rect.Bottom); ROIBitmap := CreateROIBitmap(Rect, ie24RGB, PerformAlphaCompositing); result := TIECanvas.Create(ROIBitmap.Canvas, AntiAlias, UseGDIPlus); result.ROIBitmap := ROIBitmap; result.OnDestroy := ROIBitmap.DestroyMe; result.Translate(-Rect.Left, -Rect.Top); if PerformAlphaCompositing then result.SetCompositingMode(ieCompositingModeSourceCopy, ieCompositingQualityHighQuality); end; function TIEBitmap.CreateROICanvas(AntiAlias: boolean; UseGDIPlus: boolean; PerformAlphaCompositing: boolean): TIECanvas; begin result := CreateROICanvas(Rect(0, 0, Width - 1, Height - 1), AntiAlias, UseGDIPlus, PerformAlphaCompositing); end; // called only by the Destructor procedure TIEBitmap.ReleaseROI(); begin if fROIOriginalBitmap <> nil then begin if fROICanvas <> nil then begin fROICanvas.ResetTransform(); fROICanvas.Free(); end; // copy back if fPixelFormat = ie32RGB then begin // perform alpha compositing fROIOriginalBitmap.MergeWithAlpha(self, fROIOriginalRect.Left, fROIOriginalRect.Top, -1, -1, 255, rfNone, ielNormal, false, 0, 0, 1); end else begin // just copy PixelFormat := fROIOriginalBitmap.PixelFormat; CopyRectTo(fROIOriginalBitmap, 0, 0, fROIOriginalRect.Left, fROIOriginalRect.Top, fWidth, fHeight, true); end; end; end; {!! TIEBitmap.CanvasCurrentAlpha Declaration property CanvasCurrentAlpha: integer Description Setting this property to a value >=0, makes the alpha channel an 8 bit gray scale paintable bitmap. This means that you can draw on the alpha channel using TCanvas object. The value (0..255) specifies the transparency, 0=fully transparent, 255=fully opaque. Default: -1 Examples ImageEnView1.IEBitmap.AlphaChannel.CanvasCurrentAlpha := 128; with ImageEnView1.IEBitmap.AlphaChannel.Canvas do begin FillRect(0, 0, 100, 100); Ellipse(10, 10, 200, 200); end; // Draw a line on the IEBitmap canvas and ensure it also make opaque on the transparency With ImageEnView1 do begin IEBitmap.Canvas.Pen.Color := clRed; IEBitmap.Canvas.MoveTo( 10, 10 ) ; IEBitmap.Canvas.LineTo( 100, 100 ); IEBitmap.AlphaChannel.CanvasCurrentAlpha := 255; IEBitmap.AlphaChannel.Canvas.MoveTo( 10, 10 ) ; IEBitmap.AlphaChannel.Canvas.LineTo( 100, 100 ); Update; end !!} procedure TIEBitmap.SetCanvasCurrentAlpha(v: integer); var c: TColor; begin if fCanvasCurrentAlpha = -1 then begin Location := ieTBitmap; // we need a canvas PixelFormat := ie8g; VclBitmap.PixelFormat := pf8bit; IESetGrayPalette(VclBitmap); end; if v<>-1 then begin c := $02000000 or (v) or (v shl 8) or (v shl 16); Canvas.Pen.Color := c; Canvas.Brush.Color := c; end; fCanvasCurrentAlpha := v; Changed(); end; {!! TIEBitmap.UpdateFromTBitmap Declaration procedure UpdateFromTBitmap; Description Updates the TIEBitmap with the content of the embedded TBitmap object (). This is useful if you change VclBitmap and want to refresh TIEBitmap. Example ImageEnView1.IEBitmap.VclBitmap.Width := 1000; ImageEnView1.IEBitmap.UpdateFromTBitmap; ImageEnView1.Update; !!} procedure TIEBitmap.UpdateFromTBitmap; var px: TIEPixelFormat; begin if assigned(fBitmap) and not IsVirtual then begin px := ie24RGB; case fBitmap.PixelFormat of pf1bit: px := ie1g; pf8bit: if fIsAlpha or IEIsGrayPalette(fBitmap) then px := ie8g else px := ie8p; pf24bit: px := ie24RGB; pf32bit: px := ie32RGB; end; if (fWidth <> fBitmap.Width) or (fHeight <> fBitmap.Height) or (fPixelFormat <> px) then begin fWidth := fBitmap.Width; fHeight := fBitmap.Height; fPixelFormat := px; fBitCount := IEPixelFormat2BitCount(fPixelFormat); fChannelCount := IEPixelFormat2ChannelCount(fPixelFormat); fRowLen := IEBitmapRowLen(fWidth, fBitCount, fBitAlignment); if HasAlphaChannel and ((fAlphaChannel.Width <> fWidth) or (fAlphaChannel.Height <> fHeight)) then fAlphaChannel.Allocate(fWidth, fHeight, ie8g); BuildBitmapScanlines; end; if (fHeight > 0) and (length(fBitmapScanlines) > 0) and (fBitmapScanlines[0] <> fBitmap.Scanline[0]) then BuildBitmapScanlines; if fPixelFormat=ie8p then IECopyTBitmapPaletteToTIEBitmap(fBitmap, self); end; end; {!! TIEBitmap.BitCount Declaration property BitCount: integer; Description Return the bits per pixel. Here is the - BitCount comparison: PixelFormat = ie1g -> BitCount = 1 PixelFormat = ie8g -> BitCount = 8 PixelFormat = ie8p -> BitCount = 8 PixelFormat = ie16g -> BitCount = 16 PixelFormat = ie24RGB -> BitCount = 24 PixelFormat = ie32f -> BitCount = 32 PixelFormat = ieCMYK -> BitCount = 32 PixelFormat = ie48RGB -> BitCount = 48 PixelFormat = ieCIELab -> BitCount = 24 PixelFormat = ie32RGB -> BitCount = 32 PixelFormat = ieVirtual -> BitCount = 24 !!} function TIEBitmap.GetBitCount: integer; begin if (fLocation = ieTBitmap) then UpdateFromTBitmap; result := fBitCount; end; procedure TIEBitmap.SetBitCount(Value: Integer); begin fBitCount := Value; end; {!! TIEBitmap.ChannelCount Declaration property ChannelCount: integer; Description Returns the number of channels of current pixel format. !!} function TIEBitmap.GetChannelCount: integer; begin if (fLocation = ieTBitmap) then UpdateFromTBitmap; result := fChannelCount; end; procedure TIEBitmap.SetChannelCount(Value: Integer); begin fChannelCount := Value; end; {!! TIEBitmap.Width Declaration property Width: integer; Description Specifies the image width. !!} function TIEBitmap.GetWidth: integer; begin if (fLocation = ieTBitmap) then UpdateFromTBitmap; result := fWidth; end; {!! TIEBitmap.Height Declaration property Height: integer; Description Specifies the image height. !!} function TIEBitmap.GetHeight: integer; begin if (fLocation = ieTBitmap) then UpdateFromTBitmap; result := fHeight; end; {!! TIEBitmap.PixelFormat Declaration property PixelFormat: ; Description Specifies the image pixel format. You can set PixelFormat to convert an image from one format to another. !!} function TIEBitmap.GetPixelFormat: TIEPixelFormat; begin if (fLocation = ieTBitmap) then UpdateFromTBitmap; result := fPixelFormat; end; {!! TIEBitmap.RowLen Declaration property RowLen: integer; Description Returns the count of bytes in a row. By default, a row is double word aligned (32bit). !!} function TIEBitmap.GetRowLen: integer; begin if (fLocation = ieTBitmap) then UpdateFromTBitmap; result := fRowLen; end; procedure TIEBitmap.SetRowLen(Value: Integer); begin fRowLen := Value; end; {!! TIEBitmap.VclBitmap Declaration property VclBitmap: TBitmap; Description Contains the encapsulated TBitmap object. !!} function TIEBitmap.GetVclBitmap: TBitmap; begin SetLocation(ieTBitmap); AdjustCanvasOrientation; result := fBitmap; end; // used by Allocate // set fEncapsulatedFromTBitmap to false // set fEncapsulatedFromMemory to false constructor TIEBitmap.CreateAsAlphaChannel(ImageWidth, ImageHeight: integer; ImageLocation: TIELocation); begin Create; fEncapsulatedFromTBitmap := false; fEncapsulatedFromMemory := false; fIsAlpha := true; fLocation := ImageLocation; if fLocation = ieTBitmap then fLocation := ieMemory; Allocate(ImageWidth, ImageHeight, ie8g); Fill(255); // full opaque end; {!! TIEBitmap.FeatherAlphaEdges Declaration procedure FeatherAlphaEdges(iFeatherDepth : Integer); Description Applies a feathering effect to the image. Feathering softens the edges of an image by applying alpha transparency at a rate that is proportional to the distance to the edge (specifically, adding a gradient in the alpha channel). iFeatherDepth specifies the depth in pixels of the feather effect. The range is 0 to 255, with typical values of 2 to 5. If iFeatherDepth = 0 then the image is not feathered but a simple smoothing filter is applied to reduce the jagged edges of the image. Note: Method has no effect if the image does not have an alpha channel !!} // thanks to Roy Magne Klever for feather and smooth algorithms procedure TIEBitmap.FeatherAlphaEdges(iFeatherDepth : Integer); const Smooth_Effect = True; // Always use smoothing when feathering var x, y, i: integer; ww1, hh1: integer; // Snowing routine cur_level, step: integer; palphaPrev, palpha, palphaLeft, palphaRight, palphaUp, palphaDown: pbyte; prevAlpha: TIEBitmap; procedure snow_mpixel(); begin if (palpha^ > cur_level) then begin inc(cur_level, step); if cur_level > 255 then cur_level := 255; palpha^ := cur_level; end else cur_level := palpha^; end; begin if fIsAlpha or not HasAlphaChannel then exit; ww1 := AlphaChannel.Width - 1; hh1 := AlphaChannel.Height - 1; if iFeatherDepth > 0 then begin step := 256 div iFeatherDepth; // feather must not be 0 // The two horizontal passes for y := 0 to hh1 do begin cur_level := 0; palpha := AlphaChannel.Scanline[y]; for x := 0 to ww1 do begin snow_mpixel(); inc(palpha); end; cur_level := 0; for x := ww1 downto 0 do begin dec(palpha); snow_mpixel(); end; end; // The two vertical passes for x := 0 to ww1 do begin cur_level := 0; for y := 0 to hh1 do begin palpha := AlphaChannel.Scanline[y]; inc(palpha, x); snow_mpixel(); end; cur_level := 0; for y := hh1 downto 0 do begin palpha := AlphaChannel.Scanline[y]; inc(palpha, x); snow_mpixel(); end; end; end; if Smooth_Effect or ( iFeatherDepth = 0 ) then begin prevAlpha := TIEBitmap.Create(AlphaChannel); for y := 0 to hh1 do begin palpha := AlphaChannel.ScanLine[y]; palphaPrev := prevAlpha.ScanLine[y]; palphaLeft := palphaPrev; dec(palphaLeft); palphaRight := palphaPrev; inc(palphaRight); palphaUp := prevAlpha.Scanline[imax(y - 1, 0)]; palphaDown := prevAlpha.Scanline[imin(y + 1, hh1)]; for x := 0 to ww1 do begin if palpha^ <> 0 then begin i := 0; if x > 0 then inc(i, palphaLeft^); if x <= ww1 then inc(i, palphaRight^); inc(i, palphaUp^); inc(i, palphaDown^); palpha^ := i shr 2; end; inc(palpha); inc(palphaLeft); inc(palphaRight); inc(palphaUp); inc(palphaDown); end; end; prevAlpha.Free(); end; Changed(); end; {!! TIEBitmap.RemoveAlphaChannel Declaration procedure RemoveAlphaChannel(Merge: boolean = false; BackgroundColor: TColor = clWhite); Description Removes the associated alpha channel. When Merge is true, the specified BackgroundColor is merged with the semitransparent areas of the image (like a shadow). !!} procedure TIEBitmap.RemoveAlphaChannel(Merge: boolean = False; BackgroundColor: TColor = clWhite); begin if fIsAlpha or not HasAlphaChannel then exit; // merges with Background color? if Merge then BlendAlpha(BackgroundColor); FreeAndNil(fAlphaChannel); Changed(); end; // changes pixels color merging pixels with alpha < 255 with the background color // works only with ie24RGB procedure TIEBitmap.BlendAlpha(BackgroundColor: TColor); var x, y: integer; px: PRGB; al: pbyte; a: integer; br, bg, bb: integer; begin if (PixelFormat = ie24RGB) and (HasAlphaChannel) then begin with TColor2TRGB(BackgroundColor) do begin br := r; bg := g; bb := b; end; for y := 0 to fHeight - 1 do begin px := Scanline[y]; al := AlphaChannel.Scanline[y]; for x := 0 to fWidth - 1 do begin a := al^ shl 10; with px^ do begin r := a * (r - br) shr 18 + br; g := a * (g - bg) shr 18 + bg; b := a * (b - bb) shr 18 + bb; end; inc(px); inc(al); end; end; end; end; {!! TIEBitmap.AlphaChannel Declaration property AlphaChannel: ; Description TIEBitmap handles the alpha channel as an encapsulated TIEBitmap object with pixelformat of ie8g. This property returns the associated AlphaChannel. If an image doesn't have an alpha channel, you can create it just using AlphaChannel property. To determine whether an image has an alpha channel, examine the property. Example // Assign an alpha channel to an image using a source file // For simple transparency, use a monochrome bitmap where the black pixels will become transparent // Otherwise, a 256 color gray-scale image can provide a range of tranparency values (from white/fully opaque to black/fully transparent) aBMP := TIEBitmap.create( 'D:\alpha.bmp' ); // Use our bitmap as the alpha channel ImageEnView1.IEBitmap.AlphaChannel.Assign( aBMP ); // Ensure size of alpha channel matches size of image (and is ie8g) ImageEnView1.IEBitmap.SyncAlphaChannel(); // Update the container ImageEnView1.Update; aBMP.free; Source Image: Image to use for Alpha (Black will be come transparent, gray will be 50% transparent and white will be fully opaque): Result (on a white TImageEnView): See Also - - - !!} function TIEBitmap.GetAlphaChannel: TIEBitmap; begin if (not fIsAlpha) and (not assigned(fAlphaChannel)) then // we need to create alpha channel fAlphaChannel := TIEBitmap.CreateAsAlphaChannel(fWidth, fHeight, fLocation); result := fAlphaChannel; end; {!! TIEBitmap.AlphaChannelOpt Declaration property AlphaChannelOpt: ; Description Returns the alpha channel if present, otherwise returns nil. See also: . !!} function TIEBitmap.GetAlphaChannelOpt: TIEBitmap; begin result := fAlphaChannel; end; {!! TIEBitmap.HasAlphaChannel Declaration property HasAlphaChannel: boolean; Description Specifies whether the current image has an alpha channel. !!} // used by HasAlphaChannel function TIEBitmap.GetHasAlphaChannel: boolean; begin result := assigned(fAlphaChannel); end; {!! TIEBitmap.ReplaceAlphaChannel Declaration procedure ReplaceAlphaChannel(Value: ); Description Destroy the current alpha channel (if it exists) and set a new one. Note: The new alpha channel will be freed automatically on destroy. See Also - - - !!} procedure TIEBitmap.ReplaceAlphaChannel(Value: TIEBitmap); begin if Value <> fAlphaChannel then begin FreeAndNil(fAlphaChannel); fAlphaChannel := Value; fAlphaChannel.fIsAlpha := true; Changed(); end; end; {!! TIEBitmap.DetachAlphaChannel Declaration procedure DetachAlphaChannel(CreateIfNotExists: Boolean = false); Description Detach the current alpha channel (if it exists) and return it. Note: It is the responsibility of application to free it. Parameter Description CreateIfNotExists Creates an alpha channel if the image hasn't one.
See Also -
- !!} function TIEBitmap.DetachAlphaChannel(CreateIfNotExists: Boolean): TIEBitmap; begin if CreateIfNotExists then result := GetAlphaChannel() else result := fAlphaChannel; if result <> nil then begin fAlphaChannel := nil; Changed(); end; end; {!! TIEBitmap.SyncAlphaChannel Declaration procedure SyncAlphaChannel(AntiAlias: Boolean = True); Description If you have manually loaded or set the , calling this method will ensure it matches the size of the image and has a pixelformat of ie8g (alpha channels with invalid sizes or color depths will not display). AntiAlias specifies that a Bicubic filter is used if the alpha channel needs to be stretched (which will create a range of transparency values). Set to false to ensure an alpha channel with only 0 and 255 values (i.e. full alpha or full opaque pixels) will not have semi-transparent pixels. Example // Assign an alpha channel to an image using a source file // For simple transparency, use a monochrome bitmap where the black pixels will become transparent // Otherwise, a 256 color gray-scale image can provide a range of tranparency values (from white/fully opaque to black/fully transparent) aBMP := TIEBitmap.create( 'D:\alpha.bmp' ); // Use our bitmap as the alpha channel ImageEnView1.IEBitmap.AlphaChannel.Assign( aBMP ); // Ensure size of alpha channel matches size of image (and is ie8g) ImageEnView1.IEBitmap.SyncAlphaChannel(); // Update the container ImageEnView1.Update; aBMP.free; Source Image: Image to use for Alpha (Black will be come transparent, gray will be 50% transparent and white will be fully opaque): Result (on a white TImageEnView): See Also - - - !!} procedure TIEBitmap.SyncAlphaChannel(AntiAlias: Boolean = True); begin if not assigned( fAlphaChannel ) then begin // Just create it GetAlphaChannel(); end else begin // Create it GetAlphaChannel(); fAlphaChannel.PixelFormat := ie8g; if AntiAlias then fAlphaChannel.Resample( fWidth, fHeight, rfBicubic ) else fAlphaChannel.Resample( fWidth, fHeight, rfNone ); SyncFull; end; end; {!! TIEBitmap.Destroy Declaration destructor Destroy; Description Destroys the TIEBitmap object. !!} destructor TIEBitmap.Destroy; begin ReleaseROI(); FreeAndNil(fIECanvas); FreeImage(true); FreeAndNil(fmemmap); FreeAndNil(fScanlinesToUnMapPtr); FreeAndNil(fScanlinesToUnMapRow); FreeAndNil(fVirtualBitmapProvider); FreeAndNil(fColorProfile); FreeAndNil(fRenderColorProfile); FreeAndNil(fAdjustmentsMask); FreeAndNil(fSavedBitmaps); FreeAndNil( fIOParams ); inherited; end; {!! TIEBitmap.SwitchTo Declaration procedure SwitchTo(Target: ); Description Assigns the current image to the target object. The source object will be empty. Executes more quickly than a copy operation because the image is transferred rather than copied. In detail, it assigns all fields to Target, and set to zero all parameters (do not free the image or allocated memory). !!} // set fEncapsulatedFromTBitmap to false // set fEncapsulatedFromMemory to false // note: fIsAlpha is not reset! (otherwise this could be not recognized as AlphaChannel) // warn: fSavedBitmaps must be NOT switched! procedure TIEBitmap.SwitchTo(Target: TIEBitmap); begin Target.FreeImage(true); Target.fWidth := fWidth; Target.fHeight := fHeight; Target.fBitCount := fBitCount; Target.fChannelCount := fChannelCount; Target.fWorkingMap := fWorkingMap; Target.fRowLen := fRowLen; Target.fPixelFormat := fPixelFormat; Target.fRGBPalette := fRGBPalette; Target.fRGBPaletteLen := fRGBPaletteLen; Target.fPaletteUsed := fPaletteUsed; Target.fAlphaChannel := fAlphaChannel; Target.fIsAlpha := fIsAlpha; Target.fMemory := fMemory; Target.fRealMemory := fRealMemory; Target.fBitmap := fBitmap; Target.fLocation := fLocation; Target.fFull := fFull; Target.fEncapsulatedFromTBitmap := fEncapsulatedFromTBitmap; Target.fEncapsulatedFromMemory := fEncapsulatedFromMemory; Target.fBitmapScanlines := fBitmapScanlines; Target.fFragmentsCount := fFragmentsCount; Target.fFragments := fFragments; Target.fRowsPerFragment := fRowsPerFragment; Target.fOrigin := fOrigin; FreeAndNil(Target.fmemmap); Target.fmemmap := fmemmap; FreeAndNil(Target.fScanlinesToUnMapPtr); FreeAndNil(Target.fScanlinesToUnMapRow); Target.fScanlinesToUnMapPtr := fScanlinesToUnMapPtr; Target.fScanlinesToUnMapRow := fScanlinesToUnMapRow; Target.fDefaultDitherMethod := fDefaultDitherMethod; Target.fBitAlignment := fBitAlignment; Target.fMemoryAllocator := fMemoryAllocator; Target.fOnRenderVirtualPixel := fOnRenderVirtualPixel; Target.fVirtualBitmapProvider := fVirtualBitmapProvider; Target.fIECanvas := fIECanvas; // Target.fIECanvas is always nil after Target.FreeImage() Target.fColorProfile.Assign(fColorProfile); Target.fOnChanged := fOnChanged; Target.fModified := fModified; // warning! this doesn't reset fIsAlpha!! fWidth := 0; fHeight := 0; fBitCount := 0; fChannelCount := 0; fWorkingMap := nil; fRowLen := 0; fPixelFormat := ienull; fRGBPalette := nil; fRGBPaletteLen := 0; fAlphaChannel := nil; fMemory := nil; fRealMemory := nil; fBitmap := nil; fBitmapScanlines := nil; fScanlinesToUnMapPtr := TList.Create; fScanlinesToUnMapRow := TList.Create; fFull := false; fFullReallocate := true; fEncapsulatedFromTBitmap := false; fEncapsulatedFromMemory := false; fmemmap := TIEFileBuffer.Create; fFragmentsCount := 0; fFragments := nil; fRowsPerFragment := 0; fOrigin := ieboBOTTOMLEFT; fOnRenderVirtualPixel := nil; fVirtualBitmapProvider := nil; fIECanvas := nil; fOnChanged := nil; fColorProfile.Clear(); end; {!! TIEBitmap.SaveState Declaration procedure SaveState(); Description Pushes the current TIEBitmap state onto the states stack so it can be restored later calling . Note: When TImageEnView.LegacyBitmap = True, applications should block TImageEnView updates between calls to SaveState() and RestoreState(), calling TImageEnView.LockUpdate() and TImageEnView.UnLockUpdate(). Example // merges alpha channel to save image as BMP, and restore it ImageEnView1.IO.LoadFromFile('input.png'); ImageEnView1.LockUpdate(); ImageEnView1.IEBitmap.SaveState(); ImageEnView1.RemoveAlphaChannel(true); ImageEnView1.IO.SaveToFile('output.bmp'); ImageEnView1.IEBitmap.RestoreState(); ImageEnView1.UnLockUpdate(); // as above with LegacyBitmap = False ImageEnView1.LegacyBitmap := false; ImageEnView1.IO.LoadFromFile('input.png'); ImageEnView1.IEBitmap.SaveState(); ImageEnView1.RemoveAlphaChannel(true); ImageEnView1.IO.SaveToFile('output.bmp'); ImageEnView1.IEBitmap.RestoreState(); !!} procedure TIEBitmap.SaveState(); var bmp: TIEBitmap; begin if fSavedBitmaps = nil then fSavedBitmaps := TObjectList.Create(); bmp := TIEBitmap.Create(); SwitchTo(bmp); Assign(bmp); // this objects now contains a copy of the saved one fSavedBitmaps.Add(bmp); end; {!! TIEBitmap.RestoreState Declaration procedure RestoreState(); Description Pops the top state on the states stack, restoring the TIEBitmap to that state. See . Example // merges alpha channel to save image as BMP, and restore it ImageEnView1.IO.LoadFromFile('input.png'); ImageEnView1.LockUpdate(); ImageEnView1.IEBitmap.SaveState(); ImageEnView1.RemoveAlphaChannel(true); ImageEnView1.IO.SaveToFile('output.bmp'); ImageEnView1.IEBitmap.RestoreState(); ImageEnView1.UnLockUpdate(); // as above with LegacyBitmap = False ImageEnView1.LegacyBitmap := false; ImageEnView1.IO.LoadFromFile('input.png'); ImageEnView1.IEBitmap.SaveState(); ImageEnView1.RemoveAlphaChannel(true); ImageEnView1.IO.SaveToFile('output.bmp'); ImageEnView1.IEBitmap.RestoreState(); Pops the top state on the stack, restoring the context to that state. !!} procedure TIEBitmap.RestoreState(); begin if assigned(fSavedBitmaps) and (fSavedBitmaps.Count > 0) then begin (TObject(fSavedBitmaps.Last()) as TIEBitmap).SwitchTo(self); fSavedBitmaps.Remove(fSavedBitmaps.Last()); end; end; // free bitmap scanlines procedure TIEBitmap.FreeBitmapScanlines; begin SetLength(fBitmapScanlines, 0); end; // free and build bitmap scanlines procedure TIEBitmap.BuildBitmapScanlines; var i: integer; begin FreeBitmapScanlines; if assigned(fBitmap) then begin SetLength(fBitmapScanlines, fHeight); for i := 0 to fHeight - 1 do fBitmapScanlines[i] := fBitmap.Scanline[i]; end; end; {!! TIEBitmap.BitAlignment Declaration property BitAlignment: integer; Description Specifies the number of bits of alignment (32 is the default). This works only when is ieMemory. !!} procedure TIEBitmap.SetBitAlignment(value: integer); var old: TIEBitmap; row, mi: integer; begin if value <> fBitAlignment then begin if IsVirtual then fBitAlignment := value else begin fFullReallocate := true; if (fLocation = ieMemory) then begin old := TIEBitmap.Create; SwitchTo(old); fBitAlignment := value; Allocate(old.Width, old.fHeight, old.fPixelFormat); mi := imin(fRowLen, old.fRowLen); for row := 0 to fHeight - 1 do CopyMemory(ScanLine[row], old.ScanLine[row], mi); // copy palette old.CopyPaletteTo(self); // copy alpha (already sized in "resize alpha") if old.HasAlphaChannel then AlphaChannel.Assign(old.AlphaChannel); FreeAndNil(old); end; end; Changed(); end; end; // resize also alpha channel procedure TIEBitmap.SetWidth(Value: integer); var old: TIEBitmap; row, mi, mih: integer; tmpbmp: TBitmap; begin if Value <> fWidth then begin // resize alpha if HasAlphaChannel then AlphaChannel.Width := Value; if IsVirtual then fWidth := Value else begin // resize image case fLocation of ieMemory, ieFile: begin if (fPixelFormat <> ienull) and (fHeight > 0) then begin old := TIEBitmap.Create; SwitchTo(old); Allocate(Value, old.fHeight, old.fPixelFormat); if old.fPixelFormat <> ienull then begin mi := imin(fRowLen, old.fRowLen); mih := imin(fHeight, old.fHeight); for row := 0 to mih - 1 do CopyMemory(ScanLine[row], old.ScanLine[row], mi); end; // copy alpha (already sized in "resize alpha") if old.HasAlphaChannel then AlphaChannel.Assign(old.AlphaChannel); FreeAndNil(old); fFull := false; end else fWidth := Value; end; ieTBitmap: begin if fBitmap = nil then fBitmap := TBitmap.Create; if (fBitmap.PixelFormat = pf1bit) and (IEGlobalSettings().SystemColors > 16) then begin // we need this because sometime just set fBitmap.Width := xx doesn't work tmpbmp := TBitmap.Create; IECopyBitmap(fBitmap, tmpbmp); fBitmap.Width := Value; fbitmap.HandleType := bmDDB; fBitmap.Canvas.Draw(0, 0, tmpbmp); fbitmap.HandleType := bmDIB; FreeAndNil(tmpbmp); end else fBitmap.Width := Value; fWidth := fBitmap.Width; fRowLen := IEBitmapRowLen(fWidth, fBitCount, fBitAlignment); BuildBitmapScanlines; // no need to copy alpha end; end; end; // end case Changed(); end; end; // resize also alpha channel procedure TIEBitmap.SetHeight(Value: integer); var old: TIEBitmap; row, mi, miw: integer; tmpbmp: TBitmap; begin if Value <> fHeight then begin // resize alpha if HasAlphaChannel then AlphaChannel.Height := Value; if IsVirtual then fHeight := Value else begin case fLocation of ieMemory, ieFile: begin if (fPixelFormat <> ienull) and (fWidth > 0) then begin old := TIEBitmap.Create; SwitchTo(old); Allocate(old.fWidth, Value, old.fPixelFormat); if old.fPixelFormat <> ienull then begin mi := imin(fHeight, old.fHeight); miw := imin(fRowLen, old.fRowLen); for row := 0 to mi - 1 do CopyMemory(ScanLine[row], old.ScanLine[row], miw); end; // copy alpha (already sized in "resize alpha") if old.HasAlphaChannel then AlphaChannel.Assign(old.AlphaChannel); FreeAndNil(old); fFull := false; end else fHeight := Value; end; ieTBitmap: begin if fBitmap = nil then fBitmap := TBitmap.Create; if (fBitmap.PixelFormat = pf1bit) and (IEGlobalSettings().SystemColors > 16) then begin // we need this because sometime just set fBitmap.Height := xx doesn't work tmpbmp := TBitmap.Create; IECopyBitmap(fBitmap, tmpbmp); fBitmap.Height := Value; if IEGlobalSettings().SystemColors <> 16 then fbitmap.HandleType := bmDDB; fBitmap.Canvas.Draw(0, 0, tmpbmp); fbitmap.HandleType := bmDIB; FreeAndNil(tmpbmp); end else fBitmap.Height := Value; fHeight := fBitmap.Height; BuildBitmapScanlines; // no need to copy alpha end; end; // end case end; Changed(); end; end; // works only on enlarging bitmap procedure DoAlignAfter(Bitmap: TIEBitmap; OldWidth, OldHeight: integer; bk: double; HorizAlign: TIEHAlign; VertAlign: TIEVAlign); begin if Bitmap.Width > OldWidth then begin Bitmap.FillRect(OldWidth, 0, Bitmap.Width - 1, Bitmap.Height - 1, bk); case HorizAlign of iehLeft: ; // do nothing, already aligned iehCenter: Bitmap.MoveRegion(0, 0, OldWidth - 1, OldHeight - 1, ((Bitmap.Width - OldWidth) div 2), 0, bk); iehRight: Bitmap.MoveRegion(0, 0, OldWidth - 1, OldHeight - 1, Bitmap.Width - OldWidth, 0, bk); end; end; if Bitmap.Height > OldHeight then begin Bitmap.FillRect(0, OldHeight, Bitmap.Width - 1, Bitmap.Height - 1, bk); case VertAlign of ievTop: ; // do nothing, already aligned ievCenter: Bitmap.MoveRegion(0, 0, Bitmap.Width - 1, OldHeight - 1, 0, ((Bitmap.Height - OldHeight) div 2), bk); ievBottom: Bitmap.MoveRegion(0, 0, Bitmap.Width - 1, OldHeight - 1, 0, Bitmap.Height - OldHeight, bk); end; end; end; // works only on reducing bitmap procedure DoAlignBefore(Bitmap: TIEBitmap; NewWidth, NewHeight: integer; bk: double; HorizAlign: TIEHAlign; VertAlign: TIEVAlign); var cx, cy: integer; begin if Bitmap.Width > NewWidth then begin cx := (Bitmap.Width - NewWidth) div 2; case HorizAlign of iehLeft: ; // do nothing, already aligned iehCenter: Bitmap.MoveRegion(cx, 0, cx + NewWidth - 1, Bitmap.Height - 1, 0, 0, bk); iehRight: Bitmap.MoveRegion(Bitmap.Width - NewWidth, 0, Bitmap.Width - 1, Bitmap.Height - 1, 0, 0, bk); end; end; if Bitmap.Height > NewHeight then begin cy := (Bitmap.Height - NewHeight) div 2; case VertAlign of ievTop: ; // do nothing, already aligned ievCenter: Bitmap.MoveRegion(0, cy, Bitmap.Width - 1, cy + NewHeight - 1, 0, 0, bk); ievBottom: Bitmap.MoveRegion(0, Bitmap.Height - NewHeight, Bitmap.Width - 1, Bitmap.height - 1, 0, 0, bk); end; end; end; {!! TIEBitmap.Resize Declaration procedure Resize(NewWidth, NewHeight: integer; BackgroundValue: double = 0; FillAlpha: integer = 255; HorizAlign: = iehLeft; VertAlign: TIEVAlign = ); overload procedure Resize(AddLeft, AddTop, AddRight, AddBottom: integer; BackgroundValue: double = 0; FillAlpha: integer = 255); overload; Description Resize the image without resampling (i.e. the image content is not stretched). This method also resizes the alpha channel. Overload 1: Parameter Description NewWidth New image width NewHeight New image height BackgroundValue TColor value for ie24RGB images or a gray level for gray scale or black/white images. It is used to fill added regions AlphaValue Alpha value used to fill added regions (0: Fully Transparent - 255: Opaque) HorizAlign Specifies how to horizontally align the old image (has no effect unless the new width is greater than the old width) VertAlign Specifies how to vertically align the old image (has no effect unless the new height is greater than the old height)
Overload 2: Parameter Description AddLeft Pixels to add to the left of the image (or remove if AddLeft < 0) AddTop Pixels to add to the top of the image (or remove if AddTop < 0) AddRight Pixels to add to the right of the image (or remove if AddRight < 0) AddBottom Pixels to add to the bottom of the image (or remove if AddBottom < 0) BackgroundValue TColor value for ie24RGB images or a gray level for gray scale or black/white images. It is used to fill added regions AlphaValue Alpha value used to fill added regions (0: Fully Transparent - 255: Opaque)
Examples // resize image to 1000x1000 MyIEBitmap.Resize( 1000, 1000 ); // make a contour around the image MyIEBitmap.Resize( MyIEBitmap.Width + 80, MyIEBitmap.Height + 80, clBlack, 255, iehCenter, ievCenter ); // which is the same as: MyIEBitmap.Resize( 80, 80, 80, 80, clBlack, 255 ); // Add 50 pixels to the top and bottom of the image, remove 80 pixels from the left and right MyIEBitmap.Resize( -80, 50, -80, 50, 255 ); !!} // HorizAlign acts only when NewWidth>Width // VertAlign acts only when NewHeight>Height // AlphaValue is valid only when HasAlphaChannel is true and this is not an alpha channel procedure TIEBitmap.Resize(NewWidth, NewHeight: integer; BackgroundValue: double = 0; FillAlpha: integer = 255; HorizAlign: TIEHAlign = iehLeft; VertAlign: TIEVAlign = ievTop); var lw, lh: integer; begin if IsVirtual then begin SetWidth(NewWidth); SetHeight(NewHeight); end else begin lw := Width; lh := Height; DoAlignBefore(self, NewWidth, NewHeight, BackgroundValue, HorizAlign, VertAlign); if HasAlphaChannel then DoAlignBefore(AlphaChannel, NewWidth, NewHeight, FillAlpha, HorizAlign, VertAlign); SetWidth(NewWidth); SetHeight(NewHeight); DoAlignAfter(self, lw, lh, BackgroundValue, HorizAlign, VertAlign); if HasAlphaChannel then DoAlignAfter(AlphaChannel, lw, lh, FillAlpha, HorizAlign, VertAlign); end; end; procedure TIEBitmap.Resize(AddLeft, AddTop, AddRight, AddBottom: integer; BackgroundValue: double; FillAlpha: integer = 255); var newWidth, newHeight: integer; begin // if first call clears entire bitmap, then just blank and resize if ( -1 * AddLeft >= Width ) or ( -1 * AddTop >= Height ) then begin newWidth := Width + AddLeft + AddRight; newHeight := Height + AddTop + AddBottom; Clear; Resize( newWidth, newHeight, BackgroundValue, FillAlpha ); end else begin if ( AddLeft <> 0 ) or ( AddTop <> 0 ) then Resize( Width + AddLeft, Height + AddTop, BackgroundValue, FillAlpha, iehRight, ievBottom ); if ( AddRight <> 0 ) or ( AddBottom <> 0 ) then Resize( Width + AddRight, Height + AddBottom, BackgroundValue, FillAlpha, iehLeft, ievTop ); end; end; {!! TIEBitmap.Flip Declaration procedure Flip(Dir:
); Description Flips (mirrors) the current image across the horizontal or vertical axis. Examples ABitmap.Flip(fdHorizontal); ABitmap.Flip(fdVertical); See Also - !!} procedure TIEBitmap.Flip(Dir: TFlipDir); begin _FlipEx(Self, Dir); Changed(); end; {!! TIEBitmap.Rotate Declaration procedure Rotate(Angle: double; AntialiasMode: = ierFast; BackgroundColor: TColor = clWhite); Description Rotates the current image by the specified angle (negative or positive degrees counter-clockwise). AntialiasMode specifies the anti-aliasing algorithm that is used to improve rotation quality: ierNone : No anti-aliasing (lowest quality) ierFast : Fast but lower quality ierBilinear : Bilinear, high quality ierBicubic : Bicubic, highest quality BackgroundColor specifies a background color to fill new regions (i.e. when not rotating at a 90 degree angle) Examples // Rotate the image 45° clockwise at highest quality with a white background color ABitmap.Rotate(315, ierBicubic, clWhite); // Rotate the image 90° clockwise (Note: AntialiasMode is irrelevant for 90 deg. rotates) ABitmap.Rotate(270); // Rotate the image 180° clockwise ABitmap.Rotate(180); // Rotate the image 90° counter-clockwise; ABitmap.Rotate(90); See Also - - !!} procedure TIEBitmap.Rotate(Angle: double; AntialiasMode: TIEAntialiasMode = ierFast; BackgroundColor: TColor = clWhite); begin RotateEx(Angle, AntialiasMode, BackgroundColor, nil, nil); end; {$ifdef IEIncludeDeprecatedInV4} // Deprecated in 5.0.0 procedure TIEBitmap.Rotate(Angle: double; AntiAlias: boolean; AntialiasMode: TIEAntialiasMode; BackgroundColor: TColor); begin if AntiAlias then RotateEx(Angle, AntialiasMode, BackgroundColor, nil, nil) else RotateEx(Angle, ierNone, BackgroundColor, nil, nil); end; {$endif} procedure TIEBitmap.RotateEx(Angle: double; AntiAliasMode: TIEAntialiasMode; BackgroundColor: TColor; OnProgress: TIEProgressEvent; Sender: TObject); var alpha: TIEBitmap; bRectAngle: Boolean; begin if HasAlphaChannel then begin alpha := TIEBitmap.Create; alpha.Assign(AlphaChannel); end else alpha := nil; if (AntialiasMode <> ierNone) and ((PixelFormat = ie24RGB) or (PixelFormat = ie1g)) then begin // Is angle 90, 180, 270, 360? bRectAngle := (trunc(angle) = Angle) and ((trunc(Angle) mod 90) = 0); // SHEAR if (AntialiasMode = ierFast) or bRectAngle or (PixelFormat <> ie24RGB) then begin // rotate alpha channel if assigned(alpha) then begin if PixelFormat = ie1g then // if the image is black/white we haven't to apply a filter to the alpha channel (so have better result) _rotate8bit(alpha, Angle, 0) else // we need to rotate alpha using a filter, because the image is colored _RotateEx8(alpha, Angle, True, 0, OnProgress, Sender); end; // rotate image _RotateEx(Self, Angle, True, TColor2TRGB(BackgroundColor), OnProgress, Sender); end else begin // rotate alpha channel if assigned(alpha) then IEQRotate8(alpha, Angle, 0, AntialiasMode); // rotate image IEQRotate(Self, Angle, BackgroundColor, AntialiasMode, OnProgress, Sender); end; end else begin // SINCOS if assigned(alpha) then IEGRotate(alpha, Angle, 0, nil, nil); IEGRotate(Self, Angle, BackgroundColor, OnProgress, Sender); end; if assigned(alpha) then begin AlphaChannel.Assign(alpha); FreeAndNil(alpha); end; Changed(); end; {!! TIEBitmap.Resample Declaration procedure Resample(NewWidth, NewHeight: integer; FilterType: = rfNone; bMaintainAspectRatio : Boolean = False); overload; procedure Resample(ScaleBy: Double; FilterType: TResampleFilter = rfNone); overload; Description Resizes the current image. The content of the image changes (stretched to the new size). Parameter Description NewWidth New image width in pixels. If NewWidth is -1 then it is calculated automatically, respecting the proportions. NewHeight New image height in pixels. If NewHeight is -1 then it is calculated automatically, respecting the proportions. FilterType Resampling interpolation algorithm. bMaintainAspectRatio Automatically reduces NewWidth or NewHeight to ensure the original proportions of the image are maintained
Examples ABitmap.Resample( 50, -1, rfNone ); // Resizes the image to width of 50 (with height automatically set) without any smoothing algorithm ABitmap.Resample( -1, 100, rfLanczos3 ); // Resizes the image to height of 100 (with width automatically calculated) and high quality smoothing ABitmap.Resample( 100, 100, rfLanczos3, True ); // Resizes the image so that it is no higher or wider than 100, but maintains the original aspect ratio (e.g. a 4:3 portrait image would have the new dimensions 100 x 75) ABitmap.Resample( 0.5, rfFastLinear ); // Resizes the image to half its current size with fast, but good quality smoothing !!} procedure TIEBitmap.Resample(NewWidth, NewHeight: integer; FilterType: TResampleFilter = rfNone; bMaintainAspectRatio : Boolean = False); begin if IsEmpty or ((NewWidth = Width) and (NewHeight = Height)) then exit; _IEAdjustResampleDimensions(NewWidth, NewHeight, Width, Height, bMaintainAspectRatio); _IEResampleIEBitmap2(Self, FilterType, NewWidth, NewHeight, nil, nil); Changed(); end; procedure TIEBitmap.Resample(ScaleBy: Double; FilterType: TResampleFilter = rfNone); begin if IsEmpty or ( ScaleBy = 0 ) then exit; Resample( Round( Width * ScaleBy ), Round( Height * ScaleBy ), FilterType, False ); end; {!! TIEBitmap.Crop Declaration procedure Crop(x1, y1, x2, y2 : Integer); procedure Crop(Rect : TRect); Description Replace the current image with that within the specified rectangle (i.e. keep only the specified region). Examples // Crop the image at position, Top-Left: (20, 20), Bottom-right: (100, 100). The resulting image will be 80 x 80 pixels IEBmp.Crop( 20, 20, 100, 100 ); See Also -
- - - !!} procedure TIEBitmap.Crop(x1, y1, x2, y2: Integer); var tmpImage: TIEBitmap; w, h: Integer; begin if (x1 = 0) and (y1 = 0) and (x2 = Width-1) and (y2 = Height-1) then exit; if ( x2 < x1 ) or ( y2 < y1 ) then exit; w := x2 - x1 + 1; h := y2 - y1 + 1; tmpImage := TIEBitmap.Create(); tmpImage.Allocate(w, h, PixelFormat); try CopyRectTo(tmpImage, x1, y1, 0, 0, w, h, false); if PixelFormat = ie8p then CopyPaletteTo(tmpImage); AssignImage(tmpImage); if HasAlphaChannel then begin // suppose AssignImage has not changed AlphaChannel size AlphaChannel.CopyRectTo(tmpImage.AlphaChannel, x1, y1, 0, 0, w, h, false); AlphaChannel.AssignImage(tmpImage.AlphaChannel); end; finally FreeAndNil(tmpImage); end; end; procedure TIEBitmap.Crop(Rect: TRect); begin Crop(Rect.Left, Rect.Top, Rect.Right, Rect.Bottom); end; {!! TIEBitmap.CropAlpha Declaration function CropAlpha(): Boolean; Description Removes any transparent area on the edge of the image, resizing the resulting image to the visible rectangle. Result is true if the image was cropped (i.e. alpha was removed). Example IEBitmap.CropAlpha(); See Also - - !!} function TIEBitmap.CropAlpha(): Boolean; var r: TRect; begin Result := False; r := IEGetVisibleArea( Self, nil, nil ); if ( r.Right >= 0 ) and ( r.Bottom >= 0 ) then begin Crop( r ); Result := True; end; end; {!! TIEBitmap.MoveRegion Declaration procedure MoveRegion(x1, y1, x2, y2, DstX, DstY: integer; BackgroundValue: double; FillSource: boolean = true); Description Moves a rectangle specified in x1, y1, x2, y2 to DstX, DstY position. The BackgroundValue parameter specifies the color that fills the source rectangle. If FillSource is true (default) then the source rectangle is filled with BackgroundValue. MoveRegion doesn't copy the alpha channel. !!} procedure TIEBitmap.MoveRegion(x1, y1, x2, y2, DstX, DstY: integer; BackgroundValue: double; FillSource: boolean); var tmp: TIEBitmap; begin tmp := TIEBitmap.Create; tmp.Allocate(x2 - x1 + 1, y2 - y1 + 1, PixelFormat); CopyRectTo(tmp, x1, y1, 0, 0, tmp.Width, tmp.Height, false); if FillSource then FillRect(x1, y1, x2, y2, BackgroundValue); tmp.CopyRectTo(self, 0, 0, DstX, DstY, tmp.Width, tmp.Height, false); FreeAndNil(tmp); end; procedure TIEBitmap.SetPixelFormat(Value: TIEPixelFormat); begin if Value <> fPixelFormat then begin if IsVirtual then fPixelFormat := Value else ConvertToPixelFormat(Value); end; end; function TIEBitmap.CheckFormat(AllowedFormats: TIEPixelFormatSet; AutoConvert: boolean): boolean; const MAXDEST = 6; TConvSource: array [TIEPixelFormat] of array [0..MAXDEST] of TIEPixelFormat = ( (ienull, ienull, ienull, ienull, ienull, ienull, ienull), // ienull (ie8g, ie16g, ie32f, ie24RGB, ienull, ienull, ienull), // ie1g (ie24RGB, ieCMYK, ie48RGB, ieCIELab, ienull, ienull, ienull), // ie8p (ie16g, ie32f, ie24RGB, ieCMYK, ie48RGB, ienull, ienull), // ie8g (ie32f, ie8g, ie48RGB, ie24RGB, ieCMYK, ienull, ienull), // ie16g (ieCMYK, ieCIELab, ie48RGB, ie8p, ie16g, ie8g, ienull), // ie24RGB (ie16g, ie8g, ie24RGB, ie48RGB, ieCIELab, ienull, ienull), // ie32f (ie24RGB, ie48RGB, ieCIELab, ie8g, ienull, ienull, ienull), // ieCMYK (ie24RGB, ieCMYK, ieCIELab, ie16g, ienull, ienull, ienull), // ie48RGB (ie24RGB, ieCMYK, ie48RGB, ie8g, ienull, ienull, ienull), // ieCIELab (ie24RGB, ieCMYK, ie48RGB, ie8g, ienull, ienull, ienull) // ie32RGB ); var i: integer; l: TIEPixelFormat; begin result := (AllowedFormats = []) or (PixelFormat in AllowedFormats); if not result and AutoConvert then begin // convert to one allowed format // try according to TConvSource table for i := 0 to MAXDEST do begin l := TConvSource[PixelFormat, i]; if l in AllowedFormats then begin PixelFormat := l; result := true; break; end; end; // try the first format available if l = ienull then begin for l := high(TIEPixelFormat) downto low(TIEPixelFormat) do if l in AllowedFormats then begin PixelFormat := l; result := true; break; end; end; end; end; procedure TIEBitmap.FreeAllMaps; begin if fWorkingMap <> nil then fmemmap.UnMap(fWorkingMap); while fScanlinesToUnMapPtr.Count > 0 do begin fmemmap.UnMap(fScanlinesToUnMapPtr[fScanlinesToUnMapPtr.Count - 1]); fScanlinesToUnMapPtr.Delete(fScanlinesToUnMapPtr.Count - 1); end; fScanlinesToUnMapRow.Clear; fWorkingMap := nil; end; {!! TIEBitmap.FreeImage Declaration procedure FreeImage(freeAlpha: boolean = true); Description Destroys the image and frees memory. !!} // set fEncapsulatedFromTBitmap to false // set fEncapsulatedFromMemory to false procedure TIEBitmap.FreeImage(freeAlpha: boolean); begin if freeAlpha and assigned(fAlphaChannel) then FreeAndNil(fAlphaChannel); if fRGBPalette <> nil then freemem(fRGBPalette); FreeAllMaps; fmemmap.DeAllocate; if (not fEncapsulatedFromMemory) and (fMemory <> nil) and (fRealMemory<>nil) then begin case fMemoryAllocator of iemaVCL: freemem(fRealMemory); iemaSystem: IESystemFree(fRealMemory); iemaAuto: IEAutoFree(fRealMemory); end; end; FreeAndNil(fIECanvas); if (not fEncapsulatedFromTBitmap) and (fBitmap <> nil) then FreeAndNil(fBitmap); FreeBitmapScanlines; // this sets fBitmapScanlines := nil FreeFragments(); fMemory := nil; fRealMemory := nil; fBitmap := nil; fRGBPalette := nil; fRGBPaletteLen := 0; fWidth := 0; fHeight := 0; fRowlen := 0; fBitCount := 0; fChannelCount := 0; fFull := false; fEncapsulatedFromTBitmap := false; fEncapsulatedFromMemory := false; if fVirtualBitmapRowBuffer <> nil then begin freemem(fVirtualBitmapRowBuffer); fVirtualBitmapRowBuffer := nil; end; fColorProfile.Clear(); end; {!! TIEBitmap.Clear Declaration procedure Clear; Description Sets the image width and height to zero. !!} procedure TIEBitmap.Clear; begin Width := 0; Height := 0; end; {!! TIEBitmap.IsEmpty Declaration function IsEmpty: boolean; Description Returns true if the bitmap is empty (width=0, height=0, etc...). !!} function TIEBitmap.IsEmpty: boolean; begin result := (fWidth = 0) or (fHeight = 0) or (fRowLen = 0) or (fBitCount = 0); end; // before call AllocateImage make sure to call FreeImage // returns false on fail function TIEBitmap.AllocateImage: boolean; const UNSUPMSG = 'pixel format not allowed when Location=ieTBitmap Please set TImageEnView.LegacyBitmap=false.'; var ms: int64; begin result := false; if (fWidth > 0) and (fHeight > 0) and (fPixelFormat <> ienull) then begin FreeAndNil(fIECanvas); if fPixelFormat = ie8p then begin getmem(fRGBPalette, sizeof(TRGB) * 256); if fRGBPalette = nil then exit; // FAIL! fRGBPaletteLen := 256; end; fBitCount := IEPixelFormat2BitCount(fPixelFormat); fChannelCount := IEPixelFormat2ChannelCount(fPixelFormat); fRowLen := IEBitmapRowLen(fWidth, fBitCount, fBitAlignment); if not IsVirtual then begin ms := fRowLen * int64(fHeight); if (fLocation = ieFile) and (ms <= fMinFileSize) then fLocation := ieMemory; if (fLocation = ieMemory) and (ms > fMinFileSize) then fLocation := ieFile; if fLocation = ieFile then begin // use file memory if not fmemmap.AllocateFile(ms, 'IMG', true) then fLocation := ieMemory; end; if fLocation = ieMemory then begin // use memory AllocateMemory(ms, fRealMemory, fMemory); if fRealMemory=nil then begin FragmentedAlloc(); if fFragments = nil then begin // failed to allocate memory if not IEGlobalSettings().AutoLocateOnDisk then exit; // use file fLocation := ieFile; if not fmemmap.AllocateFile(ms, 'IMG', true) then exit; end; end; end; if fLocation = ieTBitmap then begin // use VCL TBitmap if int64(fHeight) * fRowlen > IEGetMemory(false) then exit; if not fEncapsulatedFromTBitmap then fBitmap := TBitmap.Create; try {$ifdef Delphi7orNewer} fBitmap.Width := 1; fBitmap.Height := 1; fBitmap.PixelFormat := pfDevice; // needed, otherwise when switch to pe1bit the bitmap could not work well (!) {$endif} case fPixelFormat of ie1g: fBitmap.PixelFormat := pf1bit; ie8p: fBitmap.PixelFormat := pf8bit; ie8g: fBitmap.PixelFormat := pf8bit; ie16g: // ie16g in TBitmap converted to ie8g begin fBitmap.PixelFormat := pf8bit; fPixelFormat := ie8g; fBitCount := IEPixelFormat2BitCount(fPixelFormat); fChannelCount := IEPixelFormat2ChannelCount(fPixelFormat); fRowLen := IEBitmapRowLen(fWidth, fBitCount, fBitAlignment); end; ie32f: // ie32f not supported when Location=ieTBitmap raise EIEException.Create('ie32f '+UNSUPMSG); ieCMYK: // ieCMYK not supported when Location=ieTBitmap raise EIEException.Create('ieCMYK '+UNSUPMSG); ieCIELab: // ieCIELab not supported when Location=ieTBitmap raise EIEException.Create('ieCIELab '+UNSUPMSG); ie24RGB: fBitmap.PixelFormat := pf24bit; ie48RGB: // ieRGB48 not supported when Location=ieTBitmap raise EIEException.Create('ieRGB48 '+UNSUPMSG); ie32RGB: fBitmap.PixelFormat := pf32bit; end; fBitmap.Width := fWidth; fBitmap.Height := fHeight; if fPixelFormat=ie8g then IESetGrayPalette(fBitmap); // this must be executed after set the bitmap sizes BuildBitmapScanlines; except exit; end; end; end; fFull := false; result := true; end; end; // AlignedBuffer is StartBuffer align by 64 bytes // StartBuffer and AlignedBuffer are "nil" on fail procedure TIEBitmap.AllocateMemory(size: int64; var StartBuffer: pointer; var AlignedBuffer: pointer); begin AlignedBuffer := nil; case fMemoryAllocator of iemaVCL: begin try getmem(StartBuffer, size + 128); except StartBuffer := nil; end; end; iemaSystem : StartBuffer := IESystemAlloc(size + 128); iemaAuto : StartBuffer := IEAutoAlloc(size + 128); end; if StartBuffer <> nil then begin AlignedBuffer := StartBuffer; while (uint64(AlignedBuffer) mod 64)<>0 do inc(pbyte(AlignedBuffer)); end; end; procedure TIEBitmap.FreeFragments(); var i: integer; begin if fFragments<>nil then begin for i := 0 to fFragmentsCount-1 do if fFragments[i]<>nil then IESystemFree(fFragments[i]); freemem(fFragments); end; fFragments := nil; fFragmentsCount := 0; fRowsPerFragment := 0; end; // allocates in chunks procedure TIEBitmap.FragmentedAlloc(); const STARTWITH = 4; MINIMUMSIZE = 10*1024*1024; var i: integer; exitLoop: boolean; fc: integer; bufSize: integer; begin FreeFragments; if not IEGlobalSettings().AutoFragmentBitmap then exit; fc := STARTWITH; // start with 4 blocks (fragments) repeat exitLoop := true; fFragmentsCount := fc; fRowsPerFragment := Ceil( fHeight / fFragmentsCount ); bufSize := fRowLen * fRowsPerFragment; if (bufSizeSTARTWITH) then begin // to avoid excessive framentation we cannot allow framents minor than MINIMUMSIZE FreeFragments; break; end; fFragments := allocmem(sizeof(pointer)*fFragmentsCount); // zero filled for i := 0 to fFragmentsCount-1 do begin fFragments[i] := IESystemAlloc(bufSize); if fFragments[i] = nil then begin // FAIL! Reduce block size FreeFragments; fc := fc*2; if (fcTIEBitmap.Allocate Declaration function Allocate(ImageWidth, ImageHeight: integer; ImagePixelFormat: =ie24RGB): boolean; Description Prepares space for an image with ImageWidth and ImageHeight sizes. Returns true on success. Note: When TIEBitmap is connected to , ensure that is False before setting pixel formats other than ie1g and ie24RGB. Example ImageEnView1.LegacyBitmap := False; ImageEnView1.IEBitmap.Allocate(1000, 1000, ieCMYK); !!} function TIEBitmap.Allocate(ImageWidth, ImageHeight: integer; ImagePixelFormat: TIEPixelFormat): boolean; begin result := true; if fFullReallocate or (ImageWidth <> fWidth) or (ImageHeight <> fHeight) or (ImagePixelFormat <> fPixelFormat) then begin if not fEncapsulatedFromTBitmap then FreeImage(true) else begin if assigned(fAlphaChannel) then FreeAndNil(fAlphaChannel) end; fWidth := ImageWidth; fHeight := ImageHeight; fPixelFormat := ImagePixelFormat; result := AllocateImage; if result = false then begin fWidth := 0; fHeight := 0; end; fFullReallocate := false; end; Changed(); end; {!! TIEBitmap.EncapsulateTBitmap Declaration procedure EncapsulateTBitmap(obj: TBitmap; DoFreeImage: boolean); Description Encapsulates an existing TBitmap object. It is useful to pass a TBitmap object to routines that require a TIEBitmap. Any changes to the TIEBitmap will be reflected in the TBitmap. If DoFreeImage is true, the TBitmap object will be freed when the object is destroyed. Supports only TBitmap with PixelFormat pf1bit, pf8bit and pf24bit Example iebmp := TIEBitmap.Create; try tbmp.EncapsulateTBitmap( bmp, False ); RotateMyIEBitmap( iebmp ); finally FreeAndNil( iebmp ); end; !!} // procedure TIEBitmap.EncapsulateTBitmap(obj: TBitmap; DoFreeImage: boolean); begin if DoFreeImage then FreeImage(true); if (obj<>nil) and ((obj<>fBitmap) or (obj.Width<>fWidth) or (obj.Height<>fHeight) or (IEVCLPixelFormat2ImageEnPixelFormat(obj.PixelFormat)<>fPixelFormat)) then begin fWidth := obj.Width; fHeight := obj.Height; case obj.PixelFormat of pf1bit: fPixelFormat := ie1g; pf8bit: begin fPixelFormat := ie8p; CopyPaletteFromTBitmap(obj, 256); end; pf24bit: fPixelFormat := ie24RGB; pf32bit: fPixelFormat := ie32RGB; end; fBitCount := IEPixelFormat2BitCount(fPixelFormat); fChannelCount := IEPixelFormat2ChannelCount(fPixelFormat); fRowLen := IEBitmapRowLen(fWidth, fBitCount, fBitAlignment); fLocation := ieTBitmap; fEncapsulatedFromTBitmap := true; fBitmap := obj; FreeAndNil(fIECanvas); BuildBitmapScanlines; end; end; {!! TIEBitmap.EncapsulateMemory Declaration procedure EncapsulateMemory(mem: pointer; bmpWidth, bmpHeight: integer; bmpPixelFormat: ; DoFreeImage: boolean; Origin: TIEBitmapOrigin = ieboBOTTOMLEFT); Description Encapsulates an existing bitmap from its buffer. It is useful to pass a TBitmap object to routines that require a TIEBitmap. If DoFreeImage is true, the buffer will be freed when the object is destroyed. Origin specifies the image orientation (default is bottom-left, that is Windows default. For example set ieboTOPLEFT with OpenCV images). !!} // note: an encapsulated from memory cannot be allocated/resized/freedom, but just used procedure TIEBitmap.EncapsulateMemory(mem: pointer; bmpWidth, bmpHeight: integer; bmpPixelFormat: TIEPixelFormat; DoFreeImage: boolean; Origin: TIEBitmapOrigin); begin if DoFreeImage then FreeImage(true); if mem <> nil then begin fWidth := bmpWidth; fHeight := bmpHeight; fPixelFormat := bmpPixelFormat; fBitCount := IEPixelFormat2BitCount(fPixelFormat); fChannelCount := IEPixelFormat2ChannelCount(fPixelFormat); fRowLen := IEBitmapRowLen(fWidth, fBitCount, fBitAlignment); fLocation := ieMemory; fEncapsulatedFromMemory := true; fMemory := mem; fRealMemory := mem; fOrigin := Origin; if (bmpPixelFormat=ie8p) and (fRGBPalette=nil) then begin getmem(fRGBPalette, sizeof(TRGB) * 256); fRGBPaletteLen := 256; end; FreeAndNil(fIECanvas); BuildBitmapScanlines; end; end; procedure TIEBitmap.AssignMetaInfo(Source: TIEBitmap); var i: Integer; begin // copy palette Source.CopyPaletteTo(self); // Copy other params fDefaultDitherMethod := Source.fDefaultDitherMethod; fBlackValue := Source.fBlackValue; fWhiteValue := Source.fWhiteValue; for i := 0 to IEMAXCHANNELS - 1 do fChannelOffset[i] := Source.fChannelOffset[i]; fEnableChannelOffset := Source.fEnableChannelOffset; fContrast := Source.fContrast; fColorProfile.Assign(Source.fColorProfile); // Copy Params if GetParamsEnabled and Source.ParamsEnabled then Params.Assign( Source.Params ); end; {!! TIEBitmap.Assign Declaration procedure Assign(Source: TObject); Description Copies an image from source object. Source can be a or a TBitmap. Note: are also copied if is true for both source and destination !!} procedure TIEBitmap.Assign(Source: TObject); var src: TIEBitmap; row, mi: integer; l1, l2: TIEDataAccess; begin fFullReallocate := true; if Source is TIEBitmap then begin src := Source as TIEBitmap; if fLocation = ieTBitmap then begin // works with fBitmap (TBitmap) if src.IsEmpty then exit; fWidth := src.fWidth; fHeight := src.fHeight; fPixelFormat := src.fPixelFormat; fBitAlignment := src.fBitAlignment; fOrigin := src.fOrigin; fFull := src.fFull; if fBitmap = nil then fBitmap := TBitmap.Create; fBitmap.Width := 1; fBitmap.Height := 1; case fPixelFormat of ie1g : fBitmap.PixelFormat := pf1bit; ie8p : fBitmap.PixelFormat := pf8bit; ie8g : fBitmap.PixelFormat := pf8bit; ie16g : ; // not supported ie32f : ; // not supported ieCMYK : ; // not supported ieCIELab: ; // not supported ie24RGB : fBitmap.PixelFormat := pf24bit; ie48RGB : ; // not supported ie32RGB : fBitmap.PixelFormat := pf32bit; end; fBitmap.Width := fWidth; fBitmap.Height := fHeight; if fPixelFormat=ie8g then IESetGrayPalette(fBitmap); // this must be executed after set the bitmap sizes fBitCount := IEPixelFormat2BitCount(fPixelFormat); fChannelCount := IEPixelFormat2ChannelCount(fPixelFormat); fRowLen := IEBitmapRowLen(fWidth, fBitCount, fBitAlignment); FreeAndNil(fIECanvas); BuildBitmapScanlines; end else begin // works with native mapped file or memory bitmap FreeImage(true); fWidth := src.fWidth; fHeight := src.fHeight; fPixelFormat := src.fPixelFormat; fFull := src.fFull; fBitAlignment := src.fBitAlignment; fOrigin := src.fOrigin; AllocateImage; end; // copy image l1 := src.Access; l2 := Access; src.Access := [iedRead]; Access := [iedWrite]; if (fLocation = ieFile) and (src.fLocation = ieFile) then begin // do raw copy FreeAllMaps; src.FreeAllMaps; src.fmemmap.CopyTo(fmemmap, 0, fRowLen * fHeight); end else begin mi := imin(fRowLen, src.RowLen); for row := 0 to fHeight - 1 do copymemory(ScanLine[row], src.ScanLine[row], mi); end; src.Access := l1; Access := l2; // copy alpha channel if not fIsAlpha then begin if src.HasAlphaChannel then // here we use GetAlphaChannel instead of fAlphaChannel to create alphachannel on the fly AlphaChannel.Assign(src.AlphaChannel) else RemoveAlphaChannel; // remove if there was an alpha channel end; // copy meta info (palette, display settings, params...) AssignMetaInfo(src); Changed(); end else if Source is TBitmap then begin CopyFromTBitmap(Source as TBitmap); end; end; {!! TIEBitmap.AssignImage Declaration procedure AssignImage(Source: ); Description Copies an image from Source object, but not the alpha channel. !!} // assign only from TIEBitmap and without alpha channel // do not assign BitAlignment procedure TIEBitmap.AssignImage(Source: TIEBaseBitmap); var row, mi: integer; l1, l2: TIEDataAccess; SourceImpl: TIEBitmap; begin SourceImpl := Source as TIEBitmap; if SourceImpl.IsEmpty then exit; fFullReallocate := true; if fLocation = ieTBitmap then begin // works with fBitmap (TBitmap) fWidth := SourceImpl.fWidth; fHeight := SourceImpl.fHeight; fPixelFormat := SourceImpl.fPixelFormat; fFull := false; if fBitmap = nil then fBitmap := TBitmap.Create; fBitmap.Width := 1; fBitmap.Height := 1; fBitmap.PixelFormat := pfDevice; // needed, otherwise when switch to pe1bit the bitmap could not work well (!) case fPixelFormat of ie1g: fBitmap.PixelFormat := pf1bit; ie8p: fBitmap.PixelFormat := pf8bit; ie8g: fBitmap.PixelFormat := pf8bit; ie16g: ; // not supported ie32f: ; // not supported ieCMYK: ; // not supported ieCIELab: ; // not supported ie24RGB: fBitmap.PixelFormat := pf24bit; ie48RGB: ; // not supported ie32RGB: fBitmap.PixelFormat := pf32bit; end; fBitmap.Width := fWidth; fBitmap.Height := fHeight; if fPixelFormat = ie8g then IESetGrayPalette(fBitmap); // this must be executed after set the bitmap sizes fBitCount := IEPixelFormat2BitCount(fPixelFormat); fChannelCount := IEPixelFormat2ChannelCount(fPixelFormat); fRowLen := IEBitmapRowLen(fWidth, fBitCount, fBitAlignment); FreeAndNil(fIECanvas); BuildBitmapScanlines; end else begin // works with native mapped file or memory bitmap FreeImage(false); // this doesn't free alpha channel fWidth := SourceImpl.fWidth; fHeight := SourceImpl.fHeight; fPixelFormat := SourceImpl.fPixelFormat; fFull := false; AllocateImage; end; // copy image l1 := SourceImpl.Access; l2 := Access; SourceImpl.Access := [iedRead]; Access := [iedWrite]; if (fLocation = ieFile) and (SourceImpl.fLocation = ieFile) then begin // do a raw copy FreeAllMaps; SourceImpl.FreeAllMaps; SourceImpl.fmemmap.CopyTo(fmemmap, 0, fRowLen * fHeight); end else begin mi := imin(fRowLen, SourceImpl.RowLen); for row := 0 to fHeight - 1 do CopyMemory(ScanLine[row], SourceImpl.ScanLine[row], mi); end; SourceImpl.Access := l1; Access := l2; // copy palette SourceImpl.CopyPaletteTo(self); // copy other params fColorProfile.Assign(SourceImpl.fColorProfile); Changed(); end; {!! TIEBitmap.AssignRect Declaration procedure AssignRect(Source: TObject; SourceRect: TRect); Description Copies a rectangle from source object. Source can be a , or a TBitmap. When Source is TImageEnView the currently selected layer is copied. Note: are also copied if is true for both source and destination !!} procedure TIEBitmap.AssignRect(Source: TObject; SourceRect: TRect); var srcTIEBitmap: TIEBitmap; rectWidth, rectHeight: Integer; begin rectWidth := SourceRect.Right - SourceRect.Left + 1; rectHeight := SourceRect.Bottom - SourceRect.Top + 1; if (rectWidth <= 0) or (rectHeight <= 0) then exit; if Source is TIEBitmap then begin srcTIEBitmap := Source as TIEBitmap; Allocate(rectWidth, rectHeight, srcTIEBitmap.PixelFormat); srcTIEBitmap.CopyRectTo(self, SourceRect.Left, SourceRect.Top, 0, 0, rectWidth, rectHeight, false); // copy alpha channel if not fIsAlpha then begin if srcTIEBitmap.HasAlphaChannel then AlphaChannel.AssignRect(srcTIEBitmap.AlphaChannel, SourceRect) else RemoveAlphaChannel(); // remove if there was an alpha channel end; // copy meta info (palette, display settings, params...) AssignMetaInfo(srcTIEBitmap); end else if Source is TBitmap then begin srcTIEBitmap := TIEBitmap.Create(); srcTIEBitmap.EncapsulateTBitmap(Source as TBitmap); try AssignRect(srcTIEBitmap, SourceRect); finally srcTIEBitmap.Free(); end; end else if ( Source is TImageEnView ) and ( (Source as TImageEnView).IEBitmap <> nil ) then begin AssignRect((Source as TImageEnView).IEBitmap, SourceRect); end; end; {!! TIEBitmap.GetSegment Declaration function GetSegment(Row: integer; Col: integer; Width: integer): pointer; Description Returns the pointer to a buffer containing a specified image segment. For =ieFile or =ieVirtual you can use only the last line obtained from Scanline[] (consequently this is not thread safe). Parameter Description Row Row to retrieve (0 = first row). Col Column to retrieve (0 = first column). Width Number of pixels to retrieve.
See Also -
- - !!} function TIEBitmap.GetSegment(Row: integer; Col: integer; Width: integer): pointer; var p_byte: pbyte; x: integer; begin if IsVirtual then begin result := nil; if assigned(fVirtualBitmapProvider) then begin if fVirtualBitmapProvider is TIEVirtualBitmapProvider then result := (fVirtualBitmapProvider as TIEVirtualBitmapProvider).GetSegment(self, Row, Col, Width); end else if assigned(fOnRenderVirtualPixel) then begin if fVirtualBitmapRowBuffer = nil then getmem(fVirtualBitmapRowBuffer, fRowLen); // size must be fRowLen otherwise GetScanLine will not work on other sizes p_byte := pbyte(fVirtualBitmapRowbuffer); for x := 0 to Width-1 do begin fOnRenderVirtualPixel(self, Col + x, Row, p_byte^); inc(p_byte, BitCount div 8); end; result := fVirtualBitmapRowBuffer; end; end else begin result := Scanline[Row]; inc(pbyte(result), Col * (BitCount div 8)); end; end; {!! TIEBitmap.Scanline Declaration property Scanline[row: integer]: pointer Description Retrieves an entire line of pixels at a time. For =ieFile or =ieVirtual you can use only last line obtained from Scanline[] (consequently this is not thread safe). Examples // Convert image to gray-scale (PixelFormat must be ie24RGB) // Same as TImageEnProc.ConvertToGray var x, y: Integer; pPix: PRGB; Gray: Byte; begin for y := 0 to ImageEnView1.IEBitmap.Height - 1 do begin pPix := ImageEnView1.IEBitmap.ScanLine[ y ]; for x := 0 to ImageEnView1.SelectionMask.Width - 1 do begin Gray := (pPix^.R * IEGlobalSettings().RedToGrayCoef + pPix^.G * IEGlobalSettings().GreenToGrayCoef + pPix^.B * IEGlobalSettings().BlueToGrayCoef) div 100; pPix^.R := Gray; pPix^.G := Gray; pPix^.B := Gray; inc( pPix ); end; end; ImageEnView1.Update(); end; // Set all pixels within selection as red // Same as ImageEnView1.SetSelectedPixelsColor var x, y: Integer; pSel: pbyte; pPix: PRGB; begin if ImageEnView1.SelectionMask.IsEmpty then raise Exception.create( 'Nothing selected' ); if ImageEnView1.IEBitmap.PixelFormat <> ie24RGB then raise Exception.create( 'Not 24bit' ); // Process selected area for y := 0 to ImageEnView1.SelectionMask.Height - 1 do begin pSel := ImageEnView1.SelectionMask.ScanLine[ y ]; pPix := ImageEnView1.IEBitmap.ScanLine[ y ]; case ImageEnView1.SelectionMask.BitsPerPixel of 1: for x := 0 to ImageEnView1.SelectionMask.Width - 1 do begin // 1 Bit mask (values are 0 or 1) if (pbytearray(pSel)^[x shr 3] and iebitmask1[x and $7]) <> 0 then begin pPix^.R := 255; pPix^.G := 0; pPix^.B := 0; end; inc( pPix ); end; 8: for x := 0 to ImageEnView1.SelectionMask.Width - 1 do begin // 8 Bit mask (values are 0 to 255) if pSel^ <> 0 then begin pPix^.R := 255; pPix^.G := 0; pPix^.B := 0; end; inc( pSel ); inc( pPix ); end; end; end; ImageEnView1.Update(); end; See Also - - - !!} // for performance we never control if Row is valid function TIEBitmap.GetScanLine(Row: integer): pointer; var col: integer; p_byte: pbyte; begin if fOrigin = ieboTOPLEFT then Row := fHeight - Row - 1; if IsVirtual then begin // virtual pixel format (not thread safe) result := nil; if assigned(fVirtualBitmapProvider) then begin if fVirtualBitmapProvider is TIEVirtualBitmapProvider then result := (fVirtualBitmapProvider as TIEVirtualBitmapProvider).GetSegment(self, Row, 0, fWidth); end else if assigned(fOnRenderVirtualPixel) then begin if fVirtualBitmapRowBuffer = nil then getmem(fVirtualBitmapRowBuffer, fRowLen); p_byte := pbyte(fVirtualBitmapRowbuffer); for col := 0 to fWidth-1 do begin fOnRenderVirtualPixel(self, col, Row, p_byte^); inc(p_byte, BitCount div 8); end; result := fVirtualBitmapRowBuffer; end; exit; end; case fLocation of ieMemory: begin if fFragments = nil then begin p_byte := fMemory; inc(p_byte, (fHeight - Row - 1) * fRowlen); result := p_byte; end else begin p_byte := fFragments[Row div fRowsPerFragment]; inc(p_byte, fRowlen * (Row mod fRowsPerFragment)); result := p_byte; end; end; ieTBitmap: begin result := fBitmapScanlines[row]; end; ieFile: begin if fWorkingMap <> nil then fmemmap.UnMap(fWorkingMap); fWorkingMap := fmemmap.Map(int64(Row) * fRowLen, fRowLen, fAccess); // int64(Row) to promote expression to 64 bit result := fWorkingMap; end; else result := nil; end; end; {!! TIEBitmap.GetRow Declaration function GetRow(Row: integer): pointer; Description Retrieves a pointer to the specified Row. Returned pointer is valid until the application calls . Just like if is ieMemory or ieTBitmap. !!} // for performance we never control if Row is valid function TIEBitmap.GetRow(Row: integer): pointer; var pb: pbyte; begin if fOrigin = ieboTOPLEFT then Row := fHeight - Row - 1; if IsVirtual then begin result := GetScanLine(Row); exit; end; case fLocation of ieMemory: if fFragments=nil then begin pb := fMemory; inc(pb, (fHeight - Row - 1) * fRowlen); result := pb; end else begin pb := fFragments[Row div fRowsPerFragment]; inc(pb, fRowlen * (Row mod fRowsPerFragment)); result := pb; end; ieTBitmap: result := fBitmapScanlines[row]; ieFile: begin if fWorkingMap<>nil then begin // flushes the working map (from Scnaline[]) fmemmap.UnMap(fWorkingMap); fWorkingMap := nil; end; result := fmemmap.Map(Row * fRowLen, fRowLen, fAccess); fScanlinesToUnMapPtr.Add(result); fScanlinesToUnMapRow.Add(pointer(Row)); end; else result := nil; end; end; {!! TIEBitmap.FreeRow Declaration procedure FreeRow(Row: integer); Description Frees a row obtained using . Does nothing if is ieMemory or ieTBitmap. !!} // for performance we never control if Row is valid procedure TIEBitmap.FreeRow(Row: integer); var idx: integer; begin if (fLocation = ieFile) then begin idx := fScanlinesToUnMapRow.IndexOf(pointer(Row)); if idx >= 0 then begin fmemmap.UnMap(fScanlinesToUnMapPtr[idx]); fScanlinesToUnMapPtr.Delete(idx); fScanlinesToUnMapRow.Delete(idx); end; end; end; {!! TIEBitmap.CopyFromMemory Declaration procedure CopyFromMemory(SrcBuffer: pointer; SrcWidth: integer; SrcHeight: integer; SrcPixelFormat: TIEPixelFormat; SrcOrigin: TIEBitmapOrigin; SrcRowLen: integer); Description Copies an image from memory buffer. Parameter Description SrcBuffer Source memory buffer. SrcWidth Source image width. SrcHeight Source image height. SrcPixelFormat Source pixel format. SrcOrigin Source orientation. SrcRowLen Source row length.
!!} procedure TIEBitmap.CopyFromMemory(SrcBuffer: pointer; SrcWidth: integer; SrcHeight: integer; SrcPixelFormat: TIEPixelFormat; SrcOrigin: TIEBitmapOrigin; SrcRowLen: integer); var bmp: TIEBitmap; row: integer; begin bmp := TIEBitmap.Create; try bmp.EncapsulateMemory(SrcBuffer, SrcWidth, SrcHeight, SrcPixelFormat, false, SrcOrigin); bmp.fRowlen := SrcRowLen; Allocate(SrcWidth, SrcHeight, SrcPixelFormat); for row := 0 to SrcHeight-1 do CopyMemory(Scanline[row], bmp.Scanline[row], bmp.RowLen); fFull := false; finally bmp.Free; end; end; {!! TIEBitmap.CopyAndConvertFormat Declaration procedure CopyAndConvertFormat(Source:
); Description Copies from the specified source image, converting to current pixel format. Uses color quantizers when convert from a true color to a paletted. Not supported if is ieTBitmap. !!} procedure TIEBitmap.CopyAndConvertFormat(Source: TIEBitmap); var old: TIEBitmap; row, col, q, v: integer; px_src, px_dst: pbyte; px_src_w, px_dst_w: pword; px_src_rgb: PRGB; px_dst_f, px_src_f: psingle; px_dst_cmyk, px_src_cmyk: PCMYK; px_dst_cielab, px_src_cielab: PCIELAB; px_dst_48rgb: pword; px_dst_rgb: PRGB; px_src_48rgb: PRGB48; px_dst_rgb32: PRGBA; qt: TIEQuantizer; tmpcolormap: array[0..255] of TRGB; NullProgress: TProgressRec; range: double; black, white: integer; RedToGrayCoef, GreenToGrayCoef, BlueToGrayCoef: integer; begin if (fWidth <> Source.fWidth) or (fHeight <> Source.fHeight) or (fLocation = ieTBitmap) then exit; NullProgress := NullProgressRec( nil ); RedToGrayCoef := IEGlobalSettings().RedToGrayCoef; GreenToGrayCoef := IEGlobalSettings().GreenToGrayCoef; BlueToGrayCoef := IEGlobalSettings().BlueToGrayCoef; old := Source; if old.fPixelFormat <> ienull then begin case old.fPixelFormat of ie1g: case fPixelFormat of ie8p: begin // 1bit gray scale ==> 8bit paletted with fRGBPalette[0] do begin r := 0; b := 0; g := 0; end; with fRGBPalette[1] do begin r := 255; b := 255; g := 255; end; for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst^ := ord(GetPixelbw_inline(px_src, col) <> 0); inc(px_dst); end; end; end; ie8g: begin // 1bit gray scale ==> 8bit gray scale for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst^ := ord(GetPixelbw_inline(px_src, col) <> 0) * 255; inc(px_dst); end; end; end; ie16g: begin // 1bit gray scale ==> 16bit gray scale for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst_w := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst_w^ := ord(GetPixelbw_inline(px_src, col) <> 0) * 65535; inc(px_dst_w); end; end; end; ie24RGB: begin // 1bit gray scale ==> 24bit RGB for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin v := ord(GetPixelbw_inline(px_src, col) <> 0) * 255; px_dst^ := v; inc(px_dst); px_dst^ := v; inc(px_dst); px_dst^ := v; inc(px_dst); end; end; end; ie32RGB: begin // 1bit gray scale ==> 32bit RGB for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin v := ord(GetPixelbw_inline(px_src, col) <> 0) * 255; px_dst^ := v; inc(px_dst); px_dst^ := v; inc(px_dst); px_dst^ := v; inc(px_dst); px_dst^ := 255; inc(px_dst); end; end; end; ie32f: begin // 1bit gray scale ==> 32bit floating point gray scale for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst_f := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst_f^ := ord(GetPixelbw_inline(px_src, col) <> 0); inc(px_dst_f); end; end; end; ieCMYK: begin // 1bit gray scale ==> CMYK old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ieCIELab: begin // 1bit gray scale ==> CIELab old.ConvertToPixelFormat(ieCIELab); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie48RGB: begin // 1bit gray scale ==> 48bit RGB for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst_48RGB := ScanLine[row]; for col := 0 to fWidth - 1 do begin v := ord(GetPixelbw_inline(px_src, col) <> 0) * 65535; px_dst_48rgb^ := v; inc(px_dst_48rgb); px_dst_48rgb^ := v; inc(px_dst_48rgb); px_dst_48rgb^ := v; inc(px_dst_48rgb); end; end; end; end; ie8p: case fPixelFormat of ie1g: begin // 8bit paletted ==> 1bit gray scale case fDefaultDitherMethod of ieOrdered: // use ordered black/white conversion for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin with old.fRGBPalette[px_src^] do v := ((r * RedToGrayCoef + g * GreenToGrayCoef + b * BlueToGrayCoef) div 100) shr 2; SetPixelbw_inline(px_dst, col, ord(v > BWORDERPATTERN[col and 7][row and 7])); inc(px_src); end; end; ieThreshold: // use threshold conversion _ConvertToBWThresholdEx(old, self, -1, NullProgress); end; end; ie8g: begin // 8bit paletted ==> 8bit gray scale for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin with old.fRGBPalette[px_src^] do px_dst^ := (r * RedToGrayCoef + g * GreenToGrayCoef + b * BlueToGrayCoef) div 100; inc(px_dst); inc(px_src); end; end; end; ie16g: begin // 8bit paletted ==> 16bit gray scale for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst_w := ScanLine[row]; for col := 0 to fWidth - 1 do begin with old.fRGBPalette[px_src^] do px_dst_w^ := (212 * (r*257) + 713 * (g*257) + 75 * (b*257)) div 1000; inc(px_dst_w); inc(px_src); end; end; end; ie24RGB: begin // 8bit paletted ==> 24bit RGB for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin with old.fRGBPalette[px_src^] do begin px_dst^ := b; inc(px_dst); px_dst^ := g; inc(px_dst); px_dst^ := r; inc(px_dst); end; inc(px_src); end; end; end; ie32RGB: begin // 8bit paletted ==> 32bit RGB for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin with old.fRGBPalette[px_src^] do begin px_dst^ := b; inc(px_dst); px_dst^ := g; inc(px_dst); px_dst^ := r; inc(px_dst); px_dst^ := 255; inc(px_dst); end; inc(px_src); end; end; end; ie32f: begin // 8bit paletted ==> 32bit floating point gray scale for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst_f := ScanLine[row]; for col := 0 to fWidth - 1 do begin with old.fRGBPalette[px_src^] do px_dst_f^ := (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255; // Rec 709 inc(px_dst_f); inc(px_src); end; end; end; ieCMYK: begin // 8bit paletted ==> CMYK old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ieCIELab: begin // 8bit paletted ==> CIELab old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie48RGB: begin // 8bit paletted ==> 48bit RGB for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst_48rgb := ScanLine[row]; for col := 0 to fWidth - 1 do begin with old.fRGBPalette[px_src^] do begin px_dst_48rgb^ := r *257; inc(px_dst_48rgb); px_dst_48rgb^ := g *257; inc(px_dst_48rgb); px_dst_48rgb^ := b *257; inc(px_dst_48rgb); end; inc(px_src); end; end; end; end; ie8g: case fPixelFormat of ie1g: begin // 8bit gray scale ==> 1bit gray scale case fDefaultDitherMethod of ieOrdered: // use ordered black/white conversion for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin SetPixelbw_inline(px_dst, col, ord((px_src^ shr 2) > BWORDERPATTERN[col and 7][row and 7])); inc(px_src); end; end; ieThreshold: // use threshold conversion _ConvertToBWThresholdEx(old, self, -1, NullProgress); end; end; ie8p: begin // 8bit gray scale ==> 8bit paletted for q := 0 to 255 do with fRGBPalette[q] do begin r := q; g := q; b := q; end; for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst := ScanLine[row]; CopyMemory(px_dst, px_src, fRowLen); end; end; ie16g: begin // 8bit gray scale ==> 16bit gray scale for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst_w := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst_w^ := px_src^ *257; inc(px_src); inc(px_dst_w); end; end; end; ie24RGB: begin // 8bit gray scale ==> 24bit RGB range := fWhiteValue - fBlackValue; if range = 0 then begin for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst^ := px_src^; inc(px_dst); px_dst^ := px_src^; inc(px_dst); px_dst^ := px_src^; inc(px_dst); inc(px_src); end end end else begin black := trunc(fBlackValue); white := trunc(fWhiteValue); for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin v := px_src^; if v < black then v := black; if v > white then v := white; v := trunc(((v - black) / range) * 255); px_dst^ := v; inc(px_dst); px_dst^ := v; inc(px_dst); px_dst^ := v; inc(px_dst); inc(px_src); end; end; fBlackValue := 0; fWhiteValue := 0; end; end; ie32RGB: begin // 8bit gray scale ==> 32bit RGB for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst^ := px_src^; inc(px_dst); px_dst^ := px_src^; inc(px_dst); px_dst^ := px_src^; inc(px_dst); px_dst^ := 255; inc(px_dst); inc(px_src); end; end; end; ie32f: begin // 8bit gray scale ==> 32bit floating point gray scale for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst_f := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst_f^ := px_src^ / 255; inc(px_src); inc(px_dst_f); end; end; end; ieCMYK: begin // 8bit gray scale ==> CMYK old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ieCIELab: begin // 8bit gray scale ==> CIELab old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie48RGB: begin // 8bit gray scale ==> 48bit RGB for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst_48rgb := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst_48rgb^ := px_src^ *257; inc(px_dst_48rgb); px_dst_48rgb^ := px_src^ *257; inc(px_dst_48rgb); px_dst_48rgb^ := px_src^ *257; inc(px_dst_48rgb); inc(px_src); end; end; end; end; ie16g: case fPixelFormat of ie1g: begin // 16bit gray scale ==> 1bit gray scale case fDefaultDitherMethod of ieOrdered: // use ordered black/white conversion for row := 0 to fHeight - 1 do begin px_src_w := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin SetPixelbw_inline(px_dst, col, ord((px_src_w^ shr 10) > BWORDERPATTERN[col and 7][row and 7])); inc(px_src_w); end; end; ieThreshold: // use threshold conversion _ConvertToBWThresholdEx(old, self, -1, NullProgress); end; end; ie8p: begin // 16bit gray scale ==> 8bit paletted for q := 0 to 255 do with fRGBPalette[q] do begin r := q; g := q; b := q; end; for row := 0 to fHeight - 1 do begin px_src_w := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst^ := px_src_w^ shr 8; inc(px_dst); inc(px_src_w); end; end; end; ie8g: begin // 16bit gray scale ==> 8bit gray scale for row := 0 to fHeight - 1 do begin px_src_w := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst^ := px_src_w^ shr 8; inc(px_dst); inc(px_src_w); end; end; end; ie24RGB: begin // 16bit gray scale ==> 24bit RGB range := fWhiteValue - fBlackValue; if range = 0 then begin for row := 0 to fHeight - 1 do begin px_src_w := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst^ := px_src_w^ shr 8; inc(px_dst); px_dst^ := px_src_w^ shr 8; inc(px_dst); px_dst^ := px_src_w^ shr 8; inc(px_dst); inc(px_src_w); end; end; end else begin black := trunc(fBlackValue); white := trunc(fWhiteValue); for row := 0 to fHeight - 1 do begin px_src_w := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin v := px_src_w^; if v < black then v := black; if v > white then v := white; v := trunc(((v - black) / range) * 255); px_dst^ := v; inc(px_dst); px_dst^ := v; inc(px_dst); px_dst^ := v; inc(px_dst); inc(px_src_w); end; end; fBlackValue := 0; fWhiteValue := 0; end; end; ie32RGB: begin // 16bit gray scale ==> 32bit RGB for row := 0 to fHeight - 1 do begin px_src_w := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst^ := px_src_w^ shr 8; inc(px_dst); px_dst^ := px_src_w^ shr 8; inc(px_dst); px_dst^ := px_src_w^ shr 8; inc(px_dst); px_dst^ := 255; inc(px_dst); inc(px_src_w); end; end; end; ie32f: begin // 16bit gray scale ==> 32bit floating point gray scale for row := 0 to fHeight - 1 do begin px_src_w := old.ScanLine[row]; px_dst_f := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst_f^ := px_src_w^ / 65535; inc(px_dst_f); inc(px_src_w); end; end; end; ieCMYK: begin // 16bit gray scale ==> CMYK old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ieCIELab: begin // 16bit gray scale ==> CIELab old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie48RGB: begin // 16bit gray scale ==> 48bit RGB for row := 0 to fHeight - 1 do begin px_src_w := old.ScanLine[row]; px_dst_48rgb := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst_48rgb^ := px_src_w^; inc(px_dst_48rgb); px_dst_48rgb^ := px_src_w^; inc(px_dst_48rgb); px_dst_48rgb^ := px_src_w^; inc(px_dst_48rgb); inc(px_src_w); end; end; end; end; ie24RGB: case fPixelFormat of ie1g: begin // 24bit RGB ==> 1bit gray scale case fDefaultDitherMethod of ieOrdered: // use ordered black/white conversion for row := 0 to fHeight - 1 do begin px_src_rgb := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin with px_src_rgb^ do v := ((r * RedToGrayCoef + g * GreenToGrayCoef + b * BlueToGrayCoef) div 100) shr 2; SetPixelbw_inline(px_dst, col, ord(v > BWORDERPATTERN[col and 7][row and 7])); inc(px_src_rgb); end; end; ieThreshold: // use threshold conversion _ConvertToBWThresholdEx(old, self, -1, NullProgress); end; end; ie8p: begin // 24bit RGB ==> 8bit paletted // use color reduction qt := TIEQuantizer.Create(old, tmpcolormap, fPaletteUsed); for q := 0 to 255 do begin fRGBPalette[q].r := tmpcolormap[q].r; fRGBPalette[q].g := tmpcolormap[q].g; fRGBPalette[q].b := tmpcolormap[q].b; end; for row := 0 to fHeight - 1 do begin px_src_rgb := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst^ := qt.RGBIndex[px_src_rgb^]; inc(px_dst); inc(px_src_rgb); end; end; FreeAndNil(qt); end; ie8g: begin // 24bit RGB ==> 8bit gray scale for row := 0 to fHeight - 1 do begin px_src_rgb := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin with px_src_rgb^ do px_dst^ := (r * RedToGrayCoef + g * GreenToGrayCoef + b * BlueToGrayCoef) div 100; inc(px_src_rgb); inc(px_dst); end; end; end; ie16g: begin // 24bit RGB ==> 16bit gray scale for row := 0 to fHeight - 1 do begin px_src_rgb := old.ScanLine[row]; px_dst_w := ScanLine[row]; for col := 0 to fWidth - 1 do begin with px_src_rgb^ do px_dst_w^ := (212 * (r*257) + 713 * (g*257) + 75 * (b*257)) div 1000; inc(px_src_rgb); inc(px_dst_w); end; end; end; ie32f: begin // 24bit RGB ==> 32bit floating point gray scale for row := 0 to fHeight - 1 do begin px_src_rgb := old.ScanLine[row]; px_dst_f := ScanLine[row]; for col := 0 to fWidth - 1 do begin with px_src_rgb^ do px_dst_f^ := (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255; // Rec 709 inc(px_src_rgb); inc(px_dst_f); end; end; end; ieCMYK: begin // 24bit RGB ==> CMYK for row := 0 to fHeight-1 do begin px_src_rgb := old.ScanLine[row]; px_dst_cmyk := ScanLine[row]; for col := 0 to fWidth-1 do begin px_dst_cmyk^ := IERGB2CMYK(px_src_rgb^); inc(px_src_rgb); inc(px_dst_cmyk); end; end; end; ieCIELab: begin // 24bit RGB ==> CIELab for row := 0 to fHeight-1 do begin px_src_rgb := old.ScanLine[row]; px_dst_cielab := ScanLine[row]; for col := 0 to fWidth-1 do begin px_dst_cielab^ := IERGB2CIELAB(px_src_rgb^); inc(px_src_rgb); inc(px_dst_cielab); end; end; end; ie48RGB: begin // 24bit RGB ==> 48bit RGB for row := 0 to fHeight - 1 do begin px_src_rgb := old.ScanLine[row]; px_dst_48rgb := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst_48rgb^ := px_src_rgb^.r *257; inc(px_dst_48rgb); px_dst_48rgb^ := px_src_rgb^.g *257; inc(px_dst_48rgb); px_dst_48rgb^ := px_src_rgb^.b *257; inc(px_dst_48rgb); inc(px_src_rgb); end; end; end; ie32RGB: begin // 24bit RGB ==> 32bit RGB for row := 0 to fHeight - 1 do begin px_src := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst^ := px_src^; inc(px_dst); inc(px_src); px_dst^ := px_src^; inc(px_dst); inc(px_src); px_dst^ := px_src^; inc(px_dst); inc(px_src); px_dst^ := 255; inc(px_dst); end; end; end; end; ie32f: case fPixelFormat of ie1g: begin // 32bit floating pointgray scale ==> 1bit gray scale case fDefaultDitherMethod of ieOrdered: // use ordered black/white conversion for row := 0 to fHeight - 1 do begin px_src_f := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin SetPixelbw_inline(px_dst, col, ord((px_src_f^ / 2) > BWORDERPATTERN[col and 7][row and 7])); inc(px_src_f); end; end; ieThreshold: // use threshold conversion _ConvertToBWThresholdEx(old, self, -1, NullProgress); end; end; ie8p: begin // 32bit floating point gray scale ==> 8bit paletted for q := 0 to 255 do with fRGBPalette[q] do begin r := q; g := q; b := q; end; for row := 0 to fHeight - 1 do begin px_src_f := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst^ := trunc(px_src_f^ * 255); inc(px_src_f); inc(px_dst); end; end; end; ie8g: begin // 32bit floating point gray scale ==> 8bit gray scale for row := 0 to fHeight - 1 do begin px_src_f := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst^ := trunc(px_src_f^ * 255); inc(px_src_f); inc(px_dst); end; end; end; ie16g: begin // 32bit floating point gray scale ==> 16bit gray scale for row := 0 to fHeight - 1 do begin px_src_f := old.ScanLine[row]; px_dst_w := ScanLine[row]; for col := 0 to fWidth - 1 do begin px_dst_w^ := trunc(px_src_f^ * 65535); inc(px_src_f); inc(px_dst_w); end; end; end; ie24RGB: begin // 32bit floating point gray scale ==> 24bit RGB for row := 0 to fHeight - 1 do begin px_src_f := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin v := trunc(px_src_f^ * 255); px_dst^ := v; inc(px_dst); px_dst^ := v; inc(px_dst); px_dst^ := v; inc(px_dst); inc(px_src_f); end; end; end; ie32RGB: begin // 32bit floating point gray scale ==> 32bit RGB for row := 0 to fHeight - 1 do begin px_src_f := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin v := trunc(px_src_f^ * 255); px_dst^ := v; inc(px_dst); px_dst^ := v; inc(px_dst); px_dst^ := v; inc(px_dst); px_dst^ := 255; inc(px_dst); inc(px_src_f); end; end; end; ieCMYK: begin // 32bit floating point gray scale ==> CMYK old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ieCIELab: begin // 32bit floating point gray scale ==> CIELab old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie48RGB: begin // 32bit floating point gray scale ==> 48bit RGB for row := 0 to fHeight - 1 do begin px_src_f := old.ScanLine[row]; px_dst_48rgb := ScanLine[row]; for col := 0 to fWidth - 1 do begin v := trunc(px_src_f^ * 65535); px_dst_48rgb^ := v; inc(px_dst_48rgb); px_dst_48rgb^ := v; inc(px_dst_48rgb); px_dst_48rgb^ := v; inc(px_dst_48rgb); inc(px_src_f); end; end; end; end; ieCMYK: case fPixelFormat of ie1g: begin // CMYK ==> 1bit gray scale old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie8p: begin // CMYK ==> 8bit paletted old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie8g: begin // CMYK ==> 8bit gray scale old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie16g: begin // CMYK ==> 16bit gray scale old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie32f: begin // CMYK ==> 32bit floating point gray scale old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ieCIELab: begin // CMYK ==> CIELab old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie24RGB: begin // CMYK ==> RGB24 for row := 0 to fHeight-1 do begin px_src_cmyk := old.ScanLine[row]; px_dst_rgb := ScanLine[row]; IECMYK2RGBROW(px_src_cmyk, px_dst_rgb, fWidth); end; end; ie32RGB: begin // CMYK ==> RGB32 for row := 0 to fHeight-1 do begin px_src_cmyk := old.ScanLine[row]; px_dst_rgb32 := ScanLine[row]; for col := 0 to fWidth-1 do begin with IECMYK2RGB(px_src_cmyk^) do begin px_dst_rgb32^.r := r; px_dst_rgb32^.g := g; px_dst_rgb32^.b := b; px_dst_rgb32^.a := 255; end; inc(px_src_cmyk); inc(px_dst_rgb32); end; end; end; ie48RGB: begin // CMYK ==> 48 BIT RGB old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; end; ieCIELab: case fPixelFormat of ie1g: begin // CIELab ==> 1bit gray scale old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie8p: begin // CIELab ==> 8bit paletted old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie8g: begin // CIELab ==> 8bit gray scale old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie16g: begin // CIELab ==> 16bit gray scale old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie32f: begin // CIELab ==> 32bit floating point gray scale old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie24RGB: begin // CIELab ==> RGB24 for row := 0 to fHeight-1 do begin px_src_cielab := old.ScanLine[row]; px_dst_rgb := ScanLine[row]; for col := 0 to fWidth-1 do begin px_dst_rgb^ := IECIELAB2RGB(px_src_cielab^); inc(px_src_cielab); inc(px_dst_rgb); end; end; end; ie32RGB: begin // CIELab ==> RGB32 for row := 0 to fHeight-1 do begin px_src_cielab := old.ScanLine[row]; px_dst_rgb32 := ScanLine[row]; for col := 0 to fWidth-1 do begin with IECIELAB2RGB(px_src_cielab^) do begin px_dst_rgb32^.r := r; px_dst_rgb32^.g := g; px_dst_rgb32^.b := b; px_dst_rgb32^.a := 255; end; inc(px_src_cielab); inc(px_dst_rgb32); end; end; end; ieCMYK: begin // CIELab ==> CMYK old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie48RGB: begin // CIELab ==> 48 BIT RGB old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; end; ie48RGB: case fPixelFormat of ie1g: begin // 48bit RGB ==> 1bit gray scale case fDefaultDitherMethod of ieOrdered: // use ordered black/white conversion for row := 0 to fHeight - 1 do begin px_src_48rgb := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin with px_src_48rgb^ do v := (((r shr 8) * RedToGrayCoef + (g shr 8) * GreenToGrayCoef + (b shr 8) * BlueToGrayCoef) div 100) shr 2; SetPixelbw_inline(px_dst, col, ord(v > BWORDERPATTERN[col and 7][row and 7])); inc(px_src_48rgb); end; end; ieThreshold: // use threshold conversion begin old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate _ConvertToBWThresholdEx(old, self, -1, NullProgress); end; end; end; ie8p, ieCMYK, ieCIELab: begin // 48bit RGB ==> 8bit paletted, CMYK, CIELab old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie8g: begin // 48bit RGB ==> 8bit gray scale for row := 0 to fHeight - 1 do begin px_src_48rgb := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth - 1 do begin with px_src_48rgb^ do px_dst^ := ((r shr 8) * RedToGrayCoef + (g shr 8) * GreenToGrayCoef + (b shr 8) * BlueToGrayCoef) div 100; inc(px_src_48rgb); inc(px_dst); end; end; end; ie16g: begin // 24bit RGB ==> 16bit gray scale for row := 0 to fHeight - 1 do begin px_src_48rgb := old.ScanLine[row]; px_dst_w := ScanLine[row]; for col := 0 to fWidth - 1 do begin with px_src_48rgb^ do px_dst_w^ := (212 * (r) + 713 * (g) + 75 * (b)) div 1000; inc(px_src_48rgb); inc(px_dst_w); end; end; end; ie32f: begin // 24bit RGB ==> 32bit floating point gray scale for row := 0 to fHeight - 1 do begin px_src_48rgb := old.ScanLine[row]; px_dst_f := ScanLine[row]; for col := 0 to fWidth - 1 do begin with px_src_48rgb^ do px_dst_f^ := (0.2126 * r/256 + 0.7152 * g/256 + 0.0722 * b/256) / 255; // Rec 709 inc(px_src_48rgb); inc(px_dst_f); end; end; end; ie24RGB: begin // 48bit RGB ==> 24bit RGB for row := 0 to fHeight - 1 do begin px_src_48rgb := old.ScanLine[row]; px_dst_rgb := ScanLine[row]; for col := 0 to fWidth - 1 do begin with px_dst_rgb^ do begin r := px_src_48rgb^.r shr 8; g := px_src_48rgb^.g shr 8; b := px_src_48rgb^.b shr 8; end; inc(px_src_48rgb); inc(px_dst_rgb); end; end; end; ie32RGB: begin // 48bit RGB ==> 32bit RGB for row := 0 to fHeight - 1 do begin px_src_48rgb := old.ScanLine[row]; px_dst_rgb32 := ScanLine[row]; for col := 0 to fWidth - 1 do begin with px_dst_rgb32^ do begin r := px_src_48rgb^.r shr 8; g := px_src_48rgb^.g shr 8; b := px_src_48rgb^.b shr 8; a := 255; end; inc(px_src_48rgb); inc(px_dst_rgb32); end; end; end; end; ie32RGB: case fPixelFormat of ie1g: begin // ie32RGB ==> 1bit gray scale old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie8p: begin // ie32RGB ==> 8bit paletted old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie8g: begin // ie32RGB ==> 8bit gray scale old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie16g: begin // ie32RGB ==> 16bit gray scale old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie32f: begin // ie32RGB ==> 32bit floating point gray scale old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie24RGB: begin // ie32RGB ==> RGB24 for row := 0 to fHeight-1 do begin px_src := old.ScanLine[row]; px_dst := ScanLine[row]; for col := 0 to fWidth-1 do begin px_dst^ := px_src^; inc(px_dst); inc(px_src); px_dst^ := px_src^; inc(px_dst); inc(px_src); px_dst^ := px_src^; inc(px_dst); inc(px_src); inc(px_src); // bypass last byte end; end; end; ieCIELab: begin // ie32RGB ==> ieCIELab old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ieCMYK: begin // ie32RGB ==> CMYK old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; ie48RGB: begin // ie32RGB ==> 48 BIT RGB old.ConvertToPixelFormat(ie24RGB); // ie24RGB intermediate CopyAndConvertFormat(old); end; end; end; // end of src PixelFormat case end; // alpha channel if old.HasAlphaChannel then AlphaChannel.Assign(old.AlphaChannel); UpdateTBitmapPalette; // Do not call Changed(). CopyAndConvertFormat has many internal uses end; procedure IEConv24To8(SrcBitmap, DstBitmap: TBitmap); var x, y: integer; src: PRGB; dst: pbyte; width, height: integer; RedToGrayCoef, GreenToGrayCoef, BlueToGrayCoef: integer; begin RedToGrayCoef := IEGlobalSettings().RedToGrayCoef; GreenToGrayCoef := IEGlobalSettings().GreenToGrayCoef; BlueToGrayCoef := IEGlobalSettings().BlueToGrayCoef; width := SrcBitmap.Width; height := SrcBitmap.Height; DstBitmap.Width := 1; DstBitmap.Height := 1; DstBitmap.PixelFormat := pf8bit; DstBitmap.Width := width; DstBitmap.Height := height; IESetGrayPalette(DstBitmap); for y := 0 to height - 1 do begin src := SrcBitmap.ScanLine[y]; dst := DstBitmap.ScanLine[y]; for x := 0 to width - 1 do begin with src^ do dst^ := (r * RedToGrayCoef + g * GreenToGrayCoef + b * BlueToGrayCoef) div 100; inc(src); inc(dst); end; end; end; // if fLocation is ieTBitmap only ie1g and ie24RGB are supported procedure TIEBitmap.ConvertToPixelFormat(DestPixelFormat: TIEPixelFormat); var old: TIEBitmap; bold: TBitmap; NullProgress: TProgressRec; tmp: TIEBitmap; begin NullProgress := NullProgressRec( nil ); case fLocation of ieMemory, ieFile: begin old := TIEBitmap.Create(); try SwitchTo(old); fWidth := old.fWidth; fHeight := old.fHeight; fPixelFormat := DestPixelFormat; AllocateImage; if old.fPixelFormat <> ienull then CopyAndConvertFormat(old); finally FreeAndNil(old); end; end; ieTBitmap: begin if (fBitmap.Width<>0) and (fBitmap.Height<>0) then begin case fBitmap.PixelFormat of pf1bit: case DestPixelFormat of ie8g: // from pf1bit to ie8g begin fBitmap.PixelFormat := pf8bit; IESetGrayPalette(fBitmap); end; ie24RGB: // from pf1bit to ie24RGB begin bold := IECloneBitmap(fBitmap); try _Conv1To24(bold, fBitmap, NullProgress); finally FreeAndNil(bold); end; end; end; pf8bit: case DestPixelFormat of ie24RGB: // from pf8bit to ie24RGB begin fBitmap.PixelFormat := pf24bit; end; end; pf24bit: case DestPixelFormat of ie1g: // from pf24bit to ie1g begin tmp := TIEBitmap.Create(); try tmp.EncapsulateTBitmap(fBitmap, true); case fDefaultDitherMethod of ieOrdered: // use ordered conversion _ConvertToBWOrdered(tmp, NullProgress); ieThreshold: // use threshold conversion _ConvertToBWThreshold(tmp, -1, NullProgress); end; finally FreeAndNil(tmp); end; end; ie8g: // from pf24bit to ie8g begin bold := IECloneBitmap(fBitmap); try IEConv24To8(bold, fBitmap); finally FreeAndNil(bold); end; end; ie32RGB: // from pf24bit to ie32RGB begin fBitmap.PixelFormat := pf32bit; end; end; pf32bit: case DestPixelFormat of ie24RGB: // from pf32bit to ie24RGB begin fBitmap.PixelFormat := pf24bit; end; end; end; end else begin // empty bitmap case DestPixelFormat of ie1g: fBitmap.PixelFormat := pf1bit; ie24RGB: fBitmap.PixelFormat := pf24bit; end; end; fPixelFormat := DestPixelFormat; fBitCount := IEPixelFormat2BitCount(fPixelFormat); fChannelCount := IEPixelFormat2ChannelCount(fPixelFormat); fRowLen := IEBitmapRowLen(fWidth, fBitCount, fBitAlignment); BuildBitmapScanlines(); end; end; // Don't call Changed() as PixelConversion often occurs by necessity on Save end; {!! TIEBitmap.CopyToTBitmap Declaration procedure CopyToTBitmap(Dest: TBitmap); Description Copies the image to the Dest TBitmap object. These conversions are applied: ie1g -> pf1bit ie8p -> pf8bit ie8g -> pf8bit (create gray scale palette) ie16g -> pf8bit (copy only high 8 bit) ie24RGB -> pf24bit !!} procedure TIEBitmap.CopyToTBitmap(Dest: TBitmap); const UNSUPMSG = 'to TBitmap not supported'; var i, row, col, mi: integer; ppee: array[0..255] of TPALETTEENTRY; px_w: pword; px_b: pbyte; px_f: psingle; begin Dest.Width := 1; Dest.Height := 1; case fPixelFormat of ie1g: // gray scale (black/white) ==>> pf1bit begin Dest.PixelFormat := pf1bit; ppee[0].peRed := 0; ppee[0].peGreen := 0; ppee[0].peBlue := 0; ppee[0].peFlags := 0; ppee[1].peRed := 255; ppee[1].peGreen := 255; ppee[1].peBlue := 255; ppee[1].peFlags := 0; SetPaletteEntries(dest.palette, 0, 2, ppee); dest.Monochrome := true; end; ie8p: // color (palette) ==>> pf8bit begin Dest.PixelFormat := pf8bit; for i := 0 to 255 do begin ppee[i].peRed := fRGBPalette[i].r; ppee[i].peGreen := fRGBPalette[i].g; ppee[i].peBlue := fRGBPalette[i].b; ppee[i].peFlags := 0; end; SetPaletteEntries(dest.palette, 0, 256, ppee); end; ie8g: // gray scale (256 levels) ==>> pf8bit begin Dest.PixelFormat := pf8bit; for i := 0 to 255 do begin ppee[i].peRed := i; ppee[i].peGreen := i; ppee[i].peBlue := i; ppee[i].peFlags := 0; end; SetPaletteEntries(dest.palette, 0, 256, ppee); end; ie16g: // gray scale (65536 levels) ==>> pf8bit begin Dest.PixelFormat := pf8bit; for i := 0 to 255 do begin ppee[i].peRed := i; ppee[i].peGreen := i; ppee[i].peBlue := i; ppee[i].peFlags := 0; end; SetPaletteEntries(dest.palette, 0, 256, ppee); Dest.Width := fWidth; Dest.Height := fHeight; for row := 0 to fHeight - 1 do begin px_w := Scanline[row]; px_b := Dest.Scanline[row]; for col := 0 to fWidth - 1 do begin px_b^ := px_w^ shr 8; inc(px_b); inc(px_w); end; end; end; ie32f: // gray scale (32bit floating point) ==>> pf8bit begin Dest.PixelFormat := pf8bit; for i := 0 to 255 do begin ppee[i].peRed := i; ppee[i].peGreen := i; ppee[i].peBlue := i; ppee[i].peFlags := 0; end; SetPaletteEntries(dest.palette, 0, 256, ppee); Dest.Width := fWidth; Dest.Height := fHeight; for row := 0 to fHeight - 1 do begin px_f := Scanline[row]; px_b := Dest.Scanline[row]; for col := 0 to fWidth - 1 do begin px_b^ := trunc(px_f^ * 255); inc(px_b); inc(px_f); end; end; end; ie24RGB: // color (true color) ==>> pf24bit begin Dest.PixelFormat := pf24bit; end; ie32RGB: // color (true color) ==>> pf32bit begin Dest.PixelFormat := pf32bit; end; ieCMYK: // CMYK begin raise EIEException.Create('CMYK '+UNSUPMSG); end; ieCIELab: // CIELab begin raise EIEException.Create('CIELab '+UNSUPMSG); end; ie48RGB: // 48RGB begin raise EIEException.Create('RGB48 '+UNSUPMSG); end; end; if (fPixelFormat <> ie16g) and (fPixelFormat <> ie32f) then begin Dest.Width := fWidth; Dest.Height := fHeight; mi := imin(fRowLen, IEVCLPixelFormat2RowLen(Dest.Width, Dest.PixelFormat)); for row := 0 to fHeight - 1 do CopyMemory(Dest.Scanline[row], Scanline[row], mi); end; end; {!! TIEBitmap.CopyRectTo Declaration procedure CopyRectTo(Dest: ; SrcX, SrcY, DstX, DstY: integer; RectWidth, RectHeight: integer; CopyAlpha: boolean = false); Description Copies a rectangle to the Dest image. Parameter Description Dest Destination bitmap. Must have same as the source image SrcX Left source position SrcY Top source position DstX Left destination position. Can be negative (cut top-left rectangle and reduces size) DstY Top destination position RectWidth Width of rectangle to copy RectHeight Height of rectangle to copy CopyAlpha If true alpha channel is also copied (only if the source bitmap has an alpha channel)
!!} // also works with negative values for DstX, DstY (cut the top-left rectangle and reduce sizes) procedure TIEBitmap.CopyRectTo(Dest: TIEBitmap; SrcX, SrcY, DstX, DstY: integer; RectWidth, RectHeight: integer; CopyAlpha: boolean); var y, x, v: integer; ps, pd: pbyte; rgb: PRGB; begin if CopyAlpha and HasAlphaChannel then begin AlphaChannel.CopyRectTo(Dest.AlphaChannel, SrcX, SrcY, DstX, DstY, RectWidth, RectHeight, false); Dest.AlphaChannel.Full := Dest.AlphaChannel.Full and AlphaChannel.Full; // take care of previous state of Dest.AlphaChannel.Full end; // adjust DstX and DstY if DstX < 0 then begin inc(SrcX, -DstX); dec(RectWidth, -DstX); DstX := 0; end; if DstY < 0 then begin inc(SrcY, -DstY); dec(RectHeight, -DstY); DstY := 0; end; DstX := imin(DstX, Dest.Width - 1); DstY := imin(DstY, Dest.Height - 1); // adjust SrcX and SrcY SrcX := imin(imax(SrcX, 0), Width - 1); SrcY := imin(imax(SrcY, 0), Height - 1); // adjust rect size comparing with Source if SrcX + RectWidth > Width then RectWidth := Width - SrcX; if SrcY + RectHeight > Height then RectHeight := Height - SrcY; // adjust rect size comparing with Dest if DstX + RectWidth > Dest.Width then RectWidth := Dest.Width - DstX; if DstY + RectHeight > Dest.Height then RectHeight := Dest.Height - DstY; if assigned(fOnRenderVirtualPixel) and (Dest.PixelFormat = ie24RGB) then // do not use IsVirtual, because "same format" case will handle fVirtualBitmapProvider<>nil also begin // virtual bitmap (RGB), just an optimization to avoid using Scanline[] or GetSegment for y := 0 to RectHeight - 1 do begin rgb := Dest.Scanline[DstY + y]; inc(rgb, DstX); for x := SrcX to SrcX + RectWidth - 1 do begin fOnRenderVirtualPixel(self, x, SrcY + y, rgb^); inc(rgb); end; end; end else if (PixelFormat = ie1g) and (Dest.PixelFormat = ie1g) then begin // gray scale (black/white) for y := 0 to RectHeight - 1 do begin ps := Scanline[SrcY + y]; pd := Dest.Scanline[DstY + y]; IECopyBits_large(pd, ps, DstX, SrcX, RectWidth, Rowlen); end; end else if (PixelFormat = ie1g) and (dest.PixelFormat = ie24RGB) then begin // blackwhite to rgb for y := 0 to RectHeight - 1 do begin ps := Scanline[SrcY + y]; pd := Dest.Scanline[DstY + y]; inc(pd, DstX * 3); for x := SrcX to SrcX + RectWidth - 1 do begin v := ord(GetPixelbw_inline(ps, x) <> 0) * 255; pd^ := v; inc(pd); pd^ := v; inc(pd); pd^ := v; inc(pd); end; end; end else if (PixelFormat = Dest.PixelFormat) then begin // same format for y := 0 to RectHeight - 1 do begin ps := GetSegment(SrcY + y, SrcX, RectWidth); pd := Dest.GetSegment(DstY + y, DstX, RectWidth); CopyMemory(pd, ps, RectWidth * (fBitCount div 8)); end; end; Dest.Changed(); end; {!! TIEBitmap.CopyToClipboard Declaration function CopyToClipboard(IncludeImageEnFormat: Boolean = True; DpiX: Integer = 200; DpiY: Integer = 200): Boolean; Description Copy the image to the clipboard. If IncludeImageEnFormat is True, two bitmap are saved: one in standard DIB format and one in an "ImageEn" format which preserves the pixel format and alpha channel. Returns False if copying fails. Typically this only happens with very large images that exceed the available memory. See Also - - - !!} function TIEBitmap.CopyToClipboard(IncludeImageEnFormat: Boolean = True; DpiX: Integer = 200; DpiY: Integer = 200): Boolean; begin Result := _CopyBitmaptoClipboardEx( Self, True, IncludeImageEnFormat, 0, 0, 0, 0, nil, 0, nil, 0, // These will not be used DpiX, DpiY ); end; {!! TIEBitmap.PasteFromClipboard Declaration function PasteFromClipboard(): Boolean; Description Paste an image from the clipboard. Returns False if pasting fails, e.g. there is not an image found on the clipboard. See Also - - - !!} function TIEBitmap.PasteFromClipboard(): Boolean; var proc: TImageEnProc; begin proc := TImageEnProc.CreateFromBitmap( Self ); try Result := proc.PasteFromClipboard( iecpFullImage ); finally FreeAndNil( proc ); end; end; {!! TIEBitmap.MergeAlphaRectTo Declaration procedure MergeAlphaRectTo(Dest: ; SrcX, SrcY, DstX, DstY: integer; RectWidth, RectHeight: integer); Description This method copies the alpha channel to Dest bitmap alpha channel. !!} procedure TIEBitmap.MergeAlphaRectTo(Dest: TIEBitmap; SrcX, SrcY, DstX, DstY: integer; RectWidth, RectHeight: integer); var y, x: integer; ps, pd: pbyte; dst: TIEBitmap; begin dst := Dest.AlphaChannel; with AlphaChannel do begin if (PixelFormat<>ie8g) or (dst.PixelFormat<>ie8g) then exit; // adjust DstX and DstY if DstX < 0 then begin inc(SrcX, -DstX); dec(RectWidth, -DstX); DstX := 0; end; if DstY < 0 then begin inc(SrcY, -DstY); dec(RectHeight, -DstY); DstY := 0; end; DstX := imin(DstX, Dst.Width - 1); DstY := imin(DstY, Dst.Height - 1); // adjust SrcX and SrcY SrcX := imin(imax(SrcX, 0), Width - 1); SrcY := imin(imax(SrcY, 0), Height - 1); // adjust rect size comparing with Source if SrcX + RectWidth > Width then RectWidth := Width - SrcX; if SrcY + RectHeight > Height then RectHeight := Height - SrcY; // adjust rect size comparing with Dst if DstX + RectWidth > Dst.Width then RectWidth := Dst.Width - DstX; if DstY + RectHeight > Dst.Height then RectHeight := Dst.Height - DstY; // for y := 0 to RectHeight - 1 do begin ps := Scanline[SrcY + y]; pd := dst.Scanline[DstY + y]; inc(pd, DstX ); inc(ps, SrcX ); for x := SrcX to SrcX + RectWidth - 1 do begin pd^ := imax(ps^, pd^); inc(pd); inc(ps); end; end; end; Dest.Changed(); end; {!! TIEBitmap.CopyFromTBitmap Declaration procedure CopyFromTBitmap(Source: TBitmap); Description Copies the image from the Source TBitmap object. The source's TBitmap.PixelFormat allowed values are: pf1bit, pf4bit, pf8bit, pf15bit, pf16bit, pf24bit, pf32bit. If is ieTBitmap, then only pf1bit and pf24bit and pf32bit are accepted. !!} procedure TIEBitmap.CopyFromTBitmap(Source: TBitmap); var row, col, mi: integer; pxb1, pxb2: pbyte; pxw1: pword; pxrgb: PRGB; begin case fLocation of ieMemory, ieFile: begin case Source.PixelFormat of pf1bit: // pf1bit ==>> ie1g or ie8p begin if Source.Monochrome then begin // pf1bit to ie1g Allocate(Source.Width, Source.Height, ie1g); mi := imin(fRowLen, IEVCLPixelFormat2RowLen(Source.Width, Source.PixelFormat)); for row := 0 to fHeight - 1 do CopyMemory(Scanline[row], Source.Scanline[row], mi); end else begin // pf1bit to ie8p Allocate(Source.Width, Source.Height, ie8p); CopyPaletteFromTBitmap(Source, 2); for row := 0 to fHeight - 1 do begin pxb1 := Source.Scanline[row]; pxb2 := Scanline[row]; for col := 0 to fWidth - 1 do begin pxb2^ := ord(GetPixelbw_inline(pxb1, col) <> 0); inc(pxb2); end; end; end; end; pf4bit: // pf4bit ==>> ie8p begin Allocate(Source.Width, Source.Height, ie8p); CopyPaletteFromTBitmap(Source, 16); for row := 0 to fHeight - 1 do begin pxb1 := Source.Scanline[row]; pxb2 := Scanline[row]; for col := 0 to fWidth - 1 do begin if (col mod 2) = 0 then begin pxb2^ := (pxb1^ and $F0) shr 4; end else begin pxb2^ := pxb1^ and $0F; inc(pxb1); end; inc(pxb2); end; end; end; pf8bit: // pf8bit ==>> ie8p begin Allocate(Source.Width, Source.Height, ie8p); CopyPaletteFromTBitmap(Source, 256); mi := imin(fRowLen, IEVCLPixelFormat2RowLen(Source.Width, Source.PixelFormat)); for row := 0 to fHeight - 1 do CopyMemory(Scanline[row], Source.Scanline[row], mi); end; pf15bit: // pf15bit ==>> ie24RGB // 5 43210 98765 43210 // 0 rrrrr ggggg bbbbb // 0-31 0-31 0-31 begin Allocate(Source.Width, Source.Height, ie24RGB); for row := 0 to fHeight - 1 do begin pxw1 := Source.Scanline[row]; pxrgb := Scanline[row]; for col := 0 to fWidth - 1 do begin with pxrgb^ do begin r := ((pxw1^ and $7C00) shr 10) shl 3; g := ((pxw1^ and $03E0) shr 5) shl 3; b := (pxw1^ and $001F) shl 3; end; inc(pxw1); inc(pxrgb); end; end; end; pf16bit: // pf16bit ==>> ie24RGB // 54321 098765 43210 // rrrrr gggggg bbbbb // 0-31 0-63 0-31 begin Allocate(Source.Width, Source.Height, ie24RGB); for row := 0 to fHeight - 1 do begin pxw1 := Source.Scanline[row]; pxrgb := Scanline[row]; for col := 0 to fWidth - 1 do begin with pxrgb^ do begin r := ((pxw1^ and $F800) shr 11) shl 3; g := ((pxw1^ and $07E0) shr 5) shl 2; b := (pxw1^ and $001F) shl 3; end; inc(pxw1); inc(pxrgb); end; end; end; pf24bit: begin // pf24bit ==>> ie24RGB Allocate(Source.Width, Source.Height, ie24RGB); mi := imin(fRowLen, IEVCLPixelFormat2RowLen(Source.Width, Source.PixelFormat)); for row := 0 to fHeight - 1 do CopyMemory(Scanline[row], Source.Scanline[row], mi); end; pf32bit: begin // pf32bit ==>> ie32RGB Allocate(Source.Width, Source.Height, ie32RGB); mi := imin(fRowLen, IEVCLPixelFormat2RowLen(Source.Width, Source.PixelFormat)); for row := 0 to fHeight - 1 do CopyMemory(Scanline[row], Source.Scanline[row], mi); end; end; fFull := false; end; ieTBitmap: begin if fBitmap = nil then fBitmap := TBitmap.Create; if (Source.PixelFormat<>pf1bit) and (Source.PixelFormat<>pf24bit) and (Source.PixelFormat<>pf32bit) then Source.PixelFormat := pf24bit; // 3.0.1 IECopyBitmap(Source, fBitmap); fWidth := fBitmap.Width; fHeight := fBitmap.Height; case fBitmap.PixelFormat of pf1bit: fPixelFormat := ie1g; pf24bit: fPixelFormat := ie24RGB; pf32bit: fPixelFormat := ie32RGB; end; fBitCount := IEPixelFormat2BitCount(fPixelFormat); fChannelCount := IEPixelFormat2ChannelCount(fPixelFormat); fRowLen := IEBitmapRowLen(fWidth, fBitCount, fBitAlignment); BuildBitmapScanlines; end; end; // end case Changed(); end; {!! TIEBitmap.CopyFromTIEMask Declaration procedure CopyFromTIEMask(Source: ); Description Copies the image from a object. If Source is nil then fills the bitmap with all 255. !!} procedure TIEBitmap.CopyFromTIEMask(Source: TIEMask); var row, mi: integer; begin if assigned(Source) then begin case Source.BitsPerPixel of 1: begin Allocate(Source.Width, Source.Height, ie1g); mi := imin(fRowLen, Source.RowLen); for row := 0 to fHeight - 1 do CopyMemory(Scanline[row], Source.Scanline[row], mi); fFull := Source.fFull; end; 8: begin Allocate(Source.Width, Source.Height, ie8g); mi := imin(fRowLen, Source.RowLen); for row := 0 to fHeight - 1 do CopyMemory(Scanline[row], Source.Scanline[row], mi); fFull := Source.fFull; end; end; end else self.Fill(255); Changed(); end; {!! TIEBitmap.CopyFromTDibBitmap Declaration procedure CopyFromTDibBitmap(Source: ); Description Copies the image from a object. !!} procedure TIEBitmap.CopyFromTDibBitmap(Source: TIEDibBitmap); var row, mi: integer; begin if assigned(Source) then begin if fLocation = ieTBitmap then begin fWidth := Source.Width; fHeight := Source.Height; if fBitmap = nil then fBitmap := TBitmap.Create; case Source.BitCount of 1: begin fPixelFormat := ie1g; fBitmap.Width := 1; fBitmap.Height := 1; fBitmap.PixelFormat := pf1bit; end; 24: begin fPixelFormat := ie24RGB; fBitmap.Width := 1; fBitmap.Height := 1; fBitmap.PixelFormat := pf24bit; end; end; fBitmap.Width := fWidth; fBitmap.Height := fHeight; fBitCount := IEPixelFormat2BitCount(fPixelFormat); fChannelCount := IEPixelFormat2ChannelCount(fPixelFormat); fRowLen := IEBitmapRowLen(fWidth, fBitCount, fBitAlignment); BuildBitmapScanlines; end else begin case Source.BitCount of 1: Allocate(Source.Width, Source.Height, ie1g); 8: Allocate(Source.Width, Source.Height, ie8g); // don't copy palette (useful only when source is an alpha channel) 24: Allocate(Source.Width, Source.Height, ie24RGB); end; end; mi := imin(fRowLen, Source.RowLen); for row := 0 to fHeight - 1 do CopyMemory(Scanline[row], Source.Scanline[row], mi); end; Changed(); end; {!! TIEBitmap.CopyFromDIB Declaration procedure CopyFromDIB(Source: THandle); overload; procedure CopyFromDIB(BitmapInfo: pointer; Pixels: pointer = nil); overload; Description Copies from the specified DIB handle. The second overload copies from a DIB composed by a BitmapInfo structure and pixels buffer pointer. When Pixels is null, pixels are supposed to stay just after BitmapInfo structure. Note: if = True, then the DPI is returned in . and . Example IEBmp :=TIEBitmap.create; IEBmp.ParamsEnabled := true; // So we can get the DPI IEBmp.CopyFromDIB( HDib ); // Copy from HDIB passed by scanner lblDPI.caption := IntToStr( IEBmp.Params.DpiX ); ImageEnView1.IEBitmap.assign( IEBmp ); IEBmp.Free; !!} procedure TIEBitmap.CopyFromDIB(Source: THandle); begin _CopyDIB2BitmapEx(Source, self, nil, false); Changed(); end; procedure TIEBitmap.CopyFromDIB(BitmapInfo: pointer; Pixels: pointer=nil); begin _CopyDIB2BitmapEx(THandle(BitmapInfo), self, Pixels, true); Changed(); end; {!! TIEBitmap.CreateDIB Declaration function CreateDIB: THandle; function CreateDIB(x1, y1, x2, y2: integer): THandle; Description Creates a DIB from current image. You are responsible to free memory (calling GlobalFree). The second overload creates a DIB from specified rectangle of current image. !!} function TIEBitmap.CreateDIB: THandle; begin if ParamsEnabled then result := _CopyBitmaptoDIBEx(self, 0, 0, 0, 0, Params.DPIX, Params.DPIY) else result := _CopyBitmaptoDIBEx(self, 0, 0, 0, 0, IEGlobalSettings().DefaultDPIX, IEGlobalSettings().DefaultDPIY); end; function TIEBitmap.CreateDIB(x1, y1, x2, y2: integer): THandle; begin if ParamsEnabled then result := _CopyBitmaptoDIBEx(self, x1, y1, x2, y2, Params.DPIX, Params.DPIY) else result := _CopyBitmaptoDIBEx(self, x1, y1, x2, y2, IEGlobalSettings().DefaultDPIX, IEGlobalSettings().DefaultDPIY); end; {!! TIEBitmap.MergeFromTDibBitmap Declaration procedure MergeFromTDibBitmap(Source: ; x, y: integer); Description Copies the image from a object, placing it at the specified coordinates. The original image is not destroyed. The source and must be both 1 bit or both 24 bit !!} // procedure TIEBitmap.MergeFromTDibBitmap(Source: TIEDibBitmap; x, y: integer); var ww, hh, row: integer; ps, pd: pbyte; begin if assigned(Source) then begin ww := imin(Source.Width, fWidth - x); hh := imin(Source.Height, fHeight - y); case Source.BitCount of 1: begin for row := 0 to hh - 1 do begin ps := Source.Scanline[row]; pd := Scanline[row + y]; IECopyBits_large(pd, ps, x, 0, ww, Source.Rowlen); end; end; 24: begin for row := 0 to hh - 1 do begin ps := Source.Scanline[row]; pd := Scanline[row + y]; inc(pd, x * 3); copymemory(pd, ps, ww * 3); end; end; end; Changed(); end; end; {!! TIEBitmap.CopyToTDibBitmap Declaration procedure CopyToTDibBitmap(Dest: ; source_x, source_y, sourceWidth, sourceHeight: integer); Description Copies specified source rectangle inside Dest (at top-left side). The destination and must both be 1 bit or both 24 bit. !!} procedure TIEBitmap.CopyToTDibBitmap(Dest: TIEDibBitmap; source_x, source_y, sourceWidth, sourceHeight: integer); var ww, hh, row: integer; ps, pd: pbyte; begin ww := imin(Dest.Width, sourceWidth); hh := imin(Dest.Height, sourceHeight); case Dest.BitCount of 1: begin for row := 0 to hh - 1 do begin ps := Scanline[row + source_y]; pd := Dest.Scanline[row]; IECopyBits_large(pd, ps, 0, source_x, ww, RowLen); end; end; 24: begin for row := 0 to hh - 1 do begin ps := GetSegment(row + source_y, source_x, ww); pd := Dest.Scanline[row]; CopyMemory(pd, ps, ww * 3); end; end; end; end; {!! TIEBitmap.CopyToTIEMask Declaration procedure CopyToTIEMask(Dest: ); Description Copies the image to a object. It works only with ie1g and ie8g pixelformats. ie24RGB is converted to ie8g. !!} procedure TIEBitmap.CopyToTIEMask(Dest: TIEMask); var row, mi, col: integer; pxrgb: PRGB; pxb: pbyte; RedToGrayCoef, GreenToGrayCoef, BlueToGrayCoef: integer; begin case PixelFormat of ie1g: begin Dest.AllocateBits(fWidth, fHeight, 1); mi := imin(fRowLen, Dest.RowLen); for row := 0 to fHeight - 1 do CopyMemory(Dest.Scanline[row], Scanline[row], mi); Dest.fFull := fFull; end; ie8g: begin Dest.AllocateBits(fWidth, fHeight, 8); mi := imin(fRowLen, Dest.RowLen); for row := 0 to fHeight - 1 do CopyMemory(Dest.Scanline[row], Scanline[row], mi); Dest.fFull := fFull; end; ie24RGB: begin RedToGrayCoef := IEGlobalSettings().RedToGrayCoef; GreenToGrayCoef := IEGlobalSettings().GreenToGrayCoef; BlueToGrayCoef := IEGlobalSettings().BlueToGrayCoef; Dest.AllocateBits(fWidth, fHeight, 8); for row := 0 to fHeight-1 do begin pxrgb := Scanline[row]; pxb := Dest.Scanline[row]; for col := 0 to fWidth-1 do begin with pxrgb^ do pxb^ := ((r * RedToGrayCoef + g * GreenToGrayCoef + b * BlueToGrayCoef) div 100) shr 2; inc(pxrgb); inc(pxb); end; end; end; end; end; function TIEBitmap.GetPalette(index: integer): TRGB; begin if (index < fRGBPaletteLen) and (index >= 0) then result := fRGBPalette[index]; end; function TIEBitmap.GetPaletteBuffer: pointer; begin result := fRGBPalette; end; procedure TIEBitmap.SetPalette(index: integer; Value: TRGB); begin if (index < fRGBPaletteLen) and (index >= 0) then begin fRGBPalette[index] := Value; UpdateTBitmapPalette; Changed(); end; end; function TIEBitmap.GetPaletteLen: integer; begin result := fRGBPaletteLen; end; function TIEBitmap.GetPaletteUsed(): integer; begin result := fPaletteUsed; end; procedure TIEBitmap.SetPaletteUsed(Value: integer); begin fPaletteUsed := Value; end; function TIEBitmap.GetPixels_ie1g(x, y: integer): boolean; begin result := (pbytearray(Scanline[y])^[x shr 3] and iebitmask1[x and $7]) <> 0; end; {!! TIEBitmap.Pixels_ie1g Declaration property Pixels_ie1g[x, y: integer]: boolean; Description Specifies a pixel value for black/white images (ie1g pixelformat). False is black, True is white. Note: This function doesn't perform a range check test. !!} procedure TIEBitmap.SetPixels_ie1g(x, y: integer; Value: boolean); begin SetPixelbw_inline(Scanline[y], x, ord(Value)); if not Value then fFull := false; end; function TIEBitmap.GetPixels_ie8(x, y: integer): byte; begin if assigned(fOnRenderVirtualPixel) then fOnRenderVirtualPixel(self, x, y, result) else result := pbyte(GetSegment(y, x, 1))^; end; {!! TIEBitmap.Pixels_ie8 Declaration property Pixels_ie8[x, y: integer]: byte; Description Specifies a pixel value for palette or gray scale images (ie8p or ie8p pixelformat). Note: This function doesn't perform a range check test. !!} procedure TIEBitmap.SetPixels_ie8(x, y: integer; Value: byte); begin pbytearray(Scanline[y])^[x] := Value; if Value < 255 then fFull := false; end; function TIEBitmap.GetPixels_ie16g(x, y: integer): word; begin result := PWord(GetSegment(y, x, 1))^ end; {!! TIEBitmap.Pixels_ie16g Declaration property Pixels_ie16g[x, y: integer]: word; Description Specifies a pixel value for 16 bit gray scale images (ie16g pixelformat). Note: This function doesn't perform a range check test. !!} procedure TIEBitmap.SetPixels_ie16g(x, y: integer; Value: word); begin pwordarray(Scanline[y])^[x] := Value; if Value < 65535 then fFull := false; end; function TIEBitmap.GetPixels_ie32f(x, y: integer): single; begin result := PSingle(GetSegment(y, x, 1))^; end; {!! TIEBitmap.Pixels_ie32f Declaration property Pixels_ie32f[x, y: integer]: single; Description Specifies a pixel value for 32 bit floating point value (single) for gray scale images (ie32f pixelformat). Note: This function doesn't perform a range check test. !!} procedure TIEBitmap.SetPixels_ie32f(x, y: integer; Value: single); begin psinglearray(Scanline[y])^[x] := Value; if Value < 1 then fFull := false; end; function TIEBitmap.GetPixels_ieCMYK(x, y: integer): TCMYK; begin result := PCMYK(GetSegment(y, x, 1))^; end; {!! TIEBitmap.Pixels_ieCMYK Declaration property Pixels_ieCMYK[x, y: integer]: ; Description Specifies a pixel value for CMYK true color images (ieCMYK pixelformat). Note: This function doesn't perform a range check test. !!} procedure TIEBitmap.SetPixels_ieCMYK(x, y: integer; Value: TCMYK); begin PCMYKROW(Scanline[y])^[x] := Value; end; function TIEBitmap.GetPixels_ieCIELab(x, y: integer): TCIELab; begin result := PCIELAB(GetSegment(y, x, 1))^; end; {!! TIEBitmap.Pixels_ieCIELab Declaration property Pixels_ieCIELab[x, y: integer]: Description Specifies a pixel value for CIELab color space (ieCIELab pixelformat). Note: This function doesn't perform a range check test. !!} procedure TIEBitmap.SetPixels_ieCIELab(x, y: integer; Value: TCIELab); begin PCIELABROW(Scanline[y])^[x] := Value; end; function TIEBitmap.GetPixels_ie24RGB(x, y: integer): TRGB; begin result := PRGB(GetSegment(y, x, 1))^; end; function TIEBitmap.GetPixels_ie32RGB(x, y: integer): TRGBA; begin result := PRGBA(GetSegment(y, x, 1))^; end; {!! TIEBitmap.PPixels_ie24RGB Declaration property PPixels_ie24RGB[x, y: integer]: ; Description Returns a pointer to specified pixel. Note: This function doesn't perform a range check test. !!} function TIEBitmap.GetPPixels_ie24RGB(x, y: integer): PRGB; begin result := @(PRGBROW(Scanline[y])^[x]); end; {!! TIEBitmap.PPixels_ie32RGB Declaration property PPixels_ie32RGB[x, y: integer]: ; Description Returns a pointer to specified pixel. Note: This function doesn't perform a range check test. !!} function TIEBitmap.GetPPixels_ie32RGB(x, y: integer): PRGBA; begin result := @(PRGB32ROW(Scanline[y])^[x]); end; {!! TIEBitmap.PPixels_ie48RGB Declaration property PPixels_ie48RGB[x, y: integer]: ; Description Returns a pointer to specified pixel. Note: This function doesn't perform a range check test. !!} function TIEBitmap.GetPixels_ie48RGB(x, y: integer): TRGB48; begin result := PRGB48ROW(Scanline[y])^[x]; end; function TIEBitmap.GetPPixels_ie48RGB(x, y: integer): PRGB48; begin result := @(PRGB48ROW(Scanline[y])^[x]); end; {!! TIEBitmap.Pixels Declaration property Pixels[x, y: integer]: ; Description Return the RGB value for the specified pixel. For black/white images it can be (0, 0, 0) or (255, 255, 255). Note: This function doesn't perform a range check test. See Also - - - !!} function TIEBitmap.GetPixels(x, y: integer): TRGB; begin case fPixelFormat of ie1g: if (pbytearray(Scanline[y])^[x shr 3] and iebitmask1[x and $7]) = 0 then with result do begin r := 0; g := 0; b := 0; end else with result do begin r := 255; g := 255; b := 255; end; ie8p: result := fRGBPalette[pbytearray(Scanline[y])^[x]]; ie8g: with result do begin r := pbytearray(Scanline[y])^[x]; g := r; b := r; end; ie16g: with result do begin r := pwordarray(Scanline[y])^[x] shr 8; g := pwordarray(Scanline[y])^[x] shr 8; b := pwordarray(Scanline[y])^[x] shr 8; end; ie32f: with result do begin r := trunc(psinglearray(Scanline[y])^[x] * 255); g := trunc(psinglearray(Scanline[y])^[x] * 255); b := trunc(psinglearray(Scanline[y])^[x] * 255); end; ie24RGB: result := PRGB(GetSegment(y, x, 1))^; ie32RGB: result := PRGB(@PRGB32ROW(Scanline[y])^[x])^; ieCMYK: result := IECMYK2RGB(PCMYKROW(Scanline[y])^[x]); ieCIELab: result := IECIELAB2RGB(PCIELABROW(Scanline[y])^[x]); ie48RGB: with result do begin r := PRGB48ROW(Scanline[y])^[x].r shr 8; g := PRGB48ROW(Scanline[y])^[x].g shr 8; b := PRGB48ROW(Scanline[y])^[x].b shr 8; end; else result := CreateRGB(0, 0, 0); end; end; procedure TIEBitmap.SetPixels(x, y: integer; value: TRGB); begin case fPixelFormat of ie1g: if (value.r=0) and (value.g=0) and (value.b=0) then SetPixelbw_inline(Scanline[y], x, 0) else SetPixelbw_inline(Scanline[y], x, 1); // ie8p: not implemented ie8g: Pixels_ie8[x, y] := (value.r * IEGlobalSettings().RedToGrayCoef + value.g * IEGlobalSettings().GreenToGrayCoef + value.b * IEGlobalSettings().BlueToGrayCoef) div 100; ie16g: Pixels_ie16g[x, y] := (value.r * IEGlobalSettings().RedToGrayCoef + value.g * IEGlobalSettings().GreenToGrayCoef + value.b * IEGlobalSettings().BlueToGrayCoef) div 100 * 257; ie32f: Pixels_ie32f[x, y] := (value.r * IEGlobalSettings().RedToGrayCoef + value.g * IEGlobalSettings().GreenToGrayCoef + value.b * IEGlobalSettings().BlueToGrayCoef) div 100 / 255; ie24RGB: Pixels_ie24RGB[x, y] := value; ie32RGB: Pixels_ie32RGB[x, y] := CreateRGBA(value.r, value.g, value.b, 255); ieCMYK: Pixels_ieCMYK[x, y] := IERGB2CMYK(value); ieCIELab: Pixels_ieCIELab[x, y] := IERGB2CIELab(value); ie48RGB: Pixels_ie48RGB[x, y] := CreateRGB48(value.r*257, value.g*257, value.b*257); end; end; {!! TIEBitmap.Pixels_ie24RGB Declaration property Pixels_ie24RGB[x, y: integer]: ; Description Specifies a pixel value for true color images (ie24RGB pixelformat). Note: This function doesn't perform a range check test. See Also - - - !!} procedure TIEBitmap.SetPixels_ie24RGB(x, y: integer; Value: TRGB); begin PRGBROW(Scanline[y])^[x] := Value; with Value do if (r < 255) or (g < 255) or (b < 255) then fFull := false; end; {!! TIEBitmap.Pixels_ie32RGB Declaration property Pixels_ie32RGB[x, y: integer]: ; Description Specifies a pixel value for true color images (ie32RGB pixelformat). Note: This function doesn't perform a range check test. !!} procedure TIEBitmap.SetPixels_ie32RGB(x, y: integer; Value: TRGBA); begin PRGB32ROW(Scanline[y])^[x] := Value; with Value do if (r < 255) or (g < 255) or (b < 255) then fFull := false; end; {!! TIEBitmap.Pixels_ie48RGB Declaration property Pixels_ie48RGB[x, y: integer]: Description Specifies a pixel value for true color 48 bit images (ie48RGB pixelformat). Note: This function doesn't perform a range check test. !!} procedure TIEBitmap.SetPixels_ie48RGB(x, y: integer; Value: TRGB48); begin PRGB48ROW(Scanline[y])^[x] := Value; with Value do if (r < 65535) or (g < 65535) or (b < 65535) then fFull := false; end; function TIEBitmap.GetAlpha(x, y: integer): byte; begin if fIsAlpha then result := GetPixels_ie8(x, y) else result := GetAlphaChannel.GetPixels_ie8(x, y); // use GetAlphaChannel instead of fAlphaChannel to create it on the fly end; {!! TIEBitmap.Alpha Declaration property Alpha[x, y: integer]: byte; Description Specifies the alpha value of a pixel. 0 is transparent, 255 is opaque, 1 - 254 are partially transparent. Note: This function doesn't perform a range check test. !!} procedure TIEBitmap.SetAlpha(x, y: integer; Value: byte); begin if fIsAlpha then SetPixels_ie8(x, y, Value) else GetAlphaChannel.SetPixels_ie8(x, y, Value); // use GetAlphaChannel instead of fAlphaChannel to create it on the fly if Value < 255 then fFull := false; Changed(); end; {!! TIEBitmap.Fill Declaration procedure Fill(Value: double); procedure Fill(Value: TRGBA); Description Fills the image with a specified value. For ie1g images, Value can be 0 or 1. For ie8g and ie8p, it can be from 0 to 255. For ie16g images, it can be from 0 to 65535. For ie24RGB, ie32RGB, ieCMYK and ieCIELab Value is a TColor value. Example // Fill an image with white IEBitmap.Fill( clWhite ); // Set image as fully transparent IEBitmap.AlphaChannel.Fill( 0 ); !!} procedure TIEBitmap.Fill(Value: double); var row, col, iValue: integer; pxw: pword; pxrgb: PRGB; pxrgb48: PRGB48; pxrgba: PRGBA; vrgb: TRGB; vrgb48: TRGB48; vrgba: TRGBA; pxf: psingle; pxcmyk: PCMYK; cmyk: TCMYK; pxcielab: PCIELab; cielab: TCIELab; bytearr: array of byte; laccess: TIEDataAccess; begin laccess := Access; Access := [iedWrite]; ivalue := trunc(Value); case fPixelFormat of ie1g: begin if iValue <> 0 then iValue := 255; for row := 0 to fHeight - 1 do fillchar(pbyte(Scanline[row])^, fRowLen, iValue); fFull := (iValue <> 0); end; ie8p, ie8g: begin // 3.0.1 for row := 0 to fHeight - 1 do fillchar(pbyte(Scanline[row])^, fRowLen, iValue); fFull := (iValue = 255); end; ie16g: begin for row := 0 to fHeight - 1 do begin pxw := Scanline[row]; for col := 0 to fWidth - 1 do begin pxw^ := iValue; inc(pxw); end; end; fFull := (iValue = 65535); end; ie32f: begin for row := 0 to fHeight - 1 do begin pxf := Scanline[row]; for col := 0 to fWidth - 1 do begin pxf^ := Value; inc(pxf); end; end; fFull := (Value = 1); end; ie24RGB: begin vrgb := TColor2TRGB(TColor(iValue)); if fHeight>0 then begin SetLength(bytearr, fRowlen); pxrgb := PRGB(@bytearr[0]); for col := 0 to fWidth - 1 do begin pxrgb^ := vrgb; inc(pxrgb); end; for row := 0 to fHeight-1 do CopyMemory(Scanline[row], @bytearr[0], fRowLen); end; with vrgb do fFull := (r = 255) and (g = 255) and (b = 255); end; ie32RGB: begin // iValue cannot contains alpha (otherwise we cannot accept colors like clRed) vrgba := TColor2TRGBA(TColor(iValue)); if fHeight > 0 then begin for row := 0 to fHeight - 1 do begin pxrgba := Scanline[row]; for col := 0 to fWidth - 1 do begin pxrgba^ := vrgba; inc(pxrgba); end; end; end; with vrgba do fFull := (r = 255) and (g = 255) and (b = 255); end; ieCMYK: begin cmyk := IERGB2CMYK(TColor2TRGB(TColor(iValue))); for row := 0 to fHeight - 1 do begin pxcmyk := Scanline[row]; for col := 0 to fWidth - 1 do begin pxcmyk^ := cmyk; inc(pxcmyk); end; end; with vrgb do fFull := (r = 255) and (g = 255) and (b = 255); end; ieCIELab: begin cielab := IERGB2CIELAB(TColor2TRGB(TColor(iValue))); for row := 0 to fHeight - 1 do begin pxcielab := Scanline[row]; for col := 0 to fWidth - 1 do begin pxcielab^ := cielab; inc(pxcielab); end; end; with vrgb do fFull := (r = 255) and (g = 255) and (b = 255); end; ie48RGB: begin vrgb := TColor2TRGB(TColor(iValue)); vrgb48.r := vrgb.r *257; vrgb48.g := vrgb.g *257; vrgb48.b := vrgb.b *257; for row := 0 to fHeight - 1 do begin pxrgb48 := Scanline[row]; for col := 0 to fWidth - 1 do begin pxrgb48^ := vrgb48; inc(pxrgb48); end; end; with vrgb do fFull := (r = 255) and (g = 255) and (b = 255); end; end; Access := laccess; Changed(); end; procedure TIEBitmap.Fill(Value: TRGBA); var row, col: integer; pxrgba: PRGBA; vrgba: TRGBA; laccess: TIEDataAccess; begin laccess := Access; Access := [iedWrite]; if fPixelFormat = ie32RGB then begin if fHeight > 0 then begin for row := 0 to fHeight - 1 do begin pxrgba := Scanline[row]; for col := 0 to fWidth - 1 do begin pxrgba^ := Value; inc(pxrgba); end; end; end; with vrgba do fFull := (r = 255) and (g = 255) and (b = 255); Changed(); end else Fill(RGB2TColor(Value.r, Value.g, Value.b)); AlphaChannel.Fill(Value.a); Access := laccess; end; {!! TIEBitmap.FillRect Declaration procedure FillRect(x1, y1, x2, y2: integer; Value: double); Description Fills the rectangle with a specified value. For ie1g images, Value can be 0 or 1. For ie8g and ie8p, it can be from 0 to 255. For ie16g images, it can be from 0 to 65535. For ie24RGB, ie32RGB, ieCMYK and ieCIELab Value is a TColor value. !!} procedure TIEBitmap.FillRect(x1, y1, x2, y2: integer; Value: double); var row, col, iValue: integer; pxb: pbyte; pxw: pword; pxrgb: PRGB; pxrgb48: PRGB48; vrgb: TRGB; vrgb48: TRGB48; pxf: psingle; cmyk: TCMYK; pxcmyk: PCMYK; cielab: TCIELab; pxcielab: PCIELab; ww: integer; begin x1 := imax(x1, 0); y1 := imax(y1, 0); x2 := imin(x2, fWidth - 1); y2 := imin(y2, fHeight - 1); ww := x2 - x1 + 1; iValue := trunc(Value); case fPixelFormat of ie1g: for row := y1 to y2 do begin pxb := Scanline[row]; for col := x1 to x2 do SetPixelbw_inline(pxb, col, iValue); end; ie8p, ie8g: begin for row := y1 to y2 do begin pxb := GetSegment(row, x1, ww); fillchar(pxb^, ww, iValue); end; if fIsAlpha then SyncFull(); end; ie16g: begin for row := y1 to y2 do begin pxw := GetSegment(row, x1, ww); for col := x1 to x2 do begin pxw^ := iValue; inc(pxw); end; end; end; ie32f: begin for row := y1 to y2 do begin pxf := GetSegment(row, x1, ww); for col := x1 to x2 do begin pxf^ := iValue; inc(pxf); end; end; end; ie24RGB: begin vrgb := TColor2TRGB(TColor(iValue)); for row := y1 to y2 do begin pxrgb := GetSegment(row, x1, ww); for col := x1 to x2 do begin pxrgb^ := vrgb; inc(pxrgb); end; end; end; ie32RGB: begin vrgb := TColor2TRGB(TColor(iValue)); for row := y1 to y2 do begin pxb := GetSegment(row, x1, ww); for col := x1 to x2 do begin pxb^ := vrgb.b; inc(pxb); pxb^ := vrgb.g; inc(pxb); pxb^ := vrgb.r; inc(pxb); inc(pxb); // bypass end; end; end; ieCMYK: begin cmyk := IERGB2CMYK(TColor2TRGB(TColor(iValue))); for row := y1 to y2 do begin pxcmyk := GetSegment(row, x1, ww); for col := x1 to x2 do begin pxcmyk^ := cmyk; inc(pxcmyk); end; end; end; ieCIELab: begin cielab := IERGB2CIELAB(TColor2TRGB(TColor(iValue))); for row := y1 to y2 do begin pxcielab := GetSegment(row, x1, ww); for col := x1 to x2 do begin pxcielab^ := cielab; inc(pxcielab); end; end; end; ie48RGB: begin vrgb := TColor2TRGB(TColor(iValue)); vrgb48.r := vrgb.r * 257; vrgb48.g := vrgb.g * 257; vrgb48.b := vrgb.b * 257; for row := y1 to y2 do begin pxrgb48 := GetSegment(row, x1, ww); for col := x1 to x2 do begin pxrgb48^ := vrgb48; inc(pxrgb48); end; end; end; end; Changed(); end; {!! TIEBitmap.Location Declaration property Location: ; Description Specifies how the image is stored (e.g. in memory). Example // Optimize TImageEnView to handle very large images ImageEnView1.LegacyBitmap := False; ImageEnView1.IEBitmap.Location := ieFile; Default: ieMemory if sufficient memory is available, otherwise ieFile See Also - !!} procedure TIEBitmap.SetLocation(Value: TIELocation); var old: TIEBitmap; row, i: integer; mi: integer; begin if (fLocation <> Value) and not IsVirtual then begin fFullReallocate := true; old := TIEBitmap.Create; SwitchTo(old); fLocation := Value; Allocate(old.fWidth, old.fHeight, old.fPixelFormat); if old.Location = fLocation then begin // failed to change location, maintain old bitmap old.SwitchTo(self); old.Free; end else begin // changed location, copy data mi := imin(fRowLen, old.RowLen); for row := 0 to fHeight - 1 do CopyMemory(Scanline[row], old.Scanline[row], mi); for i := 0 to fRGBPaletteLen - 1 do fRGBPalette[i] := old.fRGBPalette[i]; UpdateTBitmapPalette; fIsAlpha := old.fIsAlpha; fAlphaChannel := old.fAlphaChannel; old.fAlphaChannel := nil; FreeAndNil(old); end; end; end; procedure TIEBitmap.UpdateTBitmapPalette; var i: integer; ppee: array [0..255] of TPALETTEENTRY; rgbQuad: array [0..255] of TRGBQUAD; begin if fLocation = ieTBitmap then begin if fRGBPaletteLen > 0 then begin for i := 0 to fRGBPaletteLen - 1 do begin ppee[i].peRed := fRGBPalette[i].r; ppee[i].peGreen := fRGBPalette[i].g; ppee[i].peBlue := fRGBPalette[i].b; ppee[i].peFlags := 0; rgbQuad[i].rgbRed := ppee[i].peRed; rgbQuad[i].rgbGreen := ppee[i].peGreen; rgbQuad[i].rgbBlue := ppee[i].peBlue; rgbQuad[i].rgbReserved := 0; end; SetPaletteEntries(fBitmap.palette, 0, fRGBPaletteLen, ppee); SetDIBColorTable(fBitmap.Canvas.Handle, 0, fRGBPaletteLen, rgbQuad); end; Changed(); end; end; procedure TIEBitmap.CopyPaletteFromTBitmap(source: TBitmap; colors: integer); var j: integer; ppee: array[0..255] of TPALETTEENTRY; begin if (fRGBPalette = nil) then begin getmem(fRGBPalette, sizeof(TRGB) * 256); fRGBPaletteLen := 256; end; ZeroMemory(@(ppee[0]), sizeof(TPALETTEENTRY) * colors); GetPaletteEntries(Source.Palette, 0, colors, ppee); for j := 0 to colors - 1 do begin fRGBPalette[j].r := ppee[j].peRed; fRGBPalette[j].g := ppee[j].peGreen; fRGBPalette[j].b := ppee[j].peBlue; end; Changed(); end; procedure TIEBitmap.AdjustCanvasOrientation; var xform: TagXForm; begin if fOrigin = ieboTOPLEFT then begin // set world transform to draw correctly y-axis SetGraphicsMode(fBitmap.Canvas.Handle, GM_ADVANCED); xform.eM11 := 1.0; xform.eM12 := 0; xform.eM21 := 0; xform.eM22 := -1.0; xform.eDx := 0; xform.eDy := fHeight-1; SetWorldTransform(fBitmap.Canvas.Handle, xform); Changed(); end else if assigned(fBitmap) and (GetGraphicsMode(fBitmap.Canvas.Handle) = GM_ADVANCED) then begin // restore world transform to draw correctly y-axis. GM_ADVANCED means that world transform may be changed FillChar(xform, sizeof(TagXForm), 0); ModifyWorldTransform(fBitmap.Canvas.Handle, xform, MWT_IDENTITY); Changed(); end; end; {!! TIEBitmap.Canvas Declaration property Canvas: TCanvas; Description Returns the canvas when is ieTBitmap. Note: If you access the Canvas property the is automatically converted to ieTBitmap. !!} function TIEBitmap.GetCanvas: TCanvas; begin if (fLocation = ieFile) or (fLocation = ieMemory) then begin // TBitmap requires a pixel format to get a canvas if fPixelFormat = ienull then SetPixelFormat(ie24RGB); SetLocation(ieTBitmap); end; AdjustCanvasOrientation; result := fBitmap.Canvas; end; {!! TIEBitmap.IECanvas Declaration property IECanvas: ; Description Returns the IECanvas when is ieTBitmap. Note: If you access the IECanvas property the is automatically converted to ieTBitmap. !!} function TIEBitmap.GetIECanvas: TIECanvas; begin if fIECanvas = nil then fIECanvas := TIECanvas.Create(GetCanvas(), true, true); result := fIECanvas; end; // draw an hdib in a canvas procedure _DIBDrawTo(DestCanvas: TCanvas; fhdib: THANDLE; orgx, orgy, orgdx, orgdy, destx, desty, destdx, destdy: integer); var bminfo: ^TBITMAPINFO; begin bminfo := GlobalLock(fhdib); SetStretchBltMode(destcanvas.handle, COLORONCOLOR); if bminfo^.bmiHeader.biBitCount <= 8 then // <=256 colors StretchDIBits(destcanvas.Handle, destx, desty, destdx, destdy, orgx, orgy, orgdx, orgdy, pointer(cardinal(bminfo) + sizeof(TBITMAPINFOHEADER) + (1 shl bminfo^.bmiHeader.biBitCount) * 4), bminfo^, DIB_RGB_COLORS, SRCCOPY) else // >256 colors StretchDIBits(destcanvas.Handle, destx, desty, destdx, destdy, orgx, orgy, orgdx, orgdy, pointer(cardinal(bminfo) + sizeof(TBITMAPINFOHEADER)), bminfo^, DIB_RGB_COLORS, SRCCOPY); GlobalUnLock(fhdib); end; procedure PrintPict(DestCanvas: TCanvas; x, y: integer; const Bitmap: TIEBitmap; srcx, srcy, srcdx, srcdy: integer); var hdib: THandle; begin IEPrintLogWrite('PrintPict: calling _CopyBitmaptoDIBEx'); hdib := _CopyBitmaptoDIBEx(Bitmap, srcx, srcy, srcx + srcdx, srcy + srcdy, 200, 200); IEPrintLogWrite('PrintPict: calling _DIBDrawTo'); _DIBDrawTo(DestCanvas, hdib, 0, 0, srcdx, srcdy, x, y, srcdx, srcdy); IEPrintLogWrite('PrintPict: calling GlobalFree'); GlobalFree(hdib); end; {!! TIEBitmap.RenderToCanvas Declaration procedure RenderToCanvas(DestCanvas: TCanvas; xDst, yDst, dxDst, dyDst: integer; Filter: ; Gamma: double = 0; BackgroundColor: TColor = clWhite); Description Draws the bitmap to the DestCanvas at the rectangle specified by xDst, yDst, dxDst, dyDst. Filter specifies the filter if the image needs to be resampled. Gamma is the gamma correction. BackgroundColor specifies the background color when pixels aren't opaque. Example // Col 1 of a TStringGrid displays a thumbnail drawn from a TImageEnMView procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Longint; Rect: TRect; State: TGridDrawState); var aIEBitmap: IEBitmap; aCanvas: TCanvas; idx: Integer; begin // Col 1 contains thumbnail. Row 0 is fixed header row if (ACol <> 1) or (ARow = 0) then Exit; idx := ARow; aCanvas := (Sender as TStringGrid).Canvas; // Clear current cell rect aCanvas.FillRect( Rect ); // Get our image // Note: don't need to create or free the TIEBitmap aIEBitmap := ImageEnMView1.GetIEBitmap( idx ); // Adjust our rect to maintain the image aspect ratio Rect := GetImageRectWithinArea( Rect, aIEBitmap.Width, aIEBitmap.Height ); // Draw the image aIEBitmap := RenderToCanvas( aCanvas, Rect.Left, Rect.Top, Rect.Right - Rect.Left, Rect.Bottom - Rect.Top, rfFastLinear, 0 ); // Release our image ImageEnMView1.ReleaseBitmap( idx, False ); end; See Also - - !!} // render the tiebitmap to a canvas, converting a strip at the time to TBitmap then drawing it to the canvas // the tbitmap memory size will be minor than fMinFileSize procedure TIEBitmap.RenderToCanvas(DestCanvas: TCanvas; xDst, yDst, dxDst, dyDst: integer; Filter: TResampleFilter; Gamma: double = 0; BackgroundColor: TColor = clWhite); const Inv255 = 1.0 / 255; var i: Integer; InvGamma: double; lut: array[0..255] of byte; resbmp: TIEBitmap; stripHeight, y, y1, x1: integer; px: PRGB; hdib: THandle; begin IEPrintLogWrite('TIEBitmap.RenderToCanvas: begin'); if (fWidth = 0) or (fHeight = 0) or (dxDst = 0) or (dyDst = 0) then exit; if HasAlphaChannel and not AlphaChannel.Full then BlendAlpha(BackgroundColor); if Filter = rfNone then begin IEPrintLogWrite('TIEBitmap.RenderToCanvas: filter=none, gamma=1, gamma=0'); hdib := _CopyBitmaptoDIBEx(Self, 0, 0, fWidth, fHeight, 200, 200); if (Gamma<>1) and (Gamma<>0) then IEDIBGamma(hdib, Gamma); IEPrintLogWrite('TIEBitmap.RenderToCanvas: calling _DIBDrawTo'); _DIBDrawTo(DestCanvas, hdib, 0, 0, fWidth, fHeight, xDst, yDst, dxDst, dyDst); GlobalFree(hdib); end else begin // calc stripHeight stripHeight := (fMinFileSize div 4) div IEBitmapRowLen(dxDst, 24, fBitAlignment); stripHeight := imax(1, imin(dyDst, stripHeight)); while (stripHeight>1) and (IEBitmapRowLen(dxDst, 24, fBitAlignment)*stripHeight>40*1024*1024) do dec(stripHeight); IEPrintLogWrite('TIEBitmap.RenderToCanvas: stripHeight='+IntToStr(stripHeight)); // resample to resbmp resbmp := TIEBitmap.Create; IEPrintLogWrite('TIEBitmap.RenderToCanvas: allocating '+IntToStr(dxDst)+'x'+IntToStr(dyDst)); if (Filter = rfNone) or ((PixelFormat<>ie1g) and (PixelFormat<>ie24RGB)) then begin // 1bit or 24bit unfiltered resbmp.Allocate(dxDst, dyDst, fPixelFormat); IEPrintLogWrite('TIEBitmap.RenderToCanvas: _IEBmpStretchEx'); _IEBmpStretchEx(self, resbmp, nil, nil); end else if (fPixelFormat = ie1g) then begin // 1bit filtered if (Filter=rfProjectBW) or (Filter=rfProjectWB) then resbmp.Allocate(dxDst, dyDst, ie1g) else resbmp.Allocate(dxDst, dyDst, ie24RGB); IEPrintLogWrite('TIEBitmap.RenderToCanvas: _Resample1BitEx'); _Resample1BitEx(self, resbmp, Filter); end else begin // 24bit filtered resbmp.Allocate(dxDst, dyDst, ie24RGB); IEPrintLogWrite('TIEBitmap.RenderToCanvas: _ResampleEx'); _ResampleEx(self, resbmp, nil, Filter, nil, nil); end; // copy strips DestCanvas.CopyMode := cmSrcCopy; // apply gamma if (resbmp.PixelFormat = ie24RGB) and (Gamma <> 1) and (Gamma > 0) then begin // calc gamma LUT IEPrintLogWrite('TIEBitmap.RenderToCanvas: gamma'); InvGamma := 1.0 / Gamma; for i := 0 to 255 do lut[i] := blimit(round(255 * Power(i * Inv255, InvGamma))); for y1 := 0 to resbmp.Height - 1 do begin px := resbmp.Scanline[y1]; for x1 := 0 to resbmp.Width - 1 do begin with px^ do begin r := lut[r]; g := lut[g]; b := lut[b]; end; inc(px); end; end; end; // y := 0; while y < dyDst do begin // draw to canvas IEPrintLogWrite('TIEBitmap.RenderToCanvas: PrintPict y='+IntToStr(y)); PrintPict(DestCanvas, xDst, yDst, resbmp, 0, y, resbmp.Width, stripHeight); // next strip inc(yDst, stripHeight); inc(y, stripHeight); stripHeight := imin((dyDst - y), stripHeight); end; // FreeAndNil(resbmp); end; IEPrintLogWrite('TIEBitmap.RenderToCanvas: end'); end; {!! TIEBitmap.DrawToCanvas Declaration procedure DrawToCanvas(DestCanvas: TCanvas; xDst, yDst : integer); Description Draws the whole bitmap to the specified DestCanvas canvas, at coordinates xDst, yDst. Note: This is a simplified version of See Also - - !!} procedure TIEBitmap.DrawToCanvas(DestCanvas: TCanvas; xDst, yDst : integer); begin RenderToCanvas(DestCanvas, xDst, YDst, fwidth, fheight, rfNone, 0); end; {!! TIEBitmap.DrawToCanvasWithAlpha Declaration procedure DrawToCanvasWithAlpha(DestCanvas: TCanvas; xDst, yDst : integer; Transparency: integer; Opacity: double); Description Draws the whole bitmap to the specified DestCanvas canvas, at coordinates xDst, yDst with parameters: Transparency specifies the transparency value (0 to 255). Opacity specifies the opacity (0 to 1.0). This functions reads the destination canvas pixels and merges them with image using the alpha channel mask. Note: This is a simplified version of Opacity vs Transparency Both the Opacity and Transparency parameters provide the same functionality. Transparency is the traditional ImageEn value, whereas Opacity provides easier PSD compatibility. While they can be used in combination, generally only one will be used, i.e. leave Opacity=1 and make use of transparency, or alternatively, leave Transparency=255 and make use of Opacity. For example, for 50% opacity: Transparency = 255 and Opacity = 0.5, or Transparency = 128 and Opacity = 1.0 See Also - - !!} procedure TIEBitmap.DrawToCanvasWithAlpha(DestCanvas: TCanvas; xDst, yDst : integer; Transparency: integer; Opacity: Double); begin RenderToCanvasWithAlpha(DestCanvas, xDst, YDst, fwidth, fheight, 0, 0, fwidth, fheight, Transparency, rfNone, ielNormal, Opacity); end; {!! TIEBitmap.DrawToTIEBitmap Declaration procedure DrawToTIEBitmap(Dest: TIEBitmap; XDest, YDest : Integer); overload; // Draw whole image procedure DrawToTIEBitmap(Dest: TIEBitmap; XDest, YDest : Integer; SrcRect : ); overload; // Draw part of image procedure DrawToTIEBitmap(Dest: TIEBitmap; DestRect : ; SrcRect : ; Filter: = rfLanczos3); overload; // Stretch draw image Description Draws content of the current IEBitmap onto another IEBitmap. Overload 1 will draw the whole of the current image at coordinates XDest, YDest. Overload 2 allows you to specify a portion of the current image to draw at coordinates XDest, YDest. Overload 3 allows you to stretch draw (enlarge or reduce) the image. Dest must be ie24RGB. Note: Use to convert a standard TRect to a Examples // Stretch Draw an image centered within a TIEBitmap aRect := GetImageRectWithinArea( SrcBMP.Width, SrcBMP.Height, DestBMP.Width, DestBMP.Height); SrcBMP.DrawToTIEBitmap( DestBMP, IERectangle( aRect ), IERectangle( 0, 0, SrcBMP.Width, SrcBMP.Height ) ); // DRAW TWO IMAGES BESIDE EACH OTHER (USING OVERLOAD 1) // Load input files IEBitmap1.Read('D:\MyPic1.png'); IEBitmap2.Read('D:\MyPic2.jpg'); // Get Left position for IEBitmap2 iBitmap1Width := IEBitmap1.Width; // Resize IEBitmap1 IEBitmap1.Resize(IEBitmap1.Width + IEBitmap2.Width, iMax(IEBitmap1.Height, IEBitmap2.Height), clWhite, 255, iehLeft, ievCenter); // Draw IEBitmap2 IEBitmap2.DrawToTIEBitmap(IEBitmap1, iBitmap1Width, 0); // Save output file IEBitmap2.Write('D:\Output.png'); // DRAW TWO IMAGES BESIDE EACH OTHER, BUT ONLY OUTPUT CENTRAL PORTION OF SECOND IMAGE (USING OVERLOAD 2) // Load input files IEBitmap1.Read('D:\MyPic1.png'); IEBitmap2.Read('D:\MyPic2.jpg'); // Get Left position for IEBitmap2 iBitmap1Width := IEBitmap1.Width; // Resize IEBitmap1 IEBitmap1.Resize(IEBitmap1.Width + IEBitmap2.Width div 2, iMax(IEBitmap1.Height, IEBitmap2.Height div 2), clWhite, 255, iehLeft, ievCenter); // Draw IEBitmap2 IEBitmap2.DrawToTIEBitmap(IEBitmap1, iBitmap1Width, 0, IERectangle(IEBitmap2.Width div 4, IEBitmap2.Height div 4, IEBitmap2.Width div 2, IEBitmap2.Height div 2)); // Save output file IEBitmap2.Write('D:\Output.png'); // DRAW TWO IMAGES BESIDE EACH OTHER, BUT ONLY OUTPUT CENTRAL PORTION OF SECOND IMAGE AT DOUBLE SIZE (USING OVERLOAD 3) // Load input files IEBitmap1.Read('D:\MyPic1.png'); IEBitmap2.Read('D:\MyPic2.jpg'); // Get Left position for IEBitmap2 iBitmap1Width := IEBitmap1.Width; // Resize IEBitmap1 IEBitmap1.Resize(IEBitmap1.Width + IEBitmap2.Width, iMax(IEBitmap1.Height, IEBitmap2.Height), clWhite, 255, iehLeft, ievCenter); // Draw IEBitmap2 IEBitmap2.DrawToTIEBitmap(IEBitmap1, IERectangle(iBitmap1Width, 0, IEBitmap2.Width, IEBitmap2.Height), IERectangle(IEBitmap2.Width div 4, IEBitmap2.Height div 4, IEBitmap2.Width div 2, IEBitmap2.Height div 2)); // Save output file IEBitmap2.Write('D:\Output.png'); // DRAW TWO IMAGES BESIDE EACH OTHER, BUT OUTPUT SECOND IMAGE AT HALF SIZE (USING OVERLOAD 3) // Load input files IEBitmap1.Read('D:\MyPic1.png'); IEBitmap2.Read('D:\MyPic2.jpg'); // Get Left position for IEBitmap2 iBitmap1Width := IEBitmap1.Width; // Resize IEBitmap1 IEBitmap1.Resize(IEBitmap1.Width + IEBitmap2.Width div 2, iMax(IEBitmap1.Height, IEBitmap2.Height div 2), clWhite, 255, iehLeft, ievCenter); // Draw IEBitmap2 IEBitmap2.DrawToTIEBitmap(IEBitmap1, IERectangle(iBitmap1Width, 0, IEBitmap2.Width div 2, IEBitmap2.Height div 2), IERectangle(0, 0, IEBitmap2.Width, IEBitmap2.Height)); // Save output file IEBitmap2.Write('D:\Output.png'); See Also - - !!} procedure TIEBitmap.DrawToTIEBitmap(Dest: TIEBitmap; XDest, YDest: Integer); begin RenderToTIEBitmapEx(Dest, XDest, YDest, Width, Height, 0, 0, Width, Height, True, 255, rfNone, ielNormal, 1.0); end; procedure TIEBitmap.DrawToTIEBitmap(Dest: TIEBitmap; XDest, YDest: Integer; SrcRect : TIERectangle); begin if (SrcRect.Width = 0) or (SrcRect.Height = 0) then exit; if SrcRect.Width > Width then SrcRect.Width := Width; if SrcRect.Height > Height then SrcRect.Height := Height; RenderToTIEBitmapEx(Dest, XDest, YDest, SrcRect.Width, SrcRect.Height, SrcRect.X, SrcRect.Y, SrcRect.Width, SrcRect.Height, True, 255, rfNone, ielNormal, 1.0); end; procedure TIEBitmap.DrawToTIEBitmap(Dest: TIEBitmap; DestRect : TIERectangle; SrcRect : TIERectangle; Filter: TResampleFilter = rfLanczos3); begin if (SrcRect.Width = 0) or (SrcRect.Height = 0) or (DestRect.Width = 0) or (DestRect.Height = 0) then exit; if SrcRect.Width > Width - SrcRect.X then SrcRect.Width := Width - SrcRect.X; if SrcRect.Height > Height - SrcRect.Y then SrcRect.Height := Height - SrcRect.Y; RenderToTIEBitmapEx(Dest, DestRect.X, DestRect.Y, DestRect.Width, DestRect.Height, SrcRect.X, SrcRect.Y, SrcRect.Width, SrcRect.Height, True, 255, Filter, ielNormal, 1.0); end; {!! TIEBitmap.RenderToTBitmapEx Declaration procedure RenderToTBitmapEx(Dest: TBitmap; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; bEnableAlpha: Boolean = True; Transparency: integer = 255; Filter: = rfNone; RenderOperation: = ielNormal; Opacity: double = 1.0); Description Draws the rectangle xSrc, ySrc, dxSrc, dySrc inside the destination rectangle xDst, yDst, dxDst, dyDst of Dest TBitmap object. Dest. must be pf24bit. bEnableAlpha includes the alpha channel Transparency specifies the transparency value (0=Fully Transparent to 255=Fully Opaque). Filter specifies the resampling filter. RenderOperation specifies the rendering operation. Opacity specifies the opacity (0=Fully Transparent to 1.0=Fully Opaque). Opacity vs Transparency Both the Opacity and Transparency parameters provide the same functionality. Transparency is the traditional ImageEn value, whereas Opacity provides easier PSD compatibility. While they can be used in combination, generally only one will be used, i.e. leave Opacity=1 and make use of transparency, or alternatively, leave Transparency=255 and make use of Opacity. For example, for 50% opacity: Transparency = 255 and Opacity = 0.5, or Transparency = 128 and Opacity = 1.0 !!} procedure TIEBitmap.RenderToTBitmapEx(Dest: TBitmap; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; Transparency: integer = 255; Filter: TResampleFilter = rfNone; RenderOperation: TIERenderOperation = ielNormal; Opacity: double = 1.0); begin RenderToTBitmapEx( Dest, xDst, yDst, dxDst, dyDst, xSrc, ySrc, dxSrc, dySrc, True, Transparency, Filter, RenderOperation, Opacity ); end; // Internal usage procedure TIEBitmap.RenderToTBitmapEx(Dest: TBitmap; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; bEnableAlpha: Boolean; Transparency: integer; Filter: TResampleFilter; RenderOperation: TIERenderOperation = ielNormal; Opacity: double = 1.0); var XLUT, YLUT: pinteger; begin XLUT := nil; YLUT := nil; RenderToTBitmap(Dest, XLUT, YLUT, nil, xDst, yDst, dxDst, dyDst, xSrc, ySrc, dxSrc, dySrc, bEnableAlpha, false, Transparency, Filter, true, RenderOperation, Opacity); end; {!! TIEBitmap.RenderToTIEBitmapEx Declaration procedure RenderToTIEBitmapEx(Dest: ; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; bEnableAlpha: Boolean = True; Transparency: integer = 255; Filter: = rfNone; RenderOperation: = ielNormal; Opacity: double = 1.0); Description Draws the rectangle xSrc, ySrc, dxSrc, dySrc inside the destination rectangle xDst, yDst, dxDst, dyDst of Dest TIEBitmap object. Dest must be ie24RGB. bEnableAlpha includes the alpha channel Transparency specifies the transparency value (0=Fully Transparent to 255=Fully Opaque). Filter the resampling filter. RenderOperation the rendering operation. Opacity specifies the opacity (0=Fully Transparent to 1.0=Fully Opaque). Opacity vs Transparency Both the Opacity and Transparency parameters provide the same functionality. Transparency is the traditional ImageEn value, whereas Opacity provides easier PSD compatibility. While they can be used in combination, generally only one will be used, i.e. leave Opacity=1 and make use of transparency, or alternatively, leave Transparency=255 and make use of Opacity. For example, for 50% opacity: Transparency = 255 and Opacity = 0.5, or Transparency = 128 and Opacity = 1.0 Compatibility Information In v6.0.0 the bEnableAlpha parameter was added. Set this to true to maintain existing functionality. Example // Merge images of ImageEnView1 and ImageEnView2 using "InverseColorDodge" and put onto ImageEnView3 ImageEnView3.IEBitmap.Assign( ImageEnView2.IEBitmap ); ImageEnView1.IEBitmap.RenderToTIEBitmapEx( ImageEnView3.IEBitmap, 0, 0, ImageEnView2.IEBitmap.Width, ImageEnView2.IEBitmap.Height, 0, 0, ImageEnView1.IEBitmap.Width, ImageEnView1.IEBitmap.Height, False, 255, rfNone, ielInverseColorDodge ); ImageEnView3.Update; See Also - - !!} procedure TIEBitmap.RenderToTIEBitmapEx(Dest: TIEBitmap; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; bEnableAlpha: Boolean = True; Transparency: integer = 255; Filter: TResampleFilter = rfNone; RenderOperation: TIERenderOperation = ielNormal; Opacity: double = 1.0); var XLUT, YLUT: pinteger; begin XLUT := nil; YLUT := nil; RenderToTIEBitmap(Dest, XLUT, YLUT, nil, xDst, yDst, dxDst, dyDst, xSrc, ySrc, dxSrc, dySrc, bEnableAlpha, false, Transparency, Filter, true, RenderOperation, Opacity); end; {!! TIEBitmap.RenderToCanvasWithAlpha Declaration procedure RenderToCanvasWithAlpha(Dest: TCanvas; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; Transparency: integer = 255; Filter: = rfNone; RenderOperation: = ielNormal; Opacity: double = 1.0); Description Draws the rectangle, xSrc, ySrc, dxSrc, dySrc, within the destination rectangle, xDst, yDst, dxDst, dyDst, of Dest TCanvas object. Transparency specifies the transparency value (0=Fully Transparent to 255=Fully Opaque). Filter the resampling filter. RenderOperation the rendering operation. Opacity specifies the opacity (0=Fully Transparent to 1.0=Fully Opaque). This functions reads the destination canvas pixels and merges them with image using the alpha channel mask. Opacity vs Transparency Both the Opacity and Transparency parameters provide the same functionality. Transparency is the traditional ImageEn value, whereas Opacity provides easier PSD compatibility. While they can be used in combination, generally only one will be used, i.e. leave Opacity=1 and make use of transparency, or alternatively, leave Transparency=255 and make use of Opacity. For example, for 50% opacity: Transparency = 255 and Opacity = 0.5, or Transparency = 128 and Opacity = 1.0 Example // Draw aIEBitmap within aRect while maintaining the aspect ratio of the image aRect := GetImageRectWithinArea( aIEBitmap.Width, aIEBitmap.Height, aRect ); aIEBitmap.RenderToCanvasWithAlpha( aCanvas, aRect.Left, aRect.Top, aRect.Right - aRect.Left, aRect.Bottom - aRect.Top, 0, 0, aIEBitmap.Width, aIEBitmap.Height, 255, rfFastLinear ); See Also - - !!} procedure TIEBitmap.RenderToCanvasWithAlpha(Dest: TCanvas; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; Transparency: integer = 255; Filter: TResampleFilter = rfNone; RenderOperation: TIERenderOperation = ielNormal; Opacity: double = 1.0); var tempdib: TIEDIBBitmap; tempbmp: TIEBitmap; begin tempdib := TIEDIBBitmap.Create(); tempbmp := nil; try tempdib.AllocateBits(dxDst, dyDst, 24); BitBlt(tempdib.HDC, 0, 0, dxDst, dyDst, Dest.Handle, xDst, yDst, SRCCOPY); tempbmp := TIEBitmap.Create(); tempbmp.EncapsulateMemory(tempdib.Bits, dxDst, dyDst, ie24RGB, false); RenderToTIEBitmapEx(tempbmp, 0, 0, dxDst, dyDst, xSrc, ySrc, dxSrc, dySrc, True, Transparency, Filter, RenderOperation, Opacity); BitBlt(Dest.Handle, xDst, yDst, dxDst, dyDst, tempdib.HDC, 0, 0, SRCCOPY); finally tempbmp.free; tempdib.free; end; end; {!! TIEBitmap.RenderToTBitmap Declaration procedure RenderToTBitmap(ABitmap: TBitmap; var XLUT, YLUT: pinteger; UpdRect: PRect; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; EnableAlpha: boolean; SolidBackground: boolean; Transparency: integer; Filter: ; FreeTables: boolean; RenderOperation: = ielNormal; Opacity: double = 1.0); Description Used internally to render a TIEBitmap in object. ABitmap must be pf24bit Opacity vs Transparency Both the Opacity and Transparency parameters provide the same functionality. Transparency is the traditional ImageEn value, whereas Opacity provides easier PSD compatibility. While they can be used in combination, generally only one will be used, i.e. leave Opacity=1 and make use of transparency, or alternatively, leave Transparency=255 and make use of Opacity. For example, for 50% opacity: Transparency = 255 and Opacity = 0.5, or Transparency = 128 and Opacity = 1.0 See Also - !!} procedure TIEBitmap.RenderToTBitmap(ABitmap: TBitmap; var XLUT, YLUT: pinteger; UpdRect: PRect; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; EnableAlpha: boolean; SolidBackground: boolean; Transparency: integer; Filter: TResampleFilter; FreeTables: boolean; RenderOperation: TIERenderOperation; Opacity: double); var bmp: TIEBitmap; begin bmp := TIEBitmap.Create; try bmp.EncapsulateTBitmap(ABitmap, false); RenderToTIEBitmap(bmp, XLUT, YLUT, UpdRect, xDst, yDst, dxDst, dyDst, xSrc, ySrc, dxSrc, dySrc, EnableAlpha, SolidBackground, Transparency, Filter, FreeTables, RenderOperation, Opacity); finally FreeAndNil(bmp); end; end; {!! TIEBitmap.RenderToTIEBitmap Declaration procedure RenderToTIEBitmap(ABitmap: ; var XLUT, YLUT: pinteger; UpdRect: PRect; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; EnableAlpha: boolean; SolidBackground: boolean; Transparency: integer; Filter: ; FreeTables: boolean; RenderOperation: = ielNormal; Opacity: double = 1.0); Description Used internally to render a TIEBitmap in object. ABitmap must be 24 bit. XLUT, YLUT: x and y screen to bitmap conversion table, can be NIL Opacity vs Transparency Both the Opacity and Transparency parameters provide the same functionality. Transparency is the traditional ImageEn value, whereas Opacity provides easier PSD compatibility. While they can be used in combination, generally only one will be used, i.e. leave Opacity=1 and make use of transparency, or alternatively, leave Transparency=255 and make use of Opacity. For example, for 50% opacity: Transparency = 255 and Opacity = 0.5, or Transparency = 128 and Opacity = 1.0 See Also - - !!} procedure TIEBitmap.RenderToTIEBitmap(ABitmap: TIEBitmap; var XLUT, YLUT: pinteger; UpdRect: PRect; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; EnableAlpha: boolean; SolidBackground: boolean; Transparency: integer; Filter: TResampleFilter; FreeTables: boolean; RenderOperation: TIERenderOperation; Opacity: double); var i, y, x, ABitmapWidth, ABitmapHeight: integer; x2, y2: integer; rx, ry: integer; cx1, cy1, cx2, cy2: integer; SimAlphaRow: pbyte; // the simulated alpha channel, needed when Transparency is not 255 (255=opaque) UseAlpha: boolean; sxarr, psx, syarr, psy: pinteger; ietmp1: TIEBitmap; ietmp2: TIEBitmap; {$IFDEF IEDEBUG} deb1: dword; {$ENDIF} dummy1, dummy2: pinteger; zx, zy: double; laccess: TIEDataAccess; clipbmp: TIEVirtualClippedBitmap; procedure CalcC(); begin ry := trunc((dySrc / dyDst) * 16384); // 2^14 rx := trunc((dxSrc / dxDst) * 16384); y2 := imin(yDst + dyDst - 1, ABitmapHeight - 1); x2 := imin(xDst + dxDst - 1, ABitmapWidth - 1); // set update rect if UpdRect <> nil then begin cx1 := UpdRect^.Left; cy1 := UpdRect^.Top; cx2 := UpdRect^.Right; cy2 := UpdRect^.Bottom; end else begin cx1 := -2147483646; cy1 := -2147483646; cx2 := 2147483646; cy2 := 2147483646; end; cx1 := imax(cx1, xDst); cx2 := imin(cx2, x2); cy1 := imax(cy1, yDst); cy2 := imin(cy2, y2); cx1 := imax(cx1, 0); cx1 := imin(cx1, ABitmapWidth - 1); cx2 := imax(cx2, 0); cx2 := imin(cx2, ABitmapWidth - 1); cy1 := imax(cy1, 0); cy1 := imin(cy1, ABitmapHeight - 1); cy2 := imax(cy2, 0); cy2 := imin(cy2, ABitmapHeight - 1); while (assigned(YLUT) and (pintegerarray(YLUT)[cy2 - cy1] >= fHeight)) do begin dec(cy2); end; while (assigned(XLUT) and (pintegerarray(XLUT)[cx2 - cx1] >= fWidth)) do begin dec(cx2); end; end; begin try laccess := Access; Access := [iedRead]; if (dxDst = 0) or (dyDst = 0) or (dxSrc = 0) or (dySrc = 0) then exit; ABitmapWidth := ABitmap.Width; ABitmapHeight := ABitmap.Height; if (yDst > ABitmapHeight - 1) or (xDst > ABitmapWidth - 1) then exit; zy := dySrc / dyDst; zx := dxSrc / dxDst; if yDst < 0 then begin y := -yDst; yDst := 0; dec(dyDst, y); inc(ySrc, round(y * zy)); dec(dySrc, round(y * zy)); end; if xDst < 0 then begin x := -xDst; xDst := 0; dec(dxDst, x); inc(xSrc, round(x * zx)); dec(dxSrc, round(x * zx)); end; if yDst + dyDst > ABitmapHeight then begin y := yDst + dyDst - ABitmapHeight; dyDst := ABitmapHeight - yDst; dec(dySrc, trunc(y * zy)); end; if xDst + dxDst > ABitmapWidth then begin x := xDst + dxDst - ABitmapWidth; dxDst := ABitmapWidth - xDst; dec(dxSrc, trunc(x * zx)); end; xDst := imax(imin(xDst, ABitmapWidth - 1), 0); yDst := imax(imin(yDst, ABitmapHeight - 1), 0); dxDst := imax(imin(dxDst, ABitmapWidth), 0); dyDst := imax(imin(dyDst, ABitmapHeight), 0); xSrc := imax(imin(xSrc, Width - 1), 0); ySrc := imax(imin(ySrc, Height - 1), 0); dxSrc := imax(imin(dxSrc, Width), 0); dySrc := imax(imin(dySrc, Height), 0); if (dxDst = 0) or (dyDst = 0) or (dxSrc = 0) or (dySrc = 0) then exit; if (Filter <> rfNone) and ((dxSrc <> dxDst) or (dySrc <> dyDst)) then begin {$IFDEF IEDEBUG} OutputDebugStringA(PAnsiChar('TIEBitmap.RenderToTIEBitmap1')); OutputDebugStringA(PAnsiChar(' ABitmap.Width='+IEIntToStr(ABitmap.Width)+' ABitmap.Height='+IEIntToStr(ABitmap.Height) )); OutputDebugStringA(PAnsiChar(' IEBitmap.Width='+IEIntToStr(Width)+' IEBitmap.Height='+IEIntToStr(Height) )); OutputDebugStringA(PAnsiChar(' xSrc='+IEIntToStr(xSrc)+' ySrc='+IEIntToStr(ySrc) )); OutputDebugStringA(PAnsiChar(' dxSrc='+IEIntToStr(dxSrc)+' dySrc='+IEIntToStr(dySrc) )); OutputDebugStringA(PAnsiChar(' xDst='+IEIntToStr(xDst)+' yDst='+IEIntToStr(yDst) )); OutputDebugStringA(PAnsiChar(' dxDst='+IEIntToStr(dxDst)+' dyDst='+IEIntToStr(dyDst) )); OutputDebugStringA(PAnsiChar(' cx1='+IEIntToStr(cx1)+' cy1='+IEIntToStr(cy1)+' cx2='+IEIntToStr(cx2)+' cy2='+IEIntToStr(cy2) )); OutputDebugStringA(PAnsiChar(' rx='+IEIntToStr(rx)+' ry='+IEIntToStr(ry) )); {$ENDIF} dummy1 := nil; dummy2 := nil; // need to resample using a filter if (dxDst <= dxSrc) and (PixelFormat = ie1g) and ((not EnableAlpha) or (not HasAlphaChannel)) and (Filter <> rfProjectBW) and (Filter <> rfProjectWB) then begin // subsample 1 bit bitmap if (dxDst > 0) and (dyDst > 0) then begin ietmp1 := TIEBitmap.Create(); try ietmp1.Allocate(dxDst, dyDst, ie24RGB); _SubResample1bitFilteredEx(self, xSrc, ySrc, xSrc + dxSrc - 1, ySrc + dySrc - 1, ietmp1); ietmp1.RenderToTIEBitmap(ABitmap, dummy1, dummy2, UpdRect, xDst, yDst, dxDst, dyDst, 0, 0, dxDst, dyDst, EnableAlpha, SolidBackground, Transparency, rfNone, true, RenderOperation, Opacity); finally FreeAndNil(ietmp1); end; end; end else if ((dxSrc > 0) and (dySrc > 0)) then begin // sub/over resample 1/24 bits bitmap CalcC(); dxSrc := ilimit(trunc( zx * (cx2 - xDst) + xSrc ), 0, fWidth) - ilimit(trunc( zx * (cx1 - xDst) + xSrc ), 0, fWidth) + 1; dySrc := ilimit(trunc( zy * (cy2 - yDst) + ySrc ), 0, fHeight) - ilimit(trunc( zy * (cy1 - yDst) + ySrc ), 0, fHeight) + 1; ietmp1 := nil; ietmp2 := nil; clipbmp := nil; try clipbmp := TIEVirtualClippedBitmap.Create(self, Rect(xSrc, ySrc, xSrc + dxSrc - 1, ySrc + dySrc - 1)); ietmp2 := TIEBitmap.Create(); if PixelFormat = ie1g then begin ietmp1 := TIEBitmap.Create(dxSrc, dySrc, PixelFormat); CopyRectTo(ietmp1, xSrc, ySrc, 0, 0, dxSrc, dySrc, false); if (Filter = rfProjectBW) or (Filter = rfProjectWB) then ietmp2.Allocate(dxDst, dyDst, ie1g) else ietmp2.Allocate(dxDst, dyDst, ie24RGB); _Resample1bitEx(ietmp1, ietmp2, Filter); end else begin ietmp2.Allocate(dxDst, dyDst, clipbmp.PixelFormat); _ResampleEx(clipbmp, ietmp2, nil, Filter, nil, nil); end; if EnableAlpha and HasAlphaChannel then begin _Resampleie8g(clipbmp.AlphaChannel, ietmp2.AlphaChannel, Filter); ietmp2.AlphaChannel.Full := clipbmp.AlphaChannel.Full; end; for i := 0 to IEMAXCHANNELS - 1 do ietmp2.fChannelOffset[i] := fChannelOffset[i]; ietmp2.fEnableChannelOffset := fEnableChannelOffset; ietmp2.fContrast := fContrast; ietmp2.fWhiteValue := fWhiteValue; ietmp2.fBlackValue := fBlackValue; ietmp2.RenderToTIEBitmap(ABitmap, dummy1, dummy2, UpdRect, xDst, yDst, dxDst, dyDst, 0, 0, dxDst, dyDst, EnableAlpha, SolidBackground, Transparency, rfNone, true, RenderOperation, Opacity); finally FreeAndNil(ietmp1); FreeAndNil(ietmp2); FreeAndNil(clipbmp); end; end; exit; // EXIT POINT end; {$IFDEF IEDEBUG} deb1 := gettickcount; {$ENDIF} if (dxDst <> 0) and (dyDst <> 0) then begin SimAlphaRow := nil; if (Transparency < 255) or (Opacity < 1.0) then begin if SimAlphaRow = nil then getmem(SimAlphaRow, Width); fillchar(SimAlphaRow^, Width, trunc(Transparency * Opacity)); end; sxarr := nil; syarr := nil; try CalcC(); UseAlpha := EnableAlpha and HasAlphaChannel and (not AlphaChannel.Full); if (ry <> 16384) or (rx <> 16384) or (PixelFormat = ie1g) or (PixelFormat = ie16g) or (PixelFormat = ie32f) or (PixelFormat = ieCMYK) or (PixelFormat = ie48RGB) or (PixelFormat = ieCIELab) or (PixelFormat = ie8g) or (PixelFormat = ie8p) or (PixelFormat = ie32RGB) or isVirtual or (Transparency < 255) or (Opacity < 1.0) or UseAlpha or fEnableChannelOffset or (fContrast <> 0) or (RenderOperation <> ielNormal) or ((fBlackValue <> 0) or (fWhiteValue <> 0)) then begin if XLUT <> nil then begin // set provided horizontal LUT sxarr := XLUT; inc(sxarr, cx1 - xDst); end else begin // build horizontal LUT getmem(sxarr, (cx2 - cx1 + 1) * sizeof(integer)); psx := sxarr; for x := cx1 to cx2 do begin psx^ := ilimit(trunc( zx * (x - xDst) + xSrc ), 0, fWidth - 1); inc(psx); end; end; if YLUT <> nil then begin // set provided vertical LUT syarr := YLUT; inc(syarr, cy1 - yDst); end else begin // build vertical LUT getmem(syarr, (cy2 - cy1 + 1) * sizeof(integer)); psy := syarr; for y := cy1 to cy2 do begin psy^ := ilimit(trunc( zy * (y - yDst) + ySrc ), 0, fHeight - 1); inc(psy); end; end; end; {$IFDEF IEDEBUG} OutputDebugStringA(PAnsiChar('TIEBitmap.RenderToTIEBitmap2')); OutputDebugStringA(PAnsiChar(' ABitmap.Width='+IEIntToStr(ABitmap.Width)+' ABitmap.Height='+IEIntToStr(ABitmap.Height) )); OutputDebugStringA(PAnsiChar(' IEBitmap.Width='+IEIntToStr(Width)+' IEBitmap.Height='+IEIntToStr(Height) )); OutputDebugStringA(PAnsiChar(' xSrc='+IEIntToStr(xSrc)+' ySrc='+IEIntToStr(ySrc) )); OutputDebugStringA(PAnsiChar(' dxSrc='+IEIntToStr(dxSrc)+' dySrc='+IEIntToStr(dySrc) )); OutputDebugStringA(PAnsiChar(' xDst='+IEIntToStr(xDst)+' yDst='+IEIntToStr(yDst) )); OutputDebugStringA(PAnsiChar(' dxDst='+IEIntToStr(dxDst)+' dyDst='+IEIntToStr(dyDst) )); OutputDebugStringA(PAnsiChar(' cx1='+IEIntToStr(cx1)+' cy1='+IEIntToStr(cy1)+' cx2='+IEIntToStr(cx2)+' cy2='+IEIntToStr(cy2) )); OutputDebugStringA(PAnsiChar(' rx='+IEIntToStr(rx)+' ry='+IEIntToStr(ry) )); {$ENDIF} if (Transparency < 255) or (Opacity < 1.0) or UseAlpha then begin // Draw with alpha channel case PixelFormat of ie1g: // 1 bit per pixel Render_ie1g_alpha(ABitmap, Transparency, UseAlpha, SimAlphaRow, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground, Opacity); ie8g: // 8 bit gray scale Render_ie8g_alpha(ABitmap, Transparency, UseAlpha, SimAlphaRow, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground, Opacity); ie8p: // 8 bit color mapped Render_ie8p_alpha(ABitmap, Transparency, UseAlpha, SimAlphaRow, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground, Opacity); ie16g: // 16 bit gray scale Render_ie16g_alpha(ABitmap, Transparency, UseAlpha, SimAlphaRow, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground, Opacity); ie24RGB: // 24 bits per pixel Render_ie24RGB_alpha(ABitmap, Transparency, UseAlpha, SimAlphaRow, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground, RenderOperation, Opacity); ie32RGB: // 32 bits per pixel Render_ie32RGB_alpha(ABitmap, Transparency, UseAlpha, SimAlphaRow, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground, RenderOperation, Opacity); ie32f: // 32 bit floating point gray scale Render_ie32f_alpha(ABitmap, Transparency, UseAlpha, SimAlphaRow, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground, Opacity); ieCMYK: // CMYK Render_ieCMYK_alpha(ABitmap, Transparency, UseAlpha, SimAlphaRow, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground, Opacity); ieCIELab: // CIELab Render_ieCIELab_alpha(ABitmap, Transparency, UseAlpha, SimAlphaRow, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground, Opacity); ie48RGB: // 48 bit per pixel Render_ie48RGB_alpha(ABitmap, Transparency, UseAlpha, SimAlphaRow, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground, RenderOperation, Opacity); end; end else begin // Draw without alpha channel case PixelFormat of ie1g: // 1 bit per pixel Render_ie1g(ABitmap, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground); ie8g: // 8 bit gray scale Render_ie8g(ABitmap, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground); ie8p: // 8 bit color mapped Render_ie8p(ABitmap, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground); ie16g: // 16 bit gray scale Render_ie16g(ABitmap, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground); ie24RGB: // 24 bits per pixel Render_ie24RGB(ABitmap, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground, RenderOperation); ie32RGB: // 32 bits per pixel Render_ie32RGB(ABitmap, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground, RenderOperation); ie32f: // 32 bit floating point gray scale Render_ie32f(ABitmap, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground); ieCMYK: // CMYK Render_ieCMYK(ABitmap, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground); ieCIELab: // CIELab Render_ieCIELab(ABitmap, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground); ie48RGB: // 48 bits per pixel Render_ie48RGB(ABitmap, sxarr, syarr, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground, RenderOperation); end; end; except {$IFDEF IEDEBUG} OutputDebugString('TIEBitmap.RenderToTBitmap: EXCEPTION!'); {$ENDIF} end; if SimAlphaRow <> nil then FreeMem(SimAlphaRow); if (sxarr <> nil) and (XLUT = nil) then begin if FreeTables then freemem(sxarr) else XLUT := sxarr; end; if (syarr <> nil) and (YLUT = nil) then begin if FreeTables then freemem(syarr) else YLUT := syarr; end; end; {$IFDEF IEDEBUG} deb1 := gettickcount - deb1; OutputDebugStringA(PAnsiChar('TIEBitmap.RenderToTBitmap: ' + IEIntToStr(deb1) + 'ms')); {$ENDIF} finally Access := laccess; end; ABitmap.Changed(); end; procedure TIEBitmap.Render_ie8p(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean); var psy, syarr, psx, sxarr: pinteger; x, y: integer; px2: prgb; pwb: pbytearray; sr, sg, sb: integer; begin if fRGBPalette=nil then exit; sxarr := XLUT; syarr := YLUT; psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); pwb := Scanline[psy^]; psx := sxarr; for x := cx1 to cx2 do begin with fRGBPalette[pwb[psx^]] do begin sr := r; sg := g; sb := b; end; with px2^ do begin r := sr; g := sg; b := sb; end; inc(px2); inc(psx); end; inc(psy); end end; procedure TIEBitmap.Render_ie8p_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; Opacity: double); var psy, syarr, psx, sxarr: pinteger; alpha, x, y: integer; px2: prgb; px3: pbytearray; pwb: pbytearray; sr, sg, sb: integer; begin if fRGBPalette=nil then exit; sxarr := XLUT; syarr := YLUT; psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); pwb := Scanline[psy^]; if UseAlpha then px3 := AlphaChannel.ScanLine[psy^] else px3 := PByteArray(SimAlphaRow); psx := sxarr; for x := cx1 to cx2 do begin alpha := trunc(imin(Transparency, px3[psx^]) * Opacity) shl 10; with fRGBPalette[pwb[psx^]] do begin sr := r; sg := g; sb := b; end; with px2^ do begin r := (alpha * (sr - r) shr 18 + r); g := (alpha * (sg - g) shr 18 + g); b := (alpha * (sb - b) shr 18 + b); end; inc(px2); inc(psx); end; inc(psy); end end; procedure TIEBitmap.Render_ie8g(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean); var psy, syarr, psx, sxarr: pinteger; x, y, v: integer; pwb: pbytearray; black, white: integer; range: double; px2: prgb; begin black := trunc(fBlackValue); white := trunc(fWhiteValue); range := fWhiteValue - fBlackValue; // sxarr := XLUT; syarr := YLUT; psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); pwb := Scanline[psy^]; psx := sxarr; if range = 0 then begin for x := cx1 to cx2 do begin with px2^ do begin r := pwb[psx^]; g := r; b := r; end; inc(px2); inc(psx); end; end else begin // applies fBlackValue and fWhiteValue for x := cx1 to cx2 do begin v := pwb[psx^]; if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( psx^, psy^ ) then begin if v <= black then v := black; if v >= white then v := white; v := trunc(((v - black) / range) * 255); end; with px2^ do begin r := v; g := v; b := v; end; inc(px2); inc(psx); end; end; inc(psy); end end; procedure TIEBitmap.Render_ie8g_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; Opacity: double); var psy, syarr, psx, sxarr: pinteger; alpha, x, y, l: integer; px2: prgb; px3: pbytearray; pwb: pbytearray; black, white: integer; range: double; begin black := trunc(fBlackValue); white := trunc(fWhiteValue); range := fWhiteValue - fBlackValue; // sxarr := XLUT; syarr := YLUT; psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); pwb := Scanline[psy^]; if UseAlpha then px3 := AlphaChannel.ScanLine[psy^] else px3 := PByteArray(SimAlphaRow); psx := sxarr; if range = 0 then begin for x := cx1 to cx2 do begin alpha := trunc(imin(Transparency, px3[psx^]) * Opacity) shl 10; l := pwb[psx^]; with px2^ do begin r := (alpha * (l - r) shr 18 + r); g := (alpha * (l - g) shr 18 + g); b := (alpha * (l - b) shr 18 + b); end; inc(px2); inc(psx); end; end else begin for x := cx1 to cx2 do begin alpha := trunc(imin(Transparency, px3[psx^]) * Opacity) shl 10; l := pwb[psx^]; if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( psx^, psy^ ) then begin if l <= black then l := black; if l >= white then l := white; l := trunc(((l - black) / range) * 255); end; with px2^ do begin r := (alpha * (l - r) shr 18 + r); g := (alpha * (l - g) shr 18 + g); b := (alpha * (l - b) shr 18 + b); end; inc(px2); inc(psx); end; end; inc(psy); end; end; procedure TIEBitmap.Render_ie16g(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean); var psy, syarr, psx, sxarr: pinteger; x, y, v: integer; px2: prgb; pwa: pwordarray; black, white: integer; range: double; begin black := trunc(fBlackValue); white := trunc(fWhiteValue); range := fWhiteValue - fBlackValue; // sxarr := XLUT; syarr := YLUT; psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); pwa := Scanline[psy^]; psx := sxarr; if range = 0 then begin for x := cx1 to cx2 do begin with px2^ do begin r := pwa[psx^] shr 8; g := r; b := r; end; inc(px2); inc(psx); end; end else begin // applies fBlackValue and fWhiteValue for x := cx1 to cx2 do begin v := pwa[psx^]; if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( psx^, psy^ ) then begin if v <= black then v := black; if v >= white then v := white; v := trunc(((v - black) / range) * 255); end else v := v shr 8; with px2^ do begin r := v; g := v; b := v; end; inc(px2); inc(psx); end; end; inc(psy); end end; procedure TIEBitmap.Render_ie16g_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; Opacity: double); var psy, syarr, psx, sxarr: pinteger; alpha, x, y, l: integer; px2: prgb; px3: pbytearray; pwa: pwordarray; black, white: integer; range: double; begin black := trunc(fBlackValue); white := trunc(fWhiteValue); range := fWhiteValue - fBlackValue; sxarr := XLUT; syarr := YLUT; psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); pwa := Scanline[psy^]; if UseAlpha then px3 := AlphaChannel.ScanLine[psy^] else px3 := PByteArray(SimAlphaRow); psx := sxarr; if range = 0 then begin for x := cx1 to cx2 do begin alpha := trunc(imin(Transparency, px3[psx^]) * Opacity) shl 10; l := pwa[psx^] shr 8; with px2^ do begin r := (alpha * (l - r) shr 18 + r); g := (alpha * (l - g) shr 18 + g); b := (alpha * (l - b) shr 18 + b); end; inc(px2); inc(psx); end; end else begin // applies fBlackValue and fWhiteValue for x := cx1 to cx2 do begin alpha := trunc(imin(Transparency, px3[psx^]) * Opacity) shl 10; l := pwa[psx^]; if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( psx^, psy^ ) then begin if l <= black then l := black; if l >= white then l := white; l := trunc(((l - black) / range) * 255); end else l := l shr 8; with px2^ do begin r := (alpha * (l - r) shr 18 + r); g := (alpha * (l - g) shr 18 + g); b := (alpha * (l - b) shr 18 + b); end; inc(px2); inc(psx); end; end; inc(psy); end; end; procedure TIEBitmap.Render_ie32f(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean); var psy, syarr, psx, sxarr: pinteger; x, y, l: integer; px2: prgb; pwa: psinglearray; range: double; v: single; begin range := fWhiteValue - fBlackValue; // sxarr := XLUT; syarr := YLUT; psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); pwa := Scanline[psy^]; psx := sxarr; if range = 0 then begin for x := cx1 to cx2 do begin with px2^ do begin r := trunc(pwa[psx^] * 255); g := r; b := r; end; inc(px2); inc(psx); end; end else begin // applies fBlackValue and fWhiteValue for x := cx1 to cx2 do begin v := pwa[psx^]; if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( psx^, psy^ ) then begin if v <= fBlackValue then v := fBlackValue; if v >= fWhiteValue then v := fWhiteValue; l := trunc(((v - fBlackValue) / range) * 255); end else l := trunc(v * 255); with px2^ do begin r := l; g := l; b := l; end; inc(px2); inc(psx); end; end; inc(psy); end; end; procedure TIEBitmap.Render_ie32f_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; Opacity: double); var psy, syarr, psx, sxarr: pinteger; alpha, x, y, l: integer; px2: prgb; px3: pbytearray; pwa: psinglearray; range: double; v: single; begin range := fWhiteValue - fBlackValue; // sxarr := XLUT; syarr := YLUT; psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); pwa := Scanline[psy^]; if UseAlpha then px3 := AlphaChannel.ScanLine[psy^] else px3 := PByteArray(SimAlphaRow); psx := sxarr; if range = 0 then begin for x := cx1 to cx2 do begin alpha := trunc(imin(Transparency, px3[psx^]) * Opacity) shl 10; l := trunc(pwa[psx^] * 255); with px2^ do begin r := (alpha * (l - r) shr 18 + r); g := (alpha * (l - g) shr 18 + g); b := (alpha * (l - b) shr 18 + b); end; inc(px2); inc(psx); end; end else begin // applies fBlackValue and fWhiteValue for x := cx1 to cx2 do begin alpha := trunc(imin(Transparency, px3[psx^]) * Opacity) shl 10; v := pwa[psx^]; if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( psx^, psy^ ) then begin if v <= fBlackValue then v := fBlackValue; if v >= fWhiteValue then v := fWhiteValue; l := trunc(((v - fBlackValue) / range) * 255); end else l := trunc(v * 255); with px2^ do begin r := (alpha * (l - r) shr 18 + r); g := (alpha * (l - g) shr 18 + g); b := (alpha * (l - b) shr 18 + b); end; inc(px2); inc(psx); end; end; inc(psy); end; end; procedure TIEBitmap.Render_ieCMYK(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean); var psy, syarr, psx, sxarr: pinteger; x, y: integer; pwa: PCMYKROW; p_cmyk: PCMYK; stretchedCMYKRow: array of TCMYK; stretchedWidth: integer; p_rgb: PRGB; begin if IEGlobalSettings().ApplyColorProfileOnRendering and fColorProfile.IsValid() then fColorProfile.InitTransform(self.fRenderColorProfile, integer(iecmsCMYK), integer(iecmsBGR), 0, 0); stretchedWidth := cx2 - cx1 + 1; SetLength(stretchedCMYKRow, stretchedWidth); sxarr := XLUT; syarr := YLUT; psy := syarr; for y := cy1 to cy2 do begin pwa := Scanline[psy^]; p_cmyk := @stretchedCMYKRow[0]; psx := sxarr; for x := cx1 to cx2 do begin p_cmyk^ := pwa[psx^]; inc(psx); inc(p_cmyk); end; p_rgb := ABitmap.ScanLine[y]; inc(p_rgb, cx1); if IEGlobalSettings().ApplyColorProfileOnRendering and fColorProfile.IsValid() then IECMYK2RGBROW(@stretchedCMYKRow[0], p_rgb, stretchedWidth, nil, fColorProfile) else IECMYK2RGBROW(@stretchedCMYKRow[0], p_rgb, stretchedWidth); inc(psy); end; end; procedure TIEBitmap.Render_ieCMYK_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; Opacity: double); var psy, syarr, psx, sxarr: pinteger; x, y: integer; px3: pbytearray; pwa: PCMYKROW; stretchedCMYKRow: array of TCMYK; stretchedAlphaRow: array of integer; stretchedWidth: integer; p_cmyk: PCMYK; p_rgb: PRGB; p_alpha: pinteger; begin if IEGlobalSettings().ApplyColorProfileOnRendering and fColorProfile.IsValid() then fColorProfile.InitTransform(self.fRenderColorProfile, integer(iecmsCMYK), integer(iecmsBGR), 0, 0); stretchedWidth := (cx2 - cx1 + 1); SetLength(stretchedCMYKRow, stretchedWidth); SetLength(stretchedAlphaRow, stretchedWidth); sxarr := XLUT; syarr := YLUT; psy := syarr; for y := cy1 to cy2 do begin pwa := Scanline[psy^]; if UseAlpha then px3 := AlphaChannel.ScanLine[psy^] else px3 := PByteArray(SimAlphaRow); psx := sxarr; p_cmyk := @stretchedCMYKRow[0]; p_alpha := @stretchedAlphaRow[0]; for x := cx1 to cx2 do begin p_cmyk^ := pwa[psx^]; p_alpha^ := trunc(imin(Transparency, px3[psx^]) * Opacity) shl 10; inc(psx); inc(p_cmyk); inc(p_alpha); end; p_rgb := ABitmap.ScanLine[y]; inc(p_rgb, cx1); if IEGlobalSettings().ApplyColorProfileOnRendering and fColorProfile.IsValid() then IECMYK2RGBROW(@stretchedCMYKRow[0], p_rgb, stretchedWidth, @stretchedAlphaRow[0], fColorProfile) else IECMYK2RGBROW(@stretchedCMYKRow[0], p_rgb, stretchedWidth, @stretchedAlphaRow[0]); inc(psy); end; end; procedure TIEBitmap.Render_ieCIELab(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean); var psy, syarr, psx, sxarr: pinteger; x, y: integer; px2: prgb; pwa: PCIELABROW; rgb: TRGB; begin sxarr := XLUT; syarr := YLUT; psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); pwa := Scanline[psy^]; psx := sxarr; for x := cx1 to cx2 do begin rgb := IECIELAB2RGB( pwa[psx^] ); with px2^ do begin r := rgb.r; g := rgb.g; b := rgb.b; end; inc(px2); inc(psx); end; inc(psy); end; end; procedure TIEBitmap.Render_ieCIELab_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; Opacity: double); var psy, syarr, psx, sxarr: pinteger; alpha, x, y: integer; px2: prgb; px3: pbytearray; pwa: PCIELABROW; rgb: TRGB; begin sxarr := XLUT; syarr := YLUT; psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); pwa := Scanline[psy^]; if UseAlpha then px3 := AlphaChannel.ScanLine[psy^] else px3 := PByteArray(SimAlphaRow); psx := sxarr; for x := cx1 to cx2 do begin alpha := trunc(imin(Transparency, px3[psx^]) * Opacity) shl 10; rgb := IECIELAB2RGB( pwa[psx^] ); with px2^ do begin r := (alpha * (rgb.r - r) shr 18 + r); g := (alpha * (rgb.g - g) shr 18 + g); b := (alpha * (rgb.b - b) shr 18 + b); end; inc(px2); inc(psx); end; inc(psy); end; end; procedure TIEBitmap.Render_ie1g(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean); var psy, syarr, psx, sxarr: pinteger; x, y, l, rl: integer; //ww: integer; px2: prgb; px1: PRGBROW; begin //ww := ABitmap.Width; sxarr := XLUT; syarr := YLUT; l := -1; rl := abitmap.RowLen; //_PixelFormat2RowLen(ww, abitmap.pixelformat); psy := syarr; for y := cy1 to cy2 do begin if (l = psy^) and SolidBackground then begin CopyMemory(ABitmap.ScanLine[y], ABitmap.ScanLine[y - 1], rl); end else begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); px1 := Scanline[psy^]; psx := sxarr; for x := cx1 to cx2 do begin if (pbytearray(px1)^[psx^ shr 3] and iebitmask1[psx^ and $7]) = 0 then begin pword(px2)^ := 0; // set b, g inc(pword(px2)); pbyte(px2)^ := 0; // set r inc(pbyte(px2)); end else begin pword(px2)^ := $FFFF; // set b, g inc(pword(px2)); pbyte(px2)^ := $FF; // set r inc(pbyte(px2)); end; inc(psx); end; l := psy^; end; inc(psy); end; end; procedure TIEBitmap.Render_ie1g_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; Opacity: double); var psy, syarr, psx, sxarr: pinteger; alpha, x, y, l, rl: integer; px2: prgb; px1: PRGBROW; px3: pbytearray; begin //ww := ABitmap.Width; sxarr := XLUT; syarr := YLUT; l := -1; rl := ABitmap.RowLen; //_PixelFormat2RowLen(ww, abitmap.pixelformat); psy := syarr; for y := cy1 to cy2 do begin if (l = psy^) and SolidBackground then begin CopyMemory(ABitmap.ScanLine[y], ABitmap.ScanLine[y - 1], rl); end else begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); px1 := Scanline[psy^]; if UseAlpha then px3 := AlphaChannel.ScanLine[psy^] else px3 := PByteArray(SimAlphaRow); psx := sxarr; for x := cx1 to cx2 do begin alpha := trunc(imin(Transparency, px3[psx^]) * Opacity) shl 10; if (pbytearray(px1)^[psx^ shr 3] and iebitmask1[psx^ and $7]) = 0 then with px2^ do begin r := (alpha * (0 - r) shr 18 + r); g := (alpha * (0 - g) shr 18 + g); b := (alpha * (0 - b) shr 18 + b); end else with px2^ do begin r := (alpha * (255 - r) shr 18 + r); g := (alpha * (255 - g) shr 18 + g); b := (alpha * (255 - b) shr 18 + b); end; inc(px2); inc(psx); end; l := psy^; end; inc(psy); end; end; procedure TIEBitmap.Render_ie48RGB(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation); var psy, syarr, psx, sxarr: pinteger; x, y: integer; px2: prgb; vv: TRGB; px1: PRGB48ROW; vi: double; black, white: integer; range: double; rr, gg, bb: integer; begin black := trunc(fBlackValue); white := trunc(fWhiteValue); range := fWhiteValue - fBlackValue; sxarr := XLUT; syarr := YLUT; if fEnableChannelOffset or (fContrast <> 0) or (RenderOperation <> ielNormal) or (range <> 0) then begin // special drawing (channels separation) if fContrast >= 0 then vi := (1 + fContrast / 10) else vi := (1 - sqrt(- fContrast) / 10); psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); px1 := Scanline[psy^]; psx := sxarr; for x := cx1 to cx2 do begin if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( psx^, psy^ ) then begin if range <> 0 then begin rr := trunc(((ilimit(px1[psx^].r, black, white) - black) / range) * 65535); gg := trunc(((ilimit(px1[psx^].g, black, white) - black) / range) * 65535); bb := trunc(((ilimit(px1[psx^].b, black, white) - black) / range) * 65535); end else begin rr := px1[psx^].r; gg := px1[psx^].g; bb := px1[psx^].b; end; vv.r := blimit(trunc( (32768 + ((rr + fChannelOffset[0] - 32768) * vi)) ) shr 8); vv.g := blimit(trunc( (32768 + ((gg + fChannelOffset[1] - 32768) * vi)) ) shr 8); vv.b := blimit(trunc( (32768 + ((bb + fChannelOffset[2] - 32768) * vi)) ) shr 8); IEBlend(vv, px2^, RenderOperation, y); end else begin with px1[psx^] do begin px2^.r := r shr 8; px2^.g := g shr 8; px2^.b := b shr 8; end; end; inc(px2); inc(psx); end; inc(psy); end end else begin psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); px1 := Scanline[psy^]; psx := sxarr; for x := cx1 to cx2 do begin with px1[psx^] do begin px2^.r := r shr 8; px2^.g := g shr 8; px2^.b := b shr 8; end; inc(px2); inc(psx); end; inc(psy); end end; end; procedure TIEBitmap.Render_ie48RGB_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation; Opacity: double); var psy, syarr, psx, sxarr: pinteger; alpha, x, y: integer; px2: prgb; vv, v1: TRGB; px1: PRGB48ROW; px3: pbytearray; vi: double; begin sxarr := XLUT; syarr := YLUT; if fEnableChannelOffset or (fContrast <> 0) or (RenderOperation <> ielNormal) then begin // special drawing (channels separation) if fContrast >= 0 then vi := (1 + fContrast / 10) else vi := (1 - sqrt(-fContrast) / 10); psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); px1 := Scanline[psy^]; if UseAlpha then px3 := AlphaChannel.ScanLine[psy^] else px3 := PByteArray(SimAlphaRow); psx := sxarr; for x := cx1 to cx2 do begin alpha := trunc(imin(Transparency, px3[psx^]) * Opacity) shl 10; if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( psx^, psy^ ) then begin vv.r := blimit(trunc( (32768 + ((px1[psx^].r + fChannelOffset[0] - 32768) * vi)) ) shr 8); vv.g := blimit(trunc( (32768 + ((px1[psx^].g + fChannelOffset[1] - 32768) * vi)) ) shr 8); vv.b := blimit(trunc( (32768 + ((px1[psx^].b + fChannelOffset[2] - 32768) * vi)) ) shr 8); v1 := px2^; IEBlend(vv, v1, RenderOperation, y); end else begin v1.r := px1[psx^].r shr 8; v1.g := px1[psx^].g shr 8; v1.b := px1[psx^].b shr 8; end; px2^.r := (alpha * (v1.r - px2^.r) shr 18 + px2^.r); px2^.g := (alpha * (v1.g - px2^.g) shr 18 + px2^.g); px2^.b := (alpha * (v1.b - px2^.b) shr 18 + px2^.b); inc(px2); inc(psx); end; inc(psy); end end else begin psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); px1 := Scanline[psy^]; if UseAlpha then px3 := AlphaChannel.ScanLine[psy^] else px3 := PByteArray(SimAlphaRow); psx := sxarr; for x := cx1 to cx2 do begin alpha := trunc(imin(Transparency, px3[psx^]) * Opacity) shl 10; with px2^ do begin r := (alpha * (px1[psx^].r shr 8 - r) shr 18 + r); g := (alpha * (px1[psx^].g shr 8 - g) shr 18 + g); b := (alpha * (px1[psx^].b shr 8 - b) shr 18 + b); end; inc(px2); inc(psx); end; inc(psy); end; end; end; procedure TIEBitmap.Render_ie24RGB(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation); var psy, syarr, psx, sxarr: pinteger; x, y, l, rl: integer; px4, px2: prgb; vv: TRGB; px1: PRGBROW; rl4: integer; vi: integer; black, white: integer; range: double; begin // just an optimization if IsVirtual then begin Render_ieVirtual(ABitmap, XLUT, YLUT, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground, RenderOperation); exit; end; black := trunc(fBlackValue); white := trunc(fWhiteValue); range := fWhiteValue - fBlackValue; sxarr := XLUT; syarr := YLUT; l := -1; rl := ABitmap.RowLen; if fEnableChannelOffset or (fContrast <> 0) or (RenderOperation <> ielNormal) or (range <> 0) then begin // special drawing if fContrast >= 0 then vi := trunc((1 + fContrast / 10) * 65536) else vi := trunc((1 - sqrt(-fContrast) / 10) * 65536); psy := syarr; for y := cy1 to cy2 do begin if (l = psy^) and SolidBackground and (range = 0) then begin CopyMemory(ABitmap.ScanLine[y], ABitmap.ScanLine[y - 1], rl); end else begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); px1 := Scanline[psy^]; psx := sxarr; for x := cx1 to cx2 do begin if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( psx^, psy^ ) then begin vv.r := blimit(128 + (((px1[psx^].r + fChannelOffset[0] - 128) * vi) div 65536)); vv.g := blimit(128 + (((px1[psx^].g + fChannelOffset[1] - 128) * vi) div 65536)); vv.b := blimit(128 + (((px1[psx^].b + fChannelOffset[2] - 128) * vi) div 65536)); if range <> 0 then begin vv.r := trunc(((ilimit(vv.r, black, white) - black) / range) * 255); vv.g := trunc(((ilimit(vv.g, black, white) - black) / range) * 255); vv.b := trunc(((ilimit(vv.b, black, white) - black) / range) * 255); end; IEBlend(vv, px2^, RenderOperation, y); end else begin px2^ := px1[psx^]; end; inc(px2); inc(psx); end; l := psy^; end; inc(psy); end end else if (ry = 16384) and (rx = 16384) then begin // original sizes rl4 := (cx2 - cx1 + 1) * 3; for y := cy1 to cy2 do begin px4 := ScanLine[ySrc + (y - yDst)]; inc(px4, xSrc + (cx1 - xDst)); px2 := ABitmap.ScanLine[y]; inc(px2, cx1); CopyMemory(px2, px4, rl4); end; end else begin // subsample/oversample psy := syarr; for y := cy1 to cy2 do begin if (l = psy^) and SolidBackground then begin CopyMemory(ABitmap.ScanLine[y], ABitmap.ScanLine[y - 1], rl); end else begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); px1 := ScanLine[psy^]; psx := sxarr; for x := cx1 to cx2 do begin px2^ := px1[psx^]; inc(px2); inc(psx); end; l := psy^; end; inc(psy); end end; end; procedure TIEBitmap.Render_ie24RGB_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation; Opacity: double); var psy, syarr, psx, sxarr: pinteger; alpha, x, y, l, rl: integer; px2: prgb; vv, v1: TRGB; px1: PRGBROW; px3: pbytearray; vi: integer; black, white: integer; range: double; begin // just an optimization if IsVirtual then begin Render_ieVirtual_alpha(ABitmap, Transparency, UseAlpha, SimAlphaRow, XLUT, YLUT, xSrc, ySrc, xDst, yDst, cx1, cy1, cx2, cy2, rx, ry, SolidBackground, RenderOperation, Opacity); exit; end; black := trunc(fBlackValue); white := trunc(fWhiteValue); range := fWhiteValue - fBlackValue; sxarr := XLUT; syarr := YLUT; l := -1; rl := ABitmap.RowLen; //_PixelFormat2RowLen(ww, abitmap.pixelformat); if fEnableChannelOffset or (fContrast <> 0) or (RenderOperation <> ielNormal) or (range <> 0) then begin // special drawing (channels separation) if fContrast >= 0 then vi := trunc((1 + fContrast / 10) * 65536) else vi := trunc((1 - sqrt(-fContrast) / 10) * 65536); psy := syarr; for y := cy1 to cy2 do begin if (l = psy^) and SolidBackground then begin CopyMemory(ABitmap.ScanLine[y], ABitmap.ScanLine[y - 1], rl); end else begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); px1 := Scanline[psy^]; if UseAlpha then px3 := AlphaChannel.ScanLine[psy^] else px3 := PByteArray(SimAlphaRow); psx := sxarr; for x := cx1 to cx2 do begin alpha := trunc(imin(Transparency, px3[psx^]) * Opacity) shl 10; if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( psx^, psy^ ) then begin vv.r := blimit(128 + (((px1[psx^].r + fChannelOffset[0] - 128) * vi) div 65536)); vv.g := blimit(128 + (((px1[psx^].g + fChannelOffset[1] - 128) * vi) div 65536)); vv.b := blimit(128 + (((px1[psx^].b + fChannelOffset[2] - 128) * vi) div 65536)); if range <> 0 then begin vv.r := trunc(((ilimit(vv.r, black, white) - black) / range) * 255); vv.g := trunc(((ilimit(vv.g, black, white) - black) / range) * 255); vv.b := trunc(((ilimit(vv.b, black, white) - black) / range) * 255); end; v1 := px2^; IEBlend(vv, v1, RenderOperation, y); end else v1 := px1[psx^]; px2^.r := (alpha * (v1.r - px2^.r) shr 18 + px2^.r); px2^.g := (alpha * (v1.g - px2^.g) shr 18 + px2^.g); px2^.b := (alpha * (v1.b - px2^.b) shr 18 + px2^.b); inc(px2); inc(psx); end; l := psy^; end; inc(psy); end end else begin psy := syarr; for y := cy1 to cy2 do begin if (l = psy^) and SolidBackground then begin CopyMemory(ABitmap.ScanLine[y], ABitmap.ScanLine[y - 1], rl); end else begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); px1 := Scanline[psy^]; if UseAlpha then px3 := AlphaChannel.ScanLine[psy^] else px3 := PByteArray(SimAlphaRow); psx := sxarr; for x := cx1 to cx2 do begin if Transparency < px3[psx^] then alpha := trunc(Transparency * Opacity) shl 10 else alpha := trunc(px3[psx^] * Opacity) shl 10; with px2^ do begin r := (alpha * (px1[psx^].r - r) shr 18 + r); g := (alpha * (px1[psx^].g - g) shr 18 + g); b := (alpha * (px1[psx^].b - b) shr 18 + b); end; inc(px2); inc(psx); end; l := psy^; end; inc(psy); end end; end; procedure TIEBitmap.Render_ie32RGB(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation); var psy, syarr, psx, sxarr: pinteger; x, y, l, rl: integer; px2: prgb; vv: TRGB; px1: PRGB32ROW; vi: integer; begin sxarr := XLUT; syarr := YLUT; l := -1; rl := ABitmap.RowLen; if fEnableChannelOffset or (fContrast <> 0) or (RenderOperation <> ielNormal) or ((ry = 16384) and (rx = 16384)) then begin // special drawing if fContrast >= 0 then vi := trunc((1 + fContrast / 10) * 65536) else vi := trunc((1 - sqrt(-fContrast) / 10) * 65536); psy := syarr; for y := cy1 to cy2 do begin if (l = psy^) and SolidBackground then begin CopyMemory(ABitmap.ScanLine[y], ABitmap.ScanLine[y - 1], rl); end else begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); px1 := Scanline[psy^]; psx := sxarr; for x := cx1 to cx2 do begin vv.r := blimit(128 + (((px1[psx^].r + fChannelOffset[0] - 128) * vi) div 65536)); vv.g := blimit(128 + (((px1[psx^].g + fChannelOffset[1] - 128) * vi) div 65536)); vv.b := blimit(128 + (((px1[psx^].b + fChannelOffset[2] - 128) * vi) div 65536)); IEBlend(vv, px2^, RenderOperation, y); inc(px2); inc(psx); end; l := psy^; end; inc(psy); end end else begin // subsample/oversample psy := syarr; for y := cy1 to cy2 do begin if (l = psy^) and SolidBackground then begin CopyMemory(ABitmap.ScanLine[y], ABitmap.ScanLine[y - 1], rl); end else begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); px1 := Scanline[psy^]; psx := sxarr; for x := cx1 to cx2 do begin px2^.r := px1[psx^].r; px2^.g := px1[psx^].g; px2^.b := px1[psx^].b; inc(px2); inc(psx); end; l := psy^; end; inc(psy); end end; end; procedure TIEBitmap.Render_ie32RGB_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation; Opacity: double); var psy, syarr, psx, sxarr: pinteger; alpha, x, y, l, rl: integer; px2: prgb; vv, v1: TRGB; px1: PRGB32ROW; px3: pbytearray; vi: integer; begin sxarr := XLUT; syarr := YLUT; l := -1; rl := ABitmap.RowLen; //_PixelFormat2RowLen(ww, abitmap.pixelformat); if fEnableChannelOffset or (fContrast <> 0) or (RenderOperation <> ielNormal) then begin // special drawing (channels separation) if fContrast >= 0 then vi := trunc((1 + fContrast / 10) * 65536) else vi := trunc((1 - sqrt(-fContrast) / 10) * 65536); psy := syarr; for y := cy1 to cy2 do begin if (l = psy^) and SolidBackground then begin copymemory(ABitmap.ScanLine[y], ABitmap.ScanLine[y - 1], rl); end else begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); px1 := Scanline[psy^]; if UseAlpha then px3 := AlphaChannel.ScanLine[psy^] else px3 := PByteArray(SimAlphaRow); psx := sxarr; for x := cx1 to cx2 do begin alpha := trunc(imin(Transparency, px3[psx^]) * Opacity) shl 10; vv.r := blimit(128 + (((px1[psx^].r + fChannelOffset[0] - 128) * vi) div 65536)); vv.g := blimit(128 + (((px1[psx^].g + fChannelOffset[1] - 128) * vi) div 65536)); vv.b := blimit(128 + (((px1[psx^].b + fChannelOffset[2] - 128) * vi) div 65536)); v1 := px2^; IEBlend(vv, v1, RenderOperation, y); px2^.r := (alpha * (v1.r - px2^.r) shr 18 + px2^.r); px2^.g := (alpha * (v1.g - px2^.g) shr 18 + px2^.g); px2^.b := (alpha * (v1.b - px2^.b) shr 18 + px2^.b); inc(px2); inc(psx); end; l := psy^; end; inc(psy); end end else begin psy := syarr; for y := cy1 to cy2 do begin if (l = psy^) and SolidBackground then begin CopyMemory(ABitmap.ScanLine[y], ABitmap.ScanLine[y - 1], rl); end else begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); px1 := Scanline[psy^]; if UseAlpha then px3 := AlphaChannel.ScanLine[psy^] else px3 := PByteArray(SimAlphaRow); psx := sxarr; for x := cx1 to cx2 do begin alpha := trunc(imin(Transparency, px3[psx^]) * Opacity) shl 10; with px2^ do begin r := (alpha * (px1[psx^].r - r) shr 18 + r); g := (alpha * (px1[psx^].g - g) shr 18 + g); b := (alpha * (px1[psx^].b - b) shr 18 + b); end; inc(px2); inc(psx); end; l := psy^; end; inc(psy); end end; end; procedure TIEBitmap.Render_ieVirtual(ABitmap: TIEBitmap; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation); var psy, syarr, psx, sxarr: pinteger; x, y: integer; px2: prgb; rgb, vv: TRGB; vi: integer; begin if assigned(fVirtualBitmapProvider) then begin if fVirtualBitmapProvider is TIEVirtualBitmapProvider then begin (fVirtualBitmapProvider as TIEVirtualBitmapProvider).Render(self, ABitmap, ABitmap.Width, ABitmap.Height, cx1, cy1, cx2, cy2, XLUT, YLUT, 255, RenderOperation, 1.0); end; end; if assigned(fOnRenderVirtualPixel) then begin sxarr := XLUT; syarr := YLUT; if fEnableChannelOffset or (fContrast <> 0) or (RenderOperation <> ielNormal) or ((ry = 16384) and (rx = 16384)) then begin // special drawing if fContrast >= 0 then vi := trunc((1 + fContrast / 10) * 65536) else vi := trunc((1 - sqrt(-fContrast) / 10) * 65536); psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); psx := sxarr; for x := cx1 to cx2 do begin fOnRenderVirtualPixel(self, psx^, psy^, rgb); vv.r := blimit(128 + (((rgb.r + fChannelOffset[0] - 128) * vi) div 65536)); vv.g := blimit(128 + (((rgb.g + fChannelOffset[1] - 128) * vi) div 65536)); vv.b := blimit(128 + (((rgb.b + fChannelOffset[2] - 128) * vi) div 65536)); IEBlend(vv, px2^, RenderOperation, y); inc(px2); inc(psx); end; inc(psy); end end else begin // subsample/oversample psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); psx := sxarr; for x := cx1 to cx2 do begin fOnRenderVirtualPixel(self, psx^, psy^, px2^); inc(px2); inc(psx); end; inc(psy); end end; end; end; procedure TIEBitmap.Render_ieVirtual_alpha(ABitmap: TIEBitmap; Transparency: integer; UseAlpha: boolean; SimAlphaRow: pbyte; XLUT, YLUT: pinteger; xSrc, ySrc: integer; xDst, yDst: integer; cx1, cy1, cx2, cy2: integer; rx, ry: integer; SolidBackground: boolean; RenderOperation: TIERenderOperation; Opacity: double); var psy, syarr, psx, sxarr: pinteger; alpha, x, y: integer; px2: prgb; vv, v1, rgb: TRGB; vi: integer; abyte: byte; begin if assigned(fVirtualBitmapProvider) then begin if fVirtualBitmapProvider is TIEVirtualBitmapProvider then begin (fVirtualBitmapProvider as TIEVirtualBitmapProvider).Render(self, ABitmap, ABitmap.Width, ABitmap.Height, cx1, cy1, cx2, cy2, XLUT, YLUT, Transparency, RenderOperation, Opacity); end; end; if assigned(fOnRenderVirtualPixel) then begin sxarr := XLUT; syarr := YLUT; if fEnableChannelOffset or (fContrast <> 0) or (RenderOperation <> ielNormal) then begin // special drawing (channels separation) if fContrast >= 0 then vi := trunc((1 + fContrast / 10) * 65536) else vi := trunc((1 - sqrt(-fContrast) / 10) * 65536); psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); psx := sxarr; for x := cx1 to cx2 do begin if UseAlpha then abyte := AlphaChannel.pixels_ie8[psx^, psy^] else abyte := 255; if abyte > 0 then begin alpha := trunc(imin(Transparency, abyte) * Opacity) shl 10; fOnRenderVirtualPixel(self, psx^, psy^, rgb); vv.r := blimit(128 + (((rgb.r + fChannelOffset[0] - 128) * vi) div 65536)); vv.g := blimit(128 + (((rgb.g + fChannelOffset[1] - 128) * vi) div 65536)); vv.b := blimit(128 + (((rgb.b + fChannelOffset[2] - 128) * vi) div 65536)); v1 := px2^; IEBlend(vv, v1, RenderOperation, y); px2^.r := (alpha * (v1.r - px2^.r) shr 18 + px2^.r); px2^.g := (alpha * (v1.g - px2^.g) shr 18 + px2^.g); px2^.b := (alpha * (v1.b - px2^.b) shr 18 + px2^.b); end; inc(px2); inc(psx); end; inc(psy); end end else begin psy := syarr; for y := cy1 to cy2 do begin px2 := ABitmap.ScanLine[y]; inc(px2, cx1); psx := sxarr; for x := cx1 to cx2 do begin if UseAlpha then abyte := AlphaChannel.pixels_ie8[psx^, psy^] else abyte := 255; if abyte > 0 then begin alpha := trunc(imin(Transparency, abyte) * Opacity) shl 10; fOnRenderVirtualPixel(self, psx^, psy^, rgb); with px2^ do begin r := (alpha * (rgb.r - r) shr 18 + r); g := (alpha * (rgb.g - g) shr 18 + g); b := (alpha * (rgb.b - b) shr 18 + b); end; end; inc(px2); inc(psx); end; inc(psy); end end; end; end; {!! TIEBitmap.ChannelOffset Declaration property ChannelOffset[idx: integer]: integer; Description Allows an offset for each channel to be specified. Idx is the channel where 0=red, 1=green and 2=blue At the moment ChannelOffset works only with ie24RGB pixelformat. For example, to display only the red channel, just set green and blue to -255: ImageEnView.IEBitmap.ChannelOffset[1] := -255; // hide green ImageEnView.IEBitmap.ChannelOffset[2] := -255; // hide blue ImageEnView.Update; ChannelOffset is useful also to increase or decrease luminosity (brightness). Example: // trackbar1 has min=-255 and max=255. ImageEnView.IEBitmap.ChannelOffset[0] := trackbar1.Position; ImageEnView.IEBitmap.ChannelOffset[1] := trackbar1.Position; ImageEnView.IEBitmap.ChannelOffset[2] := trackbar1.Position; ImageEnView.Update; Finally you can use ChannelOffset to display the alpha channel as a black image, hiding all channels. Example: ImageEnView.IEBitmap.ChannelOffset[0] := -255; ImageEnView.IEBitmap.ChannelOffset[1] := -255; ImageEnView.IEBitmap.ChannelOffset[2] := -255; ImageEnView.Update; Demo Demos\Display\DisplayAdjust\Display.dpr !!} procedure TIEBitmap.SetChannelOffset(idx: integer; value: integer); var i: integer; begin if (idx >= 0) and (idx < IEMAXCHANNELS) then fChannelOffset[idx] := value; fEnableChannelOffset := false; for i := 0 to IEMAXCHANNELS - 1 do if fChannelOffset[i] <> 0 then begin fEnableChannelOffset := true; break; end; Changed(); end; function TIEBitmap.GetChannelOffset(idx: integer): integer; begin if (idx >= 0) and (idx < IEMAXCHANNELS) then result := fChannelOffset[idx] else result := 0; end; function TIEBitmap.GetAdjustmentsMask(): TIEMask; begin if fAdjustmentsMask = nil then fAdjustmentsMask := TIEMask.Create(); result := fAdjustmentsMask; end; {!! TIEBitmap.StretchRectTo Declaration procedure StretchRectTo(Dest: ; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; Filter: ; Transparency: integer = 255; Opacity: double = 1.0); Description Stretches source rectangle in destination rectangle. This method doesn't merge the image with the background, but just replace it (image and alpha). This function assumes that there is an alpha channel (if not creates it). Dest must be ie24RGB Opacity vs Transparency Both the Opacity and Transparency parameters provide the same functionality. Transparency is the traditional ImageEn value, whereas Opacity provides easier PSD compatibility. While they can be used in combination, generally only one will be used, i.e. leave Opacity=1 and make use of transparency, or alternatively, leave Transparency=255 and make use of Opacity. For example, for 50% opacity: Transparency = 255 and Opacity = 0.5, or Transparency = 128 and Opacity = 1.0 !!} procedure TIEBitmap.StretchRectTo(Dest: TIEBitmap; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; Filter: TResampleFilter; Transparency: integer = 255; Opacity: double = 1.0); var y, x, ww, hh: integer; px2, px4: prgb; px1: PRGBROW; pb1, pb2: pbyte; x2, y2: integer; rx, ry: integer; rl, rl4: integer; cx1, cy1, cx2, cy2: integer; fOffX, fOffY, frx, fry, fo1x, fo1y, fo2x, fo2y: integer; UseAlpha: boolean; sxarr, psx, syarr, psy: pinteger; ietmp1, ietmp2: TIEBitmap; begin if (Filter <> rfNone) and ((dxSrc <> dxDst) or (dySrc <> dyDst)) then begin // need to resample using a filter if (dxDst <= dxSrc) and (PixelFormat = ie1g) and (not HasAlphaChannel) then begin // subsample 1 bit bitmap if (dxDst > 0) and (dyDst > 0) then begin ietmp1 := TIEBitmap.Create; ietmp1.Allocate(dxDst, dyDst, ie24RGB); _SubResample1bitFilteredEx(self, xSrc, ySrc, xSrc + dxSrc - 1, ySrc + dySrc - 1, ietmp1); ietmp1.StretchRectTo(Dest, xDst, yDst, dxDst, dyDst, 0, 0, dxDst, dyDst, rfNone, Transparency, Opacity); FreeAndNil(ietmp1); end; end else begin // sub/over resample 1/24 bits bitmap ietmp1 := TIEBitmap.Create; ietmp1.Allocate(dxSrc, dySrc, PixelFormat); CopyRectTo(ietmp1, xSrc, ySrc, 0, 0, dxSrc, dySrc, true); ietmp2 := TIEBitmap.Create; if PixelFormat = ie1g then begin if (Filter=rfProjectBW) or (Filter=rfProjectWB) then ietmp2.Allocate(dxDst, dyDst, ie1g) else ietmp2.Allocate(dxDst, dyDst, ie24RGB); _Resample1bitEx(ietmp1, ietmp2, Filter); end else begin ietmp2.Allocate(dxDst, dyDst, ie24RGB); _ResampleEx(ietmp1, ietmp2, nil, Filter, nil, nil); end; if HasAlphaChannel then begin _Resampleie8g(ietmp1.AlphaChannel, ietmp2.AlphaChannel, Filter); ietmp2.AlphaChannel.Full := ietmp1.AlphaChannel.Full; end; ietmp2.StretchRectTo(Dest, xDst, yDst, dxDst, dyDst, 0, 0, dxDst, dyDst, rfNone, Transparency, Opacity); FreeAndNil(ietmp2); FreeAndNil(ietmp1); end; exit; // EXIT POINT end; fOffX := xDst; fOffY := yDst; frx := dxDst; fry := dyDst; fo1x := xSrc; fo1y := ySrc; fo2x := dxSrc; fo2y := dySrc; if (dxDst = 0) or (dyDst = 0) then exit; ww := Dest.Width; hh := Dest.Height; // if (dxDst <> 0) and (dyDst <> 0) then begin sxarr := nil; syarr := nil; try ry := trunc((fo2y / fry) * 16384); // 2^14 rx := trunc((fo2x / frx) * 16384); y2 := imin(fOffY + fry - 1, hh - 1); x2 := imin(fOffX + frx - 1, ww - 1); cx1 := -2147483646; cy1 := -2147483646; cx2 := 2147483646; cy2 := 2147483646; cx1 := imax(cx1, fOffX); cx2 := imin(cx2, x2); cy1 := imax(cy1, fOffY); cy2 := imin(cy2, y2); // cx1 := imax(cx1, 0); cx2 := imin(cx2, Dest.Width - 1); cy1 := imax(cy1, 0); cy2 := imin(cy2, Dest.Height - 1); // rl := Dest.RowLen; //l := -1; UseAlpha := HasAlphaChannel and (not AlphaChannel.Full); if (ry <> 16384) or (rx <> 16384) or (PixelFormat = ie1g) or UseAlpha then begin // build horizontal LUT getmem(sxarr, (cx2 - cx1 + 1) * sizeof(integer)); psx := sxarr; for x := cx1 to cx2 do begin psx^ := (rx * (x - fOffX) shr 14) + fo1x; inc(psx); end; // build vertical LUT getmem(syarr, (cy2 - cy1 + 1) * sizeof(integer)); psy := syarr; for y := cy1 to cy2 do begin psy^ := (ry * (y - fOffy) shr 14) + fo1y; inc(psy); end; end; if UseAlpha then begin // copy alpha channel if (ry = 16384) and (rx = 16384) then begin // original sizes rl4 := (cx2 - cx1 + 1); for y := cy1 to cy2 do begin pb1 := dest.AlphaChannel.Scanline[y]; inc(pb1, cx1); pb2 := AlphaChannel.scanline[fo1y + (y - fOffY)]; inc(pb2, fo1x + (cx1 - fOffX)); CopyMemory(pb1, pb2, rl4); end; end else begin // subsample/oversample psy := syarr; for y := cy1 to cy2 do begin pb2 := Dest.AlphaChannel.Scanline[y]; inc(pb2, cx1); pb1 := AlphaChannel.Scanline[psy^]; psx := sxarr; for x := cx1 to cx2 do begin pb2^ := pbytearray(pb1)[psx^]; inc(pb2); inc(psx); end; inc(psy); end end; for y := cy1 to cy2 do begin pb1 := Dest.AlphaChannel.Scanline[y]; inc(pb1, cx1); for x := cx1 to cx2 do begin pb1^ := trunc(imin(Transparency, pb1^) * Opacity); inc(pb1); end; end; end else dest.AlphaChannel.FillRect(cx1, cy1, cx2, cy2, trunc(Transparency * Opacity)); case PixelFormat of ie24RGB: // 24 bits per pixel begin if (ry = 16384) and (rx = 16384) then begin // original sizes rl4 := (cx2 - cx1 + 1); for y := cy1 to cy2 do begin px2 := Dest.GetSegment(y, cx1, rl4); px4 := GetSegment(fo1y + (y - fOffY), fo1x + (cx1 - fOffX), rl4); CopyMemory(px2, px4, rl4 * 3); end; end else begin // subsample/oversample psy := syarr; for y := cy1 to cy2 do begin px2 := Dest.Scanline[y]; inc(px2, cx1); px1 := Scanline[psy^]; psx := sxarr; for x := cx1 to cx2 do begin px2^ := px1[psx^]; inc(px2); inc(psx); end; inc(psy); end end; end; ie1g: // 1 bit per pixel begin psy := syarr; for y := cy1 to cy2 do begin px2 := Dest.Scanline[y]; inc(px2, cx1); px1 := Scanline[psy^]; psx := sxarr; for x := cx1 to cx2 do begin if (pbytearray(px1)^[psx^ shr 3] and iebitmask1[psx^ and $7]) = 0 then begin pword(px2)^ := 0; // set b, g inc(pword(px2)); pbyte(px2)^ := 0; // set r inc(pbyte(px2)); end else begin pword(px2)^ := $FFFF; // set b, g inc(pword(px2)); pbyte(px2)^ := $FF; // set r inc(pbyte(px2)); end; inc(psx); end; inc(psy); end end; end; // end of case except end; if (sxarr <> nil) then freemem(sxarr); if (syarr <> nil) then freemem(syarr); end; Dest.Changed(); end; {!! TIEBitmap.SyncFull Declaration procedure SyncFull; Description Sets to True if all values of the image are 255. !!} // works with all pixelformats procedure TIEBitmap.SyncFull; var px: pbyte; y, x, l: integer; begin l := IEBitmapRowLen(fWidth, fBitCount, 8); // do not use fRowLen because here we take account only 8 bit alignment for y := 0 to fHeight - 1 do begin px := Scanline[y]; for x := 0 to l - 1 do begin if (px^<$FF) then begin fFull := False; exit; end; inc(px); end; end; fFull := True; end; {!! TIEBitmap.IsAllBlack Declaration function IsAllBlack: boolean; Description Return true if all pixels are Zero. !!} function TIEBitmap.IsAllBlack: boolean; var px: pbyte; y, x, l: integer; begin l := IEBitmapRowLen(fWidth, fBitcount, 8); for y := 0 to fHeight - 1 do begin px := Scanline[y]; for x := 0 to l - 1 do begin if px^ <>0 then begin result := false; exit; end; inc(px); end; end; result := true; end; {!! TIEBitmap.IsGrayScale Declaration function IsGrayScale: boolean; Description Checks if all pixels have have equilavent R, G and B values (i.e. the bitmap is grayscale) !!} function TIEBitmap.IsGrayScale: boolean; var x, y: integer; pp: PRGB; p48: PRGB48; p32: PRGBA; begin result := true; case fPixelFormat of ie8p: for y := 0 to fRGBPaletteLen - 1 do begin with fRGBPalette[y] do if (r <> b) or (b <> g) then begin result := false; exit; end; end; ie24RGB: for y := 0 to fHeight - 1 do begin pp := scanline[y]; for x := 0 to fWidth - 1 do begin with pp^ do if (r <> b) or (b <> g) then begin result := false; exit; end; inc(pp); end; end; ie32RGB: for y := 0 to fHeight - 1 do begin p32 := scanline[y]; for x := 0 to fWidth - 1 do begin with p32^ do if (r <> b) or (b <> g) then begin result := false; exit; end; inc(p32); end; end; ie48RGB: for y := 0 to fHeight - 1 do begin p48 := scanline[y]; for x := 0 to fWidth - 1 do begin with p48^ do if (r <> b) or (b <> g) then begin result := false; exit; end; inc(p48); end; end; end; end; const IERAWVERSION: integer=0; IEMAGIKRAW: AnsiString='TIEBITMAPRAW'; // 12 chars {!! TIEBitmap.CalcRAWSize Declaration function CalcRAWSize: integer; Description Calculates the space required for method, when used with "Buffer" parameter. !!} function TIEBitmap.CalcRAWSize: integer; begin // main image result := 12; // magik inc(result, sizeof(integer)); // RAW version inc(result, sizeof(fRGBPaletteLen)); // fRGBPaletteLen inc(result, sizeof(TRGB)*fRGBPaletteLen); // fRGBPalette inc(result, sizeof(fWidth) ); // fWidth inc(result, sizeof(fHeight) ); // fHeight inc(result, sizeof(TIEPixelFormat) ); // fPixelFormat inc(result, sizeof(fFull) ); // fFull inc(result, sizeof(fPaletteUsed) ); // fPaletteUsed inc(result, sizeof(fBlackValue) ); // fBlackValue inc(result, sizeof(fWhiteValue) ); // fWhiteValue inc(result, sizeof(integer)*IEMAXCHANNELS ); // fChannelOffset[] inc(result, sizeof(fEnableChannelOffset) ); // fEnableChannelOffset inc(result, sizeof(fContrast) ); // fContrast inc(result, sizeof(fBitAlignment) ); // fBitAlignment inc(result, fRowLen * fHeight ); // the actual image inc(result, sizeof(boolean) ); // true if has alpha channel // alpha channel if HasAlphaChannel then begin inc(result, sizeof(boolean)); // fFull of alpha channel inc(result, AlphaChannel.RowLen * AlphaChannel.Height ); end; end; {!! TIEBitmap.SaveRAWToBufferOrStream Declaration procedure SaveRAWToBufferOrStream(Buffer: pointer; Stream: TStream; StreamHasSize: boolean = true); Description Saves the image using an internal format preserving pixel format and alpha channel. Location field will be lost. Only the image and its description is saved. If the image has alpha channel this is also saved. You can save the image inside a buffer or a stream. Saving in a buffer you must specify a valid Buffer (of size returned by ) and Stream must be nil. Saving in a Stream the Buffer parameter must be nil. Set StreamHasSize = true if specified Stream can set Size of stream. See Also - - !!} procedure TIEBitmap.SaveRAWToBufferOrStream(Buffer: pointer; Stream: TStream; StreamHasSize: boolean = true); var pw: integer; // writing position buf: PAnsiChar; procedure Write(const v; sz: integer); begin if Buffer<>nil then begin move(v, buf[pw], sz); inc(pw, sz); end else if assigned(Stream) then Stream.Write(v, sz); end; var row, sz: integer; bb: boolean; begin //// prepare for writing buf := Buffer; pw := 0; //// writing Write( IEMAGIKRAW[1], 12); // magik Write( IERAWVERSION, sizeof(integer)); // RAW version Write( fRGBPaletteLen, sizeof(fRGBPaletteLen)); // fRGBPaletteLen Write( fRGBPalette[0], sizeof(TRGB)*fRGBPaletteLen); // fRGBPalette Write( fWidth, sizeof(fWidth) ); // fWidth Write( fHeight, sizeof(fHeight) ); // fHeight Write( fPixelFormat, sizeof(TIEPixelFormat) ); // fPixelFormat Write( fFull, sizeof(fFull) ); // fFull Write( fPaletteUsed, sizeof(fPaletteUsed) ); // fPaletteUsed Write( fBlackValue, sizeof(fBlackValue) ); // fBlackValue Write( fWhiteValue, sizeof(fWhiteValue) ); // fWhiteValue Write( fChannelOffset[0], sizeof(integer)*IEMAXCHANNELS ); // fChannelOffset Write( fEnableChannelOffset, sizeof(fEnableChannelOffset) ); // fEnableChannelOffset Write( fContrast, sizeof(fContrast) ); // fContrast Write( fBitAlignment, sizeof(fBitAlignment) ); // fBitAlignment if assigned(Stream) and StreamHasSize then begin try sz := Stream.Position + fRowLen * fHeight; if sz > Stream.Size then Stream.Size := sz; except end; end; for row := 0 to fHeight-1 do Write( pbyte(Scanline[row])^, fRowLen ); bb := HasAlphaChannel; Write( bb, sizeof(boolean) ); // has alpha channel if bb then begin if assigned(Stream) and StreamHasSize then begin sz := Stream.Position + AlphaChannel.RowLen * fHeight; if sz > Stream.Size then Stream.Size := sz; end; for row := 0 to fHeight-1 do Write( pbyte(AlphaChannel.Scanline[row])^, AlphaChannel.RowLen ); Write( AlphaChannel.fFull, sizeof(boolean) ); end; end; {!! TIEBitmap.LoadRAWFromBufferOrStream Declaration function LoadRAWFromBufferOrStream(Buffer: pointer; Stream: TStream): boolean; Description Loads an image that was saved with . Return true on success. !!} // creates the image from the specified buffer (created using SaveRAWToBufferOrStream) function TIEBitmap.LoadRAWFromBufferOrStream(Buffer: pointer; Stream: TStream): boolean; var pr: integer; // reading position buf: PAnsiChar; procedure Read(var v; sz: integer); begin if Buffer<>nil then begin move( buf[pr], v, sz ); inc(pr, sz); end else if assigned(Stream) then Stream.Read(v, sz); end; var mag: AnsiString; ver: integer; // version NewRGBPaletteLen: integer; NewRGBPalette: pointer; NewWidth, NewHeight: integer; NewPixelFormat: TIEPixelFormat; NewFull: boolean; NewPaletteUsed: integer; NewBlackValue, NewWhiteValue: double; NewChannelOffset: array[0..IEMAXCHANNELS - 1] of integer; NewEnableChannelOffset: boolean; NewContrast: integer; NewBitAlignment: integer; NewHasAlpha: boolean; row: integer; begin result := false; pr := 0; buf := Buffer; // magik SetLength(mag, 12); Read(mag[1], 12); if mag<>IEMAGIKRAW then exit; // version Read(ver, sizeof(integer) ); if ver>=0 then begin // palette Read(NewRGBPaletteLen, sizeof(integer)); getmem(NewRGBPalette, NewRGBPaletteLen*sizeof(TRGB)); Read(NewRGBPalette^, NewRGBPaletteLen*sizeof(TRGB)); // other info Read(NewWidth, sizeof(integer)); Read(NewHeight, sizeof(integer)); Read(NewPixelFormat, sizeof(TIEPixelFormat)); Read(NewFull, sizeof(boolean)); Read(NewPaletteUsed, sizeof(integer)); Read(NewBlackValue, sizeof(double)); Read(NewWhiteValue, sizeof(double)); Read(NewChannelOffset, sizeof(integer)*IEMAXCHANNELS); Read(NewEnableChannelOffset, sizeof(boolean)); Read(NewContrast, sizeof(integer)); Read(NewBitAlignment, sizeof(integer)); // allocate bitmap BitAlignment := NewBitAlignment; Allocate(NewWidth, NewHeight, NewPixelFormat); fFull := NewFull; fPaletteUsed := NewPaletteUsed; fBlackValue := NewBlackValue; fWhiteValue := NewWhiteValue; move(NewChannelOffset[0], fChannelOffset, sizeof(integer)*IEMAXCHANNELS); fEnableChannelOffset := NewEnableChannelOffset; fContrast := NewContrast; // get image for row := 0 to fHeight-1 do Read( pbyte(Scanline[row])^, fRowLen); // get alpha Read( NewHasAlpha, sizeof(boolean) ); if NewHasAlpha then begin for row := 0 to fHeight-1 do Read( pbyte(AlphaChannel.Scanline[row])^, AlphaChannel.RowLen ); Read( AlphaChannel.fFull, sizeof(boolean) ); end else FreeAndNil(fAlphaChannel); result := true; end; fModified := False; end; {!! TIEBitmap.LoadFromResource Declaration procedure LoadFromResource(Instance: THandle; const ResName: string; ResType: PChar; Format: integer = 0); overload; procedure LoadFromResource(Instance: THandle; const ResID: Integer; ResType: PChar; Format: integer = 0); overload; Description Load an image from a resource. Parameter Description Instance The instance handle associated with the executable or shared library that contains the resource (e.g. HInstance for the current application) ResName/ResID The name or ID associated with resource ResType The type of the resource as defined when it was created, e.g. RT_BITMAP for a bitmap resource, or RT_RCDATA for raw data Format If this is 0 then the image format will be detected by reading its content, otherwise specify a type such as ioJPEG
Example // Load the About Box image from a JPEG resource in the current application MainForm1.ImageEnView1.IEBitmap.LoadFromResource( HInstance, 'AboutImage', RT_RCDATA, ioJPEG ); // Load the About Box image from a bitmap resource in the current application MainForm1.ImageEnView1.IEBitmap.LoadFromResource( HInstance, 'AboutImage', RT_BITMAP, ioBMP ); Copies current bitmap to Dest, using the SourceMask referred to the source. !!} procedure TIEBitmap.LoadFromResource(Instance: THandle; const ResName: string; ResType: PChar; Format: integer = 0); var Stream: TCustomMemoryStream; begin Stream := TResourceStream.Create(Instance, ResName, ResType); try fIsResource := True; Read(Stream, Format); finally fIsResource := False; Stream.Free; end; end; procedure TIEBitmap.LoadFromResource(Instance: THandle; const ResID: Integer; ResType: PChar; Format: integer = 0); var Stream: TCustomMemoryStream; begin Stream := TResourceStream.CreateFromID(Instance, ResID, ResType); try fIsResource := True; Read(Stream, Format); finally fIsResource := False; Stream.Free; end; end; {!! TIEBitmap.CopyWithMask1 Declaration procedure CopyWithMask1(Dest:
; SourceMask: ; Background: TColor); procedure CopyWithMask1(Dest: ; SourceMask: ); Description Copies the current bitmap to Dest, using the SourceMask referred to the source. !!} procedure TIEBitmap.CopyWithMask1(Dest: TIEBitmap; SourceMask: TIEMask; Background: TColor); begin if not SourceMask.IsEmpty then begin Dest.Allocate( SourceMask.x2 - SourceMask.x1 + 1, SourceMask.y2 - SourceMask.y1 + 1, PixelFormat ); Dest.Fill(Background); SourceMask.CopyIEBitmap(Dest, self, true, false, true); end; end; procedure TIEBitmap.CopyWithMask1(Dest: TIEBitmap; SourceMask: TIEMask); begin if not SourceMask.IsEmpty then begin Dest.Allocate( SourceMask.x2 - SourceMask.x1 + 1, SourceMask.y2 - SourceMask.y1 + 1, PixelFormat ); CopyRectTo(Dest, SourceMask.x1, SourceMask.y1, 0, 0, Dest.Width, Dest.Height, false); SourceMask.CopyIEBitmap(Dest, self, true, false, true); end; end; {!! TIEBitmap.CopyWithMask2 Declaration procedure CopyWithMask2(Dest: ; DestMask: ); Description Copies the current bitmap to Dest using DestMask referred to the destination. !!} procedure TIEBitmap.CopyWithMask2(Dest: TIEBitmap; DestMask: TIEMask); begin if not DestMask.IsEmpty then begin DestMask.CopyIEBitmap(Dest, self, false, true, false); if HasAlphaChannel then begin DestMask.CopyIEBitmap(Dest.AlphaChannel, self.AlphaChannel, false, true, false); Dest.AlphaChannel.Full := false; end; end; end; {!! TIEBitmap.AutoCalcBWValues Declaration procedure AutoCalcBWValues; Description Auto calculates and to correctly display the image. This method finds the low and high values of image pixels and sets them to the BlackValue and WhiteValue properties. !!} procedure TIEBitmap.AutoCalcBWValues; var x, y, colcount: integer; pw: pword; pb: pbyte; ps: psingle; begin case fPixelFormat of ie8g: begin fBlackValue := 255; fWhiteValue := -255; for y := 0 to fHeight-1 do begin pb := Scanline[y]; for x := 0 to fWidth-1 do begin if pb^>fWhiteValue then fWhiteValue := pb^; if pb^fWhiteValue then fWhiteValue := pw^; if pw^fWhiteValue then fWhiteValue := pb^; if pb^fWhiteValue then fWhiteValue := ps^; if ps^TIEBitmap.StretchValues Declaration procedure StretchValues(); Description Stretches the pixel values in the range of and . BlackValue and WhiteValue and then reset to zero. Works only when is ie8g, ie16g, ie24RGB and ie32f. !!} procedure TIEBitmap.StretchValues(); var row, col: integer; px8: pbyte; px16: pword; px24rgb: PRGB; px32f: psingle; range: double; iblack, iwhite: integer; begin range := fWhiteValue - fBlackValue; if range = 0 then exit; iblack := trunc(fBlackValue); iwhite := trunc(fWhiteValue); case fPixelFormat of ie8g: for row := 0 to fHeight - 1 do begin px8 := ScanLine[row]; for col := 0 to fWidth - 1 do begin if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( col, row ) then begin if px8^ < iblack then px8^ := iblack; if px8^ > iwhite then px8^ := iwhite; px8^ := trunc(((px8^ - iblack) / range) * 255); end; inc(px8); end; end; ie16g: for row := 0 to fHeight - 1 do begin px16 := ScanLine[row]; for col := 0 to fWidth - 1 do begin if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( col, row ) then begin if px16^ < iblack then px16^ := iblack; if px16^ > iwhite then px16^ := iwhite; px16^ := trunc(((px16^ - iblack) / range) * 65535); end; inc(px16); end; end; ie24RGB: for row := 0 to fHeight - 1 do begin px24rgb := ScanLine[row]; for col := 0 to fWidth - 1 do begin if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( col, row ) then begin if px24rgb^.r < iblack then px24rgb^.r := iblack; if px24rgb^.r > iwhite then px24rgb^.r := iwhite; px24rgb^.r := trunc(((px24rgb^.r - iblack) / range) * 255); if px24rgb^.g < iblack then px24rgb^.g := iblack; if px24rgb^.g > iwhite then px24rgb^.g := iwhite; px24rgb^.g := trunc(((px24rgb^.g - iblack) / range) * 255); if px24rgb^.b < iblack then px24rgb^.b := iblack; if px24rgb^.b > iwhite then px24rgb^.b := iwhite; px24rgb^.b := trunc(((px24rgb^.b - iblack) / range) * 255); end; inc(px24rgb); end; end; ie32f: for row := 0 to fHeight - 1 do begin px32f := ScanLine[row]; for col := 0 to fWidth - 1 do begin if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( col, row ) then begin if px32f^ < fBlackValue then px32f^ := fBlackValue; if px32f^ > fWhiteValue then px32f^ := fWhiteValue; px32f^ := (px32f^ - fBlackValue) / range; end; inc(px32f); end; end; end; fBlackValue := 0; fWhiteValue := 0; Changed(); end; {!! TIEBitmap.FixContrast Declaration procedure FixContrast(); Description Makes property permanent (applying specified contrast). The Contrast property is then reset to zero. Only works for ie24RGB, ie32RGB and ie48RGB pixel formats. !!} procedure TIEBitmap.FixContrast(); var row, col: integer; px24rgb: PRGB; px32rgb: PRGBA; px48rgb: PRGB48; vd: double; vi: integer; begin case fPixelFormat of ie24RGB: begin if fContrast >= 0 then vi := trunc((1 + fContrast / 10) * 65536) else vi := trunc((1 - sqrt(-fContrast) / 10) * 65536); for row := 0 to fHeight - 1 do begin px24rgb := ScanLine[row]; for col := 0 to fWidth - 1 do begin if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( col, row ) then with px24rgb^ do begin r := blimit(128 + (((r - 128) * vi) div 65536)); g := blimit(128 + (((g - 128) * vi) div 65536)); b := blimit(128 + (((b - 128) * vi) div 65536)); end; inc(px24rgb); end; end; end; ie32RGB: begin if fContrast >= 0 then vi := trunc((1 + fContrast / 10) * 65536) else vi := trunc((1 - sqrt(-fContrast) / 10) * 65536); for row := 0 to fHeight - 1 do begin px32rgb := ScanLine[row]; for col := 0 to fWidth - 1 do begin if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( col, row ) then with px32rgb^ do begin r := blimit(128 + (((r - 128) * vi) div 65536)); g := blimit(128 + (((g - 128) * vi) div 65536)); b := blimit(128 + (((b - 128) * vi) div 65536)); end; inc(px32rgb); end; end; end; ie48RGB: begin if fContrast >= 0 then vd := (1 + fContrast / 10) else vd := (1 - sqrt(-fContrast) / 10); for row := 0 to fHeight - 1 do begin px48rgb := ScanLine[row]; for col := 0 to fWidth - 1 do begin if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( col, row ) then with px48rgb^ do begin r := wlimit(trunc(32768 + (r - 32768) * vd)); g := wlimit(trunc(32768 + (g - 32768) * vd)); b := wlimit(trunc(32768 + (b - 32768) * vd)); end; inc(px48rgb); end; end; end; end; fContrast := 0; Changed(); end; {!! TIEBitmap.FixChannelOffset Declaration procedure FixChannelOffset(); Description Makes property permanent (applying specified offset). The ChannelOffset property values are then reset to zero. Only works for ie24RGB, ie32RGB and ie48RGB pixel formats. !!} procedure TIEBitmap.FixChannelOffset(); var row, col: integer; px24rgb: PRGB; px32rgb: PRGBA; px48rgb: PRGB48; i: integer; begin case fPixelFormat of ie24RGB: begin for row := 0 to fHeight - 1 do begin px24rgb := ScanLine[row]; for col := 0 to fWidth - 1 do begin if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( col, row ) then with px24rgb^ do begin r := blimit(r + fChannelOffset[0]); g := blimit(g + fChannelOffset[1]); b := blimit(b + fChannelOffset[2]); end; inc(px24rgb); end; end; end; ie32RGB: begin for row := 0 to fHeight - 1 do begin px32rgb := ScanLine[row]; for col := 0 to fWidth - 1 do begin if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( col, row ) then with px32rgb^ do begin r := blimit(r + fChannelOffset[0]); g := blimit(g + fChannelOffset[1]); b := blimit(b + fChannelOffset[2]); end; inc(px32rgb); end; end; end; ie48RGB: begin for row := 0 to fHeight - 1 do begin px48rgb := ScanLine[row]; for col := 0 to fWidth - 1 do begin if ( fAdjustmentsMask = nil ) or fAdjustmentsMask.IsEmpty or fAdjustmentsMask.IsPointInside( col, row ) then with px48rgb^ do begin r := wlimit(r + fChannelOffset[0]); g := wlimit(g + fChannelOffset[1]); b := wlimit(b + fChannelOffset[2]); end; inc(px48rgb); end; end; end; end; for i := 0 to IEMAXCHANNELS - 1 do fChannelOffset[i] := 0; Changed(); end; {!! TIEBitmap.SynchronizeRGBA Declaration procedure SynchronizeRGBA(RGBAtoAlpha: boolean; UpdatePixelFormat: Boolean = False); Description When ie32RGB (RGBA) pixel format is used, the A channel is not used. Alpha channel is stored in a separated plane (). To copy from A channel to ImageEn Alpha channel, call SynchronizeRGBA( True ); If UpdatePixelFormat is true, the will be set to ie24RGB. To copy from ImageEn Alpha channel to A channel, call SynchronizeRGBA( False ); Examples // Assign a 32bit Bitmap with alpha channel to an ImageEnView (keeping the alpha) var bmp: TBitmap; begin bmp := TBitmap.Create(); bmp.LoadFromFile( 'Bmp32_with_Alpha.bmp' ); ImageEnView1.IEBitmap.Assign( bmp ); ImageEnView1.IEBitmap.SynchronizeRGBA( true ); ImageEnView1.Update(); bmp.Free(); end; // Create a 32bit Bitmap with alpha channel var bmp: TBitmap; begin bmp := TBitmap.Create(); ImageEnView1.IEBitmap.SynchronizeRGBA( false ); ImageEnView1.IEBitmap.CopyToTBitmap( bmp ); bmp.SaveToFile( 'test.bmp' ); bmp.Free(); end; // Draw a semi-transparent ellipse var bitmap: TIEBitmap; begin bitmap := TIEBitmap.Create( 500, 500, ie32RGB ); // <= RGBA required! bitmap.Fill( 0 ); bitmap.AlphaChannel.Fill( 0 ); bitmap.IECanvas.SetCompositingMode( ieCompositingModeSourceOver, ieCompositingQualityDefault ); bitmap.IECanvas.Pen.Width := 4; bitmap.IECanvas.Pen.Color := clRed; bitmap.IECanvas.Brush.Color := clBlue; bitmap.IECanvas.Pen.Transparency := 90; bitmap.IECanvas.Brush.Transparency := 90; bitmap.IECanvas.Ellipse(10, 10, 400, 400); bitmap.SynchronizeRGBA( True ); // <= gdi+ draws alpha on RGBA. This copies 'A' to TIEBitmap alpha channel imageenview1.iebitmap.Assign( bitmap ); imageenview1.update; bitmap.Free(); end; See Also - !!} procedure TIEBitmap.SynchronizeRGBA(RGBAtoAlpha: boolean; UpdatePixelFormat: Boolean = False); var pb1, pb2: pbyte; row, col: integer; begin if RGBAToAlpha then begin // A of RGBA to AlphaChannel for row := 0 to fHeight-1 do begin AlphaChannel.Full := True; pb1 := Scanline[row]; pb2 := AlphaChannel.ScanLine[row]; for col := 0 to fWidth-1 do begin inc(pb1, 3); pb2^ := pb1^; if pb1^ < $FF then AlphaChannel.Full := False; inc(pb1); inc(pb2); end; end; if UpdatePixelFormat and ( PixelFormat = ie32RGB ) then PixelFormat := ie24RGB; end else begin // AlphaChannel to A of RGBA for row := 0 to fHeight-1 do begin pb1 := Scanline[row]; pb2 := AlphaChannel.ScanLine[row]; for col := 0 to fWidth-1 do begin inc(pb1, 3); pb1^ := pb2^; inc(pb1); inc(pb2); end; end; end; Changed(); end; {!! TIEBitmap.CopyPaletteTo Declaration procedure CopyPaletteTo(Dest: TIEBaseBitmap); Description Copies all palette colors to destination bitmap. Dest must be a object. !!} procedure TIEBitmap.CopyPaletteTo(Dest: TIEBaseBitmap); var dst: TIEBitmap; begin if Dest is TIEBitmap then begin dst := Dest as TIEBitmap; if assigned(dst.fRGBPalette) then begin freemem(dst.fRGBPalette); dst.fRGBPalette := nil; dst.fRGBPaletteLen := 0; dst.PaletteUsed := 256; end; if fRGBPaletteLen > 0 then begin getmem(dst.fRGBPalette, sizeof(TRGB) * fRGBPaletteLen); CopyMemory(dst.fRGBPalette, fRGBPalette, sizeof(TRGB)*fRGBPaletteLen); dst.fRGBPaletteLen := fRGBPaletteLen; dst.fPaletteUsed := fPaletteUsed; dst.UpdateTBitmapPalette; end; end; end; {!! TIEBitmap.MergeWithAlpha Declaration procedure MergeWithAlpha(Bitmap: ; DstX: integer=0; DstY: integer=0; DstWidth: integer=-1; DstHeight: integer=-1; Transparency: integer=255; ResampleFilter: = rfNone; Operation: = ielNormal; Resample: boolean = false; ; SrcX: integer = 0; SrcY: integer = 0; Opacity: double = 1.0); Description Merges pixels and alpha channel of Bitmap with the background. Parameter Description Bitmap Image with alpha channel to merge with the background. DstX Horizontal destination position. DstY Vertical destination position. DstWidth Destination width (Bitmap will be resampled/cropped to this value). -1 = the same width of source bitmap. DstHeight Destination height (Bitmap will be resampled/cropped to this value). -1 = the same height of source bitmap. Transparency Transparency of source bitmap. 0 = fully transparent, 255 = fully opaque. ResampleFilter Interpolation filter used when source bitmap needs to be resampled. Operation Blender operation to perform. Resample If true Bitmap is resampled, otherwise it is cropped. SrcX Source bitmap left position. SrcY Source bitmap top position.
Opacity vs Transparency Both the Opacity and Transparency parameters provide the same functionality. Transparency is the traditional ImageEn value, whereas Opacity provides easier PSD compatibility. While they can be used in combination, generally only one will be used, i.e. leave Opacity=1 and make use of transparency, or alternatively, leave Transparency=255 and make use of Opacity. For example, for 50% opacity: Transparency = 255 and Opacity = 0.5, or Transparency = 128 and Opacity = 1.0 Example // merges uplayer.png over background.png ImageEnView1.IO.LoadFromFile('background.png'); ImageEnView2.IO.LoadFromFile('uplayer.png'); ImageEnView1.IEBitmap.MergeWithAlpha(ImageEnView2.IEBitmap); ImageEnView1.Update; ImageEnView1.IO.SaveToFile('output.png'); !!} procedure TIEBitmap.MergeWithAlpha(Bitmap: TIEBitmap; DstX: integer; DstY: integer; DstWidth: integer; DstHeight: integer; Transparency: integer; ResampleFilter: TResampleFilter; Operation: TIERenderOperation; Resample: boolean; SrcX: integer; SrcY: integer; Opacity: double); var row, col: integer; rgb0: TRGB; prgb0: PRGB; // prgb0 is this bitmap and destination color prgb1: PRGB; // prgb1 is upper bitmap prgba1: PRGBA; palpha0: pbyte; // palpha0 is this bitmap alpha palpha1: pbyte; // palpha1 is upper layer alpha aa, bb, cc, opt1: double; w, h, r, g, b: integer; vrgb: TRGB; vrgba: TRGBA; negDstX, negDstY: integer; WorkingBitmap: TIEBitmap; begin if DstWidth = -1 then DstWidth := Bitmap.Width; if DstHeight = -1 then DstHeight := Bitmap.Height; if Resample and ((DstWidth <> Bitmap.Width) or (DstHeight <> Bitmap.Height)) then begin WorkingBitmap := TIEBitmap.Create(DstWidth, DstHeight, Bitmap.PixelFormat); _IEResampleIEBitmap(Bitmap, WorkingBitmap, ResampleFilter, nil, nil); end else WorkingBitmap := Bitmap; negDstX := 0; negDstY := 0; if DstX < 0 then begin negDstX := - DstX; DstX := 0; end; if DstY < 0 then begin negDstY := - DstY; DstY := 0; end; w := imin(fWidth, DstWidth + DstX - negDstX); h := imin(fHeight, DstHeight + DstY - negDstY); for row := DstY to h - 1 do begin palpha0 := AlphaChannel.ScanLine[row]; inc(palpha0, DstX); if PixelFormat <> ie24RGB then begin // Destination hasn't ie24RGB pixel format, use generic version case Bitmap.PixelFormat of ie24RGB: begin prgb1 := WorkingBitmap.Scanline[row - DstY + negDstY + SrcY]; inc(prgb1, negDstX + SrcX); palpha1 := WorkingBitmap.AlphaChannel.Scanline[row - DstY + negDstY + SrcY]; inc(palpha1, negDstX + SrcX); for col := DstX to w - 1 do begin aa := palpha0^ / 255; bb := imin(palpha1^, Transparency) / 255 * Opacity; opt1 := (1 - bb) * aa; cc := bb + opt1; rgb0 := GetPixels(col, row); vrgb := rgb0; IEBlend(prgb1^, vrgb, Operation, row); if cc <> 0 then begin rgb0.r := blimit( round((bb * vrgb.r + opt1 * rgb0.r) / cc) ); rgb0.g := blimit( round((bb * vrgb.g + opt1 * rgb0.g) / cc) ); rgb0.b := blimit( round((bb * vrgb.b + opt1 * rgb0.b) / cc) ); end else rgb0 := vrgb; SetPixels(col, row, rgb0); palpha0^ := round(cc * 255); inc(prgb1); inc(palpha0); inc(palpha1); end; end; ie32RGB: begin prgba1 := WorkingBitmap.Scanline[row - DstY + negDstY + SrcY]; inc(prgba1, negDstX + SrcX); for col := DstX to w - 1 do begin aa := palpha0^ / 255; bb := imin(prgba1^.a, Transparency) / 255 * Opacity; opt1 := (1 - bb) * aa; cc := bb + opt1; rgb0 := GetPixels(col, row); vrgba.r := rgb0.r; vrgba.g := rgb0.g; vrgba.b := rgb0.b; IEBlendRGBA(prgba1^, vrgba, Operation, row); if cc <> 0 then begin rgb0.r := blimit( round((bb * vrgba.r + opt1 * rgb0.r) / cc) ); rgb0.g := blimit( round((bb * vrgba.g + opt1 * rgb0.g) / cc) ); rgb0.b := blimit( round((bb * vrgba.b + opt1 * rgb0.b) / cc) ); end else begin rgb0.r := vrgba.r; rgb0.g := vrgba.g; rgb0.b := vrgba.b; end; SetPixels(col, row, rgb0); palpha0^ := round(cc * 255); inc(prgba1); inc(palpha0); end; end; end; end else begin // destination bitmap is ie24RGB, use optimized version prgb0 := Scanline[row]; inc(prgb0, DstX); case Bitmap.PixelFormat of ie24RGB: begin prgb1 := WorkingBitmap.Scanline[row - DstY + negDstY + SrcY]; inc(prgb1, negDstX + SrcX); palpha1 := WorkingBitmap.AlphaChannel.Scanline[row - DstY + negDstY + SrcY]; inc(palpha1, negDstX + SrcX); for col := DstX to w - 1 do begin aa := palpha0^ / 255; bb := imin(palpha1^, Transparency) / 255 * Opacity; opt1 := (1 - bb) * aa; cc := bb + opt1; vrgb.r := prgb0^.r; vrgb.g := prgb0^.g; vrgb.b := prgb0^.b; IEBlend(prgb1^, vrgb, Operation, row); if cc <> 0 then begin r := round((bb * vrgb.r + opt1 * prgb0^.r) / cc); g := round((bb * vrgb.g + opt1 * prgb0^.g) / cc); b := round((bb * vrgb.b + opt1 * prgb0^.b) / cc); prgb0^.r := blimit(r); prgb0^.g := blimit(g); prgb0^.b := blimit(b); end else prgb0^ := vrgb; palpha0^ := round(cc*255); inc(prgb0); inc(prgb1); inc(palpha0); inc(palpha1); end; end; ie32RGB: begin prgba1 := WorkingBitmap.Scanline[row - DstY + negDstY + SrcY]; inc(prgba1, negDstX + SrcX); for col := DstX to w - 1 do begin aa := palpha0^ / 255; bb := imin(prgba1^.a, Transparency) / 255 * Opacity; opt1 := (1 - bb) * aa; cc := bb + opt1; vrgba.r := prgb0^.r; vrgba.g := prgb0^.g; vrgba.b := prgb0^.b; IEBlendRGBA(prgba1^, vrgba, Operation, row); if cc <> 0 then begin r := round((bb * vrgba.r + opt1 * prgb0^.r) / cc); g := round((bb * vrgba.g + opt1 * prgb0^.g) / cc); b := round((bb * vrgba.b + opt1 * prgb0^.b) / cc); prgb0^.r := blimit(r); prgb0^.g := blimit(g); prgb0^.b := blimit(b); end else begin prgb0^.r := vrgba.r; prgb0^.g := vrgba.g; prgb0^.b := vrgba.b; end; palpha0^ := round(cc*255); inc(prgb0); inc(prgba1); inc(palpha0); end; end; end; end; end; if WorkingBitmap <> Bitmap then WorkingBitmap.Free(); Changed(); end; procedure TIEBitmap.SetOrigin(value: TIEBitmapOrigin); begin if fOrigin = value then exit; _FlipEx(self, fdVertical); AdjustCanvasOrientation; fOrigin := value; Changed(); end; {!! TIEBitmap.GetHash Declaration function GetHash(Algorithm:
= iehaMD5): AnsiString; Description Calculates the hash (using the specified hash algorithm) of the bitmap and returns the string representation of the hash. Example // calculates MD5 hash of input.jpg raster bitmap ImageEnView1.IO.LoadFromFile('input.jpg'); ShowMessage( ImageEnView1.IEBitmap.GetHash() ); // calculates MD5 hash of input.jpg with TIEHashStream.Create() do begin LoadFromFile('input.jpg'); ShowMessage( GetHash() ); end; !!} function TIEBitmap.GetHash(Algorithm: TIEHashAlgorithm): AnsiString; var hashStream: TIEHashStream; i: integer; rowbuf: pointer; begin hashStream := TIEHashStream.Create(Algorithm, false); try // hash of pixmap for i := fHeight-1 downto 0 do begin rowbuf := GetRow(i); try hashStream.Write(pbyte(rowbuf)^, fRowLen); finally FreeRow(i); end; end; if PixelFormat = ie8p then // hash of colormap hashStream.Write(pbyte(fRGBPalette)^, sizeof(TRGB) * fRGBPaletteLen); result := hashStream.GetHash(); finally hashStream.Free; end; end; {$ifdef IEVISION} {!! TIEBitmap.GetIEVisionImage Declaration function GetIEVisionImage(): ; Description Creates a TIEVisionImage container for the current image. This method can convert the image to a different pixel format and origin if necessary. Note: GetIEVisionImage will make the following changes to your image: - TIEBitmap.Origin changes to ieboTOPLEFT - If image has an 8 bit palette then TIEBitmap.PixelFormat changes to ie24RGB Example // perform OCR (English language is the default) of "input.tiff" ImageEnView1.IO.LoadFromFile('input.tiff'); str := IEVisionLib.createOCR().recognize(ImageEnView1.IEBitmap.GetIEVisionImage(), IEVisionRect(0, 0, 0, 0)).c_str(); !!} function TIEBitmap.GetIEVisionImage(): TIEVisionImage; var cFormat: TIEVisionChannelFormat; cCount: integer; begin result := nil; if PixelFormat = ie8p then PixelFormat := ie24RGB; // convert to RGB24 IEVisionConvPixelFormat(PixelFormat, cFormat, cCount); if cCount > 0 then begin Origin := ieboTOPLEFT; result := IEVisionLib.createImage(Width, Height, cFormat, cCount, Rowlen, ScanLine[0]); end; end; {!! TIEBitmap.AssignIEVisionImage Declaration procedure AssignIEVisionImage(Source: ); Description Copies source IEVision image into current TIEBitmap object, replacing previous image. Example ImageEnView1.IEBitmap.AssignIEVisionImage(ievisionImage); ImageEnView1.Update(); !!} procedure TIEBitmap.AssignIEVisionImage(Source: TIEVisionImage); var prevAccess: TIEDataAccess; minRowLen, row: DWORD; begin if not fEncapsulatedFromTBitmap then FreeImage(true) else begin if assigned(fAlphaChannel) then FreeAndNil(fAlphaChannel) end; fWidth := Source.getWidth(); fHeight := Source.getHeight(); fPixelFormat := IEVisionConvPixelFormat(Source.getChannelFormat(), Source.getChannels()); fFull := false; fBitAlignment := 32; AllocateImage(); // copy image prevAccess := Access; Access := [iedWrite]; minRowLen := i64min(fRowLen, Source.getRowLen()); for row := 0 to fHeight - 1 do CopyMemory(ScanLine[row], Source.getScanline(row), minRowLen); Access := prevAccess; // copy alpha channel if (not fIsAlpha) then begin if Source.hasAlphaMask() then // here we use GetAlphaChannel instead of fAlphaChannel to create alphachannel on the fly AlphaChannel.AssignIEVisionImage(Source.getAlphaMask()) else RemoveAlphaChannel(); // remove if there was an alpha channel end; Changed(); end; {$endif} function TIEBitmap.GetMemory(): pointer; begin if fLocation = ieTBitmap then result := self.fBitmapScanlines[fHeight - 1] else result := fMemory; end; function TIEBitmap.GetIsVirtual(): boolean; begin result := assigned(fOnRenderVirtualPixel) or assigned(fVirtualBitmapProvider); end; procedure TIEBitmap.SetVirtualBitmapProvider(value: TObject); begin if (value <> fVirtualBitmapProvider) and assigned(fVirtualBitmapProvider) then fVirtualBitmapProvider.Free(); fVirtualBitmapProvider := value; end; {!! TIEBitmap.Params Declaration property Params: ; Description If is true, then Params provides access to the object for the image. The parameters are updated when loading from files or streams. You can modify these parameters before saving the image. If is false, an exception will be raised. Note: should only be used when TIEBitmap is being used as a stand-alone object. When it is attached to a TImageEnView or TImageEnMIO, use TImageEnIO.Params instead. Example // Reduce the size of a JPEG image aBmp := TIEBitmap.create; aBmp.ParamsEnabled := True; // Load params with the image aBmp.Read( 'C:\MyImage.jpeg' ); aBmp.Params.JPEG_Quality := 70; aBmp.Write( 'C:\OutImage.jpeg' ); aBmp.Free; // Which is the same as: aBmp := TIEBitmap.create; aIOParams := TIOParams.create; aBmp.Read( 'C:\MyImage.jpeg', aIOParams ); aIOParams.JPEG_Quality := 70; aBmp.Write( 'C:\OutImage.jpeg', aIOParams ); aIOParams.free; aBmp.Free; !!} function TIEBitmap.GetParams : TIOParams; begin if GetParamsEnabled = False then Result := nil else result := fIOParams; end; {!! TIEBitmap.ParamsEnabled Declaration property ParamsEnabled: Boolean; Description If ParamsEnabled is true, then this object stores the Input/Output parameters (meta-data) for the image, which can be accessed via . Default: False. Note: should only be used when TIEBitmap is being used as a stand-alone object. When it is attached to a TImageEnView or TImageEnMIO, use TImageEnIO.Params instead. Example // Reduce the size of a JPEG image aBmp := TIEBitmap.create; aBmp.ParamsEnabled := True; // Load params with the image aBmp.Read( 'C:\MyImage.jpeg' ); aBmp.Params.JPEG_Quality := 70; aBmp.Write( 'C:\OutImage.jpeg' ); aBmp.Free; // Which is the same as: aBmp := TIEBitmap.create; aIOParams := TIOParams.create; aBmp.Read( 'C:\MyImage.jpeg', aIOParams ); aIOParams.JPEG_Quality := 70; aBmp.Write( 'C:\OutImage.jpeg', aIOParams ); aIOParams.free; aBmp.Free; !!} function TIEBitmap.GetParamsEnabled: Boolean; begin Result := assigned( fIOParams ); end; procedure TIEBitmap.SetParamsEnabled(const Value: Boolean); begin if assigned( fIOParams ) = Value then exit; if Value then begin fIOParams := TIOParams.create( Self ); end else begin FreeAndNil( fIOParams ); end; end; {!! TIEBitmap.Modified Declaration property Modified: Boolean; Description Returns true if the image has changed since loading. This includes methods such as , and , as well as any method of . Changes to the following properties do not affect Modified: - - - - - Notes: - Modified is reset to false whenever the TIEBitmap is loaded, i.e. using or via - Saving a TIEBitmap does not reset Modified Example // Check the status of the loaded image on FormClose If ImageEnView1.IEBitmap.Modified then if MessageDlg( 'Save changes to your image?', mtConfirmation, [mbYes,mbNo], 0) = mrYes then ImageEnView1.IO.SaveToFile( ImageEnView1.IEBitmap.Filename ); See Also - !!} procedure TIEBitmap.SetModified(Value: Boolean); begin if Value then Changed() else fModified := False; end; // Sets Modified and calls OnChanged procedure TIEBitmap.Changed(); begin fModified := True; if assigned( fOnChanged ) then fOnChanged( Self ); end; // end of TIEBitmap //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // TIETIFFIFDReader constructor TIETIFFIFDReader.Create(); begin inherited; LittleEndian := true; DataPosSize := 4; IsBigTIFF := false; Stream := nil; IFD := nil; BigIFD := nil; NumTags := 0; StreamBase := 0; end; destructor TIETIFFIFDReader.Destroy(); begin Clear(); inherited; end; procedure TIETIFFIFDReader.Clear(); begin if assigned(IFD) then freemem(IFD); IFD := nil; if assigned(BigIFD) then freemem(BigIFD); BigIFD := nil; end; procedure TIETIFFIFDReader.Assign(Source: TIETIFFIFDReader); begin Clear(); LittleEndian := Source.LittleEndian; Stream := Source.Stream; NumTags := Source.NumTags; StreamBase := Source.StreamBase; IsBigTIFF := Source.IsBigTIFF; DataPosSize := Source.DataPosSize; if assigned(Source.IFD) then begin getmem(IFD, NumTags * sizeof(TTIFFTAG)); CopyMemory(IFD, Source.IFD, NumTags * sizeof(TTIFFTAG)); end; if assigned(Source.BigIFD) then begin getmem(BigIFD, NumTags * sizeof(TBigTIFFTAG)); CopyMemory(BigIFD, Source.BigIFD, NumTags * sizeof(TBigTIFFTAG)); end; end; function TIETIFFIFDReader.GetDataNum(tagIndex: integer): int64; begin if assigned(IFD) then result := IFD[tagIndex].DataNum else if assigned(BigIFD) then result := BigIFD[tagIndex].DataNum else result := 0; end; function TIETIFFIFDReader.GetDataType(tagIndex: integer): word; begin if assigned(IFD) then result := IFD[tagIndex].DataType else if assigned(BigIFD) then result := BigIFD[tagIndex].DataType else result := 0; end; function TIETIFFIFDReader.GetDataPos(tagIndex: integer): int64; begin if assigned(IFD) then result := IFD[tagIndex].DataPos else if assigned(BigIFD) then result := BigIFD[tagIndex].DataPos else result := 0; end; function TIETIFFIFDReader.GetDataLengthInBytes(tagIndex: integer): int64; begin result := IETIFFCalcTagSize(GetDataType(tagIndex)) * GetDataNum(tagIndex); end; function TIETIFFIFDReader.GetItem(tagIndex: integer; dataIndex: int64): int64; var dpos: int64; dnum: int64; dtyp: word; dposptr: pbyte; itemSize: integer; begin result := 0; dnum := GetDataNum(tagIndex); dpos := GetDataPos(tagIndex); dtyp := GetDataType(tagIndex); itemSize := IETIFFCalcTagSize(dtyp); if dataIndex < dnum then begin if GetDataLengthInBytes(tagIndex) > DataPosSize then begin // load from stream Stream.Seek(StreamBase + dpos + dataIndex * itemSize, soBeginning); Stream.Read(result, itemSize); end else begin // load from "dpos" dposptr := pbyte(@dpos); inc(dposptr, dataIndex * itemSize); CopyMemory(@result, dposptr, itemSize); end; // adjust endianness if not LittleEndian then case dtyp of IETIFFTYPE_SHORT, IETIFFTYPE_SSHORT: result := IECSwapWord(result, true); IETIFFTYPE_LONG, IETIFFTYPE_SLONG, IETIFFTYPE_FLOAT, IETIFFTYPE_IFDPOINTER: result := IECSwapDWord(result, true); IETIFFTYPE_RATIONAL, IETIFFTYPE_SRATIONAL: IEChangeEndiannessDWordArray(pdword(@result), 2); // a rational is two dwords IETIFFTYPE_DOUBLE, IETIFFTYPE_LONG8, IETIFFTYPE_SLONG8, IETIFFTYPE_IFD8: result := IESwapInt64(result); end; end; end; // find tag index (-1=not found) function TIETIFFIFDReader.FindTAG(tagID: word): integer; begin if assigned(IFD) then begin for result := 0 to NumTags - 1 do if IFD[result].IdTag = tagID then exit; end else if assigned(BigIFD) then begin for result := 0 to NumTags - 1 do if BigIFD[result].IdTag = tagID then exit; end; result := -1; end; // read (S)LONG8, (S)SHORT, (S)LONG or (S)BYTE from nTag // def: the default value function TIETIFFIFDReader.ReadInteger(tagID: word; idx: int64; def: int64): int64; var t: integer; begin t := FindTAG(tagID); if t >= 0 then begin case GetDataType(t) of IETIFFTYPE_RATIONAL: begin result := trunc(ReadRational(tagID, idx, 0)); end; else result := GetItem(t, idx); end; end else result := def; end; // read a RATIONAL from nTag (specify tag id) // note: return a double function TIETIFFIFDReader.ReadRational(tagID: word; idx: integer; defaultValue: double): double; var num, den: longint; t: integer; item: int64; begin result := defaultValue; // default t := FindTAG(tagID); if t >= 0 then begin item := GetItem(t, idx); num := item and $FFFFFFFF; den := (item shr 32) and $FFFFFFFF; if den = 0 then den := 1; result := num / den; end; end; // read array of int64 (converting from original types like BYTE, SHORT, LONG...) // ar: pointer to the array (do not allocate. Free when you want) // NTag: tags count // result: elements count function TIETIFFIFDReader.ReadArrayIntegers(var ar: pint64array; tagID: word): integer; var t, q: integer; begin result := 0; t := FindTAG(tagID); if t >= 0 then begin result := GetDataNum(t); getmem(ar, sizeof(int64) * result); for q := 0 to result - 1 do ar[q] := GetItem(t, q); end; end; // assume DataPos contains an offset function TIETIFFIFDReader.ReadRawDataAsArrayOfByte(tagID: word): TIEArrayOfByte; var t: integer; dpos, dnum: int64; begin SetLength(result, 0); t := FindTAG(tagID); if t >= 0 then begin dpos := GetDataPos(t); dnum := GetDataNum(t); Stream.Seek(StreamBase + dpos, soBeginning); SetLength(result, dnum); Stream.Read(result[0], dnum); end; end; // assume DataPos contains an offset // read a block as UNDEFINED // return a pointer the data buffer (it must be freed by caller) function TIETIFFIFDReader.ReadRawData(tagID: word; var Size: integer): pointer; var t: integer; dpos, dnum: int64; begin result := nil; t := FindTAG(tagID); if t >= 0 then begin dpos := GetDataPos(t); dnum := GetDataNum(t); if dnum < Stream.Size then begin Stream.Seek(StreamBase + dpos, soBeginning); getmem(result, dnum); Stream.Read(pbyte(result)^, dnum); Size := dnum; end; end; end; function TIETIFFIFDReader.ReadString(tagID: word; truncToEZ: boolean): AnsiString; var t, i: integer; dnum: int64; begin result := ''; t := FindTAG(tagID); if t >= 0 then begin dnum := GetDataNum(t); if dnum < Stream.Size then begin SetLength(result, dnum); for i := 1 to dnum do result[i] := AnsiChar(GetItem(t, i - 1)); if truncToEZ then begin i := IEPos(#0, result); if i > 0 then SetLength(result, i - 1); end; end; end; end; function TIETIFFIFDReader.ReadWideString(tagID: word): WideString; var t, i: integer; dnum: int64; begin result := ''; t := FindTAG(tagID); if t >= 0 then begin dnum := GetDataNum(t); if dnum < Stream.Size then begin SetLength(result, (dnum - 2) div 2); for i := 0 to length(result) - 1 do result[i + 1] := WideChar( GetItem(t, i * 2) or (GetItem(t, i * 2 + 1) shl 8) ); end; end; end; // input // ImageIndex: image to read (0=first image) // Offset: the offset of the image IFD (TIFFHeader.PosIFD) // TIFFEnv.LittleEndian must be assigned // TIFFEnv.Stream must be assigned // TIFFEnv.StreamBase must be assigned // TIFFEnv.IsBigIFD must be assigned // output // ImageCount: images count // return // true = IFD loaded, false = IFD not loaded function TIETIFFIFDReader.ReadIFD(ImageIndex: integer; Offset: int64; var ImageCount: integer): boolean; var PosIFD, NextIFD: int64; i: integer; ntags: integer; begin // read TAGS for image idx result := false; Clear(); ImageCount := 0; PosIFD := Offset; repeat Stream.Seek(StreamBase + PosIFD, soBeginning); // read tag count if IsBigTIFF then ntags := IEStreamReadInt64(Stream, not LittleEndian) else ntags := IEStreamReadWord(Stream, not LittleEndian); if ntags = 0 then // to avoid infinite loop break; // is this the required IFD (page)? if ImageCount = ImageIndex then begin // read tags NumTags := ntags; if IsBigTIFF then begin BigIFD := AllocMem(ntags * sizeof(TBigTIFFTAG)); Stream.Read(pbyte(BigIFD)^, sizeof(TBigTIFFTAG) * ntags); end else begin IFD := AllocMem(ntags * sizeof(TTIFFTAG)); Stream.Read(pbyte(IFD)^, sizeof(TTIFFTAG) * ntags); end; end else begin // bypass tags if IsBigTIFF then Stream.Seek(sizeof(TBigTIFFTAG) * ntags, soCurrent) else Stream.Seek(sizeof(TTIFFTAG) * ntags, soCurrent); end; // wrong position? if Stream.Position >= Stream.Size then break; // read next IFD if IsBigTIFF then NextIFD := IEStreamReadInt64(Stream, not LittleEndian) else NextIFD := IEStreamReadDWord(Stream, not LittleEndian); if NextIFD <> PosIFD then // some TIFFs loop the IFD on itself PosIFD := NextIFD else PosIFD := 0; if (PosIFD < StreamBase + 8) or (PosIFD >= Stream.Size) then PosIFD := 0; // invalid IFD inc(ImageCount); until PosIFD = 0; if not assigned(IFD) and not assigned(BigIFD) then exit; // image doesn't exists // Convert TAGS to LittleEndian (if needed) if not LittleEndian then for i := 0 to NumTags - 1 do begin if assigned(IFD) then begin // classic TIFF IFD[i].IdTag := IESwapWord(IFD[i].IdTag); IFD[i].DataType := IESwapWord(IFD[i].DataType); IFD[i].DataNum := IESwapDWord(IFD[i].DataNum); if IFD[i].DataNum * IETIFFCalcTagSize(IFD[i].DataType) > 4 then IFD[i].DataPos := IESwapDWord(IFD[i].DataPos); // this is an offset end else if assigned(BigIFD) then begin // bigTIFF BigIFD[i].IdTag := IESwapWord(BigIFD[i].IdTag); BigIFD[i].DataType := IESwapWord(BigIFD[i].DataType); BigIFD[i].DataNum := IESwapInt64(BigIFD[i].DataNum); if BigIFD[i].DataNum * IETIFFCalcTagSize(BigIFD[i].DataType) > 8 then BigIFD[i].DataPos := IESwapInt64(BigIFD[i].DataPos); // this is an offset end; end; result := true; end; // TIETIFFIFDReader ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // TIETIFFIFDWriter constructor TIETIFFIFDWriter.Create(); begin inherited; Items := TList.Create(); end; destructor TIETIFFIFDWriter.Destroy(); var i: integer; begin for i := 0 to Items.Count - 1 do dispose(PTIFFTAG(Items[i])); Items.Free(); inherited; end; procedure TIETIFFIFDWriter.AddTag(IdTag: word; DataType: word; DataNum: integer; DataPos: dword); var tg: PTIFFTAG; begin new(tg); tg^.IdTag := IdTag; tg^.DataType := DataType; tg^.DataNum := DataNum; tg^.DataPos := DataPos; Items.Add(tg); end; function ReorderTagsCompare(Item1, Item2: Pointer): Integer; begin result := PTIFFTAG(Item1)^.IdTag - PTIFFTAG(Item2)^.IdTag; end; procedure TIETIFFIFDWriter.ReorderTags(); begin Items.Sort(ReorderTagsCompare); end; function TIETIFFIFDWriter.GetCount(): integer; begin result := Items.Count; end; function TIETIFFIFDWriter.GetTag(Index: integer): PTIFFTAG; begin result := PTIFFTAG(Items[Index]); end; procedure TIETIFFIFDWriter.WriteSingleLong(tag: integer; val: integer); begin AddTag(tag, IETIFFTYPE_LONG, 1, val); end; procedure TIETIFFIFDWriter.WriteSingleUndefined(tag: integer; val: dword; writeIfInList: TList = nil); begin if assigned(writeIfInList) and (writeIfInList.IndexOf(pointer(tag))<0) then exit; // don't write! AddTag(tag, IETIFFTYPE_UNDEFINED, 1, val); end; procedure TIETIFFIFDWriter.WriteMiniString(tag: integer; ss: AnsiString); var datapos: dword; begin datapos := 0; // just to fill with zeros move(PAnsiChar(ss)^, datapos, imin(4, length(ss))); AddTag(tag, IETIFFTYPE_ASCII, length(ss), datapos); end; procedure TIETIFFIFDWriter.WriteMiniByteString(tag: integer; ss: AnsiString); var datapos: dword; begin datapos := 0; // just to fill with zeros move(PAnsiChar(ss)^, datapos, imin(4, length(ss))); AddTag(tag, IETIFFTYPE_BYTE, length(ss), datapos); end; // write SHORT value procedure TIETIFFIFDWriter.WriteSingleShort(tag: integer; val: word; writeIfInList: TList = nil); begin if assigned(writeIfInList) and (writeIfInList.IndexOf(pointer(tag))<0) then exit; // don't write! AddTag(tag, IETIFFTYPE_SHORT, 1, val); end; // write BYTE value procedure TIETIFFIFDWriter.WriteSingleByte(tag: integer; val: byte); begin AddTag(tag, IETIFFTYPE_BYTE, 1, val); end; // write RATIONAL value procedure TIETIFFIFDWriter.WriteSingleRational(Stream: TStream; tag: integer; value: double; var Aborting: boolean; writeIfInList: TList=nil); var num, den: integer; begin if assigned(writeIfInList) and (writeIfInList.IndexOf(pointer(tag))<0) then exit; // don't write! IEDecimalToFraction(value, num, den); AddTag(tag, IETIFFTYPE_RATIONAL, 1, IEStreamWordAlign(Stream, Aborting)); SafeStreamWrite(Stream, Aborting, num, sizeof(integer)); SafeStreamWrite(Stream, Aborting, den, sizeof(integer)); end; procedure TIETIFFIFDWriter.WriteMultiRational(Stream: TStream; tag: integer; values: array of double; var Aborting: boolean); var i: integer; num, den: integer; begin AddTag(tag, IETIFFTYPE_RATIONAL, length(values), IEStreamWordAlign(Stream, Aborting)); for i := 0 to high(values) do begin IEDecimalToFraction(values[i], num, den); SafeStreamWrite(Stream, Aborting, num, sizeof(integer)); SafeStreamWrite(Stream, Aborting, den, sizeof(integer)); end; end; // writes a string (only if <> '') procedure TIETIFFIFDWriter.WriteString(Stream: TStream; tag: integer; ss: AnsiString; var Aborting: boolean); var len: integer; begin len := length(ss); if len = 0 then exit; if len < 5 then WriteMiniString(tag, ss) else begin AddTag(tag, IETIFFTYPE_ASCII, len + 1, IEStreamWordAlign(Stream, Aborting)); SafeStreamWrite(Stream, Aborting, PAnsiChar(ss)^, len + 1); end; end; procedure TIETIFFIFDWriter.WriteWideString(Stream: TStream; tag: integer; ss: WideString; var Aborting: boolean); var len: integer; w: word; datapos: dword; begin len := length(ss); if len > 0 then begin if len = 1 then begin datapos := pword( @ss[1] )^; end else begin datapos := IEStreamWordAlign(Stream, Aborting); SafeStreamWrite(Stream, Aborting, pwchar(ss)^, len * 2); w := 0; Stream.Write(w, 2); end; AddTag(tag, IETIFFTYPE_BYTE, (len + 1) * 2, datapos); end; end; procedure TIETIFFIFDWriter.WriteArrayOfByte(Stream: TStream; Tag: word; DataType: word; Buffer: TIEArrayOfByte; var Aborting: boolean); begin if length(Buffer) > 0 then begin AddTag(Tag, DataType, length(Buffer), IEStreamWordAlign(Stream, Aborting)); SafeStreamWrite(Stream, Aborting, Buffer[0], length(Buffer)); end; end; procedure TIETIFFIFDWriter.WriteMultiLongEx(Stream: TStream; tag: integer; arr: array of dword; arraylen: integer; var Aborting: boolean); begin AddTag(tag, IETIFFTYPE_LONG, arraylen, IEStreamWordAlign(Stream, Aborting)); SafeStreamWrite(Stream, Aborting, arr[0], arraylen * sizeof(dword)); end; procedure TIETIFFIFDWriter.WriteMultiShort(Stream: TStream; tag: integer; const vals: array of word; var Aborting: boolean); var len: integer; datapos: dword; begin len := length(vals); if len = 1 then begin datapos := vals[0]; end else if len = 2 then begin datapos := vals[0] or (vals[1] shl 16); end else begin datapos := IEStreamWordAlign(Stream, Aborting); SafeStreamWrite(Stream, Aborting, vals, len * sizeof(word)); end; AddTag(tag, IETIFFTYPE_SHORT, len, datapos); end; // TIETIFFIFDWriter /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // TIETagsHandler constructor TIETagsHandler.Create; begin inherited; fIFD := TIETIFFIFDReader.Create(); fUnparsedData := nil; fUnparsedDataLength := 0; fData := TMemoryStream.Create; fIFD.Stream := fData; fEXIFMakerInfo.signature := ''; fEXIFMakerInfo.base := iemnAbsolute; fEXIFMakerInfo.headerType := iemnNONE; fEXIFMakerInfo.byteOrder := ieboFromEXIF; end; destructor TIETagsHandler.Destroy; begin Clear; fData.Free; fIFD.Free(); inherited; end; procedure TIETagsHandler.Clear; begin fIFD.Clear(); if assigned(fUnparsedData) then freemem(fUnparsedData); fUnparsedData := nil; fUnparsedDataLength := 0; fEXIFMakerInfo.signature := ''; fEXIFMakerInfo.base := iemnAbsolute; fEXIFMakerInfo.headerType := iemnNONE; fEXIFMakerInfo.byteOrder := ieboFromEXIF; fIFD.LittleEndian := true; fIFD.StreamBase := 0; fIFD.NumTags := 0; fData.Clear; end; procedure TIETagsHandler.Assign(source: TIETagsHandler); begin Clear; IECopyFrom(fData, source.fData, 0); fIFD.LittleEndian := source.fIFD.LittleEndian; Update; if assigned(source.fUnparsedData) then begin fUnparsedDataLength := source.fUnparsedDataLength; getmem(fUnparsedData, fUnparsedDataLength); CopyMemory(fUnparsedData, source.fUnparsedData, fUnparsedDataLength); end; fEXIFMakerInfo := source.fEXIFMakerInfo; end; procedure TIETagsHandler.ReadFromStreamUnparse(stream: TStream; size: integer); var buffer: PAnsiChar; begin Clear(); getmem(buffer, size); UnparsedData := pointer(buffer); UnparsedDataLength := size; stream.Read(buffer^, size); end; // find EXIF Maker note type and bypass header function TIETagsHandler.CheckHeader(buffer: pointer; bufferLen: integer): TIEEXIFMakerNoteDeviceInfo; const devices: array [0..12] of TIEEXIFMakerNoteDeviceInfo = ( (signature: ''; sigbypass:0; base: iemnAbsolute; headerType: iemnNONE; byteOrder: ieboFromEXIF), // default (signature: 'SONY CAM '#0#0#0; sigbypass:0; base: iemnAbsolute; headerType: iemnNONE; byteOrder: ieboFromEXIF), // Maker1 (signature: 'SONY DSC '#0#0#0; sigbypass:0; base: iemnAbsolute; headerType: iemnNONE; byteOrder: ieboFromEXIF), // Maker2 (signature: 'Nikon'#0#2#16#0#0; sigbypass:0; base: iemnTIFFHeader; headerType: iemnTIFF; byteOrder: ieboFromTIFFHeader), // Maker3 (signature: 'QVC'#0#0#0; sigbypass:0; base: iemnAbsolute; headerType: iemnNONE; byteOrder: ieboBigEndian), // Maker4 (signature: 'EPSON'#0#1#0; sigbypass:0; base: iemnAbsolute; headerType: iemnNONE; byteOrder: ieboFromEXIF), // Maker5 (signature: 'Nikon'#0#1#0; sigbypass:0; base: iemnAbsolute; headerType: iemnNONE; byteOrder: ieboFromEXIF), // Maker6 (signature: 'Panasonic'#0#0#0; sigbypass:0; base: iemnAbsolute; headerType: iemnNONE; byteOrder: ieboFromEXIF), // Maker7 (signature: 'FUJIFILM'; sigbypass:0; base: iemnTIFFHeader; headerType: iemnIFDOFFSET; byteOrder: ieboLittleEndian), // Maker8 (signature: 'LEICA'#0#0#0; sigbypass:0; base: iemnTIFFHeader; headerType: iemnNONE; byteOrder: ieboFromEXIF), // Maker9 (signature: 'OLYMP'#0#2#0; sigbypass:0; base: iemnEXIFSegment; headerType: iemnNONE; byteOrder: ieboFromEXIF), // Maker10 (signature: 'Nikon'#0#2#17#0#0; sigbypass:0; base: iemnTIFFHeader; headerType: iemnTIFF; byteOrder: ieboFromTIFFHeader), // Maker11 (signature: 'Nikon'#0#2#0#0#0; sigbypass:0; base: iemnTIFFHeader; headerType: iemnTIFF; byteOrder: ieboFromTIFFHeader) // Maker12 ); var i: integer; begin result := devices[0]; // the default for i := 1 to High(devices) do if CompareMem(@devices[i].signature[1], buffer, imin(bufferLen, length(devices[i].signature))) then begin result := devices[i]; break; end; end; // exifSegmentPos = position of MakerNote tag relative to the beginning of EXIF segment procedure TIETagsHandler.ReadFromStream(stream: TStream; size: integer; littleEndian: boolean; exifSegmentPos: int64; clearOnFail: boolean; addTagFunc: TIETagsHandlerAddTagFunc); var i, z: integer; buffer: PAnsiChar; tagscount: word; tag: PTIFFTAG; good: boolean; datapos: dword; tagpos: dword; basePos: int64; bufferPos: integer; dpos: integer; headPos: int64; dw: dword; begin Clear(); good := false; dpos := 0; headPos := 0; if size < sizeof(word) then exit; getmem(buffer, size); UnparsedData := pointer(buffer); UnparsedDataLength := size; try basePos := stream.Position; stream.Read(buffer^, size); bufferPos := 0; fEXIFMakerInfo := CheckHeader(UnparsedData, UnparsedDataLength); inc(bufferPos, length(fEXIFMakerInfo.signature)); inc(bufferPos, fEXIFMakerInfo.sigbypass); case fEXIFMakerInfo.headerType of iemnTIFF: begin // read header as TIFF header headPos := bufferPos; CopyMemory(@fEXIFMakerInfo.TIFFHeader, @buffer[bufferPos], sizeof(TTIFFHeader)); inc(bufferPos, sizeof(TTIFFHeader)); end; iemnIFDOFFSET: begin // read IFD offset and move headPos := bufferPos - length(fEXIFMakerInfo.signature); CopyMemory(@dw, @buffer[bufferPos], sizeof(dword)); inc(bufferPos, dw - dword(length(fEXIFMakerInfo.signature))); end; end; if bufferPos >= size then exit; case fEXIFMakerInfo.byteOrder of ieboFromTIFFHeader: littleEndian := fEXIFMakerInfo.TIFFHeader.Id = $4949; ieboLittleEndian: littleEndian := true; ieboBigEndian: littleEndian := false; end; // We store all tags as littleEndian, but storing fIFD.LittleEndian with the actual byte order // is necessary for decoding SHORT and array of values by the TIFFReadXXXXX functions. fIFD.LittleEndian := littleEndian; // read tag count tagscount := IECSwapWord(pword(@buffer[bufferPos])^, not littleEndian); inc(bufferPos, sizeof(word)); if (tagscount > 256) or (size < sizeof(TTIFFTAG) * tagscount) then exit; // maximum 256 tags (it is very large...) Data.Write(tagscount, sizeof(word)); tagpos := Data.Position; datapos := tagpos + sizeof(TTIFFTAG) * tagscount; for i := 0 to tagscount - 1 do begin if bufferPos + sizeof(TTIFFTAG) >= size then break; tag := PTIFFTAG( @buffer[bufferPos] ); if assigned(addTagFunc) then addTagFunc(bufferPos + basePos, littleEndian, tag^); tag^.IdTag := IECSwapWord(tag^.IdTag, not littleEndian); tag^.DataType := IECSwapWord(tag^.DataType, not littleEndian); tag^.DataNum := IECSwapDWord(tag^.DataNum, not littleEndian); tag^.DataPos := IECSwapDWord(tag^.DataPos, not littleEndian); z := tag^.DataNum * IETIFFCalcTagSize(tag^.DataType); // size in bytes if z > 4 then begin case fEXIFMakerInfo.base of iemnAbsolute: dpos := tag^.DataPos - basePos; iemnTIFFHeader: dpos := tag^.DataPos + headPos; iemnEXIFSegment: dpos := tag^.DataPos - exifSegmentPos; end; if (dpos < 0) or (int64(dpos) + z > size) then begin // invalid data position, make tag invalid tag^.DataNum := 0; tag^.DataPos := 0; end else begin tag^.DataPos := datapos; Data.Position := datapos; // go to position to write tag data Data.Write(pbyte(@buffer[dpos])^, z); // write tag data datapos := Data.Position; // save tag data position for next writing end; end; // write the tag Data.Position := tagpos; Data.Write(tag^, sizeof(TTIFFTAG)); tagpos := Data.Position; // go to next tag to read inc(bufferPos, sizeof(TTIFFTAG)); end; Update; good := true; finally if not good and clearOnFail then Clear(); end; end; // returns written stream size function TIETagsHandler.WriteToStream(stream: TStream; exifSegmentPos: int64): integer; var i, z: integer; tagscount: word; tag: TTIFFTAG; indexPos_read, indexPos_write: integer; dataPos_write: integer; dw: dword; ww: word; streamBase: int64; littleEndian: boolean; dataOffset: integer; b: byte; begin streamBase := stream.Position; stream.Write(fEXIFMakerInfo.signature[1], length(fEXIFMakerInfo.signature)); b := 0; for i := 1 to fEXIFMakerInfo.sigbypass do stream.Write(b, 1); littleEndian := true; dataOffset := 0; case fEXIFMakerInfo.headerType of iemnTIFF: begin // prepare and write TIFF header littleEndian := fEXIFMakerInfo.TIFFHeader.Id = $4949; case fEXIFMakerInfo.base of iemnAbsolute: fEXIFMakerInfo.TIFFHeader.PosIFD := stream.Position + length(fEXIFMakerInfo.signature) + sizeof(TTIFFHeader); iemnTIFFHeader: fEXIFMakerInfo.TIFFHeader.PosIFD := sizeof(TTIFFHeader); end; fEXIFMakerInfo.TIFFHeader.PosIFD := IECSwapDWord(fEXIFMakerInfo.TIFFHeader.PosIFD, not littleEndian); stream.Write(fEXIFMakerInfo.TIFFHeader, sizeof(TTIFFHeader)); end; iemnIFDOFFSET: begin // write IFD offset dataOffset := length(fEXIFMakerInfo.signature); dw := length(fEXIFMakerInfo.signature) + 4; stream.Write(dw, sizeof(dword)); end; end; // write new tags count Data.Position := 0; Data.Read(tagscount, 2); ww := IECSwapWord(tagscount, not littleEndian); stream.Write(ww, 2); indexPos_read := 2; indexPos_write := stream.Position; dataPos_write := stream.Position + tagscount * sizeof(TTIFFTAG) + 4; // +4 = next IFD pointer for i := 0 to tagscount - 1 do begin Data.Position := indexPos_read; Data.Read(tag, sizeof(TTIFFTAG)); inc(indexPos_read, sizeof(TTIFFTAG)); z := tag.DataNum * IETIFFCalcTagSize(tag.DataType); if z > 4 then begin Data.Position := tag.DataPos; case fEXIFMakerInfo.base of iemnAbsolute: tag.DataPos := dataPos_write; iemnTIFFHeader: tag.DataPos := dataPos_write - streamBase - length(fEXIFMakerInfo.signature) + dataOffset; iemnEXIFSegment: tag.DataPos := dataPos_write + exifSegmentPos; // dpos := tag^.DataPos - exifSegmentPos; end; stream.Position := dataPos_write; if (Data.Position + z <= Data.Size) and (z > 0) then // 3.0.2 IECopyFrom(stream, Data, z); inc(dataPos_write, z); if (dataPos_write and $1) <> 0 then inc(dataPos_write); end; tag.IdTag := IECSwapWord(tag.IdTag, not littleEndian); tag.DataType := IECSwapWord(tag.DataType, not littleEndian); tag.DataNum := IECSwapDWord(tag.DataNum, not littleEndian); tag.DataPos := IECSwapDWord(tag.DataPos, not littleEndian); stream.Position := indexPos_write; stream.Write(tag, sizeof(TTIFFTAG)); inc(indexPos_write, sizeof(TTIFFTAG)); end; // next IFD (always none) dw := 0; stream.Position := indexPos_write; stream.Write(dw, sizeof(dword)); result := dataPos_write - streamBase; stream.Position := dataPos_write; if result > 65000 then begin // abort stream.Position := streamBase; result := 0; end; end; procedure TIETagsHandler.SetUnparsedData(value: pointer); begin if assigned(fUnparsedData) then freemem(fUnparsedData); fUnparsedData := value; if fUnparsedData = nil then fUnparsedDataLength := 0; end; procedure TIETagsHandler.Update; var w: word; i: integer; begin if fData.Size > 0 then begin fData.Position := 0; fData.Read(w, sizeof(word)); fIFD.NumTags := w; if fIFD.IFD <> nil then freemem(fIFD.IFD); fIFD.IFD := nil; getmem(fIFD.IFD, w * sizeof(TTIFFTAG)); for i := 0 to w - 1 do fData.Read(fIFD.IFD[i], sizeof(TTIFFTAG)); end; end; {!! TIETagsHandler.GetMiniString Declaration function GetMiniString(Tag: integer): AnsiString; Description Returns the specified tag as a string of 4 bytes. !!} function TIETagsHandler.GetMiniString(Tag: integer): AnsiString; begin result := fIFD.ReadString(Tag); end; {!! TIETagsHandler.GetString Declaration function GetString(Tag: integer): AnsiString; Description Returns the specified tag as string. !!} function TIETagsHandler.GetString(Tag: integer): AnsiString; begin result := fIFD.ReadString(Tag); end; {!! TIETagsHandler.GetRawData Declaration function GetRawData(Tag: integer): pointer; Description Returns the specified tag as a raw bytes buffer. !!} function TIETagsHandler.GetRawData(Tag: integer): pointer; var Size: integer; begin result := fIFD.ReadRawData(Tag, Size); end; {!! TIETagsHandler.GetIntegerArray Declaration function GetIntegerArray(Tag: integer; var ar: ): integer; Description Returns the speicifed tag as an array of integers. !!} function TIETagsHandler.GetIntegerArray(Tag: integer; var ar: pint64array): integer; begin result := fIFD.ReadArrayIntegers(ar, Tag); end; {!! TIETagsHandler.GetIntegerIndexed Declaration function GetIntegerIndexed(Tag: integer; index: integer): integer; Description Returns the specified tag as an array of integers. !!} function TIETagsHandler.GetIntegerIndexed(Tag: integer; index: integer): integer; begin result := fIFD.ReadInteger(Tag, index, 0); end; {!! TIETagsHandler.GetRationalIndexed Declaration function GetRationalIndexed(Tag: integer; index: integer; defVal: double = 0.0): double; Description Returns the specified tag as an array of doubles. !!} function TIETagsHandler.GetRationalIndexed(Tag: integer; index: integer; defVal: double): double; begin result := fIFD.ReadRational(Tag, index, defVal); end; {!! TIETagsHandler.GetRational Declaration function GetRational(Tag: integer; defaultValue: double = 0): double; Description Returns the specified tag as double. !!} function TIETagsHandler.GetRational(Tag: integer; defaultValue: double): double; begin result := fIFD.ReadRational(Tag, 0, defaultValue); end; {!! TIETagsHandler.GetInteger Declaration function GetInteger(Tag: integer): integer; Description Returns the specified tag as integer. !!} function TIETagsHandler.GetInteger(Tag: integer): integer; begin result := fIFD.ReadInteger(tag, 0, 0); end; {!! TIETagsHandler.GetDataType Declaration function GetDataType(Tag: integer): integer; Description Returns the type of a tag. It will be one of: IETIFFTYPE_BYTE IETIFFTYPE_ASCII IETIFFTYPE_SHORT IETIFFTYPE_LONG IETIFFTYPE_RATIONAL IETIFFTYPE_SBYTE IETIFFTYPE_UNDEFINED IETIFFTYPE_SSHORT IETIFFTYPE_SLONG IETIFFTYPE_SRATIONAL IETIFFTYPE_FLOAT IETIFFTYPE_DOUBLE IETIFFTYPE_IFDPOINTER IETIFFTYPE_UNICODE IETIFFTYPE_COMPLEX IETIFFTYPE_LONG8 IETIFFTYPE_SLONG8 IETIFFTYPE_IFD8 !!} function TIETagsHandler.GetDataType(Tag: integer): integer; begin result := fIFD.GetDataType( tag ); end; {!! TIETagsHandler.TagLength Declaration function TagLength(Tag: integer): integer; Description Returns the tag length in bytes. !!} function TIETagsHandler.TagLength(Tag: integer): integer; var t: integer; begin result := 0; t := fIFD.FindTAG(Tag); if t >= 0 then result := fIFD.GetDataLengthInBytes(t); end; {!! TIETagsHandler.TagExists Declaration function TagExists(Tag: integer): boolean; Description Returns True if the specified tag exists. !!} function TIETagsHandler.TagExists(Tag: integer): boolean; begin result := fIFD.FindTAG(Tag) > -1; end; // TIETagsHandler ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // TIETagsHandlerRelocator constructor TIETagsHandlerRelocator.Create(Stream_: TStream; Position_: int64; Offset_: int64; LittleEndian_: boolean); begin inherited Create(); Stream := Stream_; Position := Position_; Offset := Offset_; LittleEndian := LittleEndian_; TagsHandler := TIETagsHandler.Create(); end; destructor TIETagsHandlerRelocator.Destroy(); begin TagsHandler.Free(); inherited; end; procedure TIETagsHandlerRelocator.AddTagFunc(tagPosition: integer; littleEndian: boolean; var tag: TTIFFTAG); var modTag: TTIFFTAG; begin if tag.DataNum * IETIFFCalcTagSize(tag.DataType) > 4 then begin modTag := tag; modTag.DataPos := IECSwapDWord(IECSwapDWord(tag.DataPos, not littleEndian) + offset, not littleEndian); Stream.Position := tagPosition; Stream.Write(modTag, sizeof(TTIFFTAG)); end; end; procedure TIETagsHandlerRelocator.Relocate(); begin Stream.Position := Position; TagsHandler.ReadFromStream(Stream, Stream.Size, LittleEndian, 0, true, AddTagFunc); end; // TIETagsHandlerRelocator ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // TIETIFTagsReader {!! TIETIFTagsReader.GetMiniString Declaration function GetMiniString(Tag: integer): AnsiString; Description Returns a string value (maximum four characters) for the specified Tag number. !!} function TIETIFTagsReader.GetMiniString(Tag: integer): AnsiString; begin result := fIFD.ReadString(Tag); end; {!! TIETIFTagsReader.GetString Declaration function GetString(Tag: integer): AnsiString; Description Returns a string value for the specified Tag number. !!} function TIETIFTagsReader.GetString(Tag: integer): AnsiString; begin result := fIFD.ReadString(Tag); end; {!! TIETIFTagsReader.GetRawData Declaration function GetRawData(Tag: integer): pointer; Description Returns a raw buffer for the specified Tag number. You must free the buffer using FreeMem. !!} function TIETIFTagsReader.GetRawData(Tag: integer): pointer; var Size: integer; begin result := fIFD.ReadRawData(Tag, Size); end; {!! TIETIFTagsReader.GetIntegerArray Declaration function GetIntegerArray(Tag: integer; var ar: ): integer; Description Returns an array of integers for the specified Tag number. !!} function TIETIFTagsReader.GetIntegerArray(Tag: integer; var ar: pint64array): integer; begin result := fIFD.ReadArrayIntegers(ar, Tag); end; {!! TIETIFTagsReader.GetIntegerIndexed Declaration function GetIntegerIndexed(Tag: integer; index: integer): integer; Description Returns the indexed integer value for the specified Tag number. !!} function TIETIFTagsReader.GetIntegerIndexed(Tag: integer; index: integer): integer; begin result := fIFD.ReadInteger(Tag, index, 0); end; {!! TIETIFTagsReader.GetRationalIndexed Declaration function GetRationalIndexed(Tag: integer; index: integer; defVal: double=0.0): double; Description Returns the indexed double (rational) value for the specified Tag number. !!} function TIETIFTagsReader.GetRationalIndexed(Tag: integer; index: integer; defVal: double): double; begin result := fIFD.ReadRational(Tag, index, defVal); end; {!! TIETIFTagsReader.GetRational Declaration function GetRational(Tag: integer; defaultValue: double = 0): double; Description Returns the double (rational) value for the specified Tag number. !!} function TIETIFTagsReader.GetRational(Tag: integer; defaultValue: double): double; begin result := fIFD.ReadRational(Tag, 0, defaultValue); end; {!! TIETIFTagsReader.GetInteger Declaration function GetInteger(Tag: integer): int64; Description Returns the integer value for the specified Tag number. !!} function TIETIFTagsReader.GetInteger(Tag: integer): int64; begin result := fIFD.ReadInteger(tag, 0, 0); end; {!! TIETIFTagsReader.TagLength Declaration function TagLength(Tag: integer): integer; Description Returns the tag count for indexed tags. !!} function TIETIFTagsReader.TagLength(Tag: integer): integer; var t: integer; begin result := 0; t := fIFD.FindTAG(Tag); if t >= 0 then result := fIFD.GetDataLengthInBytes(t); end; {!! TIETIFTagsReader.TagExists Declaration function TagExists(Tag: integer): boolean; Description Returns True if the specified tag exists. !!} function TIETIFTagsReader.TagExists(Tag: integer): boolean; begin result := fIFD.FindTAG(Tag) > -1; end; {!! TIETIFTagsReader.CreateFromFile Declaration constructor CreateFromFile(const FileName: string; ImageIndex: integer); Description This constructor loads the tags from a file, at the ImageIndex page (0 is the first page). !!} constructor TIETIFTagsReader.CreateFromFile(const FileName: string; ImageIndex: integer); begin inherited; fIFD := TIETIFFIFDReader.Create(); fFileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); fStream := fFileStream; TIFFLoadTags(fStream, fNumi, ImageIndex, fIFD); end; {!! TIETIFTagsReader.CreateFromStream Declaration constructor CreateFromStream(Stream: TStream; ImageIndex: integer); Description This constructor loads the tags from a stream, at the ImageIndex page (0 is the first page). !!} constructor TIETIFTagsReader.CreateFromStream(Stream: TStream; ImageIndex: integer); begin inherited; fIFD := TIETIFFIFDReader.Create(); fFileStream := nil; fStream := Stream; TIFFLoadTags(fStream, fNumi, ImageIndex, fIFD); end; {!! TIETIFTagsReader.CreateFromIFD Declaration constructor CreateFromIFD(tagReader: ; IFDTag: integer); Description Creates a new from a tag. This is useful to read tiff trees. !!} constructor TIETIFTagsReader.CreateFromIFD(tagReader: TIETIFTagsReader; IFDTag: integer); var pos: int64; begin inherited; fIFD := TIETIFFIFDReader.Create(); fFileStream := nil; fStream := tagReader.fStream; pos := tagReader.GetInteger(IFDTag); fIFD.Stream := fStream; fIFD.LittleEndian := tagReader.fIFD.LittleEndian; fIFD.ReadIFD(0, pos, fnumi); end; destructor TIETIFTagsReader.Destroy; begin if assigned(fFileStream) then FreeAndNil(fFileStream); fIFD.Free(); inherited; end; ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // TIETIFFHandler ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// {$ifdef IEINCLUDETIFFHANDLER} procedure TIETIFFHandler.init(); begin fBuffers := TList.Create(); fPages := TList.Create(); fBigEndian := false; fVersion := $2A; end; {!! TIETIFFHandler.Create Declaration constructor Create(); constructor Create(const FileName: string); constructor Create(Stream: TStream); Description Creates a TIETIFFHandler object, optionally reading image data from file or stream. !!} constructor TIETIFFHandler.Create(); begin inherited Create; init(); end; constructor TIETIFFHandler.Create(const FileName: string); begin inherited Create; init(); ReadFile(FileName); end; constructor TIETIFFHandler.Create(Stream: TStream); begin inherited Create; init(); ReadStream(Stream); end; destructor TIETIFFHandler.Destroy(); begin FreeData(); FreeAndNil(fPages); FreeAndNil(fBuffers); inherited; end; // Convert BigEndian to LittleEndian (and viceversa), if necessary function TIETIFFHandler.xword(value: word): word; begin if fBigEndian then result := IESwapWord(value) else result := value; end; // Convert BigEndian to LittleEndian (and viceversa), if necessary function TIETIFFHandler.xdword(value: dword): dword; begin if fBigEndian then result := IESWapDWord(value) else result := value; end; {!! TIETIFFHandler.ReadFile Declaration function ReadFile(const FileName: string): boolean; Description Reads the TIFF from file. !!} function TIETIFFHandler.ReadFile(const FileName: string): boolean; var fs: TFileStream; begin result := false; if not IEFileExists(FileName) then exit; fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try result := ReadStream(fs); finally FreeAndNil(fs); end; end; // fills tgpos and tglen with position tag and length tag of tagCode, if it is a special tag (a data-tag with associated len-tag) // otherwise sets tgpos=-1 and tglen=-1. procedure TIETIFFHandler.CheckPairTag(tagCode: integer; var tgpos: integer; var tglen: integer); begin tgpos := -1; tglen := -1; // canonical tiff tags case tagCode of 273: // StripOffsets begin tgpos := 273; tglen := 279; end; 324: // TileOffsets begin tgpos := 324; tglen := 325; end; 513: // JPEGInterchangeFormat begin tgpos := 513; tglen := 514; end; end; // HDPhoto tags if fVersion = $1BC then case tagCode of 48320: // ImageOffset and byte count begin tgpos := 48320; tglen := 48321; end; 48322: // AlphaOffset and byte count begin tgpos := 48322; tglen := 48323; end; end; end; function TIETIFFHandler.CheckPairTag(tagCode: integer): boolean; var tgpos, tglen: integer; begin CheckPairTag(tagCode, tgpos, tglen); result := tgpos<>-1; end; // returns true if tagCode is a sub-IFD (ie EXIF) function TIETIFFHandler.CheckIFD(tagCode: integer): boolean; begin case tagCode of IETIFFTAG_EXIFIFD, // EXIF IETIFFTAG_INTEROPIFD, // Interoperability IFD (defined in EXIF) IETIFFTAG_EXIFGPSIFD: // GPS Info result := true; else result := false; end; end; // if Pages<>nil read multiple ifd (ifd must be nil) // if ifd<>nil read a single ifd (Pages must be nil, insertPos don't care) function TIETIFFHandler.ReadIFD(Stream: TStream; Pages: TList; ifd: TList; insertPos: integer): boolean; var w: word; dw: dword; i, j, l: integer; subifd: TList; tag: PTIFFTAG; sz: integer; ip, lp: int64; buf: pointer; newlist: PIntegerArray; tglen, tgpos: integer; datanum: integer; begin result := true; ip := Stream.Position; if Pages <> nil then begin ifd := TList.Create; if insertPos = Pages.Count then begin // add page Pages.Add(ifd); end else begin // insert page Pages.Insert(insertPos, ifd); end; end; assert(ifd<>nil); // read tags count Stream.Read(w, sizeof(word)); w := xword(w); // read tags for i := 0 to w-1 do begin new(tag); Stream.Read(tag^, sizeof(TTIFFTAG)); datanum := xdword(tag^.DataNum); sz := IETIFFCalcTagSize(xword(tag^.DataType)) * datanum; if sz > 4 then begin lp := Stream.Position; if (sz < Stream.Size) then begin buf := AllocMem(sz); Stream.Position := xdword(tag^.DataPos); Stream.Read(pbyte(buf)^, sz); tag^.DataPos := xdword( fBuffers.Add(buf) ); end else begin // invalid tag dispose(tag); //tag := nil; break; // different behavior. Since 3.1.2 stops reading from first invalid tag. end; Stream.Position := lp; end else if sz < 0 then begin // invalid tag dispose(tag); // see above (different behavior...etc) break; end; if assigned(tag) and CheckIFD(xword(tag^.IdTag)) then begin // this is a SubIFD (ie EXIF) // note: actually a subifd could contain multiple pages (like thumbnail in EXIF, which is stored in second page). // Here we ignore other pages other than first one. subifd := TList.Create(); lp := Stream.Position; Stream.Position := xdword(tag^.DataPos); ReadIFD(Stream, nil, subifd, 0); Stream.Position := lp; tag^.DataPos := fBuffers.Add(subifd); end; if tag<>nil then ifd.Add( tag ); end; // read sub tags (like StripOffsets and TileOffsets) lp := Stream.Position; for i := 0 to ifd.Count-1 do begin tag := ifd[i]; CheckPairTag(xword(tag^.IdTag), tgpos, tglen); if tgpos > -1 then begin if xdword(tag^.DataNum) > 1 then newlist := AllocMem(xdword(tag^.DataNum) * sizeof(integer)) else newlist := @tag^.DataPos; for j := 0 to xdword(tag^.DataNum)-1 do begin l := GetIntegerByCode(ifd, tglen, j); // length in bytes buf := AllocMem(l); Stream.Position := GetIntegerByCode(ifd, tgpos, j); // position Stream.Read(pbyte(buf)^, l); newlist[j] := xdword( fBuffers.Add(buf) ); end; if IETIFFCalcTagSize(xword(tag^.DataType)) * xdword(tag^.DataNum) > 4 then freemem(pointer( fBuffers[xdword(tag^.DataPos)] )); tag^.DataType := xword(4); // long type if xdword(tag^.DataNum) > 1 then tag^.DataPos := xdword( fBuffers.Add(newlist) ); // replace with the new list end; end; // convert from jpeg-6 to jpeg-7 (* if (GetIntegerByCode(pageIndex, 259, 0)=6) and (FindTag(pageIndex, 273)>-1) then begin DeleteTag(pageIndex, FindTag(pageIndex, 519)); DeleteTag(pageIndex, FindTag(pageIndex, 520)); DeleteTag(pageIndex, FindTag(pageIndex, 521)); DeleteTag(pageIndex, FindTag(pageIndex, 512)); DeleteTag(pageIndex, FindTag(pageIndex, 273)); DeleteTag(pageIndex, FindTag(pageIndex, 279)); SetValue(pageIndex, 259, ttShort, 7); ChangeTagCode(pageIndex, FindTag(pageIndex, 513), 273); ChangeTagCode(pageIndex, FindTag(pageIndex, 514), 279); end; *) // normalize jpeg-6 format if (GetIntegerByCode(ifd, 259, 0)=6) and (FindTag(ifd, 273)>-1) and (FindTag(ifd, 513)>-1) then begin DeleteTag(ifd, FindTag(ifd, 273), true); // stripoffsets DeleteTag(ifd, FindTag(ifd, 519), true); // jpegqtables DeleteTag(ifd, FindTag(ifd, 520), true); // jpegdctables DeleteTag(ifd, FindTag(ifd, 521), true); // jpegatables end; SortTags(ifd); Stream.Position := lp; // next ifd Stream.Read(dw, sizeof(dword)); dw := xdword(dw); if (int64(dw)<>ip) and (dw<>0) and (dwTIETIFFHandler.ReadStream Declaration function ReadStream(Stream: TStream): boolean; Description Reads the TIFF from stream. !!} function TIETIFFHandler.ReadStream(Stream: TStream): boolean; begin FreeData(); result := ReadHeader(Stream); if not result then exit; result := ReadIFD(Stream, fPages, nil, 0); end; {!! TIETIFFHandler.InsertTIFFStream Declaration function InsertTIFFStream(Stream: TStream; pageIndex: integer): boolean; Description Inserts a TIFF (even multipage TIFFs) at the specified page index. Notes: - The first page has pageIndex of 0. - The two TIFFs must have the same byte order. Example // Adds a tiff stream at the start of the existing file handler.InsertTIFFStream( aStream, 0 ); !!} function TIETIFFHandler.InsertTIFFStream(Stream: TStream; pageIndex: integer): boolean; begin result := ReadHeader(Stream); // warning all files must have the same byte orders if not result then exit; result := ReadIFD(Stream, fPages, nil, pageIndex); end; {!! TIETIFFHandler.InsertTIFFFile Declaration function InsertTIFFFile(const FileName: string; pageIndex: integer): boolean; Description Inserts a TIFF (even multipage TIFFs) at specified page index. Notes: - The first page has pageIndex of 0. - The two TIFFs must have the same byte order. Example // Adds a tiff file at the start of the existing file handler.InsertTIFFStream( 'C:\NewTiff.tiff', 0 ); !!} function TIETIFFHandler.InsertTIFFFile(const FileName: string; pageIndex: integer): boolean; var fs: TFileStream; begin result := false; if not IEFileExists(FileName) then exit; fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try result := InsertTIFFStream(fs, pageIndex); finally FreeAndNil(fs); end; end; {!! TIETIFFHandler.InsertPageAsFile Declaration function InsertPageAsFile(const FileName: string; pageIndex: integer): boolean; Description Inserts a supported file format (jpeg, bmp, ..) at the specified page index Note: The first page has pageIndex of 0. Example // Adds a JPEG file at the start of the TIFF file handler.InsertTIFFStream( 'C:\Heading.jpeg', 0 ); !!} function TIETIFFHandler.InsertPageAsFile(const FileName: string; pageIndex: integer): boolean; var fs: TFileStream; begin result := false; if not IEFileExists(FileName) then exit; fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try result := InsertPageAsStream(fs, pageIndex); finally FreeAndNil(fs); end; end; {!! TIETIFFHandler.InsertPageAsStream Declaration function InsertPageAsStream(Stream: TStream; pageIndex: integer): boolean; Description Inserts a supported file format (jpeg, bmp, ..) at the specified page index. Note: The first page has pageIndex of 0. Example // Adds a JPEG stream at the start of the TIFF file handler.InsertTIFFStream( Stream, 0 ); !!} function TIETIFFHandler.InsertPageAsStream(Stream: TStream; pageIndex: integer): boolean; var tmpie: TImageEnView; tmpStream: TMemoryStream; begin tmpie := TImageEnView.Create(nil); tmpStream := TMemoryStream.Create(); try tmpie.IO.LoadFromStream( Stream ); //tmpStream.Size := Stream.Size; // ...if uncomment remember to cut stream size to the actual size! if tmpie.IO.Params.FileType = ioJPEG then tmpie.IO.Params.TIFF_Compression := ioTIFF_JPEG; tmpie.IO.SaveToStreamTIFF(tmpStream); tmpStream.Position := 0; result := InsertTIFFStream( tmpStream, pageIndex ); finally FreeAndNil(tmpStream); FreeAndNil(tmpie); end; end; {!! TIETIFFHandler.InsertPageAsImage Declaration function InsertPageAsImage(viewer: TObject; pageIndex: integer): boolean; Description Inserts a loaded image at the specified index. Viewer must be a object or . !!} function TIETIFFHandler.InsertPageAsImage(viewer: TObject; pageIndex: integer): boolean; var tmpio: TImageEnIO; tmpStream: TMemoryStream; begin result := false; if viewer is TImageEnView then tmpio := (viewer as TImageEnView).IO else if viewer is TImageEnIO then tmpio := (viewer as TImageEnIO) else exit; tmpStream := TMemoryStream.Create(); try //tmpStream.Size := 1024*1024*3; // ...if uncomment remember to cut stream size to the actual size! tmpio.SaveToStreamTIFF(tmpStream); tmpStream.Position := 0; result := InsertTIFFStream( tmpStream, pageIndex ); finally FreeAndNil(tmpStream); end; end; function TIETIFFHandler.ReadHeader(Stream: TStream): boolean; var fHeader: TTIFFHeader; begin Stream.Read(fHeader, sizeof(TTIFFHeader)); fBigEndian := fHeader.Id = $4D4D; fVersion := xword(fHeader.Ver); result := (fHeader.Id = $4949) or (fHeader.id = $4D4D); if result then Stream.Position := xdword(fHeader.PosIFD); end; {!! TIETIFFHandler.LittleEndian Declaration property LittleEndian: boolean; Description Returns true if file has little-endian byte order (Intel byte order). Returns false when it has big-endian (Motorola, PowerPC byte order). It is not possible to change byte order. !!} function TIETIFFHandler.GetLittleEndian: boolean; begin result := not fBigEndian; end; {!! TIETIFFHandler.FreeData Declaration procedure FreeData(); Description Frees memory used by the object. !!} procedure TIETIFFHandler.FreeData(); var i: integer; begin for i := fPages.Count-1 downto 0 do DeletePage(i); fPages.Clear(); fBuffers.Clear(); end; {!! TIETIFFHandler.DeletePage Declaration procedure DeletePage(pageIndex: integer); Description Deletes the specified page. Example // Removes the first page of the TIFF file handler.DeletePage( 0 ); !!} procedure TIETIFFHandler.DeletePage(pageIndex: integer); var i: integer; ifd: TList; begin ifd := fPages[pageIndex]; for i := ifd.Count-1 downto 0 do DeleteTag(pageIndex, i); ifd.Free(); fPages.Delete(pageIndex); end; {!! TIETIFFHandler.ExchangePage Declaration procedure ExchangePage(Index1, Index2: integer); Description Exchanges specified pages. !!} procedure TIETIFFHandler.ExchangePage(Index1, Index2: integer); begin fPages.Exchange(Index1, Index2); end; {!! TIETIFFHandler.MovePage Declaration procedure MovePage(CurIndex, NewIndex: integer); Description Moves specified page to a new position. !!} procedure TIETIFFHandler.MovePage(CurIndex, NewIndex: integer); begin fPages.Move(CurIndex, NewIndex); end; {!! TIETIFFHandler.InsertPage Declaration function InsertPage(pageIndex: integer = -1): integer; function InsertPage(pageIndex: integer; sourceHandler: TIETIFFHandler; sourcePage: integer): integer; Description First overload inserts a new blank page at specified index. Second overload inserts sourcePage from sourceHandler at specified index. If pageIndex is -1 or equal to the page is added at end. Returns the index of added page. !!} function TIETIFFHandler.InsertPage(pageIndex: integer): integer; begin if (pageIndex<0) or (pageIndex>=fPages.Count) then result := fPages.Add(TList.Create()) else begin fPages.Insert(pageIndex, TList.Create()); result := pageIndex; end; end; function TIETIFFHandler.InsertPage(pageIndex: integer; sourceHandler: TIETIFFHandler; sourcePage: integer): integer; var i: integer; tagCount: integer; begin result := InsertPage(pageIndex); tagCount := sourceHandler.GetTagsCount(sourcePage); for i := 0 to tagCount-1 do CopyTag(sourcePage, i, sourceHandler, result); end; {!! TIETIFFHandler.DeleteTag Declaration procedure DeleteTag(pageIndex: integer; tagIndex: integer); Description Deletes the specified tag. Note: Use to obtain the tagIndex. !!} procedure TIETIFFHandler.DeleteTag(pageIndex: integer; tagIndex: integer); begin DeleteTag(pageIndex, tagIndex, true); end; procedure TIETIFFHandler.DeleteTag(ifd: TList; tagIndex: integer; checkOffsetTags: boolean); var j: integer; tag: PTIFFTAG; sz: integer; datanum: integer; tagcode: integer; ptr: pointer; tgpos, tglen: integer; subifd: TList; begin if tagIndex >= 0 then begin tag := ifd[tagIndex]; datanum := xdword(tag^.DataNum); tagcode := xword(tag^.IdTag); if checkOffsetTags then begin CheckPairTag(xword(tag^.IdTag), tgpos, tglen); if tgpos>-1 then for j := 0 to datanum-1 do begin ptr := GetValueRAWEx(ifd[FindTag(ifd, tagCode)], j); ptr := fBuffers[xdword(pdword(ptr)^)]; freemem(ptr); end; end; if checkIFD(tagcode) then begin // this is an IFD subifd := pointer(fBuffers[tag^.DataPos]); while subifd.Count>0 do DeleteTag(subifd, 0, true); subifd.Free; end else begin // normal tag, remove data if necessary sz := IETIFFCalcTagSize(xword(tag^.DataType)) * datanum; if sz > 4 then freemem(pointer( fBuffers[xdword(tag^.DataPos)] )); end; dispose(tag); ifd.Delete(tagIndex); end; end; procedure TIETIFFHandler.DeleteTag(pageIndex: integer; tagIndex: integer; checkOffsetTags: boolean); var ifd: TList; begin ifd := fPages[pageIndex]; DeleteTag(ifd, tagIndex, checkOffsetTags); end; function TIETIFFHandler.FindTag(ifd: TList; tagCode: integer): integer; var i: integer; begin result := -1; for i := 0 to ifd.Count-1 do with PTIFFTAG(ifd[i])^ do if xword(IdTag) = tagCode then begin result := i; break; end; end; {!! TIETIFFHandler.FindTag Declaration function FindTag(pageIndex: integer; tagCode: integer): integer; Description Returns the tag index of the first tag which has specified tagCode. If no tag is found, it returns -1. !!} function TIETIFFHandler.FindTag(pageIndex: integer; tagCode: integer): integer; var ifd: TList; begin result := -1; if pageIndex < fPages.Count then begin ifd := fPages[pageIndex]; result := FindTag(ifd, tagCode); end; end; {!! TIETIFFHandler.ChangeTagCode Declaration procedure ChangeTagCode(pageIndex: integer; tagIndex: integer; newCode: integer); Description Changes the tag code of an existing tag. Note: Use to obtain the tagIndex. !!} procedure TIETIFFHandler.ChangeTagCode(pageIndex: integer; tagIndex: integer; newCode: integer); var ifd: TList; tag: PTIFFTAG; begin ifd := fPages[pageIndex]; tag := ifd[tagIndex]; if not CheckIFD(xword(tag^.IdTag)) and not CheckPairTag(xword(tag^.IdTag)) then // special tags cannot be changed to avoid mem leaks tag^.IdTag := xword(newCode); end; function TIETIFFHandler.GetValueRAWEx(tag: PTIFFTAG; arrayIndex: integer): pointer; var sz: integer; pt: pbyte; begin sz := IETIFFCalcTagSize(xword(tag^.DataType)) * xdword(tag^.DataNum); if sz > 4 then pt := pointer( fBuffers[xdword(tag^.DataPos)] ) else pt := @(tag^.DataPos); inc(pt, IETIFFCalcTagSize(xword(tag^.DataType)) * arrayIndex ); result := pt; end; // good also to read tags with only one value function TIETIFFHandler.GetValueRAWEx(pageIndex: integer; tagindex: integer; arrayIndex: integer; var tagType: integer): pointer; var ifd: TList; tag: PTIFFTAG; begin ifd := fPages[pageIndex]; tag := ifd[tagindex]; result := GetValueRAWEx(tag, arrayIndex); tagType := xword(tag^.DataType); end; {!! TIETIFFHandler.GetValueRAW Declaration function GetValueRAW(pageIndex: integer; tagIndex: integer; arrayIndex: integer): pointer; Description Returns a pointer to the tag value. arrayIndex is used only if the tag contains an array of values, otherwise it must be 0. Use or to know the size of buffer. The returned buffer must not be freed. Note: Use to obtain the tagIndex. !!} function TIETIFFHandler.GetValueRAW(pageIndex: integer; tagIndex: integer; arrayIndex: integer): pointer; var tagType: integer; begin result := GetValueRAWEx(pageIndex, tagIndex, arrayIndex, tagType); end; function TIETIFFHandler.GetIntegerByCode(page: integer; tagcode: integer; idx: integer): integer; var ifd: TList; begin ifd := fPages[page]; result := GetIntegerByCode(ifd, tagcode, idx); end; function TIETIFFHandler.GetIntegerByCode(ifd: TList; tagcode: integer; idx: integer): integer; var tagindex: integer; begin result := 0; tagindex := FindTAG(ifd, tagcode); if tagindex > -1 then result := GetInteger(ifd, tagindex, idx); end; {!! TIETIFFHandler.WriteFile Declaration procedure WriteFile(const FileName: string; pageIndex: integer = -1); Description Saves a modified TIFF to file. pageIndex specifies the page index to write. -1 = all pages. !!} procedure TIETIFFHandler.WriteFile(const FileName: string; page: integer); var fs: TFileStream; begin fs := nil; try fs := TFileStream.Create(FileName, fmCreate); WriteStream(fs, page); finally FreeAndNil(fs); end; end; function WordAlignStream(Stream: TStream): int64; var b: byte; begin result := Stream.Position; if (result and $1) <> 0 then begin // word align offset inc(result); b := 0; Stream.Write(b, 1); end; end; {!! TIETIFFHandler.SaveTagToFile Declaration procedure SaveTagToFile(pageIndex: integer; tagIndex: integer; const fileName: string); Description Saves the content of a tag to file. Note: Use to obtain the tagIndex. !!} procedure TIETIFFHandler.SaveTagToFile(pageIndex: integer; tagIndex: integer; const fileName: string); var ifd: TList; tag: PTIFFTAG; datanum: integer; tgpos, tglen: integer; i, l, sz: integer; p: int64; Stream: TFileStream; subifd: TList; dw: dword; begin if tagIndex >- 1 then begin Stream := TFileStream.Create(fileName, fmCreate); try ifd := fPages[pageIndex]; tag := ifd[tagIndex]; datanum := xdword(tag^.DataNum); CheckPairTag(xword(tag^.IdTag), tgpos, tglen); if tgpos > -1 then begin for i := 0 to datanum-1 do begin l := GetIntegerByCode(pageIndex, tglen, i); Stream.Write( pbyte(pointer( fBuffers[GetIntegerByCode(pageIndex, tgpos, i)] ))^, l ); end; end else begin sz := IETIFFCalcTagSize(xword(tag^.DataType)) * datanum; if sz > 4 then Stream.Write( pbyte(pointer( fBuffers[xdword(tag^.DataPos)] ))^, sz ) else begin if CheckIFD(xword(tag^.IdTag)) then begin // this is a SubIFD (ie EXIF) subifd := pointer(fBuffers[tag^.DataPos]); p := WordAlignStream(Stream); WriteIFD(Stream, subifd, p); // "p" updated to the end of tag-data dw := 0; Stream.Write(dw, sizeof(dword)); // 0 = end of subifd end else Stream.Write( tag^.DataPos, sz ); end; end; finally FreeAndNil(Stream); end; end; end; function CompareTags(Item1, Item2: Pointer): Integer; var i1, i2: PTIFFTAG; begin i1 := Item1; i2 := Item2; if i1^.IdTag < i2^.IdTag then result := -1 else if i1^.IdTag = i2^.IdTag then result := 0 else result := 1; end; procedure TIETIFFHandler.SortTags(pageIndex: integer); begin if (pageIndex < fPages.Count) and assigned(fPages[pageIndex]) then SortTags(TList(fPages[pageIndex])); end; procedure TIETIFFHandler.SortTags(ifd: TList); begin ifd.Sort( CompareTags ); end; {!! TIETIFFHandler.WriteStream Declaration procedure WriteStream(Stream: TStream; page: integer = -1); Description Saves the modified TIFF to a stream. page specifies the page index to write. -1 = all pages. !!} procedure TIETIFFHandler.WriteStream(Stream: TStream; page: integer); var fHeader: TTIFFHeader; i: integer; dw: dword; dataPos: int64; begin if fBigEndian then fHeader.Id := $4D4D else fHeader.Id := $4949; fHeader.Ver := xword(fVersion); // 3.0.3 fHeader.PosIFD := xdword(Stream.Position+sizeof(TTIFFHeader)); Stream.Write(fHeader, sizeof(TTIFFHeader)); if (page > -1) and (page < fPages.Count) then begin // write specified page SortTags(page); WriteIFD(Stream, fPages[page], dataPos); end else begin // write all pages for i := 0 to fPages.Count-1 do begin SortTags(i); WriteIFD(Stream, fPages[i], dataPos); // position of next IFD if i < fPages.Count-1 then begin dw := xdword(dataPos); Stream.Write(dw, sizeof(dword)); Stream.Position := dataPos; end; end; end; // no more IFD dw := 0; Stream.Write(dw, sizeof(dword)); end; procedure TIETIFFHandler.WriteIFD(Stream: TStream; ifd: TList; var dataPos: int64); procedure WriteTagData(ifd: TList; intag, outtag: PTIFFTAG); var i, l, sz: integer; buf: pdwordarray; tgpos, tglen: integer; datanum: integer; idtag: word; subifd: TList; datatype: word; p: int64; dw: dword; begin buf := nil; move(intag^, outtag^, sizeof(TTIFFTAG)); datanum := xdword(intag^.DataNum); idtag := xword(intag^.IdTag); datatype := xword(intag^.DataType); sz := IETIFFCalcTagSize(xword(intag^.DataType)) * datanum; try // check for offset tags CheckPairTag(idtag, tgpos, tglen); if tgpos > -1 then begin buf := AllocMem(datanum * sizeof(dword)); for i := 0 to datanum-1 do begin l := GetIntegerByCode(ifd, tglen, i); if TIETagType(datatype) <> ttLongOffset then begin buf[i] := xdword(Stream.Position); Stream.Write(pbyte(pointer( fBuffers[GetIntegerByCode(ifd, tgpos, i)] ))^, l); end; end; if datanum > 1 then outtag^.DataPos := xdword(fBuffers.Add(buf)) else move(buf[0], outtag^.DataPos, sizeof(dword)); end; // check for IFD tags if CheckIFD(idtag) then begin subifd := pointer(fBuffers[intag^.DataPos]); p := WordAlignStream(Stream); outtag^.DataPos := xdword(p); // save start of SUB-IFD WriteIFD(Stream, subifd, p); // "p" updated to the end of tag-data dw := 0; Stream.Write(dw, sizeof(dword)); // 0 = end of subifd Stream.Position := p; // go to end of tag-data end; // writes actual tag data (now in "outtag") if sz > 4 then begin p := WordAlignStream(Stream); Stream.Write(pbyte(pointer( fBuffers[xdword(outtag^.DataPos)] ))^, sz); outtag^.DataPos := xdword(p); end; finally if buf<>nil then freemem(buf); end; end; var j, k, l: integer; p1: int64; wtag: TTIFFTAG; tag: PTIFFTAG; w: word; temptag: integer; ifdcount: integer; pw: pword; begin ifdcount := ifd.Count; // bypass tag 273 when 513 exists (for jpeg compression) if (FindTag(ifd, 513) <> -1) and (FindTag(ifd, 273) = -1) then inc(ifdCount); // write ifd items count w := xword(ifdcount); Stream.Write(w, sizeof(word)); // tags data will begin at "dataPos" position dataPos := Stream.Position + ifdcount*sizeof(TTIFFTAG) + sizeof(dword); temptag := -1; j := 0; while j < ifdCount do begin tag := ifd[j]; p1 := Stream.Position; Stream.Position := dataPos; // go to data position WriteTagData(ifd, tag, @wtag); // handles jpeg compression case if xword(wtag.IdTag) = 513 then begin // we need to add the tag 273 (stripoffsets) // search for begin of jpeg-raw ($FFDA) pw := pword( pointer( fBuffers[GetIntegerByCode(ifd, 513, 0)] ) ); l := GetIntegerByCode(ifd, 514, 0); k := 0; while k < l do begin if (pw^ = $DAFF) then break; inc(pbyte(pw)); inc(k); end; SetValue(ifd, 273, ttLongOffset, variant(xdword(wtag.DataPos) + dword(k))); temptag := FindTag(ifd, 273); end; dataPos := Stream.Position; // save next tags-data position Stream.Position := p1; // go to ifd-tag position Stream.Write(wtag, sizeof(TTIFFTAG)); // write tag inc(j); end; // remove temp tag if temptag<>-1 then DeleteTag(ifd, temptag, false); end; {!! TIETIFFHandler.GetTagsCount Declaration function GetTagsCount(pageIndex: integer): integer; Description Returns the number of tags present at the specified page. !!} function TIETIFFHandler.GetTagsCount(pageIndex: integer): integer; begin if (pageIndexTIETIFFHandler.GetPagesCount Declaration function GetPagesCount: integer; Description Returns the number of pages in the TIFF. !!} function TIETIFFHandler.GetPagesCount: integer; begin result := fPages.Count; end; {!! TIETIFFHandler.GetTagCode Declaration function GetTagCode(pageIndex: integer; tagIndex: integer): integer; Description Returns the tag code (also named "tag-id") indexed by tagIndex for a specified page. Note: Use to obtain the tagIndex. !!} function TIETIFFHandler.GetTagCode(pageIndex: integer; tagIndex: integer): integer; begin if (pageIndexTIETIFFHandler.GetTagType Declaration function GetTagType(pageIndex: integer; tagIndex: integer): ; Description Return the type of a tag. Note: Use to obtain the tagIndex. !!} function TIETIFFHandler.GetTagType(pageIndex: integer; tagIndex: integer): TIETagType; begin if (pageIndexTIETIFFHandler.GetTagLength Declaration function GetTagLength(pageIndex: integer; tagIndex: integer): integer; Description Return the length of a tag. Check the tag type to know the size of each item. Note: Use to obtain the tagIndex. !!} function TIETIFFHandler.GetTagLength(pageIndex: integer; tagIndex: integer): integer; begin if (pageIndexTIETIFFHandler.GetTagLengthInBytes Declaration function GetTagLengthInBytes(pageIndex: integer; tagIndex: integer): integer; Description Return the tag length in bytes. Note: Use to obtain the tagIndex. !!} function TIETIFFHandler.GetTagLengthInBytes(pageIndex: integer; tagIndex: integer): integer; begin if (pageIndexTIETIFFHandler.GetInteger Declaration function GetInteger(pageIndex: integer; tagIndex: integer; arrayIndex: integer): integer; Description Returns the tag value as an Integer. arrayIndex is used only if the tag contains an array of values, otherwise it must be 0. Note: Use to obtain the tagIndex. !!} function TIETIFFHandler.GetInteger(pageIndex: integer; tagIndex: integer; arrayIndex: integer): integer; var ifd: TList; begin ifd := fPages[pageIndex]; result := GetInteger(ifd, tagIndex, arrayIndex); end; function TIETIFFHandler.GetInteger(ifd: TList; tagIndex: integer; arrayIndex: integer): integer; type pshortint=^shortint; var ptr: pointer; tag: PTIFFTAG; begin result := 0; tag := ifd[tagIndex]; ptr := GetValueRAWEx(tag, arrayIndex); case xword(tag^.DataType) of 1, 2, 7: // byte, ascii, undefined result := pbyte(ptr)^; 3: // short result := xword(pword(ptr)^); 4: // long result := xdword(pdword(ptr)^); 6: // sbyte result := pshortint(ptr)^; 8: // sshort result := xword(psmallint(ptr)^); 9: // slong result := xdword(plongint(ptr)^); end; end; {!! TIETIFFHandler.GetString Declaration function GetString(pageIndex: integer; tagIndex: integer): AnsiString; Description Returns the tag value as a string. Note: Use to obtain the tagIndex. !!} function TIETIFFHandler.GetString(pageIndex: integer; tagIndex: integer): AnsiString; var ptr: PAnsiChar; tagType, i, l, ln: integer; begin result := ''; if tagIndex>-1 then begin ptr := GetValueRAWEx(pageIndex, tagIndex, 0, tagType); l := GetTagLength(pageIndex, tagIndex); ln := 0; for i := 0 to l-1 do begin result := result + ptr^; if ptr^ <> #0 then ln := i+1; inc(ptr); end; SetLength(result, ln); end; end; {!! TIETIFFHandler.GetFloat Declaration function GetFloat(pageIndex: integer; tagIndex: integer; arrayIndex: integer): double; Description Returns the tag value as a floating point value. arrayIndex is used only if the tag contains an array of values, otherwise it must be 0. Note: Use to obtain the tagIndex. !!} function TIETIFFHandler.GetFloat(pageIndex: integer; tagIndex: integer; arrayIndex: integer): double; var ptr: pointer; tagType: integer; num, den: dword; inum, iden: integer; begin result := 0; ptr := GetValueRAWEx(pageIndex, tagIndex, arrayIndex, tagType); case tagType of 5: // rational begin num := xdword( pdwordarray(ptr)[0] ); den := xdword( pdwordarray(ptr)[1] ); if den = 0 then den := 1; result := num / den; end; 10: // srational begin inum := xdword( pintegerarray(ptr)[0] ); iden := xdword( pintegerarray(ptr)[1] ); if iden = 0 then iden := 1; result := inum / iden; end; 11: // float result := psingle(ptr)^; 12: // double result := pdouble(ptr)^; end; end; {!! TIETIFFHandler.GetValue Declaration function GetValue(pageIndex: integer; tagIndex: integer; arrayIndex: integer): variant; Description Returns the tag value as a variant. arrayIndex is used only if the tag contains an array of values, otherwise it must be 0. Note: Use to obtain the tagIndex. !!} function TIETIFFHandler.GetValue(pageIndex: integer; tagIndex: integer; arrayIndex: integer): variant; begin case integer(GetTagType(pageIndex, tagIndex)) of 1, 3, 4, 6, 7, 8, 9: result := GetInteger(pageIndex, tagIndex, arrayIndex); 2: result := GetString(pageIndex, tagIndex); 5, 10, 11, 12: result := GetFloat(pageIndex, tagIndex, arrayIndex); end; end; {!! TIETIFFHandler.SetValue Declaration procedure SetValue(pageIndex: integer; tagCode: integer; tagType: ; value: variant); Description Set the value of a tag. If the tag doesn't exist a new one is created. !!} procedure TIETIFFHandler.SetValue(pageIndex: integer; tagCode: integer; tagType: TIETagType; value: variant); var ifd: TList; begin ifd := fPages[pageIndex]; SetValue(ifd, tagCode, tagType, value); end; procedure TIETIFFHandler.SetValue(ifd: TList; tagCode: integer; tagType: TIETagType; value: variant); type trat = packed record num: dword; den: dword; end; tsrat = packed record num: longint; den: longint; end; var t: integer; tag: PTIFFTAG; ss: AnsiString; ptr, dst: pointer; bb: byte; si: smallint; li: longint; rat: Trat; srat: Tsrat; hi: shortint; ww: word; dw: dword; fl: single; db: double; begin // remove the old tag t := FindTag(ifd, tagCode); if t > -1 then DeleteTag(ifd, t, true); // add the tag new(tag); ifd.Add( tag ); tag^.IdTag := xword( tagCode ); tag^.DataType := xword( integer(tagType) ); ptr := nil; case tagType of ttByte: begin tag^.DataNum := xdword(1); bb := integer(value); ptr := @bb; end; ttAscii: begin ss := AnsiString(value); tag^.DataNum := xdword(length(ss)+1); ptr := PAnsiChar(ss); end; ttShort: begin tag^.DataNum := xdword(1); ww := xword(word(value)); ptr := @ww; end; ttLong, ttLongOffset: begin tag^.DataNum := xdword(1); dw := xdword(dword(value)); ptr := @dw; end; ttRational: begin tag^.DataNum := xdword(1); rat.num := xdword(trunc(double(value)*10000)); rat.den := xdword(10000); ptr := @rat; end; ttSByte: begin tag^.DataNum := xdword(1); hi := shortint(value); ptr := @hi; end; ttUndefined: ; ttSShort: begin tag^.DataNum := xdword(1); si := xword(smallint(value)); ptr := @si; end; ttSLong: begin tag^.DataNum := xdword(1); li := xdword(longint(value)); ptr := @li; end; ttSRational: begin tag^.DataNum := xdword(1); srat.num := xdword(trunc(double(value)*10000)); srat.den := xdword(10000); ptr := @srat; end; ttFloat: begin tag^.DataNum := xdword(1); fl := single(value); ptr := @fl; end; ttDouble: begin tag^.DataNum := xdword(1); db := double(value); ptr := @db; end; end; t := xdword(tag^.DataNum) * IETIFFCalcTagSize(xword(tag^.DataType)); // length in bytes if t > 4 then begin dst := AllocMem(t); tag^.DataPos := xdword( fBuffers.Add(dst) ); end else dst := @tag^.DataPos; if ptr <> nil then CopyMemory(dst, ptr, t); end; {!! TIETIFFHandler.SetValueRAW Declaration procedure SetValueRAW(pageIndex: integer; tagCode: integer; tagType: ; dataNum: integer; buffer: pointer); Description Sets the value of tag as a raw buffer. If the tag doesn't exist a new one is created. dataNum is the number of items of type tagType in the buffer. This is not the buffer length in bytes. !!} procedure TIETIFFHandler.SetValueRAW(pageIndex: integer; tagCode: integer; tagType: TIETagType; dataNum: integer; buffer: pointer); var ifd: TList; begin ifd := fPages[pageIndex]; SetValueRAW(ifd, tagCode, tagType, dataNum, buffer); end; procedure TIETIFFHandler.SetValueRAW(ifd: TList; tagCode: integer; tagType: TIETagType; dataNum: integer; buffer: pointer); var t: integer; tag: PTIFFTAG; dst: pointer; begin // remove the old tag t := FindTag(ifd, tagCode); if t > -1 then DeleteTag(ifd, t, true); // add the tag new(tag); ifd.Add( tag ); tag^.IdTag := xword( tagCode ); tag^.DataType := xword( integer(tagType) ); tag^.DataNum := xdword(dataNum); t := xdword(tag^.DataNum) * IETIFFCalcTagSize(xword(tag^.DataType)); // length in bytes if t > 4 then begin dst := AllocMem(t); tag^.DataPos := xdword( fBuffers.Add(dst) ); end else dst := @tag^.DataPos; if buffer <> nil then CopyMemory(dst, buffer, t); end; {!! TIETIFFHandler.CopyTag Declaration procedure CopyTag(srcPageIndex: integer; srcTagIndex: integer; source: TIETIFFHandler; dstPageIndex: integer); Description Copies a tag from another object (i.e. another TIFF). Parameter Description srcPageIndex Source page index (0=first page) srcTagIndex Source tag index (use to get an index from tag code) source Source object, that is the source TIFF file dstPageIndex Destination page index (0=first page)
Note: Use to obtain the srcTagIndex. Example // copy tiff tag 271 (Manufacturer) from file1.tif to file2.tif var file1: TIETIFFHandler; file2: TIETIFFHandler; begin file1 := TIETIFFHandler.Create('file1.tif'); file2 := TIETIFFHandler.Create('file2.tif'); file2.CopyTag(0, file1.FindTag(0, 271), file1, 0); file2.WriteFile('file2.tif'); file2.Free; file1.Free; end; !!} procedure TIETIFFHandler.CopyTag(srcPageIndex: integer; srcTagIndex: integer; source: TIETIFFHandler; dstPageIndex: integer); var src_ifd: TList; dst_ifd: TList; begin if (srcPageIndex-1) and (source.fBigEndian=fBigEndian) then begin src_tag := src_ifd[srcTagIndex]; datanum := xdword(src_tag^.DataNum); tagcode := xword(src_tag^.IdTag); // delete destination tag DeleteTag(dst_ifd, FindTag(dst_ifd, tagcode), true); // create new-destination tag new(dst_tag); dst_tag^ := src_tag^; // fill tag data source.CheckPairTag(tagcode, tgpos, tglen); if tgpos>-1 then begin // offsets tag // // create destination buffer and get source buffer if datanum > 1 then begin dwbuf_dst := AllocMem(datanum*sizeof(integer)); dst_tag^.DataPos := xdword( fBuffers.Add(dwbuf_dst) ); end else dwbuf_dst := pdwordarray(@dst_tag^.DataPos); // copy data for i := 0 to datanum-1 do begin l := source.GetIntegerByCode(src_ifd, tglen, i); // length in bytes buf_dst := AllocMem(l); buf_src := pointer(fBuffers[source.GetIntegerByCode(src_ifd, tgpos, i)]); // get pointer from position CopyMemory(buf_dst, buf_src, l); dwbuf_dst[i] := xdword( fBuffers.Add(buf_dst) ); end; end else begin // normal tag // sz := IETIFFCalcTagSize(xword(src_tag^.DataType)) * datanum; if sz > 4 then begin buf_dst := AllocMem(sz); CopyMemory(buf_dst, pointer( source.fBuffers[xdword(src_tag^.DataPos)] ), sz); dst_tag^.DataPos := xdword( fBuffers.Add(buf_dst) ); end; // Is SUB-EXIF? if CheckIFD(tagcode) then begin dst_subifd := TList.Create(); dst_tag^.DataPos := fBuffers.Add(dst_subifd); src_subifd := pointer(source.fBuffers[src_tag^.DataPos]); for i := 0 to src_subifd.Count-1 do begin CopyTag(src_subifd, i, source, dst_subifd); end; end; end; dst_ifd.Add(dst_tag); end; end; {!! TIETIFFHandler.GetTagDescription Declaration function GetTagDescription(pageIndex: integer; tagIndex: integer): AnsiString; Description Returns a short description of specified tag. Note: Use to obtain the tagIndex. !!} function TIETIFFHandler.GetTagDescription(pageIndex: integer; tagIndex: integer): AnsiString; begin case GetTagCode(pageindex, tagIndex) of 254: result := 'NewSubfileType'; 255: result := 'SubfileType'; 256: result := 'ImageWidth'; 257: result := 'ImageLength'; 258: result := 'BitsPerSample'; 259: result := 'Compression'; 262: result := 'PhotometricInterpretation'; 263: result := 'Thresholding'; 264: result := 'CellWidth'; 265: result := 'CellHeight'; 266: result := 'FillOrder'; 269: result := 'DocumentName'; 270: result := 'ImageDescription'; 271: result := 'Manufacturer'; 272: result := 'Model'; 273: result := 'StripOffsets'; 274: result := 'Orientation'; 277: result := 'SamplesPerPixel'; 278: result := 'RowsPerStrip'; 279: result := 'StripByteCounts'; 280: result := 'MinSampleValue'; 281: result := 'MaxSampleValue'; 282: result := 'XResolution'; 283: result := 'YResolution'; 284: result := 'PlanarConfiguration'; 285: result := 'PageName'; 286: result := 'XPosition'; 287: result := 'YPosition'; 288: result := 'FreeOffsets'; 289: result := 'FreeByteCounts'; 290: result := 'GratResponseUnit'; 291: result := 'GrayResponseCurve'; 292: result := 'T4Options'; 293: result := 'T6Options'; 296: result := 'ResolutionUnit'; 297: result := 'PageNumber'; IETIFFTAG_TRANSFERFUNC: result := 'TransferFunction'; 305: result := 'Software'; 306: result := 'DateTime'; 315: result := 'Artist'; 316: result := 'HostComputer'; 317: result := 'Predictor'; 318: result := 'WhitePoint'; 319: result := 'PrimaryChromaticities'; IETIFFTAG_COLORMAP: result := 'ColorMap'; 321: result := 'HalftoneHints'; 322: result := 'TileWidth'; 323: result := 'TileLength'; 324: result := 'TileOffsets'; 325: result := 'TileByteCounts'; 326: result := 'BadFaxLines'; 327: result := 'CleanFaxData'; 328: result := 'ConsecutiveBadFaxLines'; IETIFFTAG_SUBIFD: result := 'SubIFDs'; 332: result := 'InkSet'; 333: result := 'InkNames'; 334: result := 'NumberOfInks'; 336: result := 'DotRange'; 337: result := 'TargetPrinter'; 338: result := 'ExtraSamples'; 339: result := 'SampleFormat'; 340: result := 'SMinSampleValue'; 341: result := 'SMaxSampleValue'; 342: result := 'TransferRange'; 347: result := 'JPEGTables'; 512: result := 'JPEGProc'; 513: result := 'JPEGInterchangeFormat'; 514: result := 'JPEGInterchangeFormatLength'; 515: result := 'JPEGRestartInterval'; 517: result := 'JPEGLosslessPredictors'; 518: result := 'JPEGPointTransforms'; 519: result := 'JPEGQTables'; 520: result := 'JPEGDCTables'; 521: result := 'JPEGACTables'; 529: result := 'YCbCrCoefficients'; 530: result := 'YCbCrSubSampling'; 531: result := 'YCbCrPositioning'; 532: result := 'ReferenceBlackWhite'; IETIFFTAG_XMP: result := 'XMP'; IETIFFTAG_COPYRIGHT: result := 'Copyright'; IETIFFTAG_IPTC: result := 'IPTC info'; IETIFFTAG_WANGIMAGING: result := 'Imaging Wang annot.'; IETIFFTAG_PHOTOSHOP: result := 'PhotoshopTags'; IETIFFTAG_EXIFIFD: result := 'Sub EXIF'; IETIFFTAG_ICC: result := 'ICC Color Profile'; IETIFFTAG_EXIFGPSIFD: result := 'GPS IFD'; IETIFFTAG_EPSTANDARD: result := 'EP Standard'; IETIFFTAG_INTEROPIFD: result := 'Interoperability IFD'; IETIFFTAG_DNGVERSION: result := 'DNGVersion'; else result := 'Unknown'; end; end; {$endif} // end of TIETIFFHandler ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEGraphicBase procedure TIEGraphicBase.Draw(ACanvas: TCanvas; const Rect: TRect); begin bmp.RenderToCanvas(ACanvas, Rect.Left, Rect.Top, Rect.Right - Rect.Left, Rect.Bottom - Rect.Top, fResampleFilter, 1); end; function TIEGraphicBase.GetEmpty: Boolean; begin result := false; end; function TIEGraphicBase.GetHeight: Integer; begin result := bmp.Height; end; function TIEGraphicBase.GetWidth: Integer; begin result := bmp.Width; end; procedure TIEGraphicBase.SetHeight(Value: Integer); begin bmp.Height := Value; end; procedure TIEGraphicBase.SetWidth(Value: Integer); begin bmp.Width := Value; end; constructor TIEGraphicBase.Create; begin inherited; fResampleFilter := rfNone; bmp := TIEBitmap.Create; fio := TImageEnIO.CreateFromBitmap(bmp); if self is TIETIFFImage then fFileType := ioTIFF else if self is TIEJpegImage then fFileType := ioJPEG else if self is TIEPCXImage then fFileType := ioPCX else if self is TIEBMPImage then fFileType := ioBMP else if self is TIEICOImage then fFileType := ioICO {$IFDEF IEINCLUDEPNG} else if self is TIEPNGImage then fFileType := ioPNG {$ENDIF} else if self is TIETGAImage then fFileType := ioTGA else if self is TIEPXMImage then fFileType := ioPXM else if self is TIEGIFImage then fFileType := ioGIF {$IFDEF IEINCLUDEJPEG2000} else if self is TIEJP2Image then fFileType := ioJP2 else if self is TIEJ2KImage then fFileType := ioJ2K {$ENDIF} else if self is TIEPSDImage then fFileType := ioPSD; end; destructor TIEGraphicBase.Destroy; begin FreeAndNil(fio); FreeAndNil(bmp); inherited; end; procedure TIEGraphicBase.Assign(Source: TPersistent); var vclbmp: TBitmap; begin if (Source <> nil) and (Source is TIEGraphicBase) then begin bmp.Assign((Source as TIEGraphicBase).bmp); Changed(Self); end else if (Source <> nil) and (Source is TBitmap) then begin vclbmp := Source as TBitmap; if (vclbmp.PixelFormat <> pf24bit) and (vclbmp.PixelFormat <> pf1bit) then vclbmp.PixelFormat := pf24bit; bmp.Assign(vclbmp); Changed(Self); end else inherited Assign(Source); end; procedure TIEGraphicBase.AssignTo(Dest: TPersistent); begin if (Dest <> nil) and (Dest is TIEGraphicBase) then begin (Dest as TIEGraphicBase).bmp.Assign(bmp); end else if (Dest <> nil) and (Dest is TBitmap) then begin bmp.CopyToTBitmap(Dest as TBitmap); end else inherited AssignTo(Dest); end; procedure TIEGraphicBase.LoadFromStream(Stream: TStream); begin if assigned(fio) then TImageEnIO(fio).LoadFromStream(Stream, fFileType); end; procedure TIEGraphicBase.SaveToStream(Stream: TStream); begin if assigned(fio) then TImageEnIO(fio).SaveToStream(Stream, fFiletype); end; procedure TIEGraphicBase.WriteData(Stream: TStream); var ms: TMemoryStream; sz: integer; begin ms := TMemoryStream.Create; SaveToStream(ms); ms.Position := 0; sz := ms.Size; Stream.Write(sz, sizeof(integer)); IECopyFrom(Stream, ms, ms.Size); FreeAndNil(ms); end; procedure TIEGraphicBase.ReadData(Stream: TStream); var sz: integer; begin if (Stream.Read(sz, sizeof(integer)) > 0) and (sz > 0) then LoadFromStream(Stream); end; procedure TIEGraphicBase.LoadFromClipboardFormat(AFormat: Word; AData: THandle; APalette: HPALETTE); begin if AFormat = CF_DIB then _CopyDIB2BitmapEx(AData, bmp, nil, false); end; procedure TIEGraphicBase.SaveToClipboardFormat(var AFormat: Word; var AData: THandle; var APalette: HPALETTE); begin AData := _CopyBitmaptoDIBEx(bmp, 0, 0, 0, 0, 200, 200); AFormat := CF_DIB; end; procedure IERegisterFormats; begin TPicture.RegisterFileFormat('TIF', 'TIFF Image', TIETIFFImage); TPicture.RegisterFileFormat('TIFF', 'TIFF Image', TIETIFFImage); TPicture.RegisterFileFormat('FAX', 'TIFF Image', TIETIFFImage); TPicture.RegisterFileFormat('G3N', 'TIFF Image', TIETIFFImage); TPicture.RegisterFileFormat('G3F', 'TIFF Image', TIETIFFImage); TPicture.RegisterFileFormat('GIF', 'GIF Image', TIEGIFImage); TPicture.RegisterFileFormat('JPG', 'JPEG Image', TIEJpegImage); TPicture.RegisterFileFormat('JPEG', 'JPEG Image', TIEJpegImage); TPicture.RegisterFileFormat('JPE', 'JPEG Image', TIEJpegImage); TPicture.RegisterFileFormat('PCX', 'PaintBrush', TIEPCXImage); // BMP extension disabled to avoid conflicts with VCL version //TPicture.RegisterFileFormat('BMP', 'Windows Bitmap', TIEBMPImage); TPicture.RegisterFileFormat('DIB', 'Windows Bitmap', TIEBMPImage); TPicture.RegisterFileFormat('RLE', 'Windows Bitmap', TIEBMPImage); // ICO is disabled to avoid conflicts with VCL version //TPicture.RegisterFileFormat('ICO', 'Windows Icon', TIEICOImage); {$IFDEF IEINCLUDEPNG} TPicture.RegisterFileFormat('PNG', 'Portable Network Graphics', TIEPNGImage); {$ENDIF} TPicture.RegisterFileFormat('TGA', 'Targa Image', TIETGAImage); TPicture.RegisterFileFormat('TARGA', 'Targa Image', TIETGAImage); TPicture.RegisterFileFormat('VDA', 'Targa Image', TIETGAImage); TPicture.RegisterFileFormat('ICB', 'Targa Image', TIETGAImage); TPicture.RegisterFileFormat('VST', 'Targa Image', TIETGAImage); TPicture.RegisterFileFormat('PIX', 'Targa Image', TIETGAImage); TPicture.RegisterFileFormat('PXM', 'Portable Pixmap, Greymap, Bitmap', TIEPXMImage); TPicture.RegisterFileFormat('PPM', 'Portable Pixmap, Greymap, Bitmap', TIEPXMImage); TPicture.RegisterFileFormat('PGM', 'Portable Pixmap, Greymap, Bitmap', TIEPXMImage); TPicture.RegisterFileFormat('PBM', 'Portable Pixmap, Greymap, Bitmap', TIEPXMImage); {$IFDEF IEINCLUDEJPEG2000} TPicture.RegisterFileFormat('JP2', 'JPEG2000', TIEJP2Image); TPicture.RegisterFileFormat('J2K', 'JPEG2000 Code Stream', TIEJ2KImage); TPicture.RegisterFileFormat('JPC', 'JPEG2000 Code Stream', TIEJ2KImage); TPicture.RegisterFileFormat('J2C', 'JPEG2000 Code Stream', TIEJ2KImage); {$ENDIF} TPicture.RegisterFileFormat('PSD', 'Adobe PSD', TIEPSDImage); end; procedure IEUnregisterFormats; begin try TPicture.UnregisterGraphicClass(TIETIFFImage); TPicture.UnregisterGraphicClass(TIEGIFImage); TPicture.UnregisterGraphicClass(TIEJpegImage); TPicture.UnregisterGraphicClass(TIEPCXImage); TPicture.UnregisterGraphicClass(TIEBMPImage); //TPicture.UnregisterGraphicClass(TIEICOImage); // ICO is disabled to avoid conflicts with VCL version {$ifdef IEINCLUDEPNG} TPicture.UnregisterGraphicClass(TIEPNGImage); {$endif} TPicture.UnregisterGraphicClass(TIETGAImage); TPicture.UnregisterGraphicClass(TIEPXMImage); {$ifdef IEINCLUDEJPEG2000} TPicture.UnregisterGraphicClass(TIEJP2Image); TPicture.UnregisterGraphicClass(TIEJ2KImage); {$endif} TPicture.UnregisterGraphicClass(TIEPSDImage); except end; end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEImagingAnnot {$ifdef IEINCLUDEIMAGINGANNOT} constructor TIEImagingAnnot.Create; begin inherited Create; fParent := nil; fObjects := TList.Create; end; destructor TIEImagingAnnot.Destroy; begin Clear; FreeAndNil(fObjects); inherited; end; {!! TIEImagingAnnot.Clear Declaration procedure Clear; Description Removes all annotations. !!} procedure TIEImagingAnnot.Clear; var i: integer; begin for i := 0 to fObjects.Count-1 do TIEImagingObject(fObjects[i]).Free; fObjects.Clear; end; {!! TIEImagingAnnot.Assign Declaration procedure Assign(Source: ); Description Copy annotations from another object. !!} procedure TIEImagingAnnot.Assign(Source: TIEImagingAnnot); var i, l: integer; dst, src: TIEImagingObject; begin Clear; for i := 0 to Source.fObjects.Count - 1 do begin dst := TIEImagingObject.Create; src := TIEImagingObject(Source.fObjects[i]); move(src.attrib, dst.attrib, sizeof(OIAN_MARK_ATTRIBUTES)); if assigned(src.points) then begin getmem(dst.points, sizeof(TPoint) * src.pointsLen); move(src.points[0], dst.points[0], sizeof(TPoint) * src.pointsLen); dst.pointsLen := src.pointsLen; end; if assigned(src.text) then begin l := IEStrLen(src.text) + 1; getmem(dst.text, l); move(src.text[0], dst.text[0], l); end; if assigned(src.image) then begin dst.image := TIEBitmap.Create; dst.image.Assign(src.image); end; fObjects.Add(dst); end; end; {!! TIEImagingAnnot.SaveToStream Declaration procedure SaveToStream(Stream: TStream); Description For internal use only. !!} procedure TIEImagingAnnot.SaveToStream(Stream: TStream); begin // not implemented end; {!! TIEImagingAnnot.LoadFromStream Declaration procedure LoadFromStream(Stream: TStream); Description For internal use only. !!} procedure TIEImagingAnnot.LoadFromStream(Stream: TStream); begin // not implemented end; {!! TIEImagingAnnot.Objects Declaration property Objects[idx: integer]: ; Description Contains the internal representation of an object. !!} function TIEImagingAnnot.GetObject(idx: integer): TIEImagingObject; begin result := TIEImagingObject(fObjects[idx]); end; {!! TIEImagingAnnot.ObjectsCount Declaration property ObjectsCount: integer; Description Returns the count of annotations. !!} function TIEImagingAnnot.GetObjectsCount: integer; begin result := fObjects.Count; end; {!! TIEImagingAnnot.DrawToBitmap Declaration procedure DrawToBitmap(target: ; Antialias: boolean); Description Draws all annotations to the specified bitmap. Example ImageEnView.IO.ImagingAnnot.DrawToBitmap( ImageEnView.IEBitmap, true ); ImageEnView.Update; !!} procedure TIEImagingAnnot.DrawToBitmap(target: TIEBitmap; Antialias: boolean); var ievect: TImageEnVect; begin ievect := TImageEnVect.Create(nil); try CopyToTImageEnVect(ievect); ievect.ObjGraphicRender := true; ievect.DrawObjectsToBitmap(target, Antialias); finally ievect.Free(); end; end; constructor TIEImagingObject.Create; begin inherited Create; points := nil; pointsLen := 0; text := nil; image := nil; end; destructor TIEImagingObject.Destroy; begin if assigned(points) then freemem(points); if assigned(text) then freemem(text); if assigned(image) then FreeAndNil(image); inherited; end; function TRGBQuad2TColor(q: TRGBQuad): TColor; var rgb: TRGB; begin rgb.r := q.rgbRed; rgb.g := q.rgbGreen; rgb.b := q.rgbBlue; result := TRGB2TColor(rgb); end; function TColor2TRGBQuad(q: TColor): TRGBQuad; var rgb: TRGB; begin rgb := TColor2TRGB(q); result.rgbRed := rgb.r; result.rgbGreen := rgb.g; result.rgbBlue := rgb.b; result.rgbReserved := 0; end; {$IFNDEF IEHASUTF8ENCODEDECODE} function Utf8Encode(const WS: WideString): AnsiString; begin result := AnsiString(WS); end; function Utf8Decode(const S: AnsiString): WideString; begin result := WideString(S); end; {$ENDIF} {!! TIEImagingAnnot.CopyFromTImageEnVect Declaration procedure CopyFromTImageEnVect(Target: TObject=nil); Description Copy vectorial objects from a object. If Target is nil then the parent TImageEnVect is given. Note: Only the following object kinds are supported: iekBITMAP, iekLINE, iekPOLYLINE, iekBOX, iekMEMO, iekTEXT. Use to support all TImageEnVect object types Example // save image and vectorial objects in TImageEnVect to 'TIFF_with_objects.tiff' ImageEnVect1.IO.Params.ImagingAnnot.CopyFromTImageEnVect(); ImageEnVect1.IO.SaveToFile('TIFF_with_objects.tiff'); See Also - - TIEImageEnAnnot.CopyToTImageEnVect !!} procedure TIEImagingAnnot.CopyFromTImageEnVect(Target: TObject); var vect: TImageEnVect; i, j, hobj: integer; obj: TIEImagingObject; rect: TRect; procedure AddNew; var rc: TRect; begin obj := TIEImagingObject.Create; fillchar(obj.attrib, sizeof(OIAN_MARK_ATTRIBUTES), 0); obj.attrib.dwReserved4 := $FF83F; fObjects.Add(obj); vect.GetObjRect(hobj, rect); rc := rect; if rc.Left > rc.Right then iswap(rc.Left, rc.Right); if rc.Top > rc.Bottom then iswap(rc.Top, rc.Bottom); obj.attrib.lrBounds := rc; obj.attrib.bVisible := true; end; procedure PutCommonMemoData; var l: integer; s1, s2: AnsiString; begin //obj.attrib.lfFont.lfHeight := -round((vect.ObjFontHeight[hobj] / gSystemDPIY) * 72); obj.attrib.lfFont.lfHeight := -trunc( vect.ObjFontHeight[hobj] * (ANNOT_CREATION_SCALE / 1000) ); IEStrCopy(obj.attrib.lfFont.lfFaceName, PAnsiChar(AnsiString(vect.ObjFontName[hobj]))); if fsBold in vect.ObjFontStyles[hobj] then obj.attrib.lfFont.lfWeight := FW_BOLD else obj.attrib.lfFont.lfWeight := FW_NORMAL; obj.attrib.lfFont.lfItalic := byte(fsItalic in vect.ObjFontStyles[hobj]); obj.attrib.lfFont.lfUnderline := byte(fsUnderline in vect.ObjFontStyles[hobj]); obj.attrib.lfFont.lfStrikeOut := byte(fsStrikeOut in vect.ObjFontStyles[hobj]); s1 := ''; s2 := Utf8Encode(vect.ObjText[hobj]); for l := 1 to length(s2) do if s2[l] = #10 then s1 := s1 + #13#10 else s1 := s1 + s2[l]; l := length(s1) + 1; getmem(obj.text, l); IEStrCopy(obj.text, PAnsiChar(s1)); end; begin if not assigned( Target ) and assigned( fParent ) and assigned( ( fParent as TIOParams ).ImageEnIO ) then Target := TImageEnIO( ( fParent as TIOParams).ImageEnIO ).AttachedImageEn; if not (Target is TImageEnVect) then raise EIEException.create( 'Target not a TImageEnVect' ); vect := Target as TImageEnVect; Clear; for i := 0 to vect.ObjectsCount - 1 do begin hobj := vect.GetObjFromIndex(i); case vect.ObjKind[hobj] of iekBITMAP: begin AddNew; obj.attrib.uType := IEAnnotImageEmbedded; obj.image := TIEBitmap.Create; obj.image.Assign(vect.ObjBitmap[hobj]); end; iekLINE: begin AddNew; obj.attrib.uType := IEAnnotStraightLine; obj.attrib.rgbColor1 := TColor2TRGBQuad(vect.ObjPenColor[hobj]); obj.attrib.uLineSize := vect.ObjPenWidth[hobj]; obj.attrib.bHighlighting := vect.ObjTransparency[hobj] < 200; getmem(obj.points, 2 * sizeof(TPoint)); obj.pointslen := 2; obj.points[0].x := rect.Left - obj.attrib.lrBounds.Left; obj.points[0].y := rect.Top - obj.attrib.lrBounds.Top; obj.points[1].x := rect.Right - obj.attrib.lrBounds.Left; obj.points[1].y := rect.Bottom - obj.attrib.lrBounds.Top; end; iekPOLYLINE: begin AddNew; obj.attrib.uType := IEAnnotFreehandLine; obj.attrib.rgbColor1 := TColor2TRGBQuad(vect.ObjPenColor[hobj]); obj.attrib.uLineSize := vect.ObjPenWidth[hobj]; obj.attrib.bHighlighting := vect.ObjTransparency[hobj] < 200; obj.pointslen := vect.ObjPolylinePointsCount[hobj]; getmem(obj.points, obj.pointslen * sizeof(TPoint)); for j := 0 to obj.pointslen - 1 do begin obj.points[j].x := vect.ObjPolylinePoints[hobj, j].x - obj.attrib.lrBounds.Left; obj.points[j].y := vect.ObjPolylinePoints[hobj, j].y - obj.attrib.lrBounds.Top; end; end; iekBOX: begin AddNew; if vect.ObjBrushStyle[hobj] = bsClear then begin obj.attrib.uType := IEAnnotHollowRectangle; obj.attrib.rgbColor1 := TColor2TRGBQuad(vect.ObjPenColor[hobj]); obj.attrib.uLineSize := vect.ObjPenWidth[hobj]; obj.attrib.bHighlighting := vect.ObjBoxHighLight[hobj]; end else begin obj.attrib.uType := IEAnnotFilledRectangle; obj.attrib.rgbColor1 := TColor2TRGBQuad(vect.ObjBrushColor[hobj]); obj.attrib.bHighlighting := vect.ObjBoxHighLight[hobj]; end; end; iekMEMO, iekTEXT: begin AddNew; if (vect.ObjKind[hobj] = iekTEXT) and (vect.ObjTextAutoSize[hobj]) then begin // iekTEXT is converted to iekMEMO which requires more horizontal space to draw all characters, so this increases box width by one character inc(obj.attrib.lrBounds.Right, abs(vect.ObjFontHeight[hobj])); end; if vect.ObjBrushStyle[hobj] = bsClear then begin obj.attrib.uType := IEAnnotTypedText; obj.attrib.rgbColor1 := TColor2TRGBQuad(vect.ObjPenColor[hobj]); PutCommonMemoData; end else begin obj.attrib.uType := IEAnnotAttachANote; obj.attrib.rgbColor1 := TColor2TRGBQuad(vect.ObjBrushColor[hobj]); obj.attrib.rgbColor2 := TColor2TRGBQuad(vect.ObjPenColor[hobj]); PutCommonMemoData; end; end; end; end; end; {!! TIEImagingAnnot.CopyToTImageEnVect Declaration procedure CopyToTImageEnVect(Target: TObject=nil); Description Copy to a TImageEnVect object (as vectorial objects). If Target is nil then the parent TImageEnVect is given. Example // load image and vectorial objects in 'TIFF_with_objects.tiff' to TImageEnVect ImageEnVect1.IO.LoadFromFile('TIFF_with_objects.tiff'); ImageEnVect1.IO.Params.ImagingAnnot.CopyToTImageEnVect(); See Also - - TIEImageEnAnnot.CopyToTImageEnVect !!} procedure TIEImagingAnnot.CopyToTImageEnVect(Target: TObject); var vect: TImageEnVect; idx, i, j: integer; o: TIEImagingObject; x1, y1, x2, y2: integer; poly: array of TPoint; begin if not assigned( Target ) and assigned( fParent ) and assigned( ( fParent as TIOParams ).ImageEnIO ) then Target := TImageEnIO( ( fParent as TIOParams).ImageEnIO ).AttachedImageEn; if not (Target is TImageEnVect) then raise EIEException.create( 'Target not a TImageEnVect' ); vect := Target as TImageEnVect; for i := 0 to fObjects.Count - 1 do begin o := fObjects[i]; case o.attrib.uType of IEAnnotImageEmbedded: begin idx := vect.AddNewObject; vect.ObjKind[idx] := iekBITMAP; vect.SetObjRect(idx, o.attrib.lrBounds); vect.ObjBitmap[idx] := o.image; end; IEAnnotImageReference: begin end; IEAnnotStraightLine: begin idx := vect.AddNewObject; vect.ObjKind[idx] := iekLINE; x1 := o.attrib.lrBounds.Left + o.points[0].x; y1 := o.attrib.lrBounds.Top + o.points[0].y; x2 := o.attrib.lrBounds.Left + o.points[1].x; y2 := o.attrib.lrBounds.Top + o.points[1].y; vect.SetObjRect(idx, rect(x1, y1, x2, y2)); vect.ObjPenColor[idx] := TRGBQuad2TColor(o.attrib.rgbColor1); vect.ObjPenStyle[idx] := psSolid; vect.ObjPenWidth[idx] := o.attrib.uLineSize; vect.ObjBeginShape[idx] := iesNONE; vect.ObjEndShape[idx] := iesNONE; if o.attrib.bHighlighting then vect.ObjTransparency[idx] := 127 else vect.ObjTransparency[idx] := 255; end; IEAnnotFreehandLine: begin idx := vect.AddNewObject; vect.ObjKind[idx] := iekPOLYLINE; SetLength(poly, o.pointslen); for j := 0 to o.pointslen - 1 do begin poly[j].x := o.attrib.lrBounds.Left + o.points[j].x; poly[j].y := o.attrib.lrBounds.Top + o.points[j].y; end; vect.SetObjPolylinePoints(idx, Copy(poly, 0, o.pointslen)); vect.ObjPenColor[idx] := TRGBQuad2TColor(o.attrib.rgbColor1); vect.ObjPenStyle[idx] := psSolid; vect.ObjPenWidth[idx] := o.attrib.uLineSize; if o.attrib.bHighlighting then vect.ObjTransparency[idx] := 127 else vect.ObjTransparency[idx] := 255; end; IEAnnotHollowRectangle: begin idx := vect.AddNewObject; vect.ObjKind[idx] := iekBOX; vect.SetObjRect(idx, rect(o.attrib.lrBounds.Left, o.attrib.lrBounds.Top, o.attrib.lrBounds.Right, o.attrib.lrBounds.Bottom)); vect.ObjPenColor[idx] := TRGBQuad2TColor(o.attrib.rgbColor1); vect.ObjPenWidth[idx] := o.attrib.uLineSize; vect.ObjPenStyle[idx] := psSolid; vect.ObjBrushStyle[idx] := bsClear; vect.ObjMemoCharsBrushStyle[idx] := bsClear; vect.ObjBoxHighLight[idx] := o.attrib.bHighlighting; end; IEAnnotFilledRectangle: begin idx := vect.AddNewObject; vect.ObjKind[idx] := iekBOX; vect.SetObjRect(idx, rect(o.attrib.lrBounds.Left, o.attrib.lrBounds.Top, o.attrib.lrBounds.Right, o.attrib.lrBounds.Bottom)); vect.ObjBrushColor[idx] := TRGBQuad2TColor(o.attrib.rgbColor1); vect.ObjBrushStyle[idx] := bsSolid; vect.ObjMemoCharsBrushStyle[idx] := bsSolid; vect.ObjPenStyle[idx] := psClear; vect.ObjBoxHighLight[idx] := o.attrib.bHighlighting; end; IEAnnotTypedText, IEAnnotTextStamp, IEAnnotTextFromFile: begin idx := vect.AddNewObject; vect.ObjKind[idx] := iekMEMO; vect.SetObjRect(idx, rect(o.attrib.lrBounds.Left, o.attrib.lrBounds.Top, o.attrib.lrBounds.Right, o.attrib.lrBounds.Bottom)); vect.ObjPenColor[idx] := TRGBQuad2TColor(o.attrib.rgbColor1); vect.ObjBrushColor[idx] := clwhite; vect.ObjBrushStyle[idx] := bsClear; vect.ObjMemoCharsBrushStyle[idx] := bsClear; vect.ObjMemoBorderStyle[idx] := psClear; //vect.ObjFontHeight[idx] := -round((o.attrib.lfFont.lfHeight/72)*gSystemDPIY); vect.ObjFontHeight[idx] := -trunc( o.attrib.lfFont.lfHeight * 1000 / ANNOT_CREATION_SCALE ); vect.ObjFontName[idx] := WideString(o.attrib.lfFont.lfFaceName); vect.ObjFontStyles[idx] := IEExtractStylesFromLogFont(@o.attrib.lfFont); vect.ObjTextAlign[idx] := iejLeft; vect.objFontLocked[idx] := true; {$IFDEF Delphi6orNewer} {$WARN SYMBOL_DEPRECATED OFF} {$ENDIF} vect.ObjText[idx] := Utf8Decode(o.text); {$IFDEF Delphi6orNewer} {$WARN SYMBOL_DEPRECATED ON} {$ENDIF} end; IEAnnotAttachANote: begin idx := vect.AddNewObject; vect.ObjKind[idx] := iekMEMO; vect.SetObjRect(idx, rect(o.attrib.lrBounds.Left, o.attrib.lrBounds.Top, o.attrib.lrBounds.Right, o.attrib.lrBounds.Bottom)); vect.ObjPenColor[idx] := TRGBQuad2TColor(o.attrib.rgbColor2); vect.ObjBrushColor[idx] := TRGBQuad2TColor(o.attrib.rgbColor1); vect.ObjBrushStyle[idx] := bsSolid; vect.ObjMemoCharsBrushStyle[idx] := bsSolid; vect.ObjMemoBorderStyle[idx] := psClear; //vect.ObjFontHeight[idx] := -round((o.attrib.lfFont.lfHeight/72)*gSystemDPIY); vect.ObjFontHeight[idx] := -trunc( o.attrib.lfFont.lfHeight * 1000 / ANNOT_CREATION_SCALE ); vect.ObjFontName[idx] := WideString(o.attrib.lfFont.lfFaceName); vect.ObjFontStyles[idx] := IEExtractStylesFromLogFont(@o.attrib.lfFont); vect.ObjTextAlign[idx] := iejLeft; vect.objFontLocked[idx] := true; {$IFDEF Delphi6orNewer} {$WARN SYMBOL_DEPRECATED OFF} {$ENDIF} vect.ObjText[idx] := Utf8Decode(o.text); {$IFDEF Delphi6orNewer} {$WARN SYMBOL_DEPRECATED ON} {$ENDIF} end; IEAnnotForm: begin end; IEAnnotOCRRegion: begin end; end; end; end; {!! TIEImagingAnnot.CopyFromTImageEnView Declaration procedure CopyFromTImageEnView(Target: TObject=nil); Description Copy layers from a object. If Target is nil then the parent TImageEnView is given. Example // save image and layers in TImageEnView to 'TIFF_with_layers.tiff' ImageEnView1.IO.Params.ImagingAnnot.CopyFromTImageEnView(); ImageEnView1.IO.SaveToFile('TIFF_with_layers.tiff'); See Also - - TIEImageEnAnnot.CopyToTImageEnView !!} procedure TIEImagingAnnot.CopyFromTImageEnView(Target: TObject); var ievect: TImageEnVect; begin if not assigned( Target ) and assigned( fParent ) and assigned( ( fParent as TIOParams ).ImageEnIO ) then Target := TImageEnIO( ( fParent as TIOParams).ImageEnIO ).AttachedImageEn; if not (Target is TImageEnView) then raise EIEException.create( 'Target not a TImageEnView' ); ievect := TImageEnVect.Create(nil); try ievect.CopyAllLayersFrom( TImageEnView( Target ), False ); CopyFromTImageEnVect( ievect ); finally ievect.Free(); end; end; {!! TIEImagingAnnot.CopyToTImageEnView Declaration procedure CopyToTImageEnView(Target: TObject=nil); Description Copy to a TImageEnView object (as layers). If Target is nil then the parent TImageEnView is given. Example // load image and layers in 'TIFF_with_layers.tiff' to TImageEnView ImageEnView1.IO.LoadFromFile('TIFF_with_layers.tiff'); ImageEnView1.IO.Params.ImagingAnnot.CopyToTImageEnView(); See Also - - TIEImageEnAnnot.CopyToTImageEnView !!} procedure TIEImagingAnnot.CopyToTImageEnView(Target: TObject); var ievect: TImageEnVect; begin if not assigned( Target ) and assigned( fParent ) and assigned( ( fParent as TIOParams ).ImageEnIO ) then Target := TImageEnIO( ( fParent as TIOParams).ImageEnIO ).AttachedImageEn; if not (Target is TImageEnView) then raise EIEException.create( 'Target not a TImageEnView' ); ievect := TImageEnVect.Create(nil); try CopyToTImageEnVect( ievect ); ievect.CopyAllObjectsTo( TImageEnView( Target )); finally ievect.Free(); end; end; type AN_POINTS = packed record nMaxPoints: integer; nPoints: integer; ptPoint: PPointArray; end; PAN_POINTS = ^AN_POINTS; AN_NEW_ROTATE_STRUCT = packed record rotation: integer; scale: integer; nHRes: integer; nVRes: integer; nOrigHRes: integer; nOrigVRes: integer; bReserved1: integer; bReserved2: integer; nReserved: array[0..5] of integer; end; PAN_NEW_ROTATE_STRUCT = ^AN_NEW_ROTATE_STRUCT; OIAN_TEXTPRIVDATA = packed record nCurrentOrientation: integer; uReserved1: dword; uCreationScale: dword; uAnoTextLength: dword; szAnoText: AnsiChar; end; POIAN_TEXTPRIVDATA = ^OIAN_TEXTPRIVDATA; HYPERLINK_NB = packed record nVersion: integer; nLinkSize: integer; LinkString: PAnsiChar; nLocationSize: integer; LocationString: PAnsiChar; nWorkDirSize: integer; WorkDirString: PAnsiChar; nFlags: integer; end; PHYPERLINK_NB = ^HYPERLINK_NB; TNamedBlocks = record // OiAnoDat_lines - AN_POINTS p_OiAnoDat_lines: PAN_POINTS; // OiAnoDat_images - AN_NEW_ROTATE_STRUCT p_OiAnoDat_images: PAN_NEW_ROTATE_STRUCT; // OiFilNam - AN_NAME_STRUCT p_OiFilNam: PAnsiChar; // OiDIB - AN_IMAGE_STRUCT p_OiDIB: pointer; // OiGroup - STR p_OiGroup: PAnsiChar; // OiIndex - STR p_OiIndex: PAnsiChar; // OiAnText - OIAN_TEXTPRIVDATA p_OiAnText: POIAN_TEXTPRIVDATA; // OiHypLnk - HYPERLINK_NB p_OiHypLnk: PHYPERLINK_NB; end; procedure LoadNamedBlock(var namedblocks: TNamedBlocks; ptr: pbytearray; buflen: integer; var pos: integer; IntegerLen: integer; CurrentMark: integer); var name: AnsiString; size: integer; l: integer; pc: PAnsiChar; begin pc := @ptr[pos]; name := ''; while (pc^ <> #0) and (length(name) < 8) do begin name := name + pc^; inc(pc); end; inc(pos, 8); size := pinteger(@ptr[pos])^; inc(pos, 4); if IntegerLen = 0 then inc(pos, 4); if name = 'OiAnoDat' then begin if (CurrentMark = IEAnnotForm) or (CurrentMark = IEAnnotImageEmbedded) or (CurrentMark = IEAnnotImageReference) then begin // AN_NEW_ROTATE_STRUCT if assigned(namedblocks.p_OiAnoDat_images) then dispose(namedblocks.p_OiAnoDat_images); new(namedblocks.p_OiAnoDat_images); move(ptr[pos], namedblocks.p_OiAnoDat_images^, sizeof(AN_NEW_ROTATE_STRUCT)); end else if (CurrentMark = IEAnnotFreehandLine) or (CurrentMark = IEAnnotStraightLine) then begin // AN_POINTS if assigned(namedblocks.p_OiAnoDat_lines) then dispose(namedblocks.p_OiAnoDat_lines); new(namedblocks.p_OiAnoDat_lines); move(ptr[pos], namedblocks.p_OiAnoDat_lines^, sizeof(AN_POINTS) - sizeof(PPointArray)); l := sizeof(TPoint) * namedblocks.p_OiAnoDat_lines.nPoints; getmem(namedblocks.p_OiAnoDat_lines.ptPoint, l); move(ptr[pos + sizeof(AN_POINTS) - sizeof(PPointArray)], namedblocks.p_OiAnoDat_lines.ptPoint^[0], l); end; end else if name = 'OiFilNam' then begin // STR if assigned(namedblocks.p_OiFilNam) then freemem(namedblocks.p_OiFilNam); l := IEStrLen(PAnsiChar(@ptr[pos])); getmem(namedblocks.p_OiFilNam, l + 1); move(ptr[pos], namedblocks.p_OiFilNam^, l + 1); end else if name = 'OiDIB' then begin // DIB if assigned(namedblocks.p_OiDIB) then freemem(namedblocks.p_OiDIB); getmem(namedblocks.p_OiDIB, size); move(ptr[pos], namedblocks.p_OiDIB^, size); end else if name = 'OiGroup' then begin // STR if assigned(namedblocks.p_OiGroup) then freemem(namedblocks.p_OiGroup); l := IEStrLen(PAnsiChar(@ptr[pos])); getmem(namedblocks.p_OiGroup, l + 1); move(ptr[pos], namedblocks.p_OiGroup^, l + 1); end else if name = 'OiIndex' then begin // STR if assigned(namedblocks.p_OiIndex) then freemem(namedblocks.p_OiIndex); l := IEStrLen(PAnsiChar(@ptr[pos])); getmem(namedblocks.p_OiIndex, l + 1); move(ptr[pos], namedblocks.p_OiIndex^, l + 1); end else if name = 'OiAnText' then begin // OIAN_TEXTPRIVDATA if assigned(namedblocks.p_OiAnText) then freemem(namedblocks.p_OiAnText); getmem(namedblocks.p_OiAnText, size); move(ptr[pos], namedblocks.p_OiAnText^, size); end; // OiHypLnk not supported inc(pos, size); end; procedure FreeNamedBlocks(var namedblocks: TNamedBlocks); begin if assigned(namedblocks.p_OiAnoDat_images) then dispose(namedblocks.p_OiAnoDat_images); if assigned(namedblocks.p_OiAnoDat_lines) then begin if assigned(namedblocks.p_OiAnoDat_lines.ptPoint) then freemem(namedblocks.p_OiAnoDat_lines.ptPoint); dispose(namedblocks.p_OiAnoDat_lines); end; if assigned(namedblocks.p_OiFilNam) then freemem(namedblocks.p_OiFilNam); if assigned(namedblocks.p_OiDIB) then freemem(namedblocks.p_OiDIB); if assigned(namedblocks.p_OiGroup) then freemem(namedblocks.p_OiGroup); if assigned(namedblocks.p_OiIndex) then freemem(namedblocks.p_OiIndex); if assigned(namedblocks.p_OiAnText) then freemem(namedblocks.p_OiAnText); fillchar(namedblocks, sizeof(TNamedBlocks), 0); end; // add only if Mark.uType<>0 procedure AddMark(annot: TIEImagingAnnot; const DefaultNamedBlocks: TNamedBlocks; const CurrentNamedBlocks: TNamedBlocks; const Mark: OIAN_MARK_ATTRIBUTES); var obj: TIEImagingObject; // procedure Get_OiAnoDat; begin if assigned(CurrentNamedBlocks.p_OiAnoDat_lines) then begin obj.pointsLen := CurrentNamedBlocks.p_OiAnoDat_lines^.nPoints; getmem(obj.points, sizeof(TPoint) * obj.pointslen); move(CurrentNamedBlocks.p_OiAnoDat_lines^.ptPoint^[0], obj.points[0], sizeof(TPoint) * obj.pointslen); end; end; procedure Get_OiAnText; var l: integer; begin if assigned(CurrentNamedBlocks.p_OiAnText) then begin l := IEStrLen(PAnsiChar(@CurrentNamedBlocks.p_OiAnText^.szAnoText)) + 1; getmem(obj.text, l); move(CurrentNamedBlocks.p_OiAnText^.szAnoText, obj.text^, l); if CurrentNamedBlocks.p_OiAnText^.uCreationScale = 0 then //CurrentNamedBlocks.p_OiAnText^.uCreationScale := trunc(72000 / gSystemDPIY); CurrentNamedBlocks.p_OiAnText^.uCreationScale := ANNOT_CREATION_SCALE; //obj.attrib.lfFont.lfHeight := round((obj.attrib.lfFont.lfHeight*(72000/CurrentNamedBlocks.p_OiAnText^.uCreationScale))/gSystemDPIY); l := -trunc(obj.attrib.lfFont.lfHeight * (1000 / CurrentNamedBlocks.p_OiAnText^.uCreationScale)); // object height obj.attrib.lfFont.lfHeight := -trunc( l * (ANNOT_CREATION_SCALE / 1000) ); // now uses iegAnnotCreationScale instead of uCreationScale end; end; // begin if Mark.uType > 0 then begin obj := TIEImagingObject.Create; move(Mark, obj.attrib, sizeof(OIAN_MARK_ATTRIBUTES)); case Mark.uType of IEAnnotImageEmbedded: begin if assigned(CurrentNamedBlocks.p_OiDIB) then begin obj.image := TIEBitmap.Create; _CopyDIB2BitmapEx(cardinal(CurrentNamedBlocks.p_OiDIB), obj.image, nil, true); end; end; IEAnnotImageReference: begin end; IEAnnotStraightLine, IEAnnotFreehandLine: Get_OiAnoDat; IEAnnotHollowRectangle, IEAnnotFilledRectangle: ; // nothing to do IEAnnotTypedText, IEAnnotTextStamp, IEAnnotAttachANote, IEAnnotTextFromFile: Get_OiAnText; IEAnnotForm: begin end; IEAnnotOCRRegion: begin end; end; annot.fObjects.Add(obj); end; end; {!! TIEImagingAnnot.LoadFromStandardBuffer Declaration procedure LoadFromStandardBuffer(buffer: pointer; buflen: integer); Description Loads imaging annotations from the specified buffer. Used when ImageEn loads image files, to extract imaging annotations. !!} procedure TIEImagingAnnot.LoadFromStandardBuffer(buffer: pointer; buflen: integer); var ptr: pbytearray; pos: integer; IntegerLen: integer; // integer length (0=16 bit, 1=32 bit) DataType: integer; // 2=default named blocks, 5=mark data, 6=named block //DataSize: integer; // size of the block DefaultNamedBlocks: TNamedBlocks; CurrentNamedBlocks: TNamedBlocks; CurrentMark: OIAN_MARK_ATTRIBUTES; begin if buflen = 0 then exit; pos := 0; ptr := buffer; inc(pos, 4); // bypass 4 bytes null header IntegerLen := pinteger(@ptr[pos])^; inc(pos, 4); fillchar(DefaultNamedBlocks, sizeof(TNamedBlocks), 0); fillchar(CurrentNamedBlocks, sizeof(TNamedBlocks), 0); fillchar(CurrentMark, sizeof(OIAN_MARK_ATTRIBUTES), 0); while pos < buflen do begin DataType := pinteger(@ptr[pos])^; inc(pos, 4); inc(pos, 4); case DataType of 2: // default named block begin LoadNamedBlock(DefaultNamedBlocks, ptr, buflen, pos, IntegerLen, CurrentMark.uType); end; 5: // mark data begin AddMark(self, DefaultNamedBlocks, CurrentNamedBlocks, CurrentMark); // add previuos mark FreeNamedBlocks(CurrentNamedBlocks); move(ptr[pos], CurrentMark, sizeof(OIAN_MARK_ATTRIBUTES)); inc(pos, sizeof(OIAN_MARK_ATTRIBUTES)); end; 6: // named block begin LoadNamedBlock(CurrentNamedBlocks, ptr, buflen, pos, IntegerLen, CurrentMark.uType); end; end; end; AddMark(self, DefaultNamedBlocks, CurrentNamedBlocks, CurrentMark); // add last mark FreeNamedBlocks(CurrentNamedBlocks); FreeNamedBlocks(DefaultNamedBlocks); fUserChanged := false; // the user should not call LoadFromStandardBuffer, then this is not an user changement end; {!! TIEImagingAnnot.SaveToStandardBuffer Declaration procedure SaveToStandardBuffer(var Buffer: pointer; var BufferLength: integer); Description Saves imaging objects to buffer. You must free the buffer. This method is used to embed imaging annotations inside image files. !!} procedure TIEImagingAnnot.SaveToStandardBuffer(var Buffer: pointer; var BufferLength: integer); const OiAnoDat: PAnsiChar = 'OiAnoDat'; OiAnText: PAnsiChar = 'OiAnText'; OiDIB: PAnsiChar = 'OiDIB'#0#0#0; OiIndex: PAnsiChar = 'OiIndex'#0; OiGroup: PAnsiChar = 'OiGroup'#0; var ms: TMemoryStream; i: integer; ii: integer; l: integer; o: TIEImagingObject; anp: AN_POINTS; tex: OIAN_TEXTPRIVDATA; rot: AN_NEW_ROTATE_STRUCT; hdib: THandle; ptr1: pbyte; stk: TList; ss: AnsiString; // procedure PostPos; var ii: integer; begin stk.add(pointer(ms.Position)); ii := 0; ms.Write(ii, 4); // dummy value: fill with the data size end; procedure SavePos; var pp, p1, ii: integer; begin pp := ms.Position; p1 := integer(stk[stk.count - 1]); ms.position := p1; ii := pp - p1 - 4; ms.Write(ii, 4); stk.delete(stk.Count - 1); ms.position := pp; end; begin if fObjects.Count = 0 then begin Buffer := nil; BufferLength := 0; exit; end; stk := TList.Create; ms := TMemoryStream.Create; ii := 0; ms.write(ii, 4); ii := 1; ms.Write(ii, 4); // default OiGroup ii := 2; ms.Write(ii, 4); // named block ii := 12; ms.Write(ii, 4); ms.Write(OiGroup[0], 8); // name PostPos; ss := '0'; ms.Write(PAnsiChar(ss)[0], length(ss) + 1); SavePos; // default OiIndex ii := 2; ms.Write(ii, 4); // named block ii := 12; ms.Write(ii, 4); ms.Write(OiIndex[0], 8); // name PostPos; ss := '1'; ms.Write(PAnsiChar(ss)[0], length(ss) + 1); SavePos; // for i := 0 to fObjects.Count - 1 do begin ii := 5; ms.Write(ii, 4); // mark data PostPos; o := TIEImagingObject(fObjects[i]); ms.Write(o.attrib, sizeof(OIAN_MARK_ATTRIBUTES)); SavePos; // case o.attrib.uType of IEAnnotImageEmbedded: begin // OiAnoDat ii := 6; ms.Write(ii, 4); // named block ii := 12; ms.Write(ii, 4); ms.Write(OiAnoDat[0], 8); // name PostPos; // rot.rotation := 1; rot.scale := 1000; rot.nHRes := IEGlobalSettings().SystemDPIX; rot.nVRes := IEGlobalSettings().SystemDPIY; rot.nOrigHRes := IEGlobalSettings().SystemDPIX; rot.nOrigVRes := IEGlobalSettings().SystemDPIY; rot.bReserved1 := 0; rot.bReserved2 := 0; fillchar(rot.nReserved[0], 4 * 6, 0); ms.Write(rot, sizeof(AN_NEW_ROTATE_STRUCT)); // SavePos; // OiDIB ii := 6; ms.Write(ii, 4); // named block ii := 12; ms.Write(ii, 4); ms.Write(OiDIB[0], 8); // name PostPos; // hdib := _CopyBitmaptoDIBEx(o.image, 0, 0, 0, 0, 200, 200); ptr1 := GlobalLock(hdib); ms.Write(ptr1^, GlobalSize(hdib)); GlobalUnlock(hdib); GlobalFree(hdib); // SavePos; end; IEAnnotStraightLine, IEAnnotFreehandLine: begin // OiAnoDat ii := 6; ms.Write(ii, 4); // named block ii := 12; ms.Write(ii, 4); ms.Write(OiAnoDat[0], 8); // name PostPos; // anp.nMaxPoints := o.pointsLen; anp.nPoints := o.pointsLen; ms.Write(anp, sizeof(AN_POINTS) - sizeof(PPointArray)); ms.Write(o.points[0], sizeof(TPoint) * o.pointsLen); // SavePos; end; IEAnnotHollowRectangle, IEAnnotFilledRectangle: ; // nothing to do IEAnnotTypedText, IEAnnotTextStamp, IEAnnotAttachANote, IEAnnotTextFromFile: begin // OiAnText ii := 6; ms.Write(ii, 4); // named block ii := 12; ms.Write(ii, 4); ms.Write(OiAnText[0], 8); // name PostPos; // l := IEStrLen(o.text) + 1; tex.nCurrentOrientation := 0; tex.uReserved1 := 1000; //tex.uCreationScale := trunc(72000 / gSystemDPIY); tex.uCreationScale := ANNOT_CREATION_SCALE; tex.uAnoTextLength := l - 1; ms.Write(tex, sizeof(OIAN_TEXTPRIVDATA) - 1); ms.Write(o.text[0], l); // SavePos; end; end; // OiGroup ii := 6; ms.Write(ii, 4); // named block ii := 12; ms.Write(ii, 4); ms.Write(OiGroup[0], 8); // name PostPos; ss := '0'; ms.Write(PAnsiChar(ss)[0], length(ss) + 1); SavePos; // OiIndex ii := 6; ms.Write(ii, 4); // named block ii := 12; ms.Write(ii, 4); ms.Write(OiIndex[0], 8); // name PostPos; ss := IEIntToStr(i); ms.Write(PAnsiChar(ss)[0], length(ss) + 1); SavePos; end; getmem(Buffer, ms.Size); CopyMemory(Buffer, ms.Memory, ms.Size); BufferLength := ms.Size; FreeAndNil(ms); FreeAndNil(stk); end; {$endif} // {$ifdef IEINCLUDEIMAGINGANNOT} // TIEImagingAnnot /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEImageEnAnnot constructor TIEImageEnAnnot.Create(parent: TObject); begin inherited Create(); fParent := parent; fData := TMemoryStream.Create(); fIEVectObjects := True; end; destructor TIEImageEnAnnot.Destroy(); begin fData.Free(); inherited; end; {!! TIEImageEnAnnot.IsEmpty Declaration function IsEmpty(): boolean; Description Returns True if the TIEImageEnAnnot object contains no objects. Example ImageEnView.IO.LoadFromFile('input.jpg'); if ImageEnVIew1.IO.Params.ImageEnAnnot.IsEmpty() then ShowMessage('input.jpg contains no vectorial objects'); !!} function TIEImageEnAnnot.IsEmpty(): boolean; begin result := (fData.Size = 0); end; const // Must be identical length IEVect_Annotations_Magic_Str : AnsiString = 'IMAGEENANNOT'; IEView_Annotations_Magic_Str : AnsiString = 'IENVIEWANNOT'; class function TIEImageEnAnnot.BufferContainsImageEnAnnot(buffer: pointer; buflen: integer; out IsIEVectObjects: Boolean): boolean; var magic: AnsiString; magicLen: integer; begin result := false; magicLen := length( IEVect_Annotations_Magic_Str ); if buflen >= magicLen then begin SetLength(magic, magicLen); move(PAnsiChar(buffer)^, magic[1], magicLen); if magic = IEVect_Annotations_Magic_Str then begin IsIEVectObjects := True; Result := True; end else if magic = IEView_Annotations_Magic_Str then begin IsIEVectObjects := False; Result := True; end; end; end; class function TIEImageEnAnnot.TIFFContainsImageEnAnnot(Stream: TStream; ImageIndex: integer): boolean; var lpos: int64; tags: TIETIFTagsReader; buffer: pointer; buflen: integer; dummy: Boolean; begin result := false; lpos := Stream.Position; tags := TIETIFTagsReader.CreateFromStream(Stream, ImageIndex); try if tags.TagExists(IEGlobalSettings().ObjectsTIFFTag) then begin buffer := tags.GetRawData(IEGlobalSettings().ObjectsTIFFTag); buflen := tags.TagLength(IEGlobalSettings().ObjectsTIFFTag); result := BufferContainsImageEnAnnot(buffer, buflen, dummy); end; finally tags.Free(); Stream.Position := lpos; end; end; class function TIEImageEnAnnot.TIFFContainsImageEnAnnot(const Filename: WideString; ImageIndex: integer): boolean; var stream: TIEWideFileStream; begin stream := TIEWideFileStream.Create(filename, fmOpenRead or fmShareDenyWrite); try result := TIEImageEnAnnot.TIFFContainsImageEnAnnot(stream, ImageIndex); finally stream.Free(); end; end; procedure TIEImageEnAnnot.LoadFromBuffer(buffer: pointer; buflen: integer); var magicLen: integer; begin Clear(); if BufferContainsImageEnAnnot( buffer, buflen, fIEVectObjects ) then begin magicLen := length( IEVect_Annotations_Magic_Str ); dec(buflen, magicLen); inc(pbyte(buffer), magicLen); fData.Write(pbyte(buffer)^, buflen); end; end; procedure TIEImageEnAnnot.SaveToBuffer(var Buffer: pointer; var BufferLength: integer); var destData: pointer; begin Buffer := nil; BufferLength := 0; if fData.Size > 0 then begin BufferLength := fData.Size + length( IEVect_Annotations_Magic_Str ); getmem(Buffer, BufferLength); if fIEVectObjects then move(IEVect_Annotations_Magic_Str[1], PAnsiChar(Buffer)^, length(IEVect_Annotations_Magic_Str)) else move(IEView_Annotations_Magic_Str[1], PAnsiChar(Buffer)^, length(IEView_Annotations_Magic_Str)); destData := Buffer; inc(pbyte(destData), length( IEVect_Annotations_Magic_Str )); CopyMemory(destData, fData.Memory, fData.Size); end; end; {!! TIEImageEnAnnot.Clear Declaration procedure Clear(); Description Removes all vectorial objects from TIEImageEnAnnot. Example // load a jpeg with TImageEnVect objects, remove objects, and save back ImageEnView1.IO.LoadFromFile('input.jpg'); ImageEnView1.IO.Params.ImageEnAnnot.Clear(); ImageEnView1.IO.SaveToFile('output.jpg'); !!} procedure TIEImageEnAnnot.Clear(); begin fData.Clear(); end; procedure TIEImageEnAnnot.Assign(Source: TIEImageEnAnnot); begin Clear(); IECopyFrom(fData, Source.fData, 0); fIEVectObjects := Source.fIEVectObjects; end; procedure TIEImageEnAnnot.SaveToStream(Stream: TStream); var dataLen: dword; begin // write data size dataLen := fData.Size; Stream.Write(dataLen, sizeof(dword)); // write data IECopyFrom(Stream, fData, 0); end; procedure TIEImageEnAnnot.LoadFromStream(Stream: TStream); var dataLen: dword; begin Clear(); Stream.Read(dataLen, sizeof(dword)); // V6.0.1 handle legacy streams by watching for null data if datalen > 0 then IECopyFrom(fData, Stream, dataLen); // Guess stream format fIEVectObjects := False; if GetObjectsCount() > 0 then fIEVectObjects := True; end; {!! TIEImageEnAnnot.CopyToTImageEnVect Declaration procedure CopyToTImageEnVect(Target: TObject = nil); Description Copies vectorial objects in TIEImageEnAnnot into the specified . If Target is nil then the parent TImageEnVect is given. Example // load image and vectorial objects in 'jpeg_with_objects.jpg' to TImageEnVect ImageEnVect1.IO.LoadFromFile('jpeg_with_objects.jpg'); ImageEnVect1.IO.Params.ImageEnAnnot.CopyToTImageEnVect(); See Also - - TIEImagingAnnot.CopyToTImageEnVect !!} procedure TIEImageEnAnnot.CopyToTImageEnVect(Target: TObject = nil); var vect: TImageEnVect; iev: TImageEnView; begin if not assigned( Target ) and assigned( fParent ) and assigned( ( fParent as TIOParams ).ImageEnIO ) then Target := TImageEnIO( ( fParent as TIOParams).ImageEnIO ).AttachedImageEn; if not (Target is TImageEnVect) then raise EIEException.create( 'Target not a TImageEnVect' ); vect := Target as TImageEnVect; if fIEVectObjects then begin fData.Position := 0; vect.LoadFromStreamIEV(fData, true); end else begin iev := TImageEnView.create( nil ); CopyToTImageEnView( iev ); vect.CopyAllLayersFrom( iev, False ); FreeAndNil( iev ); end; end; {!! TIEImageEnAnnot.CopyFromTImageEnVect Declaration procedure CopyFromTImageEnVect(Target: TObject = nil); Description Copies vectorial objects from a object. If Target is nil then the parent TImageEnVect is given. Notes: - The EXIF marker block has a maximum size of 65KB, so CopyFromTImageEnVect will raise an exception if the data size of all layers exceeds this - The TIOParams.ImageEnAnnot format is proprietary to ImageEn. If you need annotations in a format supported by other applications, see Example // save image and vectorial objects in TImageEnVect to 'jpeg_with_objects.jpg' ImageEnVect1.IO.Params.ImageEnAnnot.CopyFromTImageEnVect(); ImageEnVect1.IO.SaveToFile('jpeg_with_objects.jpg'); See Also - - TIEImagingAnnot.CopyFromTImageEnVect !!} procedure TIEImageEnAnnot.CopyFromTImageEnVect(Target: TObject = nil); var vect: TImageEnVect; begin if not assigned( Target ) and assigned( fParent ) and assigned( ( fParent as TIOParams ).ImageEnIO ) then Target := TImageEnIO( ( fParent as TIOParams).ImageEnIO ).AttachedImageEn; if not (Target is TImageEnVect) then raise EIEException.create( 'Target not a TImageEnVect' ); vect := Target as TImageEnVect; Clear(); fIEVectObjects := True; vect.SaveToStreamIEV(fData); if fData.Size > MaxWord then begin Clear(); raise EIEException.create( 'Annotation block too large' ); end; end; {!! TIEImageEnAnnot.CopyToTImageEnView Declaration procedure CopyToTImageEnView(Target: TObject = nil); Description Copies layers in TIEImageEnAnnot into the specified . If Target is nil then the parent TImageEnView is given. Example // load image and layers in 'jpeg_with_layers.jpg' to TImageEnView ImageEnView1.IO.LoadFromFile('jpeg_with_layers.jpg'); ImageEnView1.IO.Params.ImageEnAnnot.CopyToTImageEnView(); See Also - - TIEImagingAnnot.CopyToTImageEnView !!} procedure TIEImageEnAnnot.CopyToTImageEnView(Target: TObject = nil); var ieview: TImageEnView; ievect: TImageEnVect; begin if not assigned( Target ) and assigned( fParent ) and assigned( ( fParent as TIOParams ).ImageEnIO ) then Target := TImageEnIO( ( fParent as TIOParams).ImageEnIO ).AttachedImageEn; if not (Target is TImageEnView) then raise EIEException.create( 'Target not a TImageEnView' ); ieview := Target as TImageEnView; if fIEVectObjects then begin ievect := TImageEnVect.Create(nil); try CopyToTImageEnVect( ievect ); ievect.CopyAllObjectsTo( ieview ); finally ievect.Free(); end; end else begin fData.Position := 0; ieview.LayersLoadFromStream( fData, true ); end; end; {!! TIEImageEnAnnot.CopyFromTImageEnView Declaration procedure CopyFromTImageEnView(Target: TObject = nil); Description Copies layers from a object. If Target is nil then the parent TImageEnView is given. Notes: - The EXIF marker block has a maximum size of 65KB, so CopyFromTImageEnView will ignore any image layers - An exception is raised if the data block exceeds 65KB - The TIOParams.ImageEnAnnot format is proprietary to ImageEn. Example // save image and layers in TImageEnView to 'jpeg_with_layers.jpg' ImageEnView1.IO.Params.ImageEnAnnot.CopyFromTImageEnView(); ImageEnView1.IO.SaveToFile('jpeg_with_layers.jpg'); See Also - - TIEImagingAnnot.CopyFromTImageEnView !!} procedure TIEImageEnAnnot.CopyFromTImageEnView(Target: TObject = nil); var ieview: TImageEnView; begin if not assigned( Target ) and assigned( fParent ) and assigned( ( fParent as TIOParams ).ImageEnIO ) then Target := TImageEnIO( ( fParent as TIOParams).ImageEnIO ).AttachedImageEn; if not (Target is TImageEnView) then raise EIEException.create( 'Target not a TImageEnView' ); ieview := Target as TImageEnView; Clear(); fIEVectObjects := False; ieview.LayersSaveToStream( fData, -1, False, True, False, nil ); if fData.Size > MaxWord then begin Clear(); raise EIEException.create( 'Annotation block too large' ); end; end; {!! TIEImageEnAnnot.DrawToBitmap Declaration procedure DrawToBitmap(target: ; Antialias: boolean); Description Draws all annotations to the specified bitmap. Example ImageEnView.IO.ImageEnAnnot.DrawToBitmap( ImageEnView.IEBitmap, true ); ImageEnView.Update(); !!} procedure TIEImageEnAnnot.DrawToBitmap(target: TIEBitmap; Antialias: boolean); var ievect: TImageEnVect; begin ievect := TImageEnVect.Create(nil); try if fIEVectObjects then begin CopyToTImageEnVect(ievect); ievect.ObjGraphicRender := true; ievect.DrawObjectsToBitmap(target, Antialias); end else begin CopyToTImageEnView(ievect); ievect.LegacyBitmap := False; ievect.IEBitmap.Assign( target ); ievect.LayersDrawTo( target, False ); end; finally ievect.Free(); end; end; {!! TIEImageEnAnnot.ObjectsCount Declaration property ObjectsCount: integer; Description Returns the number of annotation objects contained in the TIEImageEnAnnot object. If was used, the result will be the count of TImageEnVect Objects. If was used, the result will be the count of TImageEnView Layers. Note: Calculating objects count can be time and memory intensive. !!} function TIEImageEnAnnot.GetObjectsCount(): integer; var dummyBMP: TIEBitmap; ievect: TImageEnVect; recHead: TLayerHeader; headWidth, headHeight: Integer; headDesc: Widestring; begin result := 0; if fIEVectObjects then begin ievect := TImageEnVect.Create(nil); try CopyToTImageEnVect(ievect); result := ievect.ObjectsCount; finally ievect.Free(); end; end else begin fData.Position := 0; dummyBMP := nil; if IELayersLoadHeaderFromStream( fData, recHead, headWidth, headHeight, headDesc, dummyBMP, False ) then Result := recHead.LayersCount; end; end; // TIEImageEnAnnot /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // PDF Support {$ifdef IEINCLUDEPDFWRITING} procedure iepdf_WriteLn(Stream: TStream; line: AnsiString); begin line := line + #10; Stream.Write(PAnsiChar(line)^, length(line)); end; procedure iepdf_Write(Stream: TStream; line: AnsiString); begin Stream.Write(PAnsiChar(line)^, length(line)) end; constructor TIEPDFObject.Create; begin DontFree := false; inherited; end; destructor TIEPDFObject.Destroy; begin inherited; end; constructor TIEPDFRefObject.Create(ObjNumber: integer; GenNumber: integer); begin inherited Create; ObjectNumber := ObjNumber; GenerationNumber := GenNumber; end; constructor TIEPDFNumericObject.Create(vv: double); begin inherited Create; Value := vv; end; constructor TIEPDFBooleanObject.Create(vv: boolean); begin inherited Create; Value := vv; end; constructor TIEPDFStringObject.Create(vv: AnsiString); begin inherited Create; Value := vv; end; constructor TIEPDFNameObject.Create(vv: AnsiString); begin inherited Create; Value := vv; end; constructor TIEPDFArrayObject.Create; begin inherited Create; Items := TList.Create; end; destructor TIEPDFArrayObject.Destroy; var i: integer; begin for i := Items.Count - 1 downto 0 do if not TIEPDFObject(Items[i]).DontFree then begin TIEPDFObject(Items[i]).Free; Items[i] := nil; end; FreeAndNil(Items); inherited; end; constructor TIEPDFDictionaryObject.Create; begin inherited Create; Items := TStringList.Create; end; destructor TIEPDFDictionaryObject.Destroy; var i: integer; begin for i := Items.Count - 1 downto 0 do if not TIEPDFObject(Items.Objects[i]).DontFree then begin TIEPDFObject(Items.Objects[i]).Free; Items.Objects[i] := nil; end; FreeAndNil(Items); inherited; end; constructor TIEPDFStreamObject.Create; begin inherited Create; cache := nil; data := nil; length := 0; dict := TIEPDFDictionaryObject.Create; dict.items.AddObject('Length', TIEPDFNumericObject.Create(0)) end; constructor TIEPDFStreamObject.CreateCopy(copydata: pointer; copylength: integer); begin inherited Create; Create; getmem(data, copylength); length := copylength; copymemory(data, copydata, length); end; destructor TIEPDFStreamObject.Destroy; begin FreeAndNil(dict); if data <> nil then freemem(data); if cache <> nil then cache.Free(); inherited; end; procedure TIEPDFRefObject.Write(Stream: TStream); begin Position := Stream.Position; iepdf_Write(Stream, IEIntToStr(ObjectNumber) + #32 + IEIntToStr(GenerationNumber) + #32 + 'R'); end; procedure TIEPDFBooleanObject.Write(Stream: TStream); const ar: array[false..true] of AnsiString = ('false', 'true'); begin Position := Stream.Position; iepdf_Write(Stream, ar[value]); end; procedure TIEPDFNumericObject.Write(Stream: TStream); begin Position := Stream.Position; iepdf_Write(Stream, IEFloatToStrA(Value)); end; procedure TIEPDFStringObject.Write(Stream: TStream); var ss: AnsiString; i: integer; begin Position := Stream.Position; // writes only normal strings (not hex) for i := 1 to length(Value) do case Value[i] of #10: ss := ss + '\n'; #13: ss := ss + '\r'; #9: ss := ss + '\t'; #8: ss := ss + '\b'; #12: ss := ss + '\f'; '(': ss := ss + '\('; ')': ss := ss + '\)'; '\': ss := ss + '\\'; else ss := ss + Value[i]; end; iepdf_Write(Stream, '(' + ss + ')'); end; procedure TIEPDFNameObject.Write(Stream: TStream); var ss: AnsiString; i: integer; begin Position := Stream.Position; for i := 1 to length(Value) do if (Value[i] < #33) or (Value[i] > #126) then ss := ss + '#' + IEIntToHex(ord(Value[i]), 2) else ss := ss + Value[i]; iepdf_Write(Stream, '/' + ss); end; procedure TIEPDFArrayObject.Write(Stream: TStream); var i: integer; begin Position := Stream.Position; iepdf_Write(Stream, '['); for i := 0 to items.Count - 1 do begin TIEPDFObject(items[i]).Write(Stream); iepdf_Write(Stream, ' '); // space among items end; iepdf_Write(Stream, ']'); end; procedure TIEPDFDictionaryObject.Write(Stream: TStream); var i: integer; begin Position := Stream.Position; iepdf_Write(Stream, '<< '); for i := 0 to items.count - 1 do begin iepdf_Write(Stream, '/' + AnsiString(items[i]) + ' '); TIEPDFObject(items.Objects[i]).Write(Stream); iepdf_Write(Stream, #10); end; iepdf_Write(Stream, '>>'); end; procedure TIEPDFStreamObject.FlushToCache(); begin assert(cache = nil); cache := TIETemporaryFileStream.Create(IEGetTempFileName2()); cache.Write(pbyte(data)^, length); freemem(data); data := nil; end; procedure TIEPDFStreamObject.Write(Stream: TStream); var i: integer; begin Position := Stream.Position; // i := dict.items.IndexOf('Length'); TObject(dict.items.Objects[i]).free; dict.items.Objects[i] := TIEPDFNumericObject.Create(length); // dict.Write(Stream); iepdf_Write(Stream, #10); iepdf_WriteLn(Stream, 'stream'); if cache <> nil then begin cache.Position := 0; IECopyFrom(Stream, cache, length); end else Stream.Write(pbyte(data)^, length); iepdf_Write(Stream, #10); iepdf_Write(Stream, 'endstream'); end; // write version and binary comment procedure iepdf_WriteHeader(Stream: TStream); begin iepdf_WriteLn(Stream, '%PDF-1.4'); // version iepdf_WriteLn(Stream, #200#210#240#254); // binary four random bytes end; function Pad(val: AnsiString; reqLen: integer; padchar: AnsiChar): AnsiString; begin result := val; while length(result) < reqLen do result := padchar + result; end; // write cross reference table (xref), trailer, startxref and the end of file procedure iepdf_WriteFooter(Stream: TStream; IndirectObjects: TList; info: TIEPDFObject); var i: integer; xrefPos: integer; begin // xref (cross reference table) xrefPos := Stream.Position; iepdf_WriteLn(Stream, 'xref'); // cross reference keyword iepdf_WriteLn(Stream, '0 ' + IEIntToStr(IndirectObjects.Count + 1)); // first object number and objects count iepdf_WriteLn(Stream, '0000000000 65535 f '); // first free object for i := 0 to IndirectObjects.Count - 1 do iepdf_Write(Stream, Pad(IEIntToStr(TIEPDFObject(IndirectObjects[i]).Position), 10, '0') + #32 + '00000' + #32 + 'n ' + #10); // trailer iepdf_WriteLn(Stream, 'trailer'); // trailer keyword iepdf_WriteLn(Stream, '<< /Size ' + IEIntToStr(IndirectObjects.Count + 1)); iepdf_WriteLn(Stream, '/Root 1 0 R'); // root must be object number 1 (the first object defined) iepdf_WriteLn(Stream, '/Info ' + IEIntToStr(info.Index) + ' 0 R'); iepdf_WriteLn(Stream, '>>'); // startxref (defines xref position) iepdf_WriteLn(Stream, 'startxref'); iepdf_WriteLn(Stream, IEIntToStr(xrefPos)); // end of file iepdf_WriteLn(Stream, '%%EOF'); end; procedure iepdf_AddIndirectObject(IndirectObjects: TList; obj: TIEPDFObject); begin IndirectObjects.Add(obj); obj.Index := IndirectObjects.Count; end; // encloses an object to make as indirect object procedure iepdf_WriteIndirectObjects(Stream: TStream; IndirectObjects: TList); var i, j: integer; obj: TIEPDFObject; begin for i := 0 to IndirectObjects.Count - 1 do begin obj := TIEPDFObject(IndirectObjects[i]); j := Stream.Position; iepdf_WriteLn(Stream, IEIntToStr(obj.Index) + ' 0 obj'); obj.Write(Stream); iepdf_Write(Stream, #10); // just new line iepdf_WriteLn(Stream, 'endobj'); obj.Position := j; // adjust position to include indirect object info end; end; // prepares the empty root catalog, adding it to IndirectObjects list (must be empty but not nil) function iepdf_AddCatalog(IndirectObjects: TList): TIEPDFDictionaryObject; begin result := TIEPDFDictionaryObject.Create; result.items.AddObject('Type', TIEPDFNameObject.Create('Catalog')); iepdf_AddIndirectObject(IndirectObjects, result); end; // * add /Pages for the specified list of /Page tags // * the list of pages is a list of indexes at the IndirectObjects list // * add "/Parent" for each page function iepdf_AddPageTree(IndirectObjects: TList; pages: TList): TIEPDFDictionaryObject; var root, page: TIEPDFDictionaryObject; parr: TIEPDFArrayObject; i: integer; begin result := TIEPDFDictionaryObject.Create; iepdf_AddIndirectObject(IndirectObjects, result); result.items.AddObject('Type', TIEPDFNameObject.Create('Pages')); parr := TIEPDFArrayObject.Create; for i := 0 to pages.Count - 1 do begin page := TIEPDFDictionaryObject(pages[i]); parr.Items.Add(TIEPDFRefObject.Create(page.Index, 0)); // add parent tag foreach page page.items.AddObject('Parent', TIEPDFRefObject.Create(result.Index, 0)); end; result.items.AddObject('Kids', parr); result.items.AddObject('Count', TIEPDFNumericObject.Create(pages.count)); // update root catalog root := TIEPDFDictionaryObject(IndirectObjects[0]); root.items.AddObject('Pages', TIEPDFRefObject.Create(result.Index, 0)); end; // add /Page object // pages is updated with the new page index inside IndirectObjects // Resources can be nil procedure iepdf_AddPage(IndirectObjects: TList; pages: TList; Resources: TIEPDFDictionaryObject; MediaBox: TIEPDFArrayObject; Content: integer); var page: TIEPDFDictionaryObject; begin page := TIEPDFDictionaryObject.Create; page.items.AddObject('Type', TIEPDFNameObject.Create('Page')); if assigned(Resources) then page.items.AddObject('Resources', TIEPDFRefObject.Create(Resources.Index, 0)); page.items.AddObject('MediaBox', MediaBox); page.items.AddObject('Contents', TIEPDFRefObject.Create(Content, 0)); iepdf_AddIndirectObject(IndirectObjects, page); pages.Add(page); // do not free items of pages list end; {$endif} // IEINCLUDEPDFWRITING // works only for clean PDFs (also compressed and encoded pdfs do not work) function IEPDFFrameCount(Stream: TStream): integer; overload; var bufStream: TIEBufferedReadStream; streamSize: int64; pos_begintag, pos_count, pos_parent, pos_endtag, pos_type, pos_spc: int64; astr: AnsiString; Params : TIOParams; lpos: Integer; begin result := 0; lpos := Stream.Position; {$IFDEF IEINCLUDEMISCPLUGINS} if IEFileFormatGetInfo( iomscWPPDF ) <> nil then begin // WP PDF Plug-In Params := TIOParams.Create; try Params.Read( Stream ); Result := Params.ImageCount; finally Params.Free; Stream.Position := lpos; end; end else if IEFileFormatGetInfo( iomscPDF ) <> nil then begin // Ghostscript PDF support Result := TIEMiscPluginsImageMagick_PDFFrameCount( Stream ); Stream.Position := lpos; end else {$endif} begin bufStream := TIEBufferedReadStream.Create(Stream, 8192); try streamSize := bufStream.Size; pos_endtag := -2; while true do begin bufStream.Position := pos_endtag + 2; pos_begintag := IEStreamFindString(bufStream, '<<', streamSize); if pos_begintag = -1 then break; pos_endtag := IEStreamFindString(bufStream, '>>', streamSize); bufStream.Position := pos_begintag; pos_count := IEStreamFindString(bufStream, '/Count ', pos_endtag); if pos_count = -1 then continue; bufStream.Position := pos_begintag; pos_parent := IEStreamFindString(bufStream, '/Parent', pos_endtag); if pos_parent > -1 then // I don't want "/Parent"! continue; bufStream.Position := pos_begintag; pos_type := IEStreamFindString(bufStream, '/Type /Pages', pos_endtag); if (pos_type > -1) then begin // found /Count without parent bufStream.Position := pos_count + 7; pos_spc := IEStreamFindString(bufStream, ' ', pos_endtag); SetLength(astr, pos_spc - pos_count - 7); bufStream.Position := pos_count + 7; bufStream.Read(astr[1], length(astr)); result := IEStrToIntDef(astr, 0); exit; end; end; finally bufStream.Free(); Stream.Position := lpos; end; end; end; function IEPDFFrameCount(const Filename: WideString): integer; overload; var fs: TIEWideFileStream; begin fs := TIEWideFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try result := IEPDFFrameCount(fs); finally fs.Free(); end; end; // End of PDF Support /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Windows CMS functions function LoadMSCMS(): boolean; begin if mscms = 0 then begin // try to load the mscms.dll dynamic library mscms := LoadLibrary('mscms.dll'); if mscms<>0 then begin IE_OpenColorProfile := GetProcAddress(mscms, 'OpenColorProfileA'); IE_CloseColorProfile := GetProcAddress(mscms, 'CloseColorProfile'); IE_CreateMultiProfileTransform := GetProcAddress(mscms, 'CreateMultiProfileTransform'); IE_DeleteColorTransform := GetProcAddress(mscms, 'DeleteColorTransform'); IE_TranslateColors := GetProcAddress(mscms, 'TranslateColors'); end; end; result := mscms<>0; end; // End of Windows CMS functions /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEICC // UseLCMS=true works only when IEINCLUDECMS is defined, otherwise it is always False constructor TIEICC.Create(UseLCMS: boolean); begin inherited Create(); {$ifdef IEINCLUDECMS} fUseLCMS := UseLCMS; {$else} fUseLCMS := false; {$endif} fRaw := nil; fRawLen := 0; fProfile := nil; fProfileStream := nil; fTransform := nil; fInputFormat := 0; fOutputFormat := 0; fDestination := nil; fIntent := 0; fFlags := 0; fApplied := false; fMSProfile := 0; fMSTransform := 0; end; destructor TIEICC.Destroy; begin Clear; inherited Destroy; end; {!! TIEICC.LoadFromBuffer Declaration procedure LoadFromBuffer(buffer: pointer; bufferlen: integer); Description Loads the ICC profile from the specified buffer. This is called automatically when loading an image from file. !!} procedure TIEICC.LoadFromBuffer(buffer: pointer; bufferlen: integer); begin Clear; fRawLen := bufferlen; getmem(fRaw, bufferlen); copymemory(fRaw, buffer, bufferlen); OpenProfileFromRaw(); end; {!! TIEICC.Clear Declaration procedure Clear; Description Close the profile and free all allocated buffers. !!} procedure TIEICC.Clear; begin CloseProfileFromRaw(); if fRaw <> nil then freemem(fRaw); fRaw := nil; fRawLen := 0; fApplied := false; end; {!! TIEICC.IsValid Declaration function IsValid: boolean; Description Returns true if the currently loaded ICC profile is valid. !!} function TIEICC.IsValid: boolean; begin result := (fProfile <> nil) or (fMSProfile <> 0); end; {!! TIEICC.SaveToStream Declaration procedure SaveToStream(Stream: TStream; StandardICC: boolean); Description Saves the current ICC to a stream. If StandardICC is False a header which specifies the ICC block size is added. Otherwise saves as standard ICC. !!} procedure TIEICC.SaveToStream(Stream: TStream; StandardICC: boolean); begin if not StandardICC then begin // non standard ICC (this means it has a 32 bit header with the ICC size) // use this only inside TIOParams.SaveToStream and LoadFromStream! Stream.Write(fRawLen, sizeof(integer)); Stream.Write(fRaw^, fRawLen); end else begin // standard ICC Stream.Write(fRaw^, fRawLen); end; end; {!! TIEICC.LoadFromStream Declaration procedure LoadFromStream(Stream: TStream; StandardICC: boolean); Description Loads an ICC from the stream. If StandardICC is False an header is expected to know the ICC block size. !!} procedure TIEICC.LoadFromStream(Stream: TStream; StandardICC: boolean); begin Clear; if not StandardICC then begin // non standard ICC (this means it has a 32 bit header with the ICC size) // use this only inside TIOParams.SaveToStream and LoadFromStream! Stream.Read(fRawLen, sizeof(integer)); getmem(fRaw, fRawLen); Stream.Read(fRaw^, fRawLen); end else begin // standard ICC // it assumes the stream contains only the ICC profile fRawLen := Stream.Size; getmem(fRaw, fRawLen); Stream.Read(fRaw^, fRawLen); end; OpenProfileFromRaw(); end; {!! TIEICC.LoadFromFile Declaration procedure LoadFromFile(const FileName: string); Description Loads an ICC from the file. The file should have an .icc extension. !!} procedure TIEICC.LoadFromFile(const FileName: string); var fs: TFileStream; begin fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try LoadFromStream(fs, true); finally fs.free; end; end; {!! TIEICC.Assign Declaration procedure Assign(source: ); Description Copies a profile from source. !!} procedure TIEICC.Assign(source: TIEICC); begin Clear; fRawLen := source.fRawLen; getmem(fRaw, fRawLen); copymemory(fRaw, source.fRaw, fRawLen); OpenProfileFromRaw(); end; procedure TIEICC.OpenProfileFromRaw(); var prof: IE_PROFILE; begin if fUseLCMS then begin {$ifdef IEINCLUDECMS} // use lcms fProfileStream := TIEMemStream.Create(fRaw, fRawLen); fProfile := IEcmsOpenProfileFromFile(fProfileStream, false, false); {$endif} end else begin // use mscms if LoadMSCMS() then begin prof.dwType := IE_PROFILE_MEMBUFFER; prof.pProfileData := fRaw; prof.cbDataSize := fRawLen; fMSProfile := IE_OpenColorProfile(@prof, IE_PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING); end; end; ExtractInfo; end; procedure TIEICC.CloseProfileFromRaw(); begin FreeTransform; // in case it was actived if fUseLCMS then begin {$ifdef IEINCLUDECMS} if fProfile <> nil then IEcmsCloseProfile(fProfile); if fProfileStream <> nil then FreeAndNil(fProfileStream); {$endif} end else try // Use MS CMS if fMSProfile <> 0 then IE_CloseColorProfile(fMSProfile); except // UNEXPECTED ERROR end; fMSProfile := 0; fProfile := nil; fProfileStream := nil; fInputFormat := 0; fOutputFormat := 0; fDestination := nil; fIntent := 0; fFlags := 0; end; function TIEICC.IsTransforming: boolean; begin if fUseLCMS then result := fTransform<>nil else result := fMSTransform<>0; end; {!! TIEICC.FreeTransform Declaration procedure FreeTransform; Description Free memory allocated to perform Transform, or . !!} procedure TIEICC.FreeTransform; begin if fUseLCMS then begin {$ifdef IEINCLUDECMS} if fTransform<>nil then begin IEcmsDeleteTransform(fTransform); fApplied := true; end; {$endif} end else begin // use mscms if fMSTransform<>0 then begin IE_DeleteColorTransform(fMSTransform); fApplied := true; end; end; fMSTransform := 0; fTransform := nil; end; {!! TIEICC.CheckTransform Declaration function CheckTransform(InputFormat: ): boolean; overload; function CheckTransform(InputFormat: integer): boolean; overload; Description Returns true if this color profile accepts the specified color space. See Also - - !!} function TIEICC.CheckTransform(InputFormat: integer): boolean; begin result := CheckTransform(TIEColorSpace(InputFormat)); end; function TIEICC.CheckTransform(InputFormat: TIEColorSpace): boolean; begin if fInputColorSpace = '' then result := true // info not available else case InputFormat of iecmsRGB, iecmsBGR, iecmsRGB48, iecmsRGB48_SE: result := (fInputColorSpace = 'RGB '); iecmsCMYK, iecmsCMYK6: result := (fInputColorSpace = 'CMYK'); iecmsCIELab: result := (fInputColorSpace = 'Lab '); iecmsGray8: result := (fInputColorSpace = 'GRAY'); iecmsYCBCR: result := (fInputColorSpace = 'YCbr'); else result := false; end; end; {!! TIEICC.InitTransform Declaration function InitTransform(Destination: ; InputFormat: integer; OutputFormat: integer; Intent: integer; Flags: integer): boolean; Description Initialize a transform from current profile to the destination profile. You must call after the whole image has been transformed. Returns False if it cannot perform the transformation. InputFormat and OutputFormat : The color format for the input and the output. See below for a list of supported color formats. Intent: The ICC intent to apply. If an appropiate tag for this intent is not found, no error is raised and the intent is reverted to perceptual. INTENT_PERCEPTUAL INTENT_RELATIVE_COLORIMETRIC INTENT_SATURATION INTENT_ABSOLUTE_COLORIMETRIC Flags: This value commands on how to handle the whole process. Some or none of this values can be joined via the 'or' operator. cmsFLAGS_MATRIXINPUT CLUT ignored on input profile, matrix-shaper used instead (for speed, and debugging purposes) cmsFLAGS_MATRIXOUTPUT Same as anterior, but for output profile only. cmsFLAGS_NOTPRECALC By default, lcms smelt luts into a device-link CLUT. This speedup whole transform greatly. If you don't wanna this, and wish every value to be translated to PCS and back to output space, include this flag. cmsFLAGS_NULLTRANFORM Don't transform anyway, only apply pack/unpack routines (usefull to deactivate color correction but keep formatting capabilities) cmsFLAGS_HIGHRESPRECALC Use 48 points instead of 33 for device-link CLUT precalculation. Not needed but for the most extreme cases of mismatch of "impedance" between profiles. cmsFLAGS_LOWRESPRECALC Use lower resolution table. Usefull when memory is a preciated resource. cmsFLAGS_BLACKPOINTCOMPENSATION Use BPC algorithm.
See Also -
!!} function TIEICC.InitTransform(Destination: TIEICC; InputFormat: integer; OutputFormat: integer; Intent: integer; Flags: integer): boolean; var mshprofs: array [0..1] of IE_HPROFILE; msintent: array [0..1] of dword; begin if fUseLCMS then begin {$ifdef IEINCLUDECMS} if (fTransform = nil) or (fInputFormat <> InputFormat) or (fOutputFormat <> OutputFormat) or (fIntent <> Intent) or (fFlags <> Flags) then begin // initialize transform FreeTransform(); // if it was already created fTransform := IEcmsCreateTransform(fProfile, InputFormat, Destination.fProfile, OutputFormat, Intent, Flags); fInputFormat := InputFormat; fOutputFormat := OutputFormat; fIntent := Intent; fFlags := Flags; end; {$endif} end else begin // use mscms if (fMSTransform = 0) or (fInputFormat <> InputFormat) or (fOutputFormat <> OutputFormat) or (fIntent <> Intent) or (fFlags <> Flags) then begin FreeTransform; msintent[0] := IE_INTENT_PERCEPTUAL; msintent[1] := IE_INTENT_PERCEPTUAL; mshprofs[0] := fMSProfile; mshprofs[1] := Destination.fMSProfile; fMSTransform := IE_CreateMultiProfileTransform(@mshprofs[0], 2, @msintent[0], 2, IE_BEST_MODE or IE_USE_RELATIVE_COLORIMETRIC, IE_INDEX_DONT_CARE); fInputFormat := InputFormat; fOutputFormat := OutputFormat; fIntent := Intent; fFlags := Flags; end; end; result := (fTransform <> nil) or (fMSTransform <> 0); end; {!! TIEICC.Transform Declaration function Transform(Destination: ; InputFormat: integer; OutputFormat: integer; Intent: integer; Flags: integer; InputBuffer: pointer; OutputBuffer: pointer; ImageWidth: integer): boolean; Description Transforms a row from current profile to the destination profile. You must call FreeTransform after the whole image has been transformed. Returns False if it cannot perform the transformation. InputFormat and OutputFormat : The color format for the input and the output. See below for a list of supported color formats. Intent: The ICC intent to apply. If an appropiate tag for this intent is not found, no error is raised and the intent is reverted to perceptual. INTENT_PERCEPTUAL INTENT_RELATIVE_COLORIMETRIC INTENT_SATURATION INTENT_ABSOLUTE_COLORIMETRIC Flags: This value commands on how to handle the whole process. Some or none of this values can be joined via the 'or' operator. cmsFLAGS_MATRIXINPUT CLUT ignored on input profile, matrix-shaper used instead (for speed, and debugging purposes) cmsFLAGS_MATRIXOUTPUT Same as anterior, but for output profile only. cmsFLAGS_NOTPRECALC By default, lcms smelt luts into a device-link CLUT. This speedup whole transform greatly. If you don't wanna this, and wish every value to be translated to PCS and back to output space, include this flag. cmsFLAGS_NULLTRANFORM Don't transform anyway, only apply pack/unpack routines (usefull to deactivate color correction but keep formatting capabilities) cmsFLAGS_HIGHRESPRECALC Use 48 points instead of 33 for device-link CLUT precalculation. Not needed but for the most extreme cases of mismatch of "impedance" between profiles. cmsFLAGS_LOWRESPRECALC Use lower resolution table. Usefull when memory is a preciated resource. cmsFLAGS_BLACKPOINTCOMPENSATION Use BPC algorithm.
See Also -
!!} function TIEICC.Transform(Destination: TIEICC; InputFormat: integer; OutputFormat: integer; Intent: integer; Flags: integer; InputBuffer: pointer; OutputBuffer: pointer; ImageWidth: integer): boolean; var i: integer; buf_src, buf_dst: array of TIECMSCOLOR; src, dst: PIECMSCOLOR; pb: pbyte; bgr: PRGB; pw: pword; begin result := InitTransform(Destination, InputFormat, OutputFormat, Intent, Flags); if fUseLCMS then begin {$ifdef IEINCLUDECMS} if fTransform <> nil then begin IEcmsDoTransform(fTransform, InputBuffer, OutputBuffer, ImageWidth); end; {$endif} end else begin // use mscms if fMSTransform <> 0 then begin SetLength(buf_src, ImageWidth); SetLength(buf_dst, ImageWidth); case TIEColorSpace(InputFormat) of iecmsRGB: begin src := @buf_src[0]; pb := InputBuffer; for i := 0 to ImageWidth - 1 do begin src^.rgb.red := pb^ * 257; inc(pb); // r src^.rgb.green := pb^ * 257; inc(pb); // g src^.rgb.blue := pb^ * 257; inc(pb); // b inc(src); end; end; iecmsBGR: begin src := @buf_src[0]; bgr := PRGB(InputBuffer); for i := 0 to ImageWidth - 1 do begin src^.rgb.red := bgr^.r * 257; // r src^.rgb.green := bgr^.g * 257; // g src^.rgb.blue := bgr^.b * 257; // b inc(src); inc(bgr); end; end; iecmsCMYK: begin src := @buf_src[0]; pb := InputBuffer; for i := 0 to ImageWidth - 1 do begin src^.cmyk.cyan := (255 - pb^) * 257; inc(pb); // c src^.cmyk.magenta := (255 - pb^) * 257; inc(pb); // m src^.cmyk.yellow := (255 - pb^) * 257; inc(pb); // y src^.cmyk.black := (255 - pb^) * 257; inc(pb); // k inc(src); end; end; iecmsCMYK6: begin src := @buf_src[0]; pb := InputBuffer; for i := 0 to ImageWidth - 1 do begin src^.cmyk.cyan := pb^ * 257; inc(pb); // c src^.cmyk.magenta := pb^ * 257; inc(pb); // m src^.cmyk.yellow := pb^ * 257; inc(pb); // y src^.cmyk.black := pb^ * 257; inc(pb); // k inc(pb, 2); inc(src); end; end; iecmsCIELab: begin src := @buf_src[0]; pb := InputBuffer; for i := 0 to ImageWidth - 1 do begin src^.Lab.L := pb^ * 257; inc(pb); src^.Lab.a := (127 + pshortint(pb)^) * 257; inc(pb); src^.Lab.b := (127 + pshortint(pb)^) * 257; inc(pb); inc(src); end; end; iecmsGray8: begin src := @buf_src[0]; pb := InputBuffer; for i := 0 to ImageWidth - 1 do begin src^.gray := pb^ * 257; inc(pb); inc(src); end; end; iecmsRGB48: begin src := @buf_src[0]; pw := InputBuffer; for i := 0 to ImageWidth - 1 do begin src^.rgb.red := pw^; inc(pw); // r src^.rgb.green := pw^; inc(pw); // g src^.rgb.blue := pw^; inc(pw); // b inc(src); end; end; iecmsRGB48_SE: begin src := @buf_src[0]; pw := InputBuffer; for i := 0 to ImageWidth - 1 do begin src^.rgb.red := IESwapWord(pw^); inc(pw); // r src^.rgb.green := IESwapWord(pw^); inc(pw); // g src^.rgb.blue := IESwapWord(pw^); inc(pw); // b inc(src); end; end; iecmsYCBCR: begin src := @buf_src[0]; pb := InputBuffer; for i := 0 to ImageWidth - 1 do begin src^.gen3ch.ch1 := pb^ * 257 ; inc(pb); src^.gen3ch.ch2 := pb^ * 257 ; inc(pb); src^.gen3ch.ch3 := pb^ * 257 ; inc(pb); inc(src); end; end; end; IE_TranslateColors(fMSTransform, @buf_src[0], ImageWidth, IE_CS2IF[InputFormat], @buf_dst[0], IE_CS2IF[OutputFormat]); case TIEColorSpace(OutputFormat) of iecmsRGB: begin end; iecmsBGR: begin dst := @buf_dst[0]; pb := OutputBuffer; for i := 0 to ImageWidth - 1 do begin pb^ := dst^.rgb.blue shr 8; inc(pb); // b pb^ := dst^.rgb.green shr 8; inc(pb); // g pb^ := dst^.rgb.red shr 8; inc(pb); // r inc(dst); end; end; iecmsCMYK: begin dst := @buf_dst[0]; pb := OutputBuffer; for i := 0 to ImageWidth - 1 do begin pb^ := 255 - dst^.cmyk.cyan shr 8; inc(pb); // c pb^ := 255 - dst^.cmyk.magenta shr 8; inc(pb); // m pb^ := 255 - dst^.cmyk.yellow shr 8; inc(pb); // y pb^ := 255 - dst^.cmyk.black shr 8; inc(pb); // k inc(dst); end; end; iecmsCMYK6: begin end; iecmsCIELab: begin end; iecmsGray8: begin end; iecmsRGB48: begin end; iecmsRGB48_SE: begin end; end; end; end; end; {!! TIEICC.Apply Declaration function Apply(SourceBitmap: ; SourceFormat: integer; DestinationBitmap: ; DestinationFormat: integer; DestinationProfile: ; Intent: integer; Flags: integer): boolean; Description Transforms a bitmap from current profile to the destination profile. See for the parameter description. You must call after the whole image has been transformed. Returns False if it cannot perform the transformation. See Also - !!} function TIEICC.Apply(SourceBitmap: TIEBaseBitmap; SourceFormat: integer; DestinationBitmap: TIEBaseBitmap; DestinationFormat: integer; DestinationProfile: TIEICC; Intent: integer; Flags: integer): boolean; var y: integer; begin result := false; // make sure sizes match DestinationBitmap.Width := SourceBitmap.Width; DestinationBitmap.Height := SourceBitmap.Height; for y := 0 to SourceBitmap.Height-1 do begin result := Transform(DestinationProfile, SourceFormat, DestinationFormat, Intent, Flags, SourceBitmap.Scanline[y], DestinationBitmap.Scanline[y], SourceBitmap.Width); if not result then exit; end; end; {!! TIEICC.Apply2 Declaration function Apply2(Bitmap: ; SourceFormat: integer; DestinationFormat: integer; DestinationProfile: ; Intent: integer; Flags: integer): boolean; Description Transforms the same bitmap from current profile to the destination profile. See for the parameter description. You must call after the whole image has been transformed. Returns False if it cannot perform the transformation. See Also - !!} function TIEICC.Apply2(Bitmap: TIEBaseBitmap; SourceFormat: integer; DestinationFormat: integer; DestinationProfile: TIEICC; Intent: integer; Flags: integer): boolean; var y: integer; begin result := false; for y := 0 to Bitmap.Height-1 do begin result := Transform(DestinationProfile, SourceFormat, DestinationFormat, Intent, Flags, Bitmap.Scanline[y], Bitmap.Scanline[y], Bitmap.Width); if not result then exit; end; end; {!! TIEICC.ConvertBitmap Declaration function ConvertBitmap(Bitmap: TIEBaseBitmap; DestPixelFormat: ; DestProfile: ): boolean; Description Transforms the same bitmap from current profile to the destination profile. Returns False if it cannot perform the transformation. !!} function TIEICC.ConvertBitmap(Bitmap: TIEBaseBitmap; DestPixelFormat: TIEPixelFormat; DestProfile: TIEICC): boolean; {$ifdef IEINCLUDECMS} const CCTOCMS: array [iecmsRGB..iecmsYCBCR] of integer = (TYPE_RGB_8, TYPE_BGR_8, TYPE_CMYK_8_REV, TYPE_CMYKcm_8, TYPE_Lab_8, TYPE_GRAY_8, TYPE_RGB_16, TYPE_RGB_16_SE, TYPE_YCbCr_8); {$endif} var y: integer; dest: TIEBitmap; SourceFormat, DestinationFormat: TIEColorSpace; begin result := false; case Bitmap.PixelFormat of ie8g: SourceFormat := iecmsGray8; ie24RGB: SourceFormat := iecmsBGR; ieCMYK: SourceFormat := iecmsCMYK; ie48RGB: SourceFormat := iecmsRGB48; ieCIELab: SourceFormat := iecmsCIELab; else exit; end; case DestPixelFormat of ie8g: DestinationFormat := iecmsGray8; ie24RGB: DestinationFormat := iecmsBGR; ieCMYK: DestinationFormat := iecmsCMYK; ie48RGB: DestinationFormat := iecmsRGB48; ieCIELab: DestinationFormat := iecmsCIELab; else exit; end; dest := TIEBitmap.Create(Bitmap.Width, Bitmap.Height, DestPixelFormat); for y := 0 to Bitmap.Height - 1 do {$ifdef IEINCLUDECMS} Transform(DestProfile, CCTOCMS[SourceFormat], CCTOCMS[DestinationFormat], INTENT_PERCEPTUAL, 0, Bitmap.ScanLine[y], dest.Scanline[y], Bitmap.Width); {$else} Transform(DestProfile, integer(SourceFormat), integer(DestinationFormat), 0, 0, Bitmap.ScanLine[y], dest.Scanline[y], Bitmap.Width); {$endif} FreeTransform; Bitmap.AssignImage( dest ); dest.Free; result := true; end; {!! TIEICC.Assign_sRGBProfile Declaration procedure Assign_sRGBProfile; Description Loads the pre-defined sRGB profile. !!} procedure TIEICC.Assign_sRGBProfile; const sRGBColorSpaceProfileLen = 3144; sRGBColorSpaceProfile: array [0..sRGBColorSpaceProfileLen - 1] of byte = ( $00, $00, $0C, $48, $4C, $69, $6E, $6F, $02, $10, $00, $00, $6D, $6E, $74, $72, $52, $47, $42, $20, $58, $59, $5A, $20, $07, $CE, $00, $02, $00, $09, $00, $06, $00, $31, $00, $00, $61, $63, $73, $70, $4D, $53, $46, $54, $00, $00, $00, $00, $49, $45, $43, $20, $73, $52, $47, $42, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $F6, $D6, $00, $01, $00, $00, $00, $00, $D3, $2D, $48, $50, $20, $20, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $11, $63, $70, $72, $74, $00, $00, $01, $50, $00, $00, $00, $33, $64, $65, $73, $63, $00, $00, $01, $84, $00, $00, $00, $6C, $77, $74, $70, $74, $00, $00, $01, $F0, $00, $00, $00, $14, $62, $6B, $70, $74, $00, $00, $02, $04, $00, $00, $00, $14, $72, $58, $59, $5A, $00, $00, $02, $18, $00, $00, $00, $14, $67, $58, $59, $5A, $00, $00, $02, $2C, $00, $00, $00, $14, $62, $58, $59, $5A, $00, $00, $02, $40, $00, $00, $00, $14, $64, $6D, $6E, $64, $00, $00, $02, $54, $00, $00, $00, $70, $64, $6D, $64, $64, $00, $00, $02, $C4, $00, $00, $00, $88, $76, $75, $65, $64, $00, $00, $03, $4C, $00, $00, $00, $86, $76, $69, $65, $77, $00, $00, $03, $D4, $00, $00, $00, $24, $6C, $75, $6D, $69, $00, $00, $03, $F8, $00, $00, $00, $14, $6D, $65, $61, $73, $00, $00, $04, $0C, $00, $00, $00, $24, $74, $65, $63, $68, $00, $00, $04, $30, $00, $00, $00, $0C, $72, $54, $52, $43, $00, $00, $04, $3C, $00, $00, $08, $0C, $67, $54, $52, $43, $00, $00, $04, $3C, $00, $00, $08, $0C, $62, $54, $52, $43, $00, $00, $04, $3C, $00, $00, $08, $0C, $74, $65, $78, $74, $00, $00, $00, $00, $43, $6F, $70, $79, $72, $69, $67, $68, $74, $20, $28, $63, $29, $20, $31, $39, $39, $38, $20, $48, $65, $77, $6C, $65, $74, $74, $2D, $50, $61, $63, $6B, $61, $72, $64, $20, $43, $6F, $6D, $70, $61, $6E, $79, $00, $00, $64, $65, $73, $63, $00, $00, $00, $00, $00, $00, $00, $12, $73, $52, $47, $42, $20, $49, $45, $43, $36, $31, $39, $36, $36, $2D, $32, $2E, $31, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $12, $73, $52, $47, $42, $20, $49, $45, $43, $36, $31, $39, $36, $36, $2D, $32, $2E, $31, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $58, $59, $5A, $20, $00, $00, $00, $00, $00, $00, $F3, $51, $00, $01, $00, $00, $00, $01, $16, $CC, $58, $59, $5A, $20, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $58, $59, $5A, $20, $00, $00, $00, $00, $00, $00, $6F, $A2, $00, $00, $38, $F5, $00, $00, $03, $90, $58, $59, $5A, $20, $00, $00, $00, $00, $00, $00, $62, $99, $00, $00, $B7, $85, $00, $00, $18, $DA, $58, $59, $5A, $20, $00, $00, $00, $00, $00, $00, $24, $A0, $00, $00, $0F, $84, $00, $00, $B6, $CF, $64, $65, $73, $63, $00, $00, $00, $00, $00, $00, $00, $16, $49, $45, $43, $20, $68, $74, $74, $70, $3A, $2F, $2F, $77, $77, $77, $2E, $69, $65, $63, $2E, $63, $68, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $16, $49, $45, $43, $20, $68, $74, $74, $70, $3A, $2F, $2F, $77, $77, $77, $2E, $69, $65, $63, $2E, $63, $68, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $64, $65, $73, $63, $00, $00, $00, $00, $00, $00, $00, $2E, $49, $45, $43, $20, $36, $31, $39, $36, $36, $2D, $32, $2E, $31, $20, $44, $65, $66, $61, $75, $6C, $74, $20, $52, $47, $42, $20, $63, $6F, $6C, $6F, $75, $72, $20, $73, $70, $61, $63, $65, $20, $2D, $20, $73, $52, $47, $42, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $2E, $49, $45, $43, $20, $36, $31, $39, $36, $36, $2D, $32, $2E, $31, $20, $44, $65, $66, $61, $75, $6C, $74, $20, $52, $47, $42, $20, $63, $6F, $6C, $6F, $75, $72, $20, $73, $70, $61, $63, $65, $20, $2D, $20, $73, $52, $47, $42, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $64, $65, $73, $63, $00, $00, $00, $00, $00, $00, $00, $2C, $52, $65, $66, $65, $72, $65, $6E, $63, $65, $20, $56, $69, $65, $77, $69, $6E, $67, $20, $43, $6F, $6E, $64, $69, $74, $69, $6F, $6E, $20, $69, $6E, $20, $49, $45, $43, $36, $31, $39, $36, $36, $2D, $32, $2E, $31, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $2C, $52, $65, $66, $65, $72, $65, $6E, $63, $65, $20, $56, $69, $65, $77, $69, $6E, $67, $20, $43, $6F, $6E, $64, $69, $74, $69, $6F, $6E, $20, $69, $6E, $20, $49, $45, $43, $36, $31, $39, $36, $36, $2D, $32, $2E, $31, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $76, $69, $65, $77, $00, $00, $00, $00, $00, $13, $A4, $FE, $00, $14, $5F, $2E, $00, $10, $CF, $14, $00, $03, $ED, $CC, $00, $04, $13, $0B, $00, $03, $5C, $9E, $00, $00, $00, $01, $58, $59, $5A, $20, $00, $00, $00, $00, $00, $4C, $09, $56, $00, $50, $00, $00, $00, $57, $1F, $E7, $6D, $65, $61, $73, $00, $00, $00, $00, $00, $00, $00, $01, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $02, $8F, $00, $00, $00, $02, $73, $69, $67, $20, $00, $00, $00, $00, $43, $52, $54, $20, $63, $75, $72, $76, $00, $00, $00, $00, $00, $00, $04, $00, $00, $00, $00, $05, $00, $0A, $00, $0F, $00, $14, $00, $19, $00, $1E, $00, $23, $00, $28, $00, $2D, $00, $32, $00, $37, $00, $3B, $00, $40, $00, $45, $00, $4A, $00, $4F, $00, $54, $00, $59, $00, $5E, $00, $63, $00, $68, $00, $6D, $00, $72, $00, $77, $00, $7C, $00, $81, $00, $86, $00, $8B, $00, $90, $00, $95, $00, $9A, $00, $9F, $00, $A4, $00, $A9, $00, $AE, $00, $B2, $00, $B7, $00, $BC, $00, $C1, $00, $C6, $00, $CB, $00, $D0, $00, $D5, $00, $DB, $00, $E0, $00, $E5, $00, $EB, $00, $F0, $00, $F6, $00, $FB, $01, $01, $01, $07, $01, $0D, $01, $13, $01, $19, $01, $1F, $01, $25, $01, $2B, $01, $32, $01, $38, $01, $3E, $01, $45, $01, $4C, $01, $52, $01, $59, $01, $60, $01, $67, $01, $6E, $01, $75, $01, $7C, $01, $83, $01, $8B, $01, $92, $01, $9A, $01, $A1, $01, $A9, $01, $B1, $01, $B9, $01, $C1, $01, $C9, $01, $D1, $01, $D9, $01, $E1, $01, $E9, $01, $F2, $01, $FA, $02, $03, $02, $0C, $02, $14, $02, $1D, $02, $26, $02, $2F, $02, $38, $02, $41, $02, $4B, $02, $54, $02, $5D, $02, $67, $02, $71, $02, $7A, $02, $84, $02, $8E, $02, $98, $02, $A2, $02, $AC, $02, $B6, $02, $C1, $02, $CB, $02, $D5, $02, $E0, $02, $EB, $02, $F5, $03, $00, $03, $0B, $03, $16, $03, $21, $03, $2D, $03, $38, $03, $43, $03, $4F, $03, $5A, $03, $66, $03, $72, $03, $7E, $03, $8A, $03, $96, $03, $A2, $03, $AE, $03, $BA, $03, $C7, $03, $D3, $03, $E0, $03, $EC, $03, $F9, $04, $06, $04, $13, $04, $20, $04, $2D, $04, $3B, $04, $48, $04, $55, $04, $63, $04, $71, $04, $7E, $04, $8C, $04, $9A, $04, $A8, $04, $B6, $04, $C4, $04, $D3, $04, $E1, $04, $F0, $04, $FE, $05, $0D, $05, $1C, $05, $2B, $05, $3A, $05, $49, $05, $58, $05, $67, $05, $77, $05, $86, $05, $96, $05, $A6, $05, $B5, $05, $C5, $05, $D5, $05, $E5, $05, $F6, $06, $06, $06, $16, $06, $27, $06, $37, $06, $48, $06, $59, $06, $6A, $06, $7B, $06, $8C, $06, $9D, $06, $AF, $06, $C0, $06, $D1, $06, $E3, $06, $F5, $07, $07, $07, $19, $07, $2B, $07, $3D, $07, $4F, $07, $61, $07, $74, $07, $86, $07, $99, $07, $AC, $07, $BF, $07, $D2, $07, $E5, $07, $F8, $08, $0B, $08, $1F, $08, $32, $08, $46, $08, $5A, $08, $6E, $08, $82, $08, $96, $08, $AA, $08, $BE, $08, $D2, $08, $E7, $08, $FB, $09, $10, $09, $25, $09, $3A, $09, $4F, $09, $64, $09, $79, $09, $8F, $09, $A4, $09, $BA, $09, $CF, $09, $E5, $09, $FB, $0A, $11, $0A, $27, $0A, $3D, $0A, $54, $0A, $6A, $0A, $81, $0A, $98, $0A, $AE, $0A, $C5, $0A, $DC, $0A, $F3, $0B, $0B, $0B, $22, $0B, $39, $0B, $51, $0B, $69, $0B, $80, $0B, $98, $0B, $B0, $0B, $C8, $0B, $E1, $0B, $F9, $0C, $12, $0C, $2A, $0C, $43, $0C, $5C, $0C, $75, $0C, $8E, $0C, $A7, $0C, $C0, $0C, $D9, $0C, $F3, $0D, $0D, $0D, $26, $0D, $40, $0D, $5A, $0D, $74, $0D, $8E, $0D, $A9, $0D, $C3, $0D, $DE, $0D, $F8, $0E, $13, $0E, $2E, $0E, $49, $0E, $64, $0E, $7F, $0E, $9B, $0E, $B6, $0E, $D2, $0E, $EE, $0F, $09, $0F, $25, $0F, $41, $0F, $5E, $0F, $7A, $0F, $96, $0F, $B3, $0F, $CF, $0F, $EC, $10, $09, $10, $26, $10, $43, $10, $61, $10, $7E, $10, $9B, $10, $B9, $10, $D7, $10, $F5, $11, $13, $11, $31, $11, $4F, $11, $6D, $11, $8C, $11, $AA, $11, $C9, $11, $E8, $12, $07, $12, $26, $12, $45, $12, $64, $12, $84, $12, $A3, $12, $C3, $12, $E3, $13, $03, $13, $23, $13, $43, $13, $63, $13, $83, $13, $A4, $13, $C5, $13, $E5, $14, $06, $14, $27, $14, $49, $14, $6A, $14, $8B, $14, $AD, $14, $CE, $14, $F0, $15, $12, $15, $34, $15, $56, $15, $78, $15, $9B, $15, $BD, $15, $E0, $16, $03, $16, $26, $16, $49, $16, $6C, $16, $8F, $16, $B2, $16, $D6, $16, $FA, $17, $1D, $17, $41, $17, $65, $17, $89, $17, $AE, $17, $D2, $17, $F7, $18, $1B, $18, $40, $18, $65, $18, $8A, $18, $AF, $18, $D5, $18, $FA, $19, $20, $19, $45, $19, $6B, $19, $91, $19, $B7, $19, $DD, $1A, $04, $1A, $2A, $1A, $51, $1A, $77, $1A, $9E, $1A, $C5, $1A, $EC, $1B, $14, $1B, $3B, $1B, $63, $1B, $8A, $1B, $B2, $1B, $DA, $1C, $02, $1C, $2A, $1C, $52, $1C, $7B, $1C, $A3, $1C, $CC, $1C, $F5, $1D, $1E, $1D, $47, $1D, $70, $1D, $99, $1D, $C3, $1D, $EC, $1E, $16, $1E, $40, $1E, $6A, $1E, $94, $1E, $BE, $1E, $E9, $1F, $13, $1F, $3E, $1F, $69, $1F, $94, $1F, $BF, $1F, $EA, $20, $15, $20, $41, $20, $6C, $20, $98, $20, $C4, $20, $F0, $21, $1C, $21, $48, $21, $75, $21, $A1, $21, $CE, $21, $FB, $22, $27, $22, $55, $22, $82, $22, $AF, $22, $DD, $23, $0A, $23, $38, $23, $66, $23, $94, $23, $C2, $23, $F0, $24, $1F, $24, $4D, $24, $7C, $24, $AB, $24, $DA, $25, $09, $25, $38, $25, $68, $25, $97, $25, $C7, $25, $F7, $26, $27, $26, $57, $26, $87, $26, $B7, $26, $E8, $27, $18, $27, $49, $27, $7A, $27, $AB, $27, $DC, $28, $0D, $28, $3F, $28, $71, $28, $A2, $28, $D4, $29, $06, $29, $38, $29, $6B, $29, $9D, $29, $D0, $2A, $02, $2A, $35, $2A, $68, $2A, $9B, $2A, $CF, $2B, $02, $2B, $36, $2B, $69, $2B, $9D, $2B, $D1, $2C, $05, $2C, $39, $2C, $6E, $2C, $A2, $2C, $D7, $2D, $0C, $2D, $41, $2D, $76, $2D, $AB, $2D, $E1, $2E, $16, $2E, $4C, $2E, $82, $2E, $B7, $2E, $EE, $2F, $24, $2F, $5A, $2F, $91, $2F, $C7, $2F, $FE, $30, $35, $30, $6C, $30, $A4, $30, $DB, $31, $12, $31, $4A, $31, $82, $31, $BA, $31, $F2, $32, $2A, $32, $63, $32, $9B, $32, $D4, $33, $0D, $33, $46, $33, $7F, $33, $B8, $33, $F1, $34, $2B, $34, $65, $34, $9E, $34, $D8, $35, $13, $35, $4D, $35, $87, $35, $C2, $35, $FD, $36, $37, $36, $72, $36, $AE, $36, $E9, $37, $24, $37, $60, $37, $9C, $37, $D7, $38, $14, $38, $50, $38, $8C, $38, $C8, $39, $05, $39, $42, $39, $7F, $39, $BC, $39, $F9, $3A, $36, $3A, $74, $3A, $B2, $3A, $EF, $3B, $2D, $3B, $6B, $3B, $AA, $3B, $E8, $3C, $27, $3C, $65, $3C, $A4, $3C, $E3, $3D, $22, $3D, $61, $3D, $A1, $3D, $E0, $3E, $20, $3E, $60, $3E, $A0, $3E, $E0, $3F, $21, $3F, $61, $3F, $A2, $3F, $E2, $40, $23, $40, $64, $40, $A6, $40, $E7, $41, $29, $41, $6A, $41, $AC, $41, $EE, $42, $30, $42, $72, $42, $B5, $42, $F7, $43, $3A, $43, $7D, $43, $C0, $44, $03, $44, $47, $44, $8A, $44, $CE, $45, $12, $45, $55, $45, $9A, $45, $DE, $46, $22, $46, $67, $46, $AB, $46, $F0, $47, $35, $47, $7B, $47, $C0, $48, $05, $48, $4B, $48, $91, $48, $D7, $49, $1D, $49, $63, $49, $A9, $49, $F0, $4A, $37, $4A, $7D, $4A, $C4, $4B, $0C, $4B, $53, $4B, $9A, $4B, $E2, $4C, $2A, $4C, $72, $4C, $BA, $4D, $02, $4D, $4A, $4D, $93, $4D, $DC, $4E, $25, $4E, $6E, $4E, $B7, $4F, $00, $4F, $49, $4F, $93, $4F, $DD, $50, $27, $50, $71, $50, $BB, $51, $06, $51, $50, $51, $9B, $51, $E6, $52, $31, $52, $7C, $52, $C7, $53, $13, $53, $5F, $53, $AA, $53, $F6, $54, $42, $54, $8F, $54, $DB, $55, $28, $55, $75, $55, $C2, $56, $0F, $56, $5C, $56, $A9, $56, $F7, $57, $44, $57, $92, $57, $E0, $58, $2F, $58, $7D, $58, $CB, $59, $1A, $59, $69, $59, $B8, $5A, $07, $5A, $56, $5A, $A6, $5A, $F5, $5B, $45, $5B, $95, $5B, $E5, $5C, $35, $5C, $86, $5C, $D6, $5D, $27, $5D, $78, $5D, $C9, $5E, $1A, $5E, $6C, $5E, $BD, $5F, $0F, $5F, $61, $5F, $B3, $60, $05, $60, $57, $60, $AA, $60, $FC, $61, $4F, $61, $A2, $61, $F5, $62, $49, $62, $9C, $62, $F0, $63, $43, $63, $97, $63, $EB, $64, $40, $64, $94, $64, $E9, $65, $3D, $65, $92, $65, $E7, $66, $3D, $66, $92, $66, $E8, $67, $3D, $67, $93, $67, $E9, $68, $3F, $68, $96, $68, $EC, $69, $43, $69, $9A, $69, $F1, $6A, $48, $6A, $9F, $6A, $F7, $6B, $4F, $6B, $A7, $6B, $FF, $6C, $57, $6C, $AF, $6D, $08, $6D, $60, $6D, $B9, $6E, $12, $6E, $6B, $6E, $C4, $6F, $1E, $6F, $78, $6F, $D1, $70, $2B, $70, $86, $70, $E0, $71, $3A, $71, $95, $71, $F0, $72, $4B, $72, $A6, $73, $01, $73, $5D, $73, $B8, $74, $14, $74, $70, $74, $CC, $75, $28, $75, $85, $75, $E1, $76, $3E, $76, $9B, $76, $F8, $77, $56, $77, $B3, $78, $11, $78, $6E, $78, $CC, $79, $2A, $79, $89, $79, $E7, $7A, $46, $7A, $A5, $7B, $04, $7B, $63, $7B, $C2, $7C, $21, $7C, $81, $7C, $E1, $7D, $41, $7D, $A1, $7E, $01, $7E, $62, $7E, $C2, $7F, $23, $7F, $84, $7F, $E5, $80, $47, $80, $A8, $81, $0A, $81, $6B, $81, $CD, $82, $30, $82, $92, $82, $F4, $83, $57, $83, $BA, $84, $1D, $84, $80, $84, $E3, $85, $47, $85, $AB, $86, $0E, $86, $72, $86, $D7, $87, $3B, $87, $9F, $88, $04, $88, $69, $88, $CE, $89, $33, $89, $99, $89, $FE, $8A, $64, $8A, $CA, $8B, $30, $8B, $96, $8B, $FC, $8C, $63, $8C, $CA, $8D, $31, $8D, $98, $8D, $FF, $8E, $66, $8E, $CE, $8F, $36, $8F, $9E, $90, $06, $90, $6E, $90, $D6, $91, $3F, $91, $A8, $92, $11, $92, $7A, $92, $E3, $93, $4D, $93, $B6, $94, $20, $94, $8A, $94, $F4, $95, $5F, $95, $C9, $96, $34, $96, $9F, $97, $0A, $97, $75, $97, $E0, $98, $4C, $98, $B8, $99, $24, $99, $90, $99, $FC, $9A, $68, $9A, $D5, $9B, $42, $9B, $AF, $9C, $1C, $9C, $89, $9C, $F7, $9D, $64, $9D, $D2, $9E, $40, $9E, $AE, $9F, $1D, $9F, $8B, $9F, $FA, $A0, $69, $A0, $D8, $A1, $47, $A1, $B6, $A2, $26, $A2, $96, $A3, $06, $A3, $76, $A3, $E6, $A4, $56, $A4, $C7, $A5, $38, $A5, $A9, $A6, $1A, $A6, $8B, $A6, $FD, $A7, $6E, $A7, $E0, $A8, $52, $A8, $C4, $A9, $37, $A9, $A9, $AA, $1C, $AA, $8F, $AB, $02, $AB, $75, $AB, $E9, $AC, $5C, $AC, $D0, $AD, $44, $AD, $B8, $AE, $2D, $AE, $A1, $AF, $16, $AF, $8B, $B0, $00, $B0, $75, $B0, $EA, $B1, $60, $B1, $D6, $B2, $4B, $B2, $C2, $B3, $38, $B3, $AE, $B4, $25, $B4, $9C, $B5, $13, $B5, $8A, $B6, $01, $B6, $79, $B6, $F0, $B7, $68, $B7, $E0, $B8, $59, $B8, $D1, $B9, $4A, $B9, $C2, $BA, $3B, $BA, $B5, $BB, $2E, $BB, $A7, $BC, $21, $BC, $9B, $BD, $15, $BD, $8F, $BE, $0A, $BE, $84, $BE, $FF, $BF, $7A, $BF, $F5, $C0, $70, $C0, $EC, $C1, $67, $C1, $E3, $C2, $5F, $C2, $DB, $C3, $58, $C3, $D4, $C4, $51, $C4, $CE, $C5, $4B, $C5, $C8, $C6, $46, $C6, $C3, $C7, $41, $C7, $BF, $C8, $3D, $C8, $BC, $C9, $3A, $C9, $B9, $CA, $38, $CA, $B7, $CB, $36, $CB, $B6, $CC, $35, $CC, $B5, $CD, $35, $CD, $B5, $CE, $36, $CE, $B6, $CF, $37, $CF, $B8, $D0, $39, $D0, $BA, $D1, $3C, $D1, $BE, $D2, $3F, $D2, $C1, $D3, $44, $D3, $C6, $D4, $49, $D4, $CB, $D5, $4E, $D5, $D1, $D6, $55, $D6, $D8, $D7, $5C, $D7, $E0, $D8, $64, $D8, $E8, $D9, $6C, $D9, $F1, $DA, $76, $DA, $FB, $DB, $80, $DC, $05, $DC, $8A, $DD, $10, $DD, $96, $DE, $1C, $DE, $A2, $DF, $29, $DF, $AF, $E0, $36, $E0, $BD, $E1, $44, $E1, $CC, $E2, $53, $E2, $DB, $E3, $63, $E3, $EB, $E4, $73, $E4, $FC, $E5, $84, $E6, $0D, $E6, $96, $E7, $1F, $E7, $A9, $E8, $32, $E8, $BC, $E9, $46, $E9, $D0, $EA, $5B, $EA, $E5, $EB, $70, $EB, $FB, $EC, $86, $ED, $11, $ED, $9C, $EE, $28, $EE, $B4, $EF, $40, $EF, $CC, $F0, $58, $F0, $E5, $F1, $72, $F1, $FF, $F2, $8C, $F3, $19, $F3, $A7, $F4, $34, $F4, $C2, $F5, $50, $F5, $DE, $F6, $6D, $F6, $FB, $F7, $8A, $F8, $19, $F8, $A8, $F9, $38, $F9, $C7, $FA, $57, $FA, $E7, $FB, $77, $FC, $07, $FC, $98, $FD, $29, $FD, $BA, $FE, $4B, $FE, $DC, $FF, $6D, $FF, $FF); begin Clear; if fUseLCMS then begin {$ifdef IEINCLUDECMS} fProfile := IEcmsCreate_sRGBProfile; {$endif} end else begin // use mscms, reading (embedded) system file 'sRGB Color Space Profile.icm' LoadFromBuffer(@sRGBColorSpaceProfile[0], sRGBColorSpaceProfileLen); end; end; {!! TIEICC.Assign_AdobeRGB1998 Declaration procedure Assign_AdobeRGB1998(); Description Loads the pre-defined AdobeRGB1998 profile. !!} procedure TIEICC.Assign_AdobeRGB1998(); const AdobeRGB1998Len = 560; AdobeRGB1998: array [0..AdobeRGB1998Len - 1] of byte = ( $00, $00, $02, $30, $41, $44, $42, $45, $02, $10, $00, $00, $6D, $6E, $74, $72, $52, $47, $42, $20, $58, $59, $5A, $20, $07, $D0, $00, $08, $00, $0B, $00, $13, $00, $33, $00, $3B, $61, $63, $73, $70, $41, $50, $50, $4C, $00, $00, $00, $00, $6E, $6F, $6E, $65, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $F6, $D6, $00, $01, $00, $00, $00, $00, $D3, $2D, $41, $44, $42, $45, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $0A, $63, $70, $72, $74, $00, $00, $00, $FC, $00, $00, $00, $32, $64, $65, $73, $63, $00, $00, $01, $30, $00, $00, $00, $6B, $77, $74, $70, $74, $00, $00, $01, $9C, $00, $00, $00, $14, $62, $6B, $70, $74, $00, $00, $01, $B0, $00, $00, $00, $14, $72, $54, $52, $43, $00, $00, $01, $C4, $00, $00, $00, $0E, $67, $54, $52, $43, $00, $00, $01, $D4, $00, $00, $00, $0E, $62, $54, $52, $43, $00, $00, $01, $E4, $00, $00, $00, $0E, $72, $58, $59, $5A, $00, $00, $01, $F4, $00, $00, $00, $14, $67, $58, $59, $5A, $00, $00, $02, $08, $00, $00, $00, $14, $62, $58, $59, $5A, $00, $00, $02, $1C, $00, $00, $00, $14, $74, $65, $78, $74, $00, $00, $00, $00, $43, $6F, $70, $79, $72, $69, $67, $68, $74, $20, $32, $30, $30, $30, $20, $41, $64, $6F, $62, $65, $20, $53, $79, $73, $74, $65, $6D, $73, $20, $49, $6E, $63, $6F, $72, $70, $6F, $72, $61, $74, $65, $64, $00, $00, $00, $64, $65, $73, $63, $00, $00, $00, $00, $00, $00, $00, $11, $41, $64, $6F, $62, $65, $20, $52, $47, $42, $20, $28, $31, $39, $39, $38, $29, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $58, $59, $5A, $20, $00, $00, $00, $00, $00, $00, $F3, $51, $00, $01, $00, $00, $00, $01, $16, $CC, $58, $59, $5A, $20, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $63, $75, $72, $76, $00, $00, $00, $00, $00, $00, $00, $01, $02, $33, $00, $00, $63, $75, $72, $76, $00, $00, $00, $00, $00, $00, $00, $01, $02, $33, $00, $00, $63, $75, $72, $76, $00, $00, $00, $00, $00, $00, $00, $01, $02, $33, $00, $00, $58, $59, $5A, $20, $00, $00, $00, $00, $00, $00, $9C, $18, $00, $00, $4F, $A5, $00, $00, $04, $FC, $58, $59, $5A, $20, $00, $00, $00, $00, $00, $00, $34, $8D, $00, $00, $A0, $2C, $00, $00, $0F, $95, $58, $59, $5A, $20, $00, $00, $00, $00, $00, $00, $26, $31, $00, $00, $10, $2F, $00, $00, $BE, $9C); begin LoadFromBuffer(@AdobeRGB1998[0], AdobeRGB1998Len); end; {!! TIEICC.Assign_CMYKProfile Declaration procedure Assign_CMYKProfile(); Description Loads the pre-defined CMYK profile, based on public domain 'Fogra27L CMYK Coated Press' color profile. !!} procedure TIEICC.Assign_CMYKProfile(); {$IFDEF IEINCLUDEZLIB} var buf: Pointer; buflen: Integer; begin ZDecompress(@IECMYKPROFILE[0], length(IECMYKPROFILE) * 8, buf, buflen, 118188); LoadFromBuffer(buf, buflen); freemem(buf); end; {$ELSE} begin end; {$ENDIF} {!! TIEICC.Assign_LabProfile Declaration procedure Assign_LabProfile(WhitePoint_x, WhitePoint_y, WhitePoint_Y_: double); Description Creates a new Lab profile based on specified white points. Note: Available only when ImageEn is compiled with IEINCLUDECMS defined in ie.inc. !!} procedure TIEICC.Assign_LabProfile(WhitePoint_x, WhitePoint_y, WhitePoint_Y_: double); begin Clear; if fUseLCMS then begin {$ifdef IEINCLUDECMS} fProfile := IEcmsCreateLabProfile( WhitePoint_x, WhitePoint_y, WhitePoint_Y_ ); {$endif} end; end; {!! TIEICC.Assign_LabProfileFromTemp Declaration procedure Assign_LabProfileFromTemp(TempK: integer); Description Creates a new Lab color profile based on specified temperature. Note: Available only when ImageEn is compiled with IEINCLUDECMS defined in ie.inc. !!} procedure TIEICC.Assign_LabProfileFromTemp(TempK: integer); {$ifdef IEINCLUDECMS} var WhitePoint_x, WhitePoint_y, WhitePoint_Y_: double; {$endif} begin Clear; if fUseLCMS then begin {$ifdef IEINCLUDECMS} IEcmsWhitePointFromTemp(TempK, WhitePoint_x, WhitePoint_y, WhitePoint_Y_); fProfile := IEcmsCreateLabProfile( WhitePoint_x, WhitePoint_y, WhitePoint_Y_ ); {$endif} end; end; {!! TIEICC.Assign_LabProfileD50 Declaration procedure Assign_LabProfileD50(); Description Creates a new Lab D59 color profile. Note: Available only when ImageEn is compiled with IEINCLUDECMS defined in ie.inc. !!} procedure TIEICC.Assign_LabProfileD50(); begin Clear; if fUseLCMS then begin {$ifdef IEINCLUDECMS} fProfile := IEcmsCreateLabProfileD50; {$endif} end; end; {!! TIEICC.Assign_XYZProfile Declaration procedure Assign_XYZProfile(); Description Creates a XYZ color profile. Note: Available only when ImageEn is compiled with IEINCLUDECMS defined in ie.inc. !!} procedure TIEICC.Assign_XYZProfile(); begin Clear; if fUseLCMS then begin {$ifdef IEINCLUDECMS} fProfile := IEcmsCreateXYZProfile; {$endif} end; end; // parses the raw profile to extract info procedure TIEICC.ExtractInfo(); var p: pbyte; tagCount, i: integer; tagSign: array [0..3] of AnsiChar; tagOffset: integer; tagSize: integer; procedure ParseTag(); var tp: pbyte; begin tp := fRaw; inc(tp, tagOffset); if (tagSign = 'cprt') and (tagSize < 1000) then begin inc(tp, 8); if IEStrLen(PAnsiChar(tp)) < 1000 then fCopyright := PAnsiChar(tp); end else if (tagSign = 'desc') and (tagSize < 1000) then begin inc(tp, 12); if IEStrLen(PAnsiChar(tp)) < 1000 then fDescription := PAnsiChar(tp); end; end; begin fCopyright := ''; fDescription := ''; fInputColorSpace := ''; fOutputColorSpace := ''; if (fRaw <> nil) and (fRawLen > 128) then begin p := pbyte(fRaw); // read color space from header and bypass the rest inc(p, 16); Move(p^, tagSign[0], 4); fInputColorSpace := AnsiString(tagSign); inc(p, 4); Move(p^, tagSign[0], 4); fOutputColorSpace := AnsiString(tagSign); inc(p, 128 - 16 - 4); // tag count tagCount := IESwapDWord(pinteger(p)^); inc(p, 4); if (tagCount > 1000) or (tagCount < 0) then exit; // read tags for i := 0 to tagCount - 1 do begin Move(p^, tagSign[0], 4); inc(p, 4); tagOffset := IESwapDWord(pinteger(p)^); inc(p, 4); tagSize := IESwapDWord(pinteger(p)^); inc(p, 4); if (tagOffset > fRawLen) or (tagOffset < 0) then exit; if (tagSize > fRawLen) or (tagSize < 0) then exit; ParseTag(); end; end; end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function IEIFI(cond: boolean; val1, val2: integer): integer; begin if cond then result := val1 else result := val2; end; function IEIFD(cond: boolean; val1, val2: double): double; begin if cond then result := val1 else result := val2; end; function IEIFB(cond: boolean; val1, val2: TIEBitmap): TIEBitmap; begin if cond then result := val1 else result := val2; end; procedure IEAdjustEXIFOrientation(Bitmap: TIEBitmap; Orientation: integer); begin if (Orientation <> 1) then begin case Orientation of 2: // 0th row = top of the image, 0th column = right-hand side. begin _FlipEx(Bitmap, fdHorizontal); end; 3: // 0th row = bottom of the image, 0th column = right-hand side. begin _FlipEx(Bitmap, fdVertical); _FlipEx(Bitmap, fdHorizontal); end; 4: // 0th row = bottom of the image, 0th column = left-hand side. begin _FlipEx(Bitmap, fdVertical); end; 5: // 0th row = left-hand side of the image, 0th column = visual top. begin _RotateEx(Bitmap, 90, false, creatergb(0, 0, 0), nil, nil); _FlipEx(Bitmap, fdHorizontal); end; 6: // 0th row = right-hand side of the image, 0th column = visual top. begin _RotateEx(Bitmap, -90, false, creatergb(0, 0, 0), nil, nil); end; 7: // 0th row = right-hand side of the image, 0th column = visual bottom. begin _RotateEx(Bitmap, -90, false, creatergb(0, 0, 0), nil, nil); _FlipEx(Bitmap, fdHorizontal); end; 8: // 0th row = left-hand side of the image, 0th column = visual bottom. begin _RotateEx(Bitmap, 90, false, creatergb(0, 0, 0), nil, nil); end; end; end; end; // swap word if sc=true function IECSwapWord(i: word; sc: boolean): word; begin if sc then result := hibyte(i) or (lobyte(i) shl 8) else result := i; end; // swap dword if sc=true function IECSwapDWord(i: integer; sc: boolean): integer; begin if sc then begin {$ifdef IEUSEASM} asm mov EAX,i bswap EAX mov @result,EAX end; {$else} PByteArray(@result)[0] := PByteArray(@i)[3]; PByteArray(@result)[1] := PByteArray(@i)[2]; PByteArray(@result)[2] := PByteArray(@i)[1]; PByteArray(@result)[3] := PByteArray(@i)[0]; {$endif} end else result := i; end; // swap int64 if sc=true function IECSwapInt64(i: int64; sc: boolean): int64; begin if sc then begin PByteArray(@result)[0] := PByteArray(@i)[7]; PByteArray(@result)[1] := PByteArray(@i)[6]; PByteArray(@result)[2] := PByteArray(@i)[5]; PByteArray(@result)[3] := PByteArray(@i)[4]; PByteArray(@result)[4] := PByteArray(@i)[3]; PByteArray(@result)[5] := PByteArray(@i)[2]; PByteArray(@result)[6] := PByteArray(@i)[1]; PByteArray(@result)[7] := PByteArray(@i)[0]; end else result := i; end; ///////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////// // IEStreamXXXX functions function IEStreamReadWord(Stream: TStream; bigEndian: boolean): word; begin Stream.Read(result, sizeof(word)); result := IECSwapWord(result, bigEndian); end; function IEStreamReadDWord(Stream: TStream; bigEndian: boolean): dword; begin Stream.Read(result, sizeof(dword)); result := IECSwapDWord(result, bigEndian); end; function IEStreamReadInt64(Stream: TStream; bigEndian: boolean): int64; begin Stream.Read(result, sizeof(int64)); result := IECSwapInt64(result, bigEndian); end; // returns new stream position function IEStreamWordAlign(Stream: TStream; var Aborting: boolean): integer; var b: byte; begin result := Stream.Position; if (result and 1) <> 0 then begin inc(result); // align to word b := 0; SafeStreamWrite(Stream, Aborting, b, 1); // write an align byte end; end; // adds $0D$0A at the end of line procedure IEStreamWriteLn(Stream: TStream; Text: AnsiString); const EOL: AnsiString = #$0D#$0A; begin Stream.Write(Text[1], length(Text)); Stream.Write(EOL[1], 2); end; procedure IEStreamWriteByte(Stream: TStream; Value: byte); begin Stream.Write(Value, 1); end; // IEStreamXXXX functions ///////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////// {$ifdef IEUSEBUFFEREDSTREAM} // Buffering disabled when BufferSize = 0 (calls directly fStream methods) constructor TIEBufferedReadStream.Create(InputStream: TStream; BufferSize: integer; UseRelativePosition: boolean); begin inherited Create; if UseRelativePosition then fRelativePosition := InputStream.Position else fRelativePosition := 0; fStream := InputStream; fSize := InputStream.Size; fPosition := InputStream.Position; fOverPosition := false; AllocBufferSize(BufferSize); LoadData(); end; procedure TIEBufferedReadStream.AllocBufferSize(BufferSize: integer); begin fBufferSize := BufferSize; SetLength(fMemory, BufferSize); end; destructor TIEBufferedReadStream.Destroy; begin fStream.Position := fPosition; // synchronize input stream inherited Destroy; end; // read data of length fBufferSize procedure TIEBufferedReadStream.LoadData(); begin if fBufferSize > 0 then begin fStream.Position := fPosition; fStream.Read(fMemory[0], i64min(fBufferSize, fSize - fPosition)); fPositionBuf := 0; end; end; function TIEBufferedReadStream.Read(var Buffer; Count: longint): Longint; var mx: integer; b: pbyte; begin if fBufferSize = 0 then begin result := fStream.Read(Buffer, Count); end else begin fOverPosition := false; result := 0; if Count > (fSize-fPosition) then begin Count := fSize-fPosition; fOverPosition := true; end; b := pbyte(@Buffer); if Count=1 then begin if fBufferSize=fPositionBuf then begin LoadData(); end; b^ := fMemory[fPositionBuf]; inc(fPositionBuf); inc(fPosition); result := 1; end else if Count > 1 then begin while true do begin if Count < (fBufferSize - fPositionBuf) then mx := Count else mx := fBufferSize - fPositionBuf; CopyMemory(b, @fMemory[fPositionBuf], mx); inc(fPositionBuf, mx); inc(fPosition, mx); inc(result, mx); dec(Count, mx); if Count = 0 then break; LoadData(); inc(b, mx); end; end; end; end; function TIEBufferedReadStream.Write(const Buffer; Count: longint): Longint; begin raise EIEException.Create('TIEBufferedReadStream cannot write!'); end; {$ifdef IEOLDSEEKDEF} function TIEBufferedReadStream.Seek(Offset: longint; Origin: word): longint; {$else} function TIEBufferedReadStream.Seek(const Offset: int64; Origin: TSeekOrigin): int64; {$endif} var newpos: int64; posbuf: int64; begin if fBufferSize = 0 then begin result := fStream.Seek(Offset, Origin); end else begin fOverPosition := false; newpos := fPosition; case integer(Origin) of soFromBeginning: begin newpos := fRelativePosition + Offset; // Offset must be >= 0 end; soFromCurrent: begin newpos := fPosition + Offset; end; soFromEnd: begin newpos := fSize - abs(Offset); // offset should be <= 0. Positive values handled as negative end; end; if newpos < 0 then newpos := 0; if newpos >= fSize then begin newpos := fSize; fOverPosition := true; end; posbuf := fPositionBuf + (newpos - fPosition); if (posbuf >= fBufferSize) or (posbuf < 0) then begin fPosition := newpos; LoadData(); end else begin fPositionBuf := posbuf; fPosition := newpos; end; result := fPosition - fRelativePosition; end; end; ///////////////////////////////////////////////////////////////////////// constructor TIEBufferedWriteStream.Create(InputStream: TStream; BufferSize: integer); begin inherited Create; fStream := InputStream; fBufferSize := BufferSize; getmem(fMemory, fBufferSize); fBufferPos := 0; end; destructor TIEBufferedWriteStream.Destroy; begin FlushData; freemem(fMemory); inherited Destroy; end; function TIEBufferedWriteStream.Read(var Buffer; Count: longint): Longint; begin raise EIEException.Create('TIEBufferedWriteStream cannot read!'); end; procedure TIEBufferedWriteStream.FlushData; begin if fBufferPos>0 then fStream.Write(fMemory[0], fBufferPos); fBufferPos := 0; end; function TIEBufferedWriteStream.Write(const Buffer; Count: longint): Longint; var c, m: integer; inbuf: pbyte; begin inbuf := pbyte(@Buffer); c := Count; while c>0 do begin m := i64min(c, fBufferSize-fBufferPos); move(inbuf^, fMemory[fBufferPos], m); inc(inbuf, m); inc(fBufferPos, m); if fBufferPos=fBufferSize then FlushData; dec(c, m); end; result := Count-c; end; {$ifdef IEOLDSEEKDEF} function TIEBufferedWriteStream.Seek(Offset: longint; Origin: word): longint; {$else} function TIEBufferedWriteStream.Seek(const Offset: int64; Origin: TSeekOrigin): int64; {$endif} begin FlushData; result := fStream.Seek(Offset, Origin); end; ///////////////////////////////////////////////////////////////////////////// {$else} constructor TIEBufferedReadStream.Create(InputStream: TStream; BufferSize: integer; UseRelativePosition: boolean); begin inherited Create; fStream := InputStream; end; destructor TIEBufferedReadStream.Destroy; begin inherited Destroy; end; function TIEBufferedReadStream.Read(var Buffer; Count: longint): Longint; begin result := fStream.Read(Buffer, Count); end; function TIEBufferedReadStream.Write(const Buffer; Count: longint): Longint; begin raise EIEException.Create('TIEBufferedReadStream cannot write!'); end; {$ifdef IEOLDSEEKDEF} function TIEBufferedReadStream.Seek(Offset: longint; Origin: word): longint; {$else} function TIEBufferedReadStream.Seek(const Offset: int64; Origin: TSeekOrigin): int64; {$endif} begin result := fStream.Seek(Offset, Origin); end; ///////////////////////////////////////////////////////////////////////////// constructor TIEBufferedWriteStream.Create(InputStream: TStream; BufferSize: integer); begin inherited Create; fStream := InputStream; end; destructor TIEBufferedWriteStream.Destroy; begin inherited Destroy; end; function TIEBufferedWriteStream.Read(var Buffer; Count: longint): Longint; begin raise EIEException.Create('TIEBufferedWriteStream cannot read!'); end; function TIEBufferedWriteStream.Write(const Buffer; Count: longint): Longint; begin result := fStream.Write(Buffer, Count); end; {$ifdef IEOLDSEEKDEF} function TIEBufferedWriteStream.Seek(Offset: longint; Origin: word): longint; {$else} function TIEBufferedWriteStream.Seek(const Offset: int64; Origin: TSeekOrigin): int64; {$endif} begin result := fStream.Seek(Offset, Origin); end; {$endif} ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// function IECreateGrayPalette(): HPALETTE; var logp: TMaxLogPalette; i: integer; begin logp.palVersion := $300; logp.palNumEntries := 256; for i := 0 to 255 do begin logp.palPalEntry[i].peRed := i; logp.palPalEntry[i].peGreen := i; logp.palPalEntry[i].peBlue := i; logp.palPalEntry[i].peFlags := 0; end; result := CreatePalette(PLogPalette(@logp)^); end; procedure IESetGrayPalette(Bitmap: TBitmap); var pe: array [0..255] of TRGBQuad; i: integer; begin for i := 0 to 255 do with pe[i] do begin rgbRed := i; rgbGreen := i; rgbBlue := i; rgbReserved := 0; end; SetDIBColorTable(Bitmap.Canvas.Handle, 0, 256, pe); SetStretchBltMode(Bitmap.Canvas.Handle, COLORONCOLOR); end; function IEIsGrayPalette(Bitmap: TBitmap): boolean; var pe: array [0..255] of TRGBQuad; i, n: integer; begin result := false; n := GetDIBColorTable(Bitmap.Canvas.Handle, 0, 256, pe); for i := 0 to n - 1 do with pe[i] do if (rgbRed <> i) or (rgbGreen <> i) or (rgbBlue <> i) then exit; result := true; end; // note: source.PixelFormat must be pf8bit and dest.PixelFormat must be ie8p procedure IECopyTBitmapPaletteToTIEBitmap(source: TBitmap; dest: TIEBitmap); var pe: array[0..255] of TRGBQuad; i, n: integer; begin if (source.PixelFormat<>pf8bit) or (dest.fPixelFormat<>ie8p) then exit; n := GetDIBColorTable(source.Canvas.Handle, 0, 256, pe); for i := 0 to n-1 do with pe[i] do dest.Palette[i] := CreateRGB( rgbRed, rgbGreen, rgbBlue ); end; ////////////////////////////////////////////////////////////////////////////////////////////////////////// // XMP support functions const xmpnamespace: AnsiString='http://ns.adobe.com/xap/1.0/'; function IEFindXMPFromJpegTag(Buffer: pointer; BufferLength: integer): pbyte; begin if (BufferLength>29) and CompareMem(Buffer, PAnsiChar(xmpnamespace), 24) then // 24 because we don't compare version begin result := Buffer; while result^<>0 do inc(result); inc(result); end else result := nil; end; function IELoadXMPFromJpegTag(Buffer: pointer; BufferLength: integer; params: TObject): boolean; var pt: pbyte; info: AnsiString; sz: integer; begin pt := IEFindXMPFromJpegTag(Buffer, BufferLength); result := pt <> nil; if result then begin sz := BufferLength - (PAnsiChar(pt) - PAnsiChar(Buffer)); SetLength(info, sz); Move(pt^, info[1], sz); (params as TIOParams).XMP_Info := info; end; end; procedure IESaveXMPToJpegTag(params: TObject; var Buffer: pointer; var BufferLength: integer); var info: AnsiString; pb: pbyte; begin info := (params as TIOParams).XMP_Info; BufferLength := 29+length(info); getmem(Buffer, BufferLength); pb := Buffer; move(xmpnamespace[1], pb^, 29); inc(pb, 29); move(info[1], pb^, length(info)); end; // end of XMP support functions ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Back propagation multilayer neural net (* Network: Backpropagation Network with Bias Terms and Momentum ==================================================== Application: Time-Series Forecasting Prediction of the Annual Number of Sunspots Author: Karsten Kutza Reference: D.E. Rumelhart, G.E. Hinton, R.J. Williams Learning Internal Representations by Error Propagation in: D.E. Rumelhart, J.L. McClelland (Eds.) Parallel Distributed Processing, Volume 1 MIT Press, Cambridge, MA, pp. 318-362, 1986 *) {$ifdef IEINCLUDENEURALNET} constructor TIENeurNet.Create(layerUnits: array of integer); var i: integer; begin inherited Create; LayersDefCount := length(layerUnits); getmem(LayersDef, sizeof(integer)*LayersDefCount); for i := 0 to LayersDefCount-1 do LayersDef[i] := layerUnits[i]; GenerateNetwork; RandomWeights; end; destructor TIENeurNet.Destroy; var l, i: integer; begin for l := 0 to LayersDefCount-1 do begin if (l <> 0) then begin for i := 1 to LayersDef[l] do begin freemem(Layer[l].Weight[i]); freemem(Layer[l].WeightSave[i]); freemem(Layer[l].dWeight[i]); end; end; freemem(Layer[l].Output); freemem(Layer[l].Error); freemem(Layer[l].Weight); freemem(Layer[l].WeightSave); freemem(Layer[l].dWeight); end; freemem( Layer ); freemem( LayersDef ); inherited; end; procedure TIENeurNet.GenerateNetwork; var l, i: integer; begin Layer := allocmem(LayersDefCount*sizeof(TLAYER)); for l := 0 to LayersDefCount-1 do begin Layer[l].Units := LayersDef[l]; Layer[l].Output := allocmem( (LayersDef[l]+1) * sizeof(double) ); Layer[l].Error := allocmem( (LayersDef[l]+1) * sizeof(double) ); Layer[l].Weight := allocmem( (LayersDef[l]+1) * sizeof(pdoublearray) ); Layer[l].WeightSave := allocmem( (LayersDef[l]+1) * sizeof(pdoublearray) ); Layer[l].dWeight := allocmem( (LayersDef[l]+1) * sizeof(pdoublearray) ); Layer[l].Output[0] := 1; // BIAS if (l <> 0) then begin for i := 1 to LayersDef[l] do begin Layer[l].Weight[i] := allocmem( (LayersDef[l-1]+1) * sizeof(double) ); Layer[l].WeightSave[i] := allocmem( (LayersDef[l-1]+1) * sizeof(double) ); Layer[l].dWeight[i] := allocmem( (LayersDef[l-1]+1) * sizeof(double) ); end; end; end; InputLayer := @Layer[0]; OutputLayer := @Layer[LayersDefCount - 1]; Alpha := 0.9; Eta := 0.25; Gain := 1; end; function RandomEqualREAL(Low, High: double): double; begin result := random * (High-Low) + Low; end; procedure TIENeurNet.RandomWeights; var l, i, j: integer; begin for l := 1 to LayersDefCount-1 do begin for i := 1 to Layer[l].Units do begin for j := 0 to Layer[l-1].Units do begin Layer[l].Weight[i][j] := RandomEqualREAL(-0.5, 0.5); end; end; end; end; procedure TIENeurNet.SetInput(idx: integer; value: double); begin InputLayer.Output[idx+1] := value; end; function TIENeurNet.GetOutput(idx: integer): double; begin result := OutputLayer.Output[idx+1]; end; procedure TIENeurNet.SetInput(fromIdx: integer; Input: pdoublearray); var i: integer; begin for i := 1 to InputLayer.Units do InputLayer.Output[fromIdx+i] := Input[i-1]; end; procedure TIENeurNet.GetOutput(Output: pdoublearray); var i: integer; begin for i := 1 to OutputLayer.Units do Output[i-1] := OutputLayer.Output[i]; end; procedure TIENeurNet.GetOutput(Bitmap: TIEBitmap; w, h: integer); var i, j, k: integer; pb: pbyte; max, min, v, range: double; begin max := -10000000; min := 10000000; for i := 1 to Outputlayer.Units do begin v := OutputLayer.Output[i]; if v>max then max := v else if v dstWidth) or (tmp.Height <> dstHeight) then proc.Resample(dstWidth, dstHeight, IEGlobalSettings().DefaultResampleFilter); tmp.PixelFormat := ie32f; k := 0 + fromIdx; for i := 0 to dstHeight - 1 do begin ps := tmp.Scanline[i]; for j := 0 to dstWidth - 1 do begin InputLayer.Output[k + 1] := ps^; inc(ps); inc(k); end; end; finally proc.free; tmp.free; end; end; end; procedure TIENeurNet.Train(bitmap: TIEBitmap; srcX, srcY, srcWidth, srcHeight: integer; dstWidth, dstHeight: integer; DoTrain: boolean); var proc: TImageEnProc; tmp: TIEBitmap; i, j: integer; ps: psingle; k: integer; px: PRGB; xOut, Err: double; v: double; begin Run; Error := 1; if (srcWidth=0) or (srcHeight=0) or (dstWidth=0) or (dstHeight=0) then exit; Error := 0; if (srcWidth=dstWidth) and (srcHeight=dstHeight) then begin k := 0; for i := 0 to dstHeight-1 do begin px := bitmap.Scanline[i+srcY]; inc(px, srcX); for j := 0 to dstWidth-1 do begin with px^ do v := (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255; // Rec 709 xOut := OutputLayer.Output[k+1]; Err := v-xOut; OutputLayer.Error[k+1] := Gain * xOut * (1-xOut) * Err; Error := Error + 0.5 * sqr(Err); inc(k); inc(px); end; end; end else begin tmp := TIEBitmap.Create; proc := TImageEnProc.CreateFromBitmap(tmp); try tmp.Allocate(srcWidth, srcHeight, ie24RGB); bitmap.CopyRectTo(tmp, srcX, srcY, 0, 0, srcWidth, srcHeight); if (tmp.Width <> dstWidth) or (tmp.Height <> dstHeight) then proc.Resample(dstWidth, dstHeight, IEGlobalSettings().DefaultResampleFilter); tmp.PixelFormat := ie32f; k := 0; for i := 0 to dstHeight - 1 do begin ps := tmp.Scanline[i]; for j := 0 to dstWidth - 1 do begin xOut := OutputLayer.Output[k + 1]; Err := ps^ - xOut; OutputLayer.Error[k+1] := Gain * xOut * (1-xOut) * Err; Error := Error + 0.5 * sqr(Err); inc(ps); inc(k); end; end; finally proc.free; tmp.free; end; end; if DoTrain then begin BackpropagateNet; AdjustWeights; end; end; {$endif} ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEDicomTags {$ifdef IEINCLUDEDICOM} constructor TIEDicomTags.Create; begin inherited Create; fTags := TList.Create; fSorted := true; end; destructor TIEDicomTags.Destroy; begin Clear; fTags.Free; inherited; end; {!! TIEDicomTags.Clear Declaration procedure Clear; Description Removes all loaded DICOM tags. !!} procedure TIEDicomTags.Clear; var i: integer; begin for i := 0 to fTags.Count - 1 do FreeTag(i); fTags.Clear; end; {!! TIEDicomTags.Count Declaration property Count: integer; Description Returns number of loaded DICOM tags. !!} function TIEDicomTags.GetCount: integer; begin result := fTags.Count; end; function DicomStrToTag(s: AnsiString): TIEDicomTagType; begin result := dvUNKNOWN; if s = 'AE' then Result := dvAE else if s = 'AS' then Result := dvAS else if s = 'AT' then Result := dvAT else if s = 'CS' then Result := dvCS else if s = 'DA' then Result := dvDA else if s = 'DS' then Result := dvDS else if s = 'DT' then Result := dvDT else if s = 'FD' then Result := dvFD else if s = 'FL' then Result := dvFL else if s = 'IS' then Result := dvIS else if s = 'LO' then Result := dvLO else if s = 'LT' then Result := dvLT else if s = 'OB' then Result := dvOB else if s = 'OF' then Result := dvOF else if s = 'OW' then Result := dvOW else if s = 'PN' then Result := dvPN else if s = 'SH' then Result := dvSH else if s = 'SL' then Result := dvSL else if s = 'SQ' then Result := dvSQ else if s = 'SS' then Result := dvSS else if s = 'ST' then Result := dvST else if s = 'TM' then Result := dvTM else if s = 'UI' then Result := dvUI else if s = 'UL' then Result := dvUL else if s = 'UN' then Result := dvUN else if s = 'UR' then Result := dvUR else if s = 'US' then Result := dvUS else if s = 'UT' then Result := dvUT; end; function DicomTagToStr(dt : TIEDicomTagType) : AnsiString; begin if dt = dvAE then Result := 'AE' else if dt = dvAS then Result := 'AS' else if dt = dvAT then Result := 'AT' else if dt = dvCS then Result := 'CS' else if dt = dvDA then Result := 'DA' else if dt = dvDS then Result := 'DS' else if dt = dvDT then Result := 'DT' else if dt = dvFD then Result := 'FD' else if dt = dvFL then Result := 'FL' else if dt = dvIS then Result := 'IS' else if dt = dvLO then Result := 'LO' else if dt = dvLT then Result := 'LT' else if dt = dvOB then Result := 'OB' else if dt = dvOF then Result := 'OF' else if dt = dvOW then Result := 'OW' else if dt = dvPN then Result := 'PN' else if dt = dvSH then Result := 'SH' else if dt = dvSL then Result := 'SL' else if dt = dvSQ then Result := 'SQ' else if dt = dvSS then Result := 'SS' else if dt = dvST then Result := 'ST' else if dt = dvTM then Result := 'TM' else if dt = dvUI then Result := 'UI' else if dt = dvUL then Result := 'UL' else if dt = dvUN then Result := 'UN' else if dt = dvUR then Result := 'UR' else if dt = dvUS then Result := 'US' else if dt = dvUT then Result := 'UT' else Result := '??' end; {!! TIEDicomTags.AddTag Declaration function AddTag(Group: word; Element: word; DataType: ; Data: pointer; DataLen: integer; Children: TObjectList = nil): integer; Description Adds a new DICOM tag. You can view a list of tags at: Dicom Tag List Data is the pointer to data buffer (of DataLen length). You must not free this buffer. Returns the tag position. Note: For adding and replacing tags it is normally preferable to use , or Example Children := TObjectList.Create(); SubTags := TIEDicomTags.Create(); SubTags.Sorted := false; SubTags.SetTagNumeric( $4, $1400, 0, False ); SubTags.SetTagNumeric( $4, $1410, 65535, False ); SubTags.SetTagNumeric( $4, $1420, 0, False ); SubTags.SetTagString( $4, $1430, 'PATIENT', False ); SubTags.SetTagNumeric( $4, $1400, 0, False ); SubTags.SetTagNumeric( $4, $1410, 65535, False ); SubTags.SetTagNumeric( $4, $1420, 0, False ); SubTags.SetTagString( $4, $1430, 'STUDY', False ); SubTags.SetTagNumeric( $4, $1400, 0, False ); SubTags.SetTagNumeric( $4, $1410, 65535, False ); SubTags.SetTagNumeric( $4, $1420, 0, False ); SubTags.SetTagString( $4, $1430, 'SERIES', False ); SubTags.SetTagNumeric( $4, $1400, 0, False ); SubTags.SetTagNumeric( $4, $1410, 65535, False ); SubTags.SetTagNumeric( $4, $1420, 0, False ); SubTags.SetTagString( $4, $1430, 'IMAGE', False ); SubTags.SetTagString( $4, $1500, 'C:\FileName.jpg', False ); Children.Add( SubTags ); ImageEnMView1.MIO.Params[0].DICOM_Tags.AddTag( 4, $1220, dvSQ, nil, -1, Children ); !!} function TIEDicomTags.AddTag(Group: word; Element: word; DataType: TIEDicomTagType; Data: pointer; DataLen: integer; Children: TObjectList): integer; var p: PIEDicomTag; begin new(p); FillChar(p^, sizeof(TIEDicomTag), 0); p^.Group := Group; p^.Element := Element; p^.Children := Children; p^.DataType := DataType; if DataLen < 0 then begin p^.DataLen := 0; // undefined size or length = 0 p^.Data := nil; end else begin p^.DataLen := DataLen; p^.Data := Data; end; result := SetTag(p, false); end; // versions: // 1 : <= 4.3.0 // 2 : 4.3.1 // 3 : 5.2.0 procedure TIEDicomTags.SaveToStream(Stream: TStream); var b: byte; dw: dword; i, j: integer; begin // version b := 3; Stream.Write(b, 1); // tags count i := fTags.Count; Stream.Write(i, 4); // tags for i := 0 to fTags.Count - 1 do begin Stream.Write( PIEDicomTag(fTags[i])^, sizeof(TIEDicomTag) ); with PIEDicomTag(fTags[i])^ do begin if DataLen > 0 then Stream.Write( pbyte(Data)^, DataLen ); // Children dw := 0; if assigned(Children) then dw := Children.Count; Stream.Write(dw, sizeof(dword)); if assigned(Children) then begin for j := 0 to Children.Count - 1 do (Children[j] as TIEDicomTags).SaveToStream(Stream); end; end; enD; end; procedure TIEDicomTags.LoadFromStream(Stream: TStream); var ver, b: byte; dw: dword; i, l, j: integer; p: PIEDicomTag; t: TIEDicomTags; begin Stream.Read(ver, 1); // version if ver >= 1 then begin Stream.Read(l, 4); // tags count for i := 0 to l - 1 do begin new(p); Stream.Read( p^, sizeof(TIEDicomTag) ); if p^.DataLen > 0 then begin getmem(p^.data, p^.DataLen + 1); Stream.Read( pbyte(p^.data)^, p^.Datalen ); PAnsiChar(p^.data)[p^.DataLen] := #0; end else p^.data := nil; // load children if ver >= 2 then begin if ver >= 3 then begin Stream.Read(dw, sizeof(dword)); end else begin Stream.Read(b, 1); dw := b; end; if dw > 0 then begin p^.Children := TObjectlist.Create(); for j := 0 to dw - 1 do begin t := TIEDicomTags.Create(); p^.Children.Add(t); t.LoadFromStream(Stream); end; end; end; fTags.Add(p); end; end; end; procedure TIEDicomTags.Assign(Source: TIEDicomTags); var i, j: integer; p_src, p_dst: PIEDicomTag; t: TIEDicomTags; begin Clear; for i := 0 to Source.fTags.Count - 1 do begin p_src := PIEDicomTag(Source.fTags[i]); new(p_dst); CopyMemory(p_dst, p_src, sizeof(TIEDicomtag)); if p_src^.DataLen > 0 then begin getmem(p_dst^.data, p_src^.DataLen + 1); CopyMemory(p_dst^.data, p_src^.data, p_src^.DataLen + 1); end else p_dst^.data := nil; // Children if assigned(p_src^.Children) then begin p_dst^.Children := TObjectList.Create(); for j := 0 to p_src^.Children.Count - 1 do begin t := TIEDicomTags.Create(); p_dst^.Children.Add(t); t.Assign(p_src^.Children[j] as TIEDicomTags); end; end; fTags.Add(p_dst); end; end; {!! TIEDicomTags.IndexOf Declaration function IndexOf(Group: word; Element: word): integer; Description Returns the index of tag identified by Group and Element. You can view a list of tags at: Dicom Tag List !!} function TIEDicomTags.IndexOf(Group: word; Element: word): integer; var i: integer; p: PIEDicomTag; begin result := -1; for i := 0 to fTags.Count - 1 do begin p := PIEDicomTag(fTags[i]); if (p^.Group = Group) and (p^.Element = Element) then begin result := i; break; end; end; end; {!! TIEDicomTags.GetTag Declaration function GetTag(Index: integer): ; overload; function GetTag(Group: Word; Element: Word): ; overload; Description Returns a pointer to a raw dicom tag. You can specify it by Group/Element or its index. !!} function TIEDicomTags.GetTag(index: integer): PIEDicomTag; begin if (index > -1) and (index < fTags.Count) then result := fTags[index] else result := nil; end; function TIEDicomTags.GetTag(Group: Word; Element: Word): PIEDicomTag; begin Result := GetTag(IndexOf(Group, Element)); end; {!! TIEDicomTags.GetTagChildren Declaration function GetTagChildren(Group: Word; Element: Word): TObjectList; function GetTagChildren(Index: integer): TObjectList; Description Returns the children of DICOM tag as TIEDicomTags object. You can specify it by Group/Element or its index. !!} function TIEDicomTags.GetTagChildren(Group: Word; Element: Word): TObjectList; begin result := GetTagChildren(IndexOf(Group, Element)); end; function TIEDicomTags.GetTagChildren(Index: integer): TObjectList; begin if Index > -1 then result := GetTag(Index)^.Children else result := nil; end; {!! TIEDicomTags.GetTagString Declaration function GetTagString(Index: integer): AnsiString; overload; function GetTagString(Group: Word; Element: Word): AnsiString; overload; Description Returns a DICOM tag as a string. You can specify it by Group/Element or its index. You can view a list of tags at: Dicom Tag List Example ImageType := ImageEnView1.IO.Params.DICOM_Tags.GetTagString( tags.IndexOf($0008, $0008) ); PatientName := ImageEnView1.IO.Params.DICOM_Tags.GetTagString( tags.IndexOf($0010, $0010) ); // Alternatively ImageType := ImageEnView1.IO.Params.DICOM_Tags.GetTagString($0008, $0008); PatientName := ImageEnView1.IO.Params.DICOM_Tags.GetTagString($0010, $0010); !!} function TIEDicomTags.GetTagString(index: integer): AnsiString; var p: PIEDicomTag; begin p := GetTag(index); if (p = nil) or (p^.Data = nil) then result := '' else case p^.DataType of dvFL: result := AnsiString(FloatToStrF(single(p^.Data^), ffFixed, 18, 6)); dvSL: result := AnsiString(IntToStr(Longint(p^.Data^))) ; dvSS: result := AnsiString(IntToStr(short(p^.Data^))); dvUL: result := AnsiString(IntToStr(uLong(p^.Data^))); dvUS: result := AnsiString(IntToStr(Word(p^.Data^))); dvAT: // POINTER result := AnsiString(IntToStr(Integer(p^.Data^))); dvUSorSS : // = US or SS result := AnsiString(IntToStr(Integer(p^.Data^))); else // For all other types try (like PN) result := AnsiString(PAnsiChar(p^.Data)); end; end; function TIEDicomTags.GetTagString(Group: Word; Element: Word): AnsiString; begin Result := GetTagString(IndexOf(Group, Element)); end; {!! TIEDicomTags.GetTagNumeric Declaration function GetTagNumeric(Index: integer; Default: double = 0.0): double; function GetTagNumeric(Group: Word; Element: Word; Default: double = 0.0): double; Description Returns a DICOM tag as number. You can specify it by Group/Element or its index. You can view a list of tags at: Dicom Tag List Example // Output all DICOM tags of image to a memo (same as ) for I := 0 to Dicom_Tag_Count - 1 do begin aTagInfo := IEDICOMGetTagInfo( I ); sDescription := aTagInfo.Desc; sValue := tags.GetTagString( ImageEnView1.IO.Params.DICOM_Tags.IndexOf(aTagInfo.Group, aTagInfo.Element) ); if (sDescription <> '') and (sValue <> '') then memo1.Lines.Add( sDescription + ': '+ sValue ) end; !!} function TIEDicomTags.GetTagNumeric(Index: integer; Default: double): double; var p: PIEDicomTag; begin p := GetTag(index); if (p = nil) or (p^.Data = nil) then result := Default else case p^.DataType of dvFL: result := psingle(p^.Data)^; dvFD: result := pdouble(p^.Data)^; dvSL: result := pinteger(p^.Data)^; dvUL: result := pdword(p^.Data)^; dvSS: result := psmallint(p^.Data)^; dvUS: result := pword(p^.Data)^; else result := Default; end; end; function TIEDicomTags.GetTagNumeric(Group: Word; Element: Word; Default: double): double; begin Result := GetTagNumeric(IndexOf(Group, Element), Default); end; function TIEDicomTags.SetTag(Tag: PIEDicomTag; ReplaceIfExist: boolean): integer; var i, idx: integer; begin // locate right position to insert idx := -1; if fSorted then begin for i := 0 to fTags.Count - 1 do if ((PIEDicomTag(fTags[i])^.Group = Tag^.Group) and (PIEDicomTag(fTags[i])^.Element >= Tag^.Element)) or // the same element or the next one (PIEDicomTag(fTags[i])^.Group > Tag^.Group) then // the first element of the next group begin idx := i; break; end; end; if idx > -1 then begin if (PIEDicomTag(fTags[idx])^.Group = Tag^.Group) and (PIEDicomTag(fTags[idx])^.Element = Tag^.Element) then begin // tag already exist if ReplaceIfExist then FreeTag(idx) // delete it else begin inc(idx); // do not delete, insert just after it fTags.Insert(idx, nil); end; end else fTags.Insert(idx, nil); // doesn't exist, create empty entry fTags[idx] := tag; end else begin // append to the end idx := fTags.Add(tag); end; if ReplaceIfExist then begin // remove possible other replications i := 0; while i < fTags.Count do begin if (PIEDicomTag(fTags[i])^.Group = Tag^.Group) and (PIEDicomTag(fTags[i])^.Element = Tag^.Element) and (i <> idx) then DeleteTag(i) else inc(i); end; end; result := idx; end; {!! TIEDicomTags.SetTagNumeric Declaration procedure SetTagNumeric(Group: Word; Element: Word; Value: double; ReplaceIfExist: Boolean = True); Description Adds or replaces a numeric tag. If the tag does not exist, it will be added. If the tag already exists it will be overwritten if ReplaceIfExist is true, or a second instance of the tag added if ReplaceIfExist = False. Note: An exception is raised if the tag does not support a numeric value. Example // Add a "Priority" tag to the current Dicom file (or replace tag if it already exists) ImageEnView1.IO.Params.DICOM_Tags.DICOM_Tags.SetTagNumeric( $0000, $0700, 7 ); !!} procedure TIEDicomTags.SetTagNumeric(Group: Word; Element: Word; Value: double; ReplaceIfExist: Boolean = True); var tag: PIEDicomTag; tagInfo: PIEDicomTagInfo; begin // prepare the tag new(tag); tag^.Group := Group; tag^.Element := Element; tag^.Children := nil; tagInfo := IEDicomGetTagInfo(Group, Element); if tagInfo = nil then // unknown tag, default to FD (float double) tag^.DataType := dvFD else tag^.DataType := tagInfo^.VType; if tag^.DataType = dvUSorSS then begin // US or SS if Value < 0 then tag^.DataType := dvSS else tag^.DataType := dvUS end; if tag^.DataType = dvFL then begin // Floating Point Single getmem(tag^.Data, sizeof(single)); psingle(tag^.Data)^ := Value; tag^.DataLen := sizeof(single); end else if tag^.DataType = dvFD then begin // Floating Point Double getmem(tag^.Data, sizeof(double)); pdouble(tag^.Data)^ := Value; tag^.DataLen := sizeof(double); end else if tag^.DataType = dvSL then begin // Signed Long (32 bit) getmem(tag^.Data, sizeof(integer)); pinteger(tag^.Data)^ := trunc(Value); tag^.DataLen := sizeof(integer); end else if tag^.DataType = dvUL then begin // Unsigned Long (32 bit) getmem(tag^.Data, sizeof(dword)); pdword(tag^.Data)^ := trunc(Value); tag^.DataLen := sizeof(dword); end else if tag^.DataType = dvSS then begin // Signed Short (16 bit) getmem(tag^.Data, sizeof(smallint)); psmallint(tag^.Data)^ := trunc(Value); tag^.DataLen := sizeof(smallint); end else if tag^.DataType = dvUS then begin // Unsigned Short (16 bit) getmem(tag^.Data, sizeof(word)); pword(tag^.Data)^ := trunc(Value); tag^.DataLen := sizeof(word); end else begin dispose(tag); raise EIEException.Create(Format('Tag %s,%s cannot be a number', [IntToHex(Group, 4), IntToHex(Element, 4)])); end; SetTag(tag, ReplaceIfExist); end; {!! TIEDicomTags.SetTagString Declaration procedure SetTagString(Group: Word; Element: Word; Value: AnsiString; ReplaceIfExist: Boolean = True); Description Adds or replaces a string tag. If the tag does not exist, it will be added. If the tag already exists it will be overwritten if ReplaceIfExist is true, or a second instance of the tag added if ReplaceIfExist = False. Note: An exception is raised if the tag does not support a string value. Example // Add a "Patient Name" tag to the current Dicom file (or replace tag if it already exists) ImageEnView1.IO.Params.DICOM_Tags.SetTagString( $0010, $0010, 'Joe Bloggs' ); !!} procedure TIEDicomTags.SetTagString(Group: Word; Element: Word; Value: AnsiString; ReplaceIfExist: Boolean = True); var tag: PIEDicomTag; tagInfo: PIEDicomTagInfo; slen: integer; begin // prepare the tag new(tag); tag^.Group := Group; tag^.Element := Element; tag^.Children := nil; tagInfo := IEDicomGetTagInfo(Group, Element); if tagInfo = nil then // unknown tag, default to CS (Code string) tag^.DataType := dvCS else tag^.DataType := tagInfo^.VType; // make length even slen := length(Value); while ((slen and 1) <> 0) or (slen = 0) do begin inc(slen); if tag^.DataType in [dvUI, dvOB] then Value := Value + #0 else Value := Value + ' '; end; if tag^.DataType in [dvCS, dvAS, dvAE, dvDA, dvDS, dvDT, dvIS, dvLO, dvLT, dvPN, dvSH, dvST, dvTM, dvUI, dvUT] then begin // Code string getmem(tag^.Data, slen + 1); CopyMemory(tag^.Data, @Value[1], slen + 1); // +1 embedded (but not counted in the DataLen field) trailing zero tag^.DataLen := slen; end else begin dispose(tag); raise EIEException.Create(Format('Tag %s,%s cannot be a string', [IntToHex(Group, 4), IntToHex(Element, 4)])); end; SetTag(tag, ReplaceIfExist); end; {!! TIEDicomTags.SetTagByteBuffer Declaration procedure SetTagByteBuffer(Group: Word; Element: Word; Buffer: pbyte; Length: integer; ReplaceIfExist: Boolean = True); Description Adds or replaces a byte buffer tag. If the tag does not exist, it will be added. If the tag already exists it will be overwritten if ReplaceIfExist is true, or a second instance of the tag added if ReplaceIfExist = False. Note: An exception is raised if the tag does not support a byte buffer value. !!} procedure TIEDicomTags.SetTagByteBuffer(Group: Word; Element: Word; Buffer: pbyte; Length: integer; ReplaceIfExist: Boolean = True); var tag: PIEDicomTag; tagInfo: PIEDicomTagInfo; slen: integer; begin // prepare the tag new(tag); tag^.Group := Group; tag^.Element := Element; tag^.Children := nil; tagInfo := IEDicomGetTagInfo(Group, Element); if tagInfo = nil then // unknown tag, default to OB (Other Byte String) tag^.DataType := dvOB else tag^.DataType := tagInfo^.VType; if tag^.DataType <> dvOB then begin dispose(tag); raise EIEException.Create(Format('Tag %s,%s cannot be a byte string', [IntToHex(Group, 4), IntToHex(Element, 4)])); end; // make length even slen := Length; if (slen and 1) <> 0 then inc(slen); getmem(tag^.Data, slen + 1); CopyMemory(tag^.Data, Buffer, slen + 1); // +1 embedded (but not counted in the DataLen field) trailing zero tag^.DataLen := slen; // additional byte for even length if slen > Length then pbytearray(tag^.Data)[Length] := 0; SetTag(tag, ReplaceIfExist); end; // remove tag allocated space (do not remove tag entry) // Index must be valid (>-1 and less than Count) procedure TIEDicomTags.FreeTag(Index: integer); begin if assigned(PIEDicomTag(fTags[Index])^.Children) then PIEDicomTag(fTags[Index])^.Children.Free(); freemem( PIEDicomTag(fTags[Index])^.data ); dispose( PIEDicomTag(fTags[Index]) ); end; {!! TIEDicomTags.DeleteTag Declaration procedure DeleteTag(Index: integer); overload; procedure DeleteTag(Group: Word; Element: Word; DeleteAllInstances: boolean = false); overload; Description Removes a tag from the Dicom tag list. You can specify it by Group/Element or its index. If DeleteAllInstances is true, DeleteTag removes all instances of this tag. Example // removes patient name ImageEnView1.IO.Params.DICOM_Tags.DeleteTag( tags.IndexOf($0010, $0010) ); // Or ImageEnView1.IO.Params.DICOM_Tags.DeleteTag($0010, $0010); !!} procedure TIEDicomTags.DeleteTag(index: integer); begin if (index > -1) and (index < fTags.Count) then begin FreeTag(Index); fTags.Delete(index); end; end; procedure TIEDicomTags.DeleteTag(Group: Word; Element: Word; DeleteAllInstances: boolean); var i: integer; begin repeat i := IndexOf(Group, Element); DeleteTag(i); // DeleteTag accepts i = -1 until (i = -1) or not DeleteAllInstances; end; {!! TIEDicomTags.DeleteGroup Declaration procedure DeleteGroup(Group: Word); Description Removes all tags belonging to the specified group. !!} procedure TIEDicomTags.DeleteGroup(Group: Word); var i: integer; begin i := 0; while i < fTags.Count do begin if PIEDicomTag(fTags[i])^.Group = Group then begin FreeTag(i); fTags.Delete(i); end else inc(i); end; end; {!! TIEDicomTags.GetTagDescription Declaration function GetTagDescription(Index: integer): string; overload; function GetTagDescription(Index: integer; out TagSource : ): string; overload; class function GetTagDescription(Group: Word; Element: Word): string; overload; class function GetTagDescription(Group: Word; Element: Word; out TagSource : ): string; overload; Description Returns an English description of specified tag. The overloads including TagSource allow you to determine if the tag is part of the NEMA standard (dsStandard), has been retired (dsDeprecated), or is vendor specific (dsProprietary). !!} function TIEDicomTags.GetTagDescription(Index: integer; out TagSource : TIEDicomTagSource): string; begin result := GetTagDescription( PIEDicomTag(fTags[index])^.Group, PIEDicomTag(fTags[index])^.Element, TagSource ); end; function TIEDicomTags.GetTagDescription(Index: integer): string; var aSource : TIEDicomTagSource; begin result := GetTagDescription( PIEDicomTag(fTags[index])^.Group, PIEDicomTag(fTags[index])^.Element, aSource ); end; // Does not depend on the TIEDicomTags instance, so it is a class function {$ifdef IEDICOMDESC} class function TIEDicomTags.GetTagDescription(Group: Word; Element: Word; out TagSource : TIEDicomTagSource): string; var aInfo : PIEDicomTagInfo; begin result := ''; // default, not found TagSource := dsProprietary; aInfo := IEDicomGetTagInfo(Group, Element); if assigned(aInfo) then begin result := string(aInfo^.Desc); TagSource := aInfo^.Src; end; end; {$else} class function TIEDicomTags.GetTagDescription(Group: Word; Element: Word; out TagSource : TIEDicomTagSource): string; begin result := ''; end; {$endif} class function TIEDicomTags.GetTagDescription(Group: Word; Element: Word): string; var aSource : TIEDicomTagSource; begin Result := GetTagDescription( Group, Element, aSource ) end; {!! TIEDicomTags.FindNestedTag Declaration function FindNestedTag(Group: Word; Element: Word; out Index: integer; StartFrom: = nil): ; function FindNestedTag(Group: Word; Element: Word; out Index: integer; StartFrom: TObjectList): ; Description Returns the index of tag identified by Group and Element. It searches for the tag within nested tags. You can view a list of tags at: Dicom Tag List Example var Index: integer; Tags: TIEDicomTags; begin ImageEnView1.IO.LoadFromFile('input.dcm'); Tags := imageenview1.IO.Params.DICOM_Tags.FindNestedTag($18, $1042, Index); if Index > -1 then ShowMessage( Tags.GetTagString(Index) ); end; !!} function TIEDicomTags.FindNestedTag(Group: Word; Element: Word; out Index: integer; StartFrom: TIEDicomTags): TIEDicomTags; var i: integer; tags: TList; begin result := nil; Index := -1; if StartFrom = nil then StartFrom := self; tags := StartFrom.fTags; for i := 0 to tags.Count - 1 do begin if (PIEDicomTag(tags[i])^.Group = Group) and (PIEDicomTag(tags[i])^.Element = Element) then begin result := StartFrom; Index := i; break; end else if assigned(PIEDicomTag(tags[i])^.Children) then begin result := FindNestedTag(Group, Element, Index, PIEDicomTag(tags[i])^.Children); // call second overload if assigned(result) and (Index <> -1) then break; end; end; end; function TIEDicomTags.FindNestedTag(Group: Word; Element: Word; out Index: integer; StartFrom: TObjectList): TIEDicomTags; var i: integer; begin result := nil; Index := -1; for i := 0 to StartFrom.Count - 1 do begin result := FindNestedTag(Group, Element, Index, StartFrom[i] as TIEDicomTags); // call first overload if assigned(result) and (Index <> -1) then break; end; end; {$endif} // TIEDicomTags ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// {$ifdef IERFBPROTOCOL} //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // TIE3DES (* * This is D3DES (V5.09) by Richard Outerbridge with the double and * triple-length support removed for use in VNC. Also the bytebit[] array * has been reversed so that the most significant bit in each byte of the * key is ignored, not the least significant. * * These changes are * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *) (* D3DES (V5.09) - * * A portable, public domain, version of the Data Encryption Standard. * * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge. * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation * code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau, * for humouring me on. * * Copyright (c) 1988, 1989, 1990, 1991, 1992 by Richard Outerbridge. * (GEnie : OUTER; CIS : [71755, 204]) Graven Imagery, 1992. *) (* d3des.h - * * Headers and defines for d3des.c * Graven Imagery, 1992. * * Copyright (c) 1988, 1989, 1990, 1991, 1992 by Richard Outerbridge * (GEnie : OUTER; CIS : [71755, 204]) *) // must call Reset before Transform! constructor TIE3DES.Create(); begin inherited Create; end; // password length max 8 characters constructor TIE3DES.Create(const Password: AnsiString; Mode: TIE3DESMode); begin inherited Create; Reset(Password, Mode); end; destructor TIE3DES.Destroy; begin inherited; end; procedure TIE3DES.Reset(const Password: AnsiString; Mode: TIE3DESMode); var charbuf: array of AnsiChar; i: integer; begin ZeroMemory(@KnL[0], length(KnL) * sizeof(dword)); SetLength(charbuf, 8); FillChar(charbuf[0], 8, 0); for i := 0 to imin(length(Password), 8) - 1 do charbuf[i] := Password[i + 1]; deskey(@charbuf[0], mode); end; procedure TIE3DES.Reset(Password: int64; Mode: TIE3DESMode); begin ZeroMemory(@KnL[0], length(KnL) * sizeof(dword)); deskey(pbytearray(@Password), mode); end; procedure TIE3DES.Transform(InBlock: pbyte; OutBlock: pbyte; Length: integer); var i: integer; begin if (Length and $7) <> 0 then raise EIERFBError.Create('transform length must be multiple of 8'); i := 0; while i < Length do begin des(InBlock, OutBlock); inc(InBlock, 8); inc(OutBlock, 8); inc(i, 8); end; end; const Df_Key: array [0..23] of byte = ( $01, $23, $45, $67, $89, $ab, $cd, $ef, $fe, $dc, $ba, $98, $76, $54, $32, $10, $89, $ab, $cd, $ef, $01, $23, $45, $67 ); bytebit: array [0..7] of word = ( 1, 2, 4, 8, 16, 32, 64, 128 ); bigbyte: array [0..23] of dword = ( $800000, $400000, $200000, $100000, $80000, $40000, $20000, $10000, $8000, $4000, $2000, $1000, $800, $400, $200, $100, $80, $40, $20, $10, $8, $4, $2, $1 ); pc1: array [0..55] of byte = ( 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 ); totrot: array [0..15] of byte = (1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28); pc2: array [0..47] of byte = ( 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 ); // key length must be 8 bytes procedure TIE3DES.deskey(key: pbytearray; edf: TIE3DESMode); var i, j, l, m, n: integer; pc1m: array [0..55] of byte; pcr: array [0..55] of byte; kn: array [0..31] of dword; begin for j := 0 to 55 do begin l := pc1[j]; m := l and 7; if (key[l shr 3] and bytebit[m])<>0 then pc1m[j] := 1 else pc1m[j] := 0; end; for i := 0 to 15 do begin if ( edf = ie3desDECRYPT ) then m := (15 - i) shl 1 else m := i shl 1; n := m + 1; kn[n] := 0; kn[m] := 0; for j := 0 to 27 do begin l := j + totrot[i]; if l < 28 then pcr[j] := pc1m[l] else pcr[j] := pc1m[l - 28]; end; for j := 28 to 55 do begin l := j + totrot[i]; if l < 56 then pcr[j] := pc1m[l] else pcr[j] := pc1m[l - 28]; end; for j := 0 to 23 do begin if pcr[pc2[j]]<>0 then kn[m] := kn[m] or bigbyte[j]; if pcr[pc2[j+24]]<>0 then kn[n] := kn[n] or bigbyte[j]; end; end; cookey(@kn[0]); end; procedure TIE3DES.cookey(raw1: pdword); var cook: pdword; raw0: pdword; dough: array [0..31] of dword; i: integer; begin cook := @dough[0]; for i := 0 to 15 do begin raw0 := raw1; inc(raw1); cook^ := (raw0^ and $00fc0000) shl 6; cook^ := cook^ or ((raw0^ and $00000fc0) shl 10); cook^ := cook^ or ((raw1^ and $00fc0000) shr 10); cook^ := cook^ or ((raw1^ and $00000fc0) shr 6); inc(cook); cook^ := (raw0^ and $0003f000) shl 12; cook^ := cook^ or ((raw0^ and $0000003f) shl 16); cook^ := cook^ or ((raw1^ and $0003f000) shr 4); cook^ := cook^ or (raw1^ and $0000003f); inc(cook); inc(raw1); end; usekey(@dough[0]); end; procedure TIE3DES.usekey(from: pdword); var i: integer; begin for i := 0 to 31 do begin KnL[i] := from^; inc(from); end; end; // 8 bytes buffers procedure TIE3DES.des(inblock: pbyte; outblock: pbyte); var work: array [0..1] of dword; begin scrunch(inblock, @work[0]); desfunc(@work[0], @KnL[0]); unscrun(@work[0], outblock); end; procedure TIE3DES.scrunch(outof: pbyte; into: pdword); begin into^ := (outof^ and $ff) shl 24; inc(outof); into^ := into^ or ((outof^ and $ff) shl 16); inc(outof); into^ := into^ or ((outof^ and $ff) shl 8); inc(outof); into^ := into^ or (outof^ and $ff); inc(outof); inc(into); into^ := (outof^ and $ff) shl 24; inc(outof); into^ := into^ or ((outof^ and $ff) shl 16); inc(outof); into^ := into^ or ((outof^ and $ff) shl 8); inc(outof); into^ := into^ or (outof^ and $ff); end; procedure TIE3DES.unscrun(outof: pdword; into: pbyte); begin into^ := ((outof^ shr 24) and $ff); inc(into); into^ := ((outof^ shr 16) and $ff); inc(into); into^ := ((outof^ shr 8) and $ff); inc(into); into^ := (outof^ and $ff); inc(into); inc(outof); into^ := ((outof^ shr 24) and $ff); inc(into); into^ := ((outof^ shr 16) and $ff); inc(into); into^ := ((outof^ shr 8) and $ff); inc(into); into^ := (outof^ and $ff); end; const SP1: array [0..63] of dword = ( $01010400, $00000000, $00010000, $01010404, $01010004, $00010404, $00000004, $00010000, $00000400, $01010400, $01010404, $00000400, $01000404, $01010004, $01000000, $00000004, $00000404, $01000400, $01000400, $00010400, $00010400, $01010000, $01010000, $01000404, $00010004, $01000004, $01000004, $00010004, $00000000, $00000404, $00010404, $01000000, $00010000, $01010404, $00000004, $01010000, $01010400, $01000000, $01000000, $00000400, $01010004, $00010000, $00010400, $01000004, $00000400, $00000004, $01000404, $00010404, $01010404, $00010004, $01010000, $01000404, $01000004, $00000404, $00010404, $01010400, $00000404, $01000400, $01000400, $00000000, $00010004, $00010400, $00000000, $01010004 ); SP2: array [0..63] of dword = ( $80108020, $80008000, $00008000, $00108020, $00100000, $00000020, $80100020, $80008020, $80000020, $80108020, $80108000, $80000000, $80008000, $00100000, $00000020, $80100020, $00108000, $00100020, $80008020, $00000000, $80000000, $00008000, $00108020, $80100000, $00100020, $80000020, $00000000, $00108000, $00008020, $80108000, $80100000, $00008020, $00000000, $00108020, $80100020, $00100000, $80008020, $80100000, $80108000, $00008000, $80100000, $80008000, $00000020, $80108020, $00108020, $00000020, $00008000, $80000000, $00008020, $80108000, $00100000, $80000020, $00100020, $80008020, $80000020, $00100020, $00108000, $00000000, $80008000, $00008020, $80000000, $80100020, $80108020, $00108000 ); SP3: array [0..63] of dword = ( $00000208, $08020200, $00000000, $08020008, $08000200, $00000000, $00020208, $08000200, $00020008, $08000008, $08000008, $00020000, $08020208, $00020008, $08020000, $00000208, $08000000, $00000008, $08020200, $00000200, $00020200, $08020000, $08020008, $00020208, $08000208, $00020200, $00020000, $08000208, $00000008, $08020208, $00000200, $08000000, $08020200, $08000000, $00020008, $00000208, $00020000, $08020200, $08000200, $00000000, $00000200, $00020008, $08020208, $08000200, $08000008, $00000200, $00000000, $08020008, $08000208, $00020000, $08000000, $08020208, $00000008, $00020208, $00020200, $08000008, $08020000, $08000208, $00000208, $08020000, $00020208, $00000008, $08020008, $00020200 ); SP4: array [0..63] of dword = ( $00802001, $00002081, $00002081, $00000080, $00802080, $00800081, $00800001, $00002001, $00000000, $00802000, $00802000, $00802081, $00000081, $00000000, $00800080, $00800001, $00000001, $00002000, $00800000, $00802001, $00000080, $00800000, $00002001, $00002080, $00800081, $00000001, $00002080, $00800080, $00002000, $00802080, $00802081, $00000081, $00800080, $00800001, $00802000, $00802081, $00000081, $00000000, $00000000, $00802000, $00002080, $00800080, $00800081, $00000001, $00802001, $00002081, $00002081, $00000080, $00802081, $00000081, $00000001, $00002000, $00800001, $00002001, $00802080, $00800081, $00002001, $00002080, $00800000, $00802001, $00000080, $00800000, $00002000, $00802080 ); SP5: array [0..63] of dword = ( $00000100, $02080100, $02080000, $42000100, $00080000, $00000100, $40000000, $02080000, $40080100, $00080000, $02000100, $40080100, $42000100, $42080000, $00080100, $40000000, $02000000, $40080000, $40080000, $00000000, $40000100, $42080100, $42080100, $02000100, $42080000, $40000100, $00000000, $42000000, $02080100, $02000000, $42000000, $00080100, $00080000, $42000100, $00000100, $02000000, $40000000, $02080000, $42000100, $40080100, $02000100, $40000000, $42080000, $02080100, $40080100, $00000100, $02000000, $42080000, $42080100, $00080100, $42000000, $42080100, $02080000, $00000000, $40080000, $42000000, $00080100, $02000100, $40000100, $00080000, $00000000, $40080000, $02080100, $40000100 ); SP6: array [0..63] of dword = ( $20000010, $20400000, $00004000, $20404010, $20400000, $00000010, $20404010, $00400000, $20004000, $00404010, $00400000, $20000010, $00400010, $20004000, $20000000, $00004010, $00000000, $00400010, $20004010, $00004000, $00404000, $20004010, $00000010, $20400010, $20400010, $00000000, $00404010, $20404000, $00004010, $00404000, $20404000, $20000000, $20004000, $00000010, $20400010, $00404000, $20404010, $00400000, $00004010, $20000010, $00400000, $20004000, $20000000, $00004010, $20000010, $20404010, $00404000, $20400000, $00404010, $20404000, $00000000, $20400010, $00000010, $00004000, $20400000, $00404010, $00004000, $00400010, $20004010, $00000000, $20404000, $20000000, $00400010, $20004010 ); SP7: array [0..63] of dword = ( $00200000, $04200002, $04000802, $00000000, $00000800, $04000802, $00200802, $04200800, $04200802, $00200000, $00000000, $04000002, $00000002, $04000000, $04200002, $00000802, $04000800, $00200802, $00200002, $04000800, $04000002, $04200000, $04200800, $00200002, $04200000, $00000800, $00000802, $04200802, $00200800, $00000002, $04000000, $00200800, $04000000, $00200800, $00200000, $04000802, $04000802, $04200002, $04200002, $00000002, $00200002, $04000000, $04000800, $00200000, $04200800, $00000802, $00200802, $04200800, $00000802, $04000002, $04200802, $04200000, $00200800, $00000000, $00000002, $04200802, $00000000, $00200802, $04200000, $00000800, $04000002, $04000800, $00000800, $00200002 ); SP8: array [0..63] of dword = ( $10001040, $00001000, $00040000, $10041040, $10000000, $10001040, $00000040, $10000000, $00040040, $10040000, $10041040, $00041000, $10041000, $00041040, $00001000, $00000040, $10040000, $10000040, $10001000, $00001040, $00041000, $00040040, $10040040, $10041000, $00001040, $00000000, $00000000, $10040040, $10000040, $10001000, $00041040, $00040000, $00041040, $00040000, $10041000, $00001000, $00000040, $10040040, $00001000, $00041040, $10001000, $00000040, $10000040, $10040000, $10040040, $10000000, $00040000, $10001040, $00000000, $10041040, $00040040, $10000040, $10040000, $10001000, $10001040, $00000000, $10041040, $00041000, $00041000, $00001040, $00001040, $00040040, $10000000, $10041000 ); procedure TIE3DES.desfunc(block: pdwordarray; keys: pdword); var fval, work, right, leftt: dword; round: integer; begin leftt := block[0]; right := block[1]; work := ((leftt shr 4) xor right) and $0f0f0f0f; right := right xor work; leftt := leftt xor (work shl 4); work := ((leftt shr 16) xor right) and $0000ffff; right := right xor work; leftt := leftt xor (work shl 16); work := ((right shr 2) xor leftt) and $33333333; leftt := leftt xor work; right := right xor (work shl 2); work := ((right shr 8) xor leftt) and $00ff00ff; leftt := leftt xor work; right := right xor (work shl 8); right := ((right shl 1) or ((right shr 31) and 1)) and $ffffffff; work := (leftt xor right) and $aaaaaaaa; leftt := leftt xor work; right := right xor work; leftt := ((leftt shl 1) or ((leftt shr 31) and 1)) and $ffffffff; for round := 0 to 7 do begin work := (right shl 28) or (right shr 4); work := work xor keys^; inc(keys); fval := SP7[ work and $3f]; fval := fval or SP5[(work shr 8) and $3f]; fval := fval or SP3[(work shr 16) and $3f]; fval := fval or SP1[(work shr 24) and $3f]; work := right xor keys^; inc(keys); fval := fval or SP8[work and $3f]; fval := fval or SP6[(work shr 8) and $3f]; fval := fval or SP4[(work shr 16) and $3f]; fval := fval or SP2[(work shr 24) and $3f]; leftt := leftt xor fval; work := (leftt shl 28) or (leftt shr 4); work := work xor keys^; inc(keys); fval := SP7[ work and $3f]; fval := fval or SP5[(work shr 8) and $3f]; fval := fval or SP3[(work shr 16) and $3f]; fval := fval or SP1[(work shr 24) and $3f]; work := leftt xor keys^; inc(keys); fval := fval or SP8[work and $3f]; fval := fval or SP6[(work shr 8) and $3f]; fval := fval or SP4[(work shr 16) and $3f]; fval := fval or SP2[(work shr 24) and $3f]; right := right xor fval; end; right := (right shl 31) or (right shr 1); work := (leftt xor right) and $aaaaaaaa; leftt := leftt xor work; right := right xor work; leftt := (leftt shl 31) or (leftt shr 1); work := ((leftt shr 8) xor right) and $00ff00ff; right := right xor work; leftt := leftt xor (work shl 8); work := ((leftt shr 2) xor right) and $33333333; right := right xor work; leftt := leftt xor (work shl 2); work := ((right shr 16) xor leftt) and $0000ffff; leftt := leftt xor work; right := right xor (work shl 16); work := ((right shr 4) xor leftt) and $0f0f0f0f; leftt := leftt xor work; right := right xor (work shl 4); pdword(block)^ := right; inc(pdword(block)); pdword(block)^ := leftt; end; // TIE3DES //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // TIERFBClient {!! TIERFBClient.Create Declaration constructor Create(FrameBuffer: = nil); Description Creates a new instance of TIERFBClient using the specified bitmap as framebuffer. If FrameBuffer is nil then a new bitmap is allocated and owned by the TIERFBClient object. Example var rfb: TIERFBClient; begin rfb := TIERFBClient.Create( ImageEnView1.IEBitmap ); rfb.OnUpdate := OnVNCUpdate; rfb.Connect('My_VNC_Server'); ... end; procedure TForm1.OnVNCUpdate(Sender: TNotifyEvent); begin ImageEnView1.Update; end; !!} constructor TIERFBClient.Create(FrameBuffer: TIEBitmap); begin inherited Create; m_socket := TIEClientSocket.Create; m_pixelFormat := ierfbRGB32; m_OnUpdate := nil; m_OnUpdateNonSync := nil; m_OnUpdateRect := nil; m_OnBell := nil; m_OnClipboardText := nil; m_OnCursorShapeUpdated := nil; m_OnUpdateScreenSize := nil; if assigned(FrameBuffer) then begin m_frameBuffer := FrameBuffer; m_freeFrameBuffer := false; end else begin m_frameBuffer := TIEBitmap.Create; m_freeFrameBuffer := true; end; m_cursor := TIEBitmap.Create; SetLength(m_colorMap, 256); m_cursorPos := Point(0, 0); m_cursorHotSpot := Point(0, 0); m_savedCursorArea := TIEBitmap.Create; m_suspended := false; m_frameBufferLock := TCriticalSection.Create(); m_socketSendLock := TCriticalSection.Create(); end; destructor TIERFBClient.Destroy; begin Disconnect(); m_socket.Free; m_cursor.Free; m_savedCursorArea.Free; FreeAndNil(m_socketSendLock); FreeAndNil(m_frameBufferLock); if m_freeFrameBuffer and assigned(m_frameBuffer) then FreeAndNil(m_frameBuffer); inherited; end; {!! TIERFBClient.Connect Declaration procedure Connect(const Address: string; Port: word = 5900; const Password: AnsiString = ''); Description Connects to the specified RFB (VNC) server. May throw exception if an error occurs (wrong address, wrong port, unsupported protocol version, authentication failure, etc..). Parameter Description Address IP4, IP6 or name of the RFB server. Port TCP Port of the RFB server. Password Optional password. Max 8 characters.
Example var rfb: TIERFBClient; begin rfb := TIERFBClient.Create( ImageEnView1.IEBitmap ); rfb.OnUpdate := OnVNCUpdate; try rfb.Connect('My_VNC_Server', 5900, '12345678'); except on E:Exception do begin ShowMessage(E.Message); end; end; end; procedure TForm1.OnVNCUpdate(Sender: TNotifyEvent); begin ImageEnView1.Update; end; !!} procedure TIERFBClient.Connect(const Address: string; Port: word; const Password: AnsiString); const supportedEncodings: array [0..4] of integer = ( 0, // RAW encoding 2, // RRE 1, // CopyRect encoding -239, // Cursor pseudo-encoding -223 // DesktopSize pseudo-encoding ); var charbuf: array of AnsiChar; securityType: dword; securityTypesCount: byte; securityTypes: array of byte; dw: dword; challenge: array of byte; i: integer; des: TIE3DES; version: integer; // ie 003.007: 3007 versionStr: AnsiString; errStr: AnsiString; begin m_msgThread := nil; securityType := 0; // invalid try m_socket.Connect(Address, Port); // receive ProtocolVersion SetLength(charbuf, 13); m_socket.ReceiveBuffer(@charbuf[0], 12); version := StrToIntDef(string( charbuf[4] + charbuf[5] + charbuf[6] + charbuf[8] + charbuf[9] + charbuf[10] ), 0); // decide a protocol version if version >= 3008 then // >= 003.008? version := 3008 // set 003.008 else if (version >= 3003) and (version < 3007) then // >= 003.003 and < 003.007? version := 3003 // set 003.003 else if (version <> 3007) then // <> 003.007? raise EIERFBError.Create('Unsupported protocol version'); // send ProtocolVersion versionStr := 'RFB 00'+IEIntToStr(version div 1000)+'.00'+IEIntToStr(version - (version div 1000)*1000)+#10; m_socket.SendBuffer(PAnsiChar(versionStr), 12); if version >= 3007 then // >= 003.007? begin // receive number-of-security-types (securityTypesCount) securityTypesCount := m_socket.ReceiveByte(); if securityTypesCount = 0 then begin // failed, describe reason dw := m_socket.ReceiveDWord(); SetLength(charbuf, dw+1); m_socket.ReceiveBuffer(@charbuf[0], dw); charbuf[dw] := #0; IESetStringA(errStr, @charbuf[0], dw); raise EIERFBError.Create(string(errStr)); end; // receive list of security types (securityTypes) SetLength(securityTypes, securityTypesCount); m_socket.ReceiveBuffer(@securityTypes[0], securityTypesCount); for dw := 0 to securityTypesCount-1 do if (securityTypes[dw] = 1) or (securityTypes[dw] = 2) then begin securityType := securityTypes[dw]; // select "VNC Authentication" or "none" break; end; if securityType = 0 then raise EIERFBError.Create('Client unsupports authentication'); // send selected security type m_socket.SendByte(securityType); end; if version = 3003 then // = 003.003? begin // server decides and sends security type securityType := m_socket.ReceiveDWord(); end; case securityType of 1: // no authentication begin if version >= 3008 then // >= 003.008? // receive security result (should also receive failure reason, but we ignore it) if m_socket.ReceiveDWord() <> 0 then raise EIERFBError.Create('Authentication failed'); end; 2: // VNC authentication begin // receive challenge SetLength(challenge, 16); m_socket.ReceiveBuffer(@challenge[0], 16); // encode challenge des := TIE3DES.Create(Password, ie3desENCRYPT); des.transform(@challenge[0], @challenge[0], 16); des.Free; // send encoded challenge m_socket.SendBuffer(@challenge[0], 16); // receive security result if m_socket.ReceiveDWord() <> 0 then // for 3.008 we should also receive failure reason, but we ignore it raise EIERFBError.Create('Authentication failed'); end; end; // send Client init message m_socket.SendByte(1); // 1 = shared // receive Server init message m_frameBufferSize.cx := m_socket.ReceiveWord(); m_frameBufferSize.cy := m_socket.ReceiveWord(); m_bitsPerPixel := m_socket.ReceiveByte(); m_depth := m_socket.ReceiveByte(); m_bigEndianFlag := m_socket.ReceiveByte(); m_trueColorFlag := m_socket.ReceiveByte(); m_redMax := m_socket.ReceiveWord(); m_greenMax := m_socket.ReceiveWord(); m_blueMax := m_socket.ReceiveWord(); m_redShift := m_socket.ReceiveByte(); m_greenShift := m_socket.ReceiveByte(); m_blueShift := m_socket.ReceiveByte(); m_socket.ReceivePad(3); // pad 3 bytes dw := m_socket.ReceiveDWord(); // name length SetLength(charbuf, dw+1); m_socket.ReceiveBuffer(@charbuf[0], dw); // name IESetStringA(m_name, @charbuf[0], dw); m_frameBuffer.Allocate(m_frameBufferSize.cx, m_frameBufferSize.cy, ie24RGB); // send SetEncodings message m_socket.SendByte(2); // SetEncodings message m_socket.SendPad(1); // padding m_socket.SendWord(length(supportedEncodings)); // number of encodings for i := 0 to high(supportedEncodings) do m_socket.SendDWord(supportedEncodings[i]); m_msgThread := TIERFBMessageThread.Create(self); // send SetPixelFormat message SendSetPixelFormat(m_pixelFormat); // request for the first update SendRequestUpdate(false); except m_msgThread.Free; m_msgThread := nil; m_socket.Disconnect(); raise; end; end; function TIERFBClient.GetConnected: boolean; begin result := m_socket.Connected; end; {!! TIERFBClient.Disconnect Declaration procedure Disconnect(); Description Disconnects from the server. Note: This function will waits for the message handler thread to terminate, so may require some time. !!} procedure TIERFBClient.Disconnect(); begin if assigned(m_msgThread) then m_msgThread.Terminate; m_socket.Disconnect(); if assigned(m_msgThread) then begin m_msgThread.WaitFor; FreeAndNil(m_msgThread); end; end; {!! TIERFBClient.SendRequestUpdate Declaration procedure SendRequestUpdate(x, y, width, height: word; incremental: boolean); procedure SendRequestUpdate(incremental: boolean = true); Description Sends an update request to the server for the specified rectangle or for the whole frame buffer. May throw
exception if a communication error occurs. Update requests are sent automatically by TIERFBClient, so under normal circumstances, it is not necessary to call this method. Parameter Description x Horizontal position of the rectangle to update. y Vertical position of the rectangle to udpate. width Width of the rectangle to update. height Height of the rectangle to update. incremental If true only we need only changes occurred since last update.
!!} procedure TIERFBClient.SendRequestUpdate(x, y, width, height: word; incremental: boolean); begin if not m_suspended then begin m_socketSendLock.Enter(); try m_socket.SendByte(3); // FramebufferUpdateRequest m_socket.SendByte(byte(incremental)); // incremental m_socket.SendWord(x); // x-position m_socket.SendWord(y); // y-position m_socket.SendWord(width); // width m_socket.SendWord(height); // height finally m_socketSendLock.Leave(); end; end; end; procedure TIERFBClient.SendRequestUpdate(incremental: boolean); begin SendRequestUpdate(0, 0, m_frameBufferSize.cx, m_frameBufferSize.cy, incremental); end; {!! TIERFBClient.SendPointerEvent Declaration procedure SendPointerEvent(x, y: integer; LeftButton: boolean; MiddleButton: boolean; RightButton: boolean); Description Communicates a new mouse pointer position and mouse buttons state to the server. SendPointerEvent also updates the frame buffer drawing the mouse cursor, so you should refresh the screen just after. May throw
exception if a communication error occurs. Parameter Description x Horizontal coordinate of the mouse (hotspot), relative to the frame buffer. y Vertical coordinate of the mouse (hotspot), relative to the frame buffer.. LeftButton True if the left button is down. MiddleButton True if the middle button is down. RightButton True if the right button is down.
Example procedure TForm1.ImageEnViewMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if RFB.Connected then begin RFB.SendPointerEvent(ImageEnView.XScr2Bmp(X), ImageEnView.YScr2Bmp(Y), ssLeft in Shift, ssMiddle in Shift, ssRight in Shift); ImageEnView.Update; end; end; !!} procedure TIERFBClient.SendPointerEvent(x, y: integer; LeftButton: boolean; MiddleButton: boolean; RightButton: boolean); var bb: byte; wx, wy: word; begin LockFrameBuffer(); wx := imax(0, imin(x, m_frameBufferSize.cx - 1)); wy := imax(0, imin(y, m_frameBufferSize.cy - 1)); try m_cursorPos := Point(wx, wy); RemoveCursor; PaintCursor; finally UnlockFrameBuffer(); end; m_socketSendLock.Enter(); try m_socket.SendByte(5); // msg-id bb := 0; if LeftButton then bb := bb or 1; if MiddleButton then bb := bb or 2; if RightButton then bb := bb or 4; m_socket.SendByte(bb); // button mask m_socket.SendWord(wx); // x-position m_socket.SendWord(wy); // y-position finally m_socketSendLock.Leave(); end; end; {!! TIERFBClient.SendClipboard Declaration procedure SendClipboard(const Text: AnsiString); Description Sends text to the server clipboard. Only ISO 8859-1 (Latin-1) text is supported by the protocol. May throw
exception if a communication error occurs. !!} // send ClientCutText message procedure TIERFBClient.SendClipboard(const Text: AnsiString); begin m_socketSendLock.Enter(); try m_socket.SendByte(6); // msg-id m_socket.SendPad(3); // 3 bytes padding m_socket.SendDWord(length(Text)); // text length m_socket.SendBuffer(PAnsiChar(Text), length(Text)); // Text finally m_socketSendLock.Leave(); end; end; {!! TIERFBClient.SendKeyEvent Declaration procedure SendKeyEvent(xkey: dword; down: boolean); procedure SendKeyEvent(VirtualKey: dword; KeyData: dword; down: boolean); Description Sends a Windows Virtual Key or a XWindow key to the server. The first overload (XWindow) is fully supported (you can send any XWindow key). The second overload (VirtualKey) doesn't support all key combinations (like CTRL-?, ALT-?, etc...), so applications should handle these combination manually. May throw exception if a communication error occurs. Parameter Description xkey XWindow key code. down True when the key is down, False otherwise. VirtualKey Windows Virtual Key code. KeyData Windows Virtual Key data.
Example // send CTRL-ALT-DEL procedure TForm1.Send_CTRL_ALT_DEL(); begin if RFB.Connected then begin RFB.SendKeyEvent(VK_CONTROL, 0, true); RFB.SendKeyEvent(VK_MENU, 0, true); RFB.SendKeyEvent(VK_DELETE, 0, true); RFB.SendKeyEvent(VK_DELETE, 0, false); RFB.SendKeyEvent(VK_MENU, 0, false); RFB.SendKeyEvent(VK_CONTROL, 0, false); end; end; // a very primitive and buggy keyboard sender. Some combinations could not work (ie CTRL-C, ALTR-?...) procedure TForm1.ImageEnViewVirtualKey(Sender: TObject; VirtualKey, KeyData: Cardinal; KeyDown: Boolean); begin if RFB.Connected then RFB.SendKeyEvent(Virtualkey, KeyData, KeyDown); end; // we need to handle TABS and ARROWS procedure TForm1.ImageEnViewSpecialKey(Sender: TObject; CharCode: Word; Shift: TShiftState; var Handled: Boolean); begin Handled := true; end; !!} // send X-Windows key event procedure TIERFBClient.SendKeyEvent(xkey: dword; down: boolean); begin m_socketSendLock.Enter(); try m_socket.SendByte(4); // msg-id m_socket.SendByte(byte(down)); // down-flag m_socket.SendPad(2); // 2 bytes pad m_socket.SendDWord(xkey); // key finally m_socketSendLock.Leave(); end; end; // send Microsoft Windows key event (WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP) // note: this is a very primitive routine (CTRL-key is missing, and some other combination could not work) procedure TIERFBClient.SendKeyEvent(VirtualKey: dword; KeyData: dword; down: boolean); const KEYMAP: array [0..73] of array [0..1] of dword = ( (VK_CANCEL, $FF6B), // XK_Break (VK_BACK, $FF08), // XK_BackSpace (VK_TAB, $FF09), // XK_Tab (VK_CLEAR, $FF0B), // XK_Clear (VK_RETURN, $FF0D), // XK_Return (VK_SHIFT, $FFE1), // XK_Shift_L (VK_CONTROL, $FFE3), // XK_Control_L (VK_MENU, $FFE9), // XK_Alt_L (VK_PAUSE, $FF13), // XK_Pause (VK_CAPITAL, $FFE5), // XK_Caps_Lock (VK_ESCAPE, $FF1B), // XK_Escape (VK_SPACE, $0020), // XK_space (VK_PRIOR, $FF55), // XK_Page_Up (VK_NEXT, $FF56), // XK_Page_Down (VK_END, $FF57), // XK_End (VK_HOME, $FF50), // XK_Home (VK_LEFT, $FF51), // XK_Left (VK_UP, $FF52), // XK_Up (VK_RIGHT, $FF53), // XK_Right (VK_DOWN, $FF54), // XK_Down (VK_SELECT, $FF60), // XK_Select //(VK_PRINT, $????), (VK_EXECUTE, $FF62), // XK_Execute (VK_SNAPSHOT, $FF61), // XK_Print (VK_INSERT, $FF63), // XK_Insert (VK_DELETE, $FFFF), // XK_Delete (VK_HELP, $FF6A), // XK_Help //(VK_LWIN, $????), //(VK_RWIN, $????), //(VK_APPS, $????), //(VK_SLEEP, $????), (VK_NUMPAD0, $FFB0), // XK_KP_0 (VK_NUMPAD1, $FFB1), // XK_KP_1 (VK_NUMPAD2, $FFB2), // XK_KP_2 (VK_NUMPAD3, $FFB3), // XK_KP_3 (VK_NUMPAD4, $FFB4), // XK_KP_4 (VK_NUMPAD5, $FFB5), // XK_KP_5 (VK_NUMPAD6, $FFB6), // XK_KP_6 (VK_NUMPAD7, $FFB7), // XK_KP_7 (VK_NUMPAD8, $FFB8), // XK_KP_8 (VK_NUMPAD9, $FFB9), // XK_KP_9 (VK_MULTIPLY, $FFAA), // XK_KP_Multiply (VK_ADD, $FFAB), // XK_KP_Add (VK_SEPARATOR,$FFAC), // XK_KP_Separator (VK_SUBTRACT, $FFAD), // XK_KP_Subtract (VK_DECIMAL, $FFAE), // XK_KP_Decimal (VK_DIVIDE, $FFAF), // XK_KP_Divide (VK_F1, $FFBE), // XK_F1 (VK_F2, $FFBF), // XK_F2 (VK_F3, $FFC0), // XK_F3 (VK_F4, $FFC1), // XK_F4 (VK_F5, $FFC2), // XK_F5 (VK_F6, $FFC3), // XK_F6 (VK_F7, $FFC4), // XK_F7 (VK_F8, $FFC5), // XK_F8 (VK_F9, $FFC6), // XK_F9 (VK_F10, $FFC7), // XK_F10 (VK_F11, $FFC8), // XK_F11 (VK_F12, $FFC9), // XK_F12 (VK_F13, $FFCA), // XK_F13 (VK_F14, $FFCB), // XK_F14 (VK_F15, $FFCC), // XK_F15 (VK_F16, $FFCD), // XK_F16 (VK_F17, $FFCE), // XK_F17 (VK_F18, $FFCF), // XK_F18 (VK_F19, $FFD0), // XK_F19 (VK_F20, $FFD1), // XK_F20 (VK_F21, $FFD2), // XK_F21 (VK_F22, $FFD3), // XK_F22 (VK_F23, $FFD4), // XK_F23 (VK_F24, $FFD5), // XK_F24 (VK_NUMLOCK, $FF7F), // XK_Num_Lock (VK_SCROLL, $FF14), // XK_Scroll_Lock (VK_LSHIFT, $FFE1), // XK_Shift_L (VK_RSHIFT, $FFE2), // XK_Shift_R (VK_LCONTROL, $FFE3), // XK_Control_L (VK_RCONTROL, $FFE4), // XK_Control_R (VK_LMENU, $FFE9), // XK_Alt_L (VK_RMENU, $FFEA) // XK_Alt_R ); var keyState: TKeyboardState; ch: array [0..8] of AnsiChar; xkey: dword; i: integer; begin Windows.GetKeyboardState(keyState); if (KeyData and $1000000)<>0 then case VirtualKey of VK_RETURN : begin SendKeyEvent($FF8D, Down); // send XK_KP_Enter exit; end; VK_CONTROL : VirtualKey := VK_RCONTROL; VK_MENU : VirtualKey := VK_RMENU; end; xkey := 0; for i := 0 to high(KEYMAP) do if KEYMAP[i][0] = VirtualKey then begin xkey := KEYMAP[i][1]; break; end; if xkey <> 0 then begin SendKeyEvent(xkey, down); end else begin if Windows.ToAscii(VirtualKey, 0, keyState, @ch[0], 0) = 1 then begin SendKeyEvent(dword(ch[0]), Down); end; end; end; procedure TIERFBClient.SendSetPixelFormat(pixelFormat: TIERFBPixelFormat); begin case pixelFormat of ierfbPalette256: begin m_bitsPerPixel := 8; m_depth := 8; m_bigEndianFlag := 0; m_trueColorFlag := 0; m_redMax := 255; m_greenMax := 255; m_blueMax := 255; m_redShift := 0; m_greenShift := 0; m_blueShift := 0; end; ierfbRGB16: begin m_bitsPerPixel := 16; m_depth := 16; m_bigEndianFlag := 0; m_trueColorFlag := 1; m_redMax := 31; m_greenMax := 63; m_blueMax := 31; m_redShift := 11; m_greenShift := 5; m_blueShift := 0; end; ierfbRGB32: begin m_bitsPerPixel := 32; m_depth := 24; m_bigEndianFlag := 0; m_trueColorFlag := 1; m_redMax := 255; m_greenMax := 255; m_blueMax := 255; m_redShift := 16; m_greenShift := 8; m_blueShift := 0; end; end; m_socketSendLock.Enter(); try m_socket.SendByte(0); // msg id m_socket.SendPad(3); // padding 3 bytes m_socket.SendByte(m_bitsPerPixel); // bitsPerPixel m_socket.SendByte(m_depth); // depth m_socket.SendByte(m_bigEndianFlag); // big endian flag m_socket.SendByte(m_trueColorFlag); // true color flag m_socket.SendWord(m_redMax); // red-max m_socket.SendWord(m_greenMax); // green-max m_socket.SendWord(m_blueMax); // blue-max m_socket.SendByte(m_redShift); // red-shift m_socket.SendByte(m_greenShift); // green-shift m_socket.SendByte(m_blueShift); // blue-shift m_socket.SendPad(3); // padding 3 bytes finally m_socketSendLock.Leave(); end; end; procedure TIERFBClient.RemoveCursor; begin if not m_suspended then begin LockFrameBuffer(); try if not m_savedCursorArea.IsEmpty then begin m_savedCursorArea.CopyRectTo(m_frameBuffer, 0, 0, // SrcX, SrcY m_savedCursorPos.X, m_savedCursorPos.Y, // DstX, DstY m_savedCursorArea.Width, m_savedCursorArea.Height, // RectWidth, RectHeight false ); m_savedCursorArea.FreeImage(true); end; finally UnlockFrameBuffer(); end; end; end; procedure TIERFBClient.PaintCursor; var neg: TPoint; begin if not m_suspended then begin LockFrameBuffer(); try if not m_cursor.IsEmpty then begin // save cursor area m_savedCursorPos := Point(m_cursorPos.X - m_cursorHotSpot.X, m_cursorPos.Y - m_cursorHotSpot.Y); neg := Point(-imin(0, m_savedCursorPos.X), -imin(0, m_savedCursorPos.Y)); inc(m_savedCursorPos.X, neg.X); inc(m_savedCursorPos.Y, neg.Y); m_savedCursorArea.Allocate(m_cursor.Width - neg.X, m_cursor.Height - neg.Y, ie24RGB); m_frameBuffer.CopyRectTo(m_savedCursorArea, m_savedCursorPos.X, m_savedCursorPos.Y, // sourceX, sourceY 0, 0, // destX, destY m_savedCursorArea.Width, m_savedCursorArea.Height, // rect width, rect height false ); // paint cursor m_cursor.RenderToTIEBitmapEx(m_frameBuffer, m_savedCursorPos.X-neg.X, m_savedCursorPos.Y-neg.Y, // xDst, yDst m_cursor.Width, m_cursor.Height, // dxDst, dyDst 0, 0, // xSrc, ySrc m_cursor.Width, m_cursor.Height); // dxSrc, dySrc end; finally UnlockFrameBuffer(); end; end; end; {!! TIERFBClient.LockFrameBuffer Declaration procedure LockFrameBuffer; Description Locks frame buffer and cursor bitmap preventing writing operations. This method could freeze message handler thread so make sure to call
and to maintain frame buffer locked for less time as possible. Applications could prevent frame buffer updates just setting = true, which does not freeze the connection. Example rfb.LockFrameBuffer; try ImageEnMView1.SetImage( imageIndex, rfb.FrameBuffer ); finally rfb.UnlockFrameBuffer; end; !!} procedure TIERFBClient.LockFrameBuffer; begin m_frameBufferLock.Enter(); end; {!! TIERFBClient.UnlockFrameBuffer Declaration procedure UnlockFrameBuffer; Description Unlocks frame buffer and cursor bitmap, locked by . Applications could prevent frame buffer updates just setting = true, which does not freeze the connection. Example rfb.LockFrameBuffer; try ImageEnMView1.SetImage( imageIndex, rfb.FrameBuffer ); finally rfb.UnlockFrameBuffer; end; !!} procedure TIERFBClient.UnlockFrameBuffer; begin m_frameBufferLock.Leave(); end; procedure TIERFBClient.SetSuspended(value: boolean); begin if m_suspended <> value then begin m_suspended := value; if not m_suspended then SendRequestUpdate(false); end; end; // TIERFBClient //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // TIERFBMessageThread constructor TIERFBMessageThread.Create(Client: TIERFBClient); begin m_client := Client; inherited Create(false); end; destructor TIERFBMessageThread.Destroy(); begin inherited; end; procedure TIERFBMessageThread.execute; var b: Byte; begin while not Terminated do begin try // read message type if assigned(m_client.m_socket) and m_client.m_socket.Connected and m_client.m_socket.ReceiveByteSilent(b) then begin case b of 0: msg_FrameBufferUpdate(); // FrameBufferUpdate 1: msg_SetColourMapEntries(); // SetColourMapEntries 2: msg_Bell(); // Bell 3: msg_ServerCutText(); // ServerCutText end; end else break; sleep(0); except break; // exit thread on exception end; end; end; procedure TIERFBMessageThread.msg_FrameBufferUpdate; procedure ReceiveBitmap(dst: TIEBitmap; dstX, dstY, rectWidth, rectHeight: integer); var rowbuf: array of byte; p_src: pbyte; p_dst: pbyte; row: integer; begin SetLength(rowbuf, rectWidth * rectHeight * m_client.m_bitsPerPixel div 8); m_client.m_socket.ReceiveBuffer(@rowbuf[0], length(rowbuf)); // receive frame buffer if not m_client.m_suspended then begin p_src := @rowbuf[0]; // setup source for row := 0 to rectHeight-1 do begin // setup destination p_dst := dst.ScanLine[dstY+row]; inc(p_dst, dstX*3); // copy row CopyRawRow(p_src, p_dst, rectWidth); end; end; end; procedure RAWEncoding(rectXPosition, rectYPosition, rectWidth, rectHeight: word); begin m_client.LockFrameBuffer(); try m_client.RemoveCursor; ReceiveBitmap(m_client.m_FrameBuffer, rectXPosition, rectYPosition, rectWidth, rectHeight); m_client.PaintCursor; finally m_client.UnlockFrameBuffer(); end; if assigned(m_client.m_OnUpdateRect) then synchronize(DoOnUpdateRect); end; procedure CopyRectEncoding(rectXPosition, rectYPosition, rectWidth, rectHeight: word); var srcX, srcY: word; begin srcX := m_client.m_socket.ReceiveWord(); srcY := m_client.m_socket.ReceiveWord(); if not m_client.m_suspended then begin m_client.LockFrameBuffer(); try m_client.RemoveCursor; m_client.m_frameBuffer.MoveRegion(srcX, srcY, srcX+rectWidth-1, srcY+rectHeight-1, rectXPosition, rectYPosition, 0, false); m_client.PaintCursor; finally m_client.UnlockFrameBuffer(); end; if assigned(m_client.m_OnUpdateRect) then synchronize(DoOnUpdateRect); end; end; procedure RREEncoding(rectXPosition, rectYPosition, rectWidth, rectHeight: word); function ReadPixel: TRGB; var pixelbuf: array of byte; pb: pbyte; begin SetLength(pixelbuf, m_client.m_bitsPerPixel div 8); m_client.m_socket.ReceiveBuffer(@pixelbuf[0], length(pixelbuf)); pb := @pixelbuf[0]; CopyRawRow(pb, pbyte(@result), 1); end; var subRectCount: dword; backPixelColor: TRGB; subRectPixelColor: TRGB; subRectXPos: word; subRectYPos: word; subRectWidth: word; subRectHeight: word; i: integer; begin m_client.LockFrameBuffer(); try m_client.RemoveCursor; subRectCount := m_client.m_socket.ReceiveDWord(); backPixelColor := ReadPixel(); if not m_client.m_suspended then m_client.m_frameBuffer.FillRect(rectXPosition, rectYPosition, rectXPosition + rectWidth - 1, rectYPosition + rectHeight - 1, TRGB2TColor(backPixelColor)); if subRectCount>0 then begin for i := 0 to subRectCount-1 do begin subRectPixelColor := ReadPixel(); subRectXPos := m_client.m_socket.ReceiveWord(); subRectYPos := m_client.m_socket.ReceiveWord(); subRectWidth := m_client.m_socket.ReceiveWord(); subRectHeight := m_client.m_socket.ReceiveWord(); if not m_client.m_suspended then begin if (subRectWidth = 1) and (subRectHeight = 1) then m_client.m_frameBuffer.Pixels_ie24RGB[rectXPosition + subRectXPos, rectYPosition + subRectYPos] := subRectPixelColor else m_client.m_frameBuffer.FillRect(rectXPosition + subRectXPos, rectYPosition + subRectYPos, rectXPosition + subRectXPos + subRectWidth - 1, rectYPosition + subRectYPos + subRectHeight - 1, TRGB2TColor(subRectPixelColor)); end; end; end; m_client.PaintCursor; finally m_client.UnlockFrameBuffer(); end; if assigned(m_client.m_OnUpdateRect) then synchronize(DoOnUpdateRect); end; procedure CursorPseudoEncoding(rectXPosition, rectYPosition, rectWidth, rectHeight: word); var cursorMask: array of byte; cursorMaskLength: integer; row, col: integer; pb: pbyte; begin m_client.LockFrameBuffer(); try m_client.m_cursorHotSpot := Point(rectXPosition, rectYPosition); m_client.m_cursor.Allocate(rectWidth, rectHeight, ie24RGB); ReceiveBitmap(m_client.m_cursor, 0, 0, rectWidth, rectHeight); cursorMaskLength := Floor((rectWidth+7)/8)*rectHeight; SetLength(cursorMask, cursorMaskLength); m_client.m_socket.ReceiveBuffer(@cursorMask[0], cursorMaskLength); for row := 0 to rectHeight-1 do begin pb := @cursorMask[ Floor((rectWidth+7)/8) * row ]; for col := 0 to rectWidth-1 do if GetPixelbw_inline(pb, col)=0 then m_client.m_cursor.Alpha[col, row] := 0; end; m_client.m_cursor.AlphaChannel.SyncFull; m_client.RemoveCursor; m_client.PaintCursor; finally m_client.UnlockFrameBuffer(); end; if assigned(m_client.m_OnCursorShapeUpdated) then synchronize(UpdateCursorShape); end; procedure DesktopSizePseudoEncoding(rectWidth, rectHeight: word); begin m_client.LockFrameBuffer(); try m_client.RemoveCursor; m_client.m_frameBufferSize.cx := rectWidth; m_client.m_frameBufferSize.cy := rectHeight; if not m_client.m_suspended then m_client.m_frameBuffer.Allocate(rectWidth, rectHeight, ie24RGB); finally m_client.UnlockFrameBuffer(); end; m_client.SendRequestUpdate(false); if assigned(m_client.m_OnUpdateScreenSize) then synchronize(DoOnUpdateScreenSize); end; var rectCount: word; rectXPosition: word; rectYPosition: word; rectWidth: word; rectHeight: word; rectEncoding: integer; rectIdx: integer; begin m_client.m_socket.ReceivePad(1); // padding rectCount := m_client.m_socket.ReceiveWord(); // number of rectangles for rectIdx := 0 to rectCount-1 do begin rectXPosition := m_client.m_socket.ReceiveWord(); rectYPosition := m_client.m_socket.ReceiveWord(); rectWidth := m_client.m_socket.ReceiveWord(); rectHeight := m_client.m_socket.ReceiveWord(); rectEncoding := m_client.m_socket.ReceiveDWord(); m_updatedRect := Rect(rectXPosition, rectYPosition, rectXPosition + rectWidth -1, rectYPosition + rectHeight - 1); case rectEncoding of // RAW encoding 0: RAWEncoding(rectXPosition, rectYPosition, rectWidth, rectHeight); // CopyRect encoding 1: CopyRectEncoding(rectXPosition, rectYPosition, rectWidth, rectHeight); // RRE encoding 2: RREEncoding(rectXPosition, rectYPosition, rectWidth, rectHeight); // Cursor pseudo-encoding -239: CursorPseudoEncoding(rectXPosition, rectYPosition, rectWidth, rectHeight); // DesktopSize pseudo-encoding -223: DesktopSizePseudoEncoding(rectWidth, rectHeight); else raise EIERFBError.Create('Unsupported encoding'); end; end; DoOnUpdateNonSync; // Non synchronized if assigned(m_client.m_OnUpdate) then synchronize(DoOnUpdate); m_client.SendRequestUpdate(); // always send incremental update end; procedure TIERFBMessageThread.UpdateCursorShape; begin m_client.m_OnCursorShapeUpdated(m_client); end; // modifies "src" procedure TIERFBMessageThread.CopyRawRow(var src: pbyte; dst: pbyte; columns: integer); var dw: dword; ww: word; begin if m_client.m_trueColorFlag <> 0 then begin // true color case m_client.m_bitsPerPixel of 16: while columns>0 do begin ww := pword(src)^; if m_client.m_bigEndianFlag<>0 then ww := IESwapWord(ww); // convert to littleendian // Blue dst^ := trunc(((ww shr m_client.m_blueShift) and m_client.m_blueMax)/m_client.m_blueMax*255); inc(dst); // Green dst^ := trunc(((ww shr m_client.m_greenShift) and m_client.m_greenMax)/m_client.m_greenMax*255); inc(dst); // Red dst^ := trunc(((ww shr m_client.m_redShift) and m_client.m_redMax)/m_client.m_redMax*255); inc(dst); inc(pword(src)); dec(columns); end; 32: while columns>0 do begin dw := pdword(src)^; if m_client.m_bigEndianFlag<>0 then dw := IESwapDWord(dw); // convert to littleendian // Blue dst^ := (dw shr m_client.m_blueShift) and m_client.m_blueMax; inc(dst); // Green dst^ := (dw shr m_client.m_greenShift) and m_client.m_greenMax; inc(dst); // Red dst^ := (dw shr m_client.m_redShift) and m_client.m_redMax; inc(dst); inc(pdword(src)); dec(columns); end; end; end else begin case m_client.m_bitsPerPixel of 8: // palette 256 while columns>0 do begin // Blue dst^ := m_client.m_colorMap[src^].b and $FF; inc(dst); // Green dst^ := m_client.m_colorMap[src^].g and $FF; inc(dst); // Red dst^ := m_client.m_colorMap[src^].r and $FF; inc(dst); inc(src); dec(columns); end; end; end; end; procedure TIERFBMessageThread.DoOnUpdateRect; begin if not m_client.m_suspended then m_client.m_OnUpdateRect(m_client, m_updatedRect); end; procedure TIERFBMessageThread.DoOnUpdateScreenSize; begin m_client.m_OnUpdateScreenSize(m_client); end; procedure TIERFBMessageThread.DoOnUpdate; begin if not m_client.m_suspended then m_client.m_OnUpdate(m_client); end; procedure TIERFBMessageThread.DoOnUpdateNonSync; begin if assigned(m_client.m_OnUpdateNonSync) and not m_client.m_suspended then m_client.m_OnUpdateNonSync(m_client); end; procedure TIERFBMessageThread.DoOnBell; begin m_client.m_OnBell(m_client); end; procedure TIERFBMessageThread.DoOnClipboardText; begin m_client.m_OnClipboardText(m_client, m_clipboardText); end; procedure TIERFBMessageThread.msg_SetColourMapEntries; var firstColor: word; numColors: word; i: integer; begin m_client.m_socket.ReceivePad(1); // padding firstColor := m_client.m_socket.ReceiveWord(); // first color numColors := m_client.m_socket.ReceiveWord(); // number of colors if firstColor+numColors > 256 then raise EIERFBError.Create('Unsupported number of palette colors'); for i := firstColor to numColors-1 do begin m_client.m_colorMap[i].r := m_client.m_socket.ReceiveWord(); m_client.m_colorMap[i].g := m_client.m_socket.ReceiveWord(); m_client.m_colorMap[i].b := m_client.m_socket.ReceiveWord(); end; end; procedure TIERFBMessageThread.msg_Bell; begin if assigned(m_client.m_OnBell) then Synchronize(DoOnBell); end; procedure TIERFBMessageThread.msg_ServerCutText; var dw: dword; charbuf: array of AnsiChar; begin m_client.m_socket.ReceivePad(3); // padding 3 bytes dw := m_client.m_socket.ReceiveDWord(); SetLength(charbuf, dw+1); m_client.m_socket.ReceiveBuffer(@charbuf[0], dw); IESetStringA(m_clipboardText, @charbuf[0], dw); if assigned(m_client.m_OnClipboardText) then Synchronize(DoOnClipboardText); end; // TIERFBMessageThread //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// {$endif} // IERFBPROTOCOL /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // TIEImageListItem constructor TIEImageListItem.Create(image_: TIEBitmap; filename_: WideString); begin image := image_; filename := filename_; end; constructor TIEImageList.Create(); begin inherited; m_images := TList.Create(); end; destructor TIEImageList.Destroy(); begin Clear(); m_images.Free(); inherited; end; {!! TIEImageList.Clear Declaration procedure Clear(); Description Removes all images. !!} procedure TIEImageList.Clear(); var i: integer; begin for i := 0 to m_images.Count-1 do begin TIEImageListItem(m_images[i]).image.Free(); TIEImageListItem(m_images[i]).Free(); end; m_images.Clear(); end; {!! TIEImageList.Remove Declaration procedure Remove(imageIndex: integer); Description Removes the specified image. !!} procedure TIEImageList.Remove(imageIndex: integer); begin TIEImageListItem(m_images[imageIndex]).image.Free(); TIEImageListItem(m_images[imageIndex]).Free(); m_images.Delete(imageIndex); end; {!! TIEImageList.FillFromDirectory Declaration procedure FillFromDirectory(const Directory: WideString; Limit : integer = -1; AllowUnknownFormats : boolean = false; const ExcludeExtensions : WideString = ''; DetectFileFormat : boolean = false; const FilterMask : WideString = ''; IncludeVideoFiles : Boolean = False); Description Automatically loads all known images found in a folder. Parameter Description Directory Folder to search for files Limit The maximum number of images to load. -1 means no limit. AllowUnknownFormats If false (default) only known and supported file formats are loaded. Otherwise all files are loaded ExcludeExtensions A comma separated list of file extensions to skip (e.g. 'lyr,all,iev') DetectFileFormat If true then the image type is detected by reading the header (which can be slow). Otherwise ImageEn only checks the file extension FilterMask Limits the fill to file extensions found in a comma separated list (e.g. 'jpg,jpeg,jpe'). Empty string means "all supported extensions" bIncludeVideoFiles If AllowUnknownFormats is false then by default video files are not included. Set to true to include supported video file types such as AVI and MPEG
!!} procedure TIEImageList.FillFromDirectory(const Directory: WideString; Limit : integer = -1; AllowUnknownFormats : boolean = false; const ExcludeExtensions : WideString = ''; DetectFileFormat : boolean = false; const FilterMask : WideString = ''; IncludeVideoFiles : Boolean = False); var l: integer; fpath, fname: WideString; count: integer; sep: WideString; excList: TStringList; mskList: TStringList; dir: TIEDirContent; ext: WideString; io: TImageEnIO; bmp: TIEBitmap; begin io := nil; dir := nil; excList := TStringList.Create; mskList := TStringList.Create; try io := TImageEnIO.Create(nil); excList.CommaText := LowerCase(ExcludeExtensions); mskList.CommaText := LowerCase(FilterMask); l := length(Directory); if (l=0) or (Directory[l]='\') then sep := '' else sep := '\'; dir := TIEDirContent.Create(Directory + sep + '*.*'); count := 0; while dir.getItem(fname) do begin fpath := Directory + sep + fname; ext := IEExtractFileExtW(fname, false); if (AllowUnknownFormats or (DetectFileFormat and (FindFileFormat(fpath, ffContentOnly) <> ioUnknown)) or IsKnownFormat(fpath, IncludeVideoFiles)) and (excList.IndexOf(ext)=-1) and ((mskList.Count=0) or (mskList.IndexOf(ext)>-1)) then begin if (Limit>-1) and (count=limit) then break; bmp := TIEBitmap.Create(); io.AttachedIEBitmap := bmp; try io.LoadFromFileAuto(fpath); except end; m_images.Add(TIEImageListItem.Create(bmp, fpath)); inc(count); end; end; finally io.Free; dir.Free; mskList.Free; excList.Free; end; end; {!! TIEImageList.AppendImageRef Declaration function AppendImageRef(image:
; filename: WideString): integer; Description Appends the specified image. This method doesn't copy the bitmap, just takes ownership of the image object. Parameter Description image Image to append. filename Filename of the image.
!!} function TIEImageList.AppendImageRef(image: TIEBitmap; filename: WideString): integer; begin result := m_images.Add(TIEImageListItem.Create(image, filename)); end; {!! TIEImageList.ImageCount Declaration property ImageCount: integer; Description Returns the number of images in the list. Read-only. !!} function TIEImageList.GetImageCount(): integer; begin result := m_images.Count; end; {!! TIEImageList.Image Declaration property Image[index: integer]:
; Description Gets/sets the image at the specified index. !!} function TIEImageList.GetImage(idx: integer): TIEBitmap; begin result := TIEImageListItem(m_images[idx]).image; end; procedure TIEImageList.SetImage(idx: integer; value: TIEBitmap); begin TIEImageListItem(m_images[idx]).image.Free(); TIEImageListItem(m_images[idx]).image := value; end; {!! TIEImageList.Filename Declaration property Filename[index: integer]: WideString; Description Represents the filename of the specified image. !!} function TIEImageList.GetFilename(idx: integer): WideString; begin result := TIEImageListItem(m_images[idx]).filename; end; procedure TIEImageList.SetFilename(idx: integer; value: WideString); begin TIEImageListItem(m_images[idx]).filename := value; end; //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // TIEEquirectangularRenderer {$ifdef IEINCLUDEEQUIRECTANGULARRENDERER} {!! TIEEquirectangularRenderer.Create Declaration constructor Create(Source: ; IOParams: TObject; OwnSource: boolean); overload; constructor Create(SourceView: TObject); overload; Description Creates a new instance of the class. Parameter Description Source The source equirectangular or IOParams I/O parameters where to get XMP tags. Must be a objects OwnSource If True, the Source bitmap is freed on destroy
Example // ImageEnView1 contains the equirectangular image, while ImageEnView2 will display it ImageEnView2.IEBitmap.VirtualBitmapProvider := TIEEquirectangularRenderer.Create(ImageEnView1.IEBitmap, ImageEnView1.IO.Params, false); ImageEnView2.Update(); // Same as above ImageEnView2.IEBitmap.VirtualBitmapProvider := TIEEquirectangularRenderer.Create(ImageEnView1); ImageEnView2.Update(); !!} constructor TIEEquirectangularRenderer.Create(Source: TIEBitmap; IOParams: TObject; OwnSource: boolean); begin Init(Source, IOParams, OwnSource); end; constructor TIEEquirectangularRenderer.Create(SourceView: TObject); begin Init((SourceView as TImageEnView).IEBitmap, (SourceView as TImageEnView).IO.Params, false); end; procedure TIEEquirectangularRenderer.Init(Source: TIEBitmap; IOParams: TObject; OwnSource: boolean); var i: integer; Params: TIOParams; // XMP CroppedAreaImageWidthPixels: integer; CroppedAreaImageHeightPixels: integer; FullPanoWidthPixels: integer; FullPanoHeightPixels: integer; CroppedAreaLeftPixels: integer; CroppedAreaTopPixels: integer; PoseHeadingDegrees: double; begin inherited Create(); m_source := Source; m_ownSource := OwnSource; m_quality := ierqLow; for i := Low(m_arccos_tab) to High(m_arccos_tab) do m_arccos_tab[i] := arccos(i / 10000); // get XMP GPano parameters Params := (IOParams as TIOParams); if Params.Dict.HasKey('GPano:CroppedAreaImageWidthPixels', true) then CroppedAreaImageWidthPixels := Params.Dict.GetInteger('GPano:CroppedAreaImageWidthPixels', true) else CroppedAreaImageWidthPixels := Source.Width; if Params.Dict.HasKey('GPano:CroppedAreaImageHeightPixels', true) then CroppedAreaImageHeightPixels := Params.Dict.GetInteger('GPano:CroppedAreaImageHeightPixels', true) else CroppedAreaImageHeightPixels := Source.Height; if Params.Dict.HasKey('GPano:FullPanoWidthPixels', true) then FullPanoWidthPixels := Params.Dict.GetInteger('GPano:FullPanoWidthPixels', true) else FullPanoWidthPixels := Source.Width; if Params.Dict.HasKey('GPano:FullPanoHeightPixels', true) then FullPanoHeightPixels := Params.Dict.GetInteger('GPano:FullPanoHeightPixels', true) else FullPanoHeightPixels := Source.Height; if Params.Dict.HasKey('GPano:CroppedAreaLeftPixels', true) then CroppedAreaLeftPixels := Params.Dict.GetInteger('GPano:CroppedAreaLeftPixels', true) else CroppedAreaLeftPixels := 0; if Params.Dict.HasKey('GPano:CroppedAreaTopPixels', true) then CroppedAreaTopPixels := Params.Dict.GetInteger('GPano:CroppedAreaTopPixels', true) else CroppedAreaTopPixels := 0; if Params.Dict.HasKey('GPano:PoseHeadingDegrees', true) then PoseHeadingDegrees := Params.Dict.GetDouble('GPano:PoseHeadingDegrees', true) else PoseHeadingDegrees := 90.0; // in case source image has wrong size (resized?) Source.Resample(CroppedAreaImageWidthPixels, CroppedAreaImageHeightPixels); // expand to full pano Source.Resize(FullPanoWidthPixels, FullPanoHeightPixels, clBlack); Source.MoveRegion(0, 0, CroppedAreaImageWidthPixels - 1, CroppedAreaImageHeightPixels - 1, CroppedAreaLeftPixels, CroppedAreaTopPixels, clBlack); m_cam_heading := PoseHeadingDegrees; m_cam_pitch := 90.0; m_cam_fov := 90.0; end; destructor TIEEquirectangularRenderer.Destroy(); begin FreeAndNil(m_segmentBuffer); if m_ownSource then m_source.Free(); inherited; end; function TIEEquirectangularRenderer.GetSegment(Container: TIEBitmap; Row: integer; Col: integer; Width: integer): pointer; var i: integer; SrcCols: array of integer; SrcRows: integer; begin if (m_segmentBuffer.Width <> Width) or (m_segmentBuffer.Height <> 1) then m_segmentBuffer.Allocate(Width, 1); SetLength(SrcCols, Width); for i := 0 to Width - 1 do SrcCols[i] := Col + i; SrcRows := Row; Render(Container, m_segmentBuffer, Width, 1, 0, 0, Width - 1, 0, @SrcCols[0], @SrcRows, 255, ielNormal, 1.0); result := m_segmentBuffer.ScanLine[0]; end; function arctan2opt(y: double; x: double ): double; const ONEQTR_PI = PI / 4.0; THRQTR_PI = 3.0 * PI / 4.0; var r, angle, abs_y: double; begin abs_y := abs(y) {+ 1e-10}; // kludge to prevent 0/0 condition if ( x < 0.0 ) then begin r := (x + abs_y) / (abs_y - x); angle := THRQTR_PI; end else begin r := (x - abs_y) / (x + abs_y); angle := ONEQTR_PI; end; angle := angle + (0.1963 * r * r - 0.9817) * r; if ( y < 0.0 ) then result := -angle // negate if in quad III or IV else result := angle; end; procedure TIEEquirectangularRenderer.Render(Container: TIEBitmap; DestBitmap: TIEBitmap; DestWidth: integer; DestHeight: integer; DestX1, DestY1, DestX2, DestY2: integer; SrcCols, SrcRows: PInteger; Transparency: integer; RenderOperation: TIERenderOperation; Opacity: double); begin case m_quality of ierqLow: RenderLowQuality(Container, DestBitmap, DestWidth, DestHeight, DestX1, DestY1, DestX2, DestY2, SrcCols, SrcRows, Transparency, RenderOperation, Opacity); ierqHigh: RenderHighQuality(Container, DestBitmap, DestWidth, DestHeight, DestX1, DestY1, DestX2, DestY2, SrcCols, SrcRows, Transparency, RenderOperation, Opacity); end; end; procedure TIEEquirectangularRenderer.RenderHighQuality(Container: TIEBitmap; DestBitmap: TIEBitmap; DestWidth: integer; DestHeight: integer; DestX1, DestY1, DestX2, DestY2: integer; SrcCols, SrcRows: PInteger; Transparency: integer; RenderOperation: TIERenderOperation; Opacity: double); const DEG2RAD = PI / 180.0; var src_width, src_height: integer; dest_width, dest_height: integer; theta_fac, phi_fac: double; ratioUp, ratioRight: double; camDirX, camDirY, camDirZ: double; camUpX, camUpY, camUpZ: double; camRightX, camRightZ: double; camPlaneOriginX, camPlaneOriginY, camPlaneOriginZ: double; fy_camUpX, fy_camUpZ, fy_camUpY: double; i, j: integer; fx, fy: double; rayX, rayY, rayZ: double; rayNorm: double; theta, phi: double; theta_i, phi_i: integer; pxdst, pxsrc: PRGB; begin if (m_source.Width = 0) or (m_source.Height = 0) or (m_source.PixelFormat <> ie24RGB) then exit; src_width := m_source.Width; src_height := m_source.Height; dest_width := DestWidth; dest_height := DestHeight; theta_fac := src_height / PI; phi_fac := src_width * 0.5 / PI; ratioUp := 2.0 * tan(m_cam_fov * DEG2RAD / 2.0); ratioRight := ratioUp * 1.33; camDirX := sin(m_cam_pitch * DEG2RAD) * sin(m_cam_heading * DEG2RAD); camDirY := cos(m_cam_pitch * DEG2RAD); camDirZ := sin(m_cam_pitch * DEG2RAD) * cos(m_cam_heading * DEG2RAD); camUpX := ratioUp * sin((m_cam_pitch - 90.0) * DEG2RAD) * sin(m_cam_heading * DEG2RAD); camUpY := ratioUp * cos((m_cam_pitch - 90.0) * DEG2RAD); camUpZ := ratioUp * sin((m_cam_pitch - 90.0) * DEG2RAD) * cos(m_cam_heading * DEG2RAD); camRightX := ratioRight * sin((m_cam_heading - 90.0) * DEG2RAD); camRightZ := ratioRight * cos((m_cam_heading - 90.0) * DEG2RAD); camPlaneOriginX := camDirX + 0.5 * camUpX - 0.5 * camRightX; camPlaneOriginY := camDirY + 0.5 * camUpY; camPlaneOriginZ := camDirZ + 0.5 * camUpZ - 0.5 * camRightZ; for i := DestY1 to DestY2 do begin pxdst := DestBitmap.ScanLine[i]; fy := i / dest_height; fy_camUpX := fy * camUpX; fy_camUpZ := fy * camUpZ; fy_camUpY := fy * camUpY; rayY := camPlaneOriginY - fy_camUpY; for j := DestX1 to DestX2 do begin fx := j / dest_width; rayX := camPlaneOriginX + fx * camRightX - fy_camUpX; rayZ := camPlaneOriginZ + fx * camRightZ - fy_camUpZ; rayNorm := 1.0 / sqrt(rayX * rayX + rayY * rayY + rayZ * rayZ); theta := arccos(rayY * rayNorm); phi := arctan2opt(rayZ, rayX) + PI; theta_i := floor(theta_fac * theta); phi_i := floor(phi_fac * phi); pxsrc := m_source.ScanLine[theta_i]; inc(pxsrc, phi_i); pxdst^.r := pxsrc^.r; pxdst^.g := pxsrc^.g; pxdst^.b := pxsrc^.b; inc(pxdst); end; end; end; procedure TIEEquirectangularRenderer.RenderLowQuality(Container: TIEBitmap; DestBitmap: TIEBitmap; DestWidth: integer; DestHeight: integer; DestX1, DestY1, DestX2, DestY2: integer; SrcCols, SrcRows: PInteger; Transparency: integer; RenderOperation: TIERenderOperation; Opacity: double); const DEG2RAD = PI / 180.0; var src_width, src_height: integer; dest_width, dest_height: integer; theta_fac, phi_fac: double; ratioUp, ratioRight: double; camDirX, camDirY, camDirZ: double; camUpX, camUpY, camUpZ: double; camRightX, camRightZ: double; camPlaneOriginX, camPlaneOriginY, camPlaneOriginZ: double; fy_camUpX, fy_camUpZ, fy_camUpY: double; i, j: integer; fx, fy: double; rayX, rayY, rayZ: double; rayNorm: double; phi: double; theta_i, phi_i: integer; pxdst, pxsrc: PRGB; begin if (m_source.Width = 0) or (m_source.Height = 0) or (m_source.PixelFormat <> ie24RGB) then exit; src_width := m_source.Width; src_height := m_source.Height; dest_width := DestWidth; dest_height := DestHeight; theta_fac := src_height / PI; phi_fac := src_width * 0.5 / PI; ratioUp := 2.0 * tan(m_cam_fov * DEG2RAD / 2.0); ratioRight := ratioUp * 1.33; camDirX := sin(m_cam_pitch * DEG2RAD) * sin(m_cam_heading * DEG2RAD); camDirY := cos(m_cam_pitch * DEG2RAD); camDirZ := sin(m_cam_pitch * DEG2RAD) * cos(m_cam_heading * DEG2RAD); camUpX := ratioUp * sin((m_cam_pitch - 90.0) * DEG2RAD) * sin(m_cam_heading * DEG2RAD); camUpY := ratioUp * cos((m_cam_pitch - 90.0) * DEG2RAD); camUpZ := ratioUp * sin((m_cam_pitch - 90.0) * DEG2RAD) * cos(m_cam_heading * DEG2RAD); camRightX := ratioRight * sin((m_cam_heading - 90.0) * DEG2RAD); camRightZ := ratioRight * cos((m_cam_heading - 90.0) * DEG2RAD); camPlaneOriginX := camDirX + 0.5 * camUpX - 0.5 * camRightX; camPlaneOriginY := camDirY + 0.5 * camUpY; camPlaneOriginZ := camDirZ + 0.5 * camUpZ - 0.5 * camRightZ; for i := DestY1 to DestY2 do begin pxdst := DestBitmap.ScanLine[i]; fy := i / dest_height; fy_camUpX := fy * camUpX; fy_camUpZ := fy * camUpZ; fy_camUpY := fy * camUpY; rayY := camPlaneOriginY - fy_camUpY; for j := DestX1 to DestX2 do begin fx := j / dest_width; rayX := camPlaneOriginX + fx * camRightX - fy_camUpX; rayZ := camPlaneOriginZ + fx * camRightZ - fy_camUpZ; rayNorm := 1.0 / sqrt(rayX * rayX + rayY * rayY + rayZ * rayZ); phi := arctan2opt(rayZ, rayX) + PI; theta_i := trunc(theta_fac * m_arccos_tab[trunc(rayY * rayNorm * 10000)]); phi_i := trunc(phi_fac * phi); pxsrc := m_source.ScanLine[theta_i]; inc(pxsrc, phi_i); pxdst^.r := pxsrc^.r; pxdst^.g := pxsrc^.g; pxdst^.b := pxsrc^.b; inc(pxdst); end; end; end; {$endif} //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // TIESlippyMap {$ifdef IEINCLUDESLIPPYMAP} procedure TIESlippyMap.init(const providerURL: string; const cachePath: string); begin m_maxThreads := 0; m_providerURL := providerURL; m_providerURLIndex := 0; m_loadQueue := TList.Create(); m_cachePath := cachePath; m_segmentBuffer := TIEBitmap.Create(); m_latitude := 40.60204565419533; m_longitude := -74.00844298675537; m_zoom := 14; m_memoryCache := TList.Create(); m_memoryCacheSize := 50; m_pointPosition := Point(0, 0); m_userKey := ''; m_missingTileColor := TRGB2TColor(CreateRGB(203, 233, 255)); end; {!! TIESlippyMap.Create Declaration constructor Create(provider: = iesmpMapQuest; const cachePath: string = ''); constructor Create(const providerURL: string; const cachePath: string = ''); Description Creates a TIESlippyMap object. Parameter Description provider Predefined map provider. providerURL URL of map provider. Ex. 'http://[abc].tile.openstreetmap.org'. cachePath Optional path of local cache.
Example // create a slippymap using default provider ImageEnView1.IEBitmap.VirtualBitmapProvider := TIESlippyMap.Create(); // create a slippymap using iesmpOSM_Mapnik provider ImageEnView1.IEBitmap.VirtualBitmapProvider := TIESlippyMap.Create(iesmpOSM_Mapnik); // create a slippymap using 'http://[abc].tile.openstreetmap.org' and local cache ImageEnView1.IEBitmap.VirtualBitmapProvider := TIESlippyMap.Create('http://[abc].tile.openstreetmap.org', 'C:\mapcache'); !!} constructor TIESlippyMap.Create(const providerURL: string; const cachePath: string); begin inherited Create(); init(providerURL, cachePath); end; constructor TIESlippyMap.Create(provider: TIESlippyMapProvider; const cachePath: string); const providers: array [TIESlippyMapProvider] of string = ('http://[abc].tile.openstreetmap.org', 'http://[abc].tile.opencyclemap.org/cycle', 'http://[abc].tile2.opencyclemap.org/transport', 'http://[abc].tile.cloudmade.com/$0/1/256', 'http://[abc].tile.cloudmade.com/$0/2/256', 'http://[abc].tile.cloudmade.com/$0/3/256', 'http://otile[1234].mqcdn.com/tiles/1.0.0/osm', 'http://oatile[1234].mqcdn.com/naip', 'http://tile.stamen.com/terrain-background'); begin inherited Create(); init(providers[provider], cachePath); end; destructor TIESlippyMap.Destroy(); begin ClearLoadQueue(); m_loadQueue.Free(); ClearMemoryCache(); m_memoryCache.Free(); FreeAndNil(m_segmentBuffer); inherited; end; procedure TIESlippyMap.ClearLoadQueue(); begin m_loadQueue.Clear(); end; procedure TIESlippyMap.ClearMemoryCache(); var i: integer; begin for i := 0 to m_memoryCache.Count - 1 do TIESlippyMapQueueItem(m_memoryCache[i]).Free(); m_memoryCache.Clear(); end; procedure TIESlippyMap.SetLatitude(value: double); begin if value < -85.0 then m_latitude := -85.0 else if value > 85.0 then m_latitude := 85.0 else m_latitude := value; end; procedure TIESlippyMap.SetLongitude(value: double); begin if value < -180.0 then m_longitude := -180.0 else if value > 180.0 then m_longitude := 180.0 else m_longitude := value; end; function TIESlippyMap.GetProviderURLCount(): integer; var p1, p2: integer; begin p1 := Pos('[', m_providerURL); p2 := Pos(']', m_providerURL); if (p1 > 0) and (p2 > 0) and (p1 < p2) then result := p2 - p1 - 1 else result := 1; end; function TIESlippyMap.GetProviderURL(): string; var p1, p2: integer; c: char; begin // no cache, direct download p1 := Pos('[', m_providerURL); p2 := Pos(']', m_providerURL); if (p1 > 0) and (p2 > 0) and (p1 < p2) then begin // select mirror c := m_providerURL[p1 + 1 + m_providerURLIndex]; inc(m_providerURLIndex); if m_providerURLIndex = (p2 - p1 - 1) then m_providerURLIndex := 0; result := Copy(m_providerURL, 1, p1 - 1) + c + Copy(m_providerURL, p2 + 1, length(m_providerURL)); // add optional user key p1 := Pos('$0', result); if p1 > 0 then result := Copy(result, 1, p1 - 1) + m_userKey + Copy(result, p1+2, length(result)); end else result := m_providerURL; end; function TIESlippyMap.GetCachedFileName(tileX: integer; tileY: integer): string; var i: integer; begin if not IEDirectoryExists(m_cachePath) then IEForceDirectories(m_cachePath); result := Format('\%s_%d_%d_%d.png', [m_providerURL, m_zoom, tileX, tileY]); for i := 1 to length(result) do if (result[i] = ':') or (result[i] = '/') then result[i] := '_'; result := m_cachePath + result; end; function TIESlippyMap.GetFileURL(tileX: integer; tileY: integer): string; var fpath: string; begin result := Format('%s/%d/%d/%d.png', [GetProviderURL(), m_zoom, tileX, tileY]); if m_cachePath <> '' then begin fpath := GetCachedFileName(tileX, tileY); if IEFileExists(fpath) then result := fpath; end; end; class function TIESlippyMap.LongitudeToTileX(longitude: double; zoom: integer): integer; begin result := Floor((longitude + 180.0) / 360.0 * Power(2.0, zoom)); end; class function TIESlippyMap.LatitudeToTileY(latitude: double; zoom: integer): integer; begin result := Floor((1.0 - ln( tan(latitude * PI/180.0) + 1.0 / cos(latitude * PI/180.0)) / PI) / 2.0 * Power(2.0, zoom)); end; class function TIESlippyMap.TileXToLongitude(tileX: integer; zoom: integer): double; begin result := tileX / Power(2.0, zoom) * 360.0 - 180; end; class function TIESlippyMap.TileYToLatitude(tileY: integer; zoom: integer): double; var n: double; begin n := PI - 2.0 * PI * tileY / Power(2.0, zoom); result := 180.0 / PI * arctan(0.5 * (exp(n) - exp(-n))); end; class function TIESlippyMap.CoordXToLongitude(coordX: integer; tileX: integer; zoom: integer): double; begin result := (tileX + coordX / 256) / Power(2.0, zoom); result := + (result * 2 - 1) * PI; result := result / PI * 180.0; end; class function TIESlippyMap.CoordYToLatitude(coordY: integer; tileY: integer; zoom: integer): double; begin result := (tileY + coordY / 256) / Power(2.0, zoom); result := - (result * 2 - 1) * PI; result := 2 * arctan(exp(result)) - PI / 2; result := result / PI * 180.0; end; class function TIESlippyMap.LongitudeToCoordX(longitude: double; zoom: integer): integer; var x: double; begin x := longitude * PI / 180.0; // to radians x := (1.0 + (x / PI)) / 2.0; result := Floor(Frac(x * Power(2.0, zoom)) * 256); end; class function TIESlippyMap.LatitudeToCoordY(latitude: double; zoom: integer): integer; var y: double; begin y := latitude * PI / 180.0; // to radians y := ln(tan(y) + 1.0 / cos(y)); y := (1.0 - (y / PI)) / 2.0; result := Floor(Frac(y * Power(2.0, zoom)) * 256); end; procedure TIESlippyMap.AddItemToMemoryCache(item: TIESlippyMapQueueItem); var i: integer; canRemove: boolean; begin if (m_memoryCache.Count = m_memoryCacheSize) and (m_memoryCache.Count > m_loadQueue.Count) then begin canRemove := true; for i := 0 to m_loadQueue.Count - 1 do if m_loadQueue[i] = item then begin canRemove := false; break; end; if canRemove then begin TIESlippyMapQueueItem(m_memoryCache[0]).Free(); m_memoryCache.Delete(0); end; end; m_memoryCache.Add(item); end; procedure TIESlippyMap.AddTileToLoadQueue(tile: TPoint; destBitmap: TIEBitmap; destPos: TPoint); var itm: TIESlippyMapQueueItem; i: integer; begin for i := 0 to m_memoryCache.Count - 1 do begin itm := TIESlippyMapQueueItem(m_memoryCache[i]); if (itm.tile.X = tile.X) and (itm.tile.Y = tile.Y) and (itm.zoom = m_zoom) then begin itm.destBitmap := destBitmap; itm.destPos := destPos; m_loadQueue.Add(itm); ProcessQueue(); exit; end; end; itm := TIESlippyMapQueueItem.Create(tile, m_zoom, destBitmap, destPos); m_loadQueue.Add(itm); AddItemToMemoryCache(itm); ProcessQueue(); end; function TIESlippyMap.WrapHorizTile(tileX: integer): integer; var maxTiles: integer; begin result := tileX; maxTiles := trunc(Power(2.0, m_zoom)); if result >= maxTiles then result := result mod maxTiles; if result < 0 then result := maxTiles + (result mod maxTiles); end; // ret True if it needs to be re-called to process other items function TIESlippyMap.ProcessQueue(): boolean; var i: integer; cntMax: integer; itm: TIESlippyMapQueueItem; cachedFileName: string; maxTiles: integer; itm_io: TImageEnIO; begin result := false; for i := m_loadQueue.Count - 1 downto 0 do begin itm := TIESlippyMapQueueItem(m_loadQueue[i]); itm_io := TImageEnIO(itm.io); if (itm.state = iesmqLOAD) and (itm_io.AsyncRunning = 0) then begin // loading finished if itm_io.Aborting then begin // unable to retrieve image, set all black itm.bmp.Allocate(256, 256, ie24RGB); itm.bmp.Fill(m_missingTileColor); end; if assigned(itm.destBitmap) then itm.bmp.CopyRectTo(itm.destBitmap, 0, 0, itm.destPos.X, itm.destPos.Y, 256, 256, false); itm.state := iesmqEND; if not itm_io.Aborting and (m_CachePath <> '') then begin cachedFileName := GetCachedFileName(itm.tile.X, itm.tile.Y); if cachedFileName <> itm_io.Params.FileName then begin itm_io.SaveToFile(cachedFileName); itm.state := iesmqSAVE; end; end; end else if (itm.state = iesmqSAVE) and (itm_io.AsyncRunning = 0) then begin // saving finished, can end itm.state := iesmqEND; end; if itm.state <> iesmqEND then result := true; end; if not result then exit; if m_maxThreads = 0 then cntMax := imin(m_loadQueue.Count, GetProviderURLCount()) else cntMax := imin(m_loadQueue.Count, m_maxThreads); maxTiles := trunc(Power(2.0, m_zoom)); for i := 0 to m_loadQueue.Count - 1 do begin itm := TIESlippyMapQueueItem(m_loadQueue[i]); if (itm.state = iesmqWAIT) then begin if (itm.tile.Y < 0) or (itm.tile.Y >= maxTiles) then begin itm.io := TImageEnIO.CreateFromBitmap(itm.bmp); TImageEnIO(itm.io).Aborting := true; itm.state := iesmqLOAD; end else begin itm.io := TImageEnIO.CreateFromBitmap(itm.bmp); TImageEnIO(itm.io).AsyncMode := true; TImageENIO(itm.io).LoadFromFile( GetFileURL(WrapHorizTile(itm.tile.X), itm.tile.Y) ); itm.state := iesmqLOAD; dec(cntMax); end; end else if (itm.state <> iesmqEND) then dec(cntMax); if (cntMax = 0) then break; end; end; procedure TIESlippyMap.WaitLoadQueue(); begin if assigned( m_OnBeginWork ) then m_OnBeginWork( Self ); if ProcessQueue() then while ProcessQueue() do sleep(10); if assigned( m_OnFinishWork ) then m_OnFinishWork( Self ); end; procedure TIESlippyMap.CalcTopLeftTileAndPos(var startTile: TPoint; var startPos: TPoint); var coordX, coordY: integer; v: integer; begin // calc position inside the tile coordX := LongitudeToCoordX(m_longitude, m_zoom); coordY := LatitudeToCoordY(m_latitude, m_zoom); // find top-left position and tile startTile.X := LongitudeToTileX(m_longitude, m_zoom); startTile.Y := LatitudeToTileY(m_latitude, m_zoom); startPos.X := m_pointPosition.X - coordX; startPos.Y := m_pointPosition.Y - coordY; v := ceil(startPos.X / 256.0); dec(startTile.X, v); dec(startPos.X, v * 256); v := ceil(startPos.Y / 256.0); dec(startTile.Y, v); dec(startPos.Y, v * 256); end; {!! TIESlippyMap.Render Declaration procedure TIESlippyMap.Render(Container:
; DestWidth: integer; DestHeight: integer; DestScanlines: ; DestX1, DestY1, DestX2, DestY2: integer; SrcCols, SrcRows: PInteger; Transparency: integer; RenderOperation: ; Opacity: double); Description Implements the Render method of abstract parent class. Applications should not use this method. Opacity vs Transparency Both the Opacity and Transparency parameters provide the same functionality. Transparency is the traditional ImageEn value, whereas Opacity provides easier PSD compatibility. While they can be used in combination, generally only one will be used, i.e. leave Opacity=1 and make use of transparency, or alternatively, leave Transparency=255 and make use of Opacity. For example, for 50% opacity: Transparency = 255 and Opacity = 0.5, or Transparency = 128 and Opacity = 1.0 !!} procedure TIESlippyMap.Render(Container: TIEBitmap; DestBitmap: TIEBitmap; DestWidth: integer; DestHeight: integer; DestX1, DestY1, DestX2, DestY2: integer; SrcCols, SrcRows: PInteger; Transparency: integer; RenderOperation: TIERenderOperation; Opacity: double); var row, col: integer; destpx: PRGB; srcpos: PInteger; x, y: integer; xx, yy: integer; t: TPoint; startPos: TPoint; startTile: TPoint; itm: TIESlippyMapQueueItem; w: integer; tIdx: integer; begin // get starting tile and pos CalcTopLeftTileAndPos(startTile, startPos); // load tiles from top-left ClearLoadQueue(); w := 0; t.Y := startTile.Y; y := startPos.Y; while (y < Container.Height) do begin t.X := startTile.X; x := startPos.X; w := 0; while (x < Container.Width) do begin AddTileToLoadQueue(t, nil, Point(x, y)); inc(x, 256); inc(t.X); inc(w); end; inc(y, 256); inc(t.Y); end; WaitLoadQueue(); // render requested area for row := DestY1 to DestY2 do begin destpx := DestBitmap.ScanLine[row]; inc(destpx, DestX1); srcpos := SrcCols; for col := DestX1 to DestX2 do begin x := (srcpos^ - startPos.X) div 256; y := (SrcRows^ - startPos.Y) div 256; tIdx := x + y * w; if (tIdx >= 0) and (tIdx < m_loadQueue.Count) then begin itm := TIESlippyMapQueueItem(m_loadQueue[tIdx]); xx := (srcpos^ - startPos.X) - x * 256; yy := (SrcRows^ - startPos.Y) - y*256; destpx^ := itm.bmp.Pixels_ie24RGB[xx, yy]; end else begin destpx^.r := 0; destpx^.g := 0; destpx^.b := 0; end; inc(srcpos); inc(destpx); end; inc(SrcRows); end; end; {!! TIESlippyMap.GetSegment Declaration function GetSegment(Container: ; Row: integer; Col: integer; Width: integer): pointer; Description Implements the GetSegment method of abstract parent class. Applications should not use this method. !!} function TIESlippyMap.GetSegment(Container: TIEBitmap; Row: integer; Col: integer; Width: integer): pointer; var i: integer; SrcCols: array of integer; SrcRows: integer; begin if (m_segmentBuffer.Width <> Width) or (m_segmentBuffer.Height <> 1) then m_segmentBuffer.Allocate(Width, 1); SetLength(SrcCols, Width); for i := 0 to Width - 1 do SrcCols[i] := Col + i; SrcRows := Row; Render(Container, m_segmentBuffer, Width, 1, 0, 0, Width - 1, 0, @SrcCols[0], @SrcRows, 255, ielNormal, 1.0); result := m_segmentBuffer.ScanLine[0]; end; {!! TIESlippyMap.DrawTo Declaration procedure DrawTo(destBitmap: ); Description Draws the map to the specified TIEBitmap object. Parameter Description destBitmap Destination TIEBitmap object.
Example var map: TIESlippyMap; begin map := TIESlippyMap.Create(); try map.Latitude := 51.503614574056016; map.Longitude := -0.12774750793460043; map.PointPosition := Point(ImageEnView1.IEBitmap.Width div 2, ImageEnView1.IEBitmap.Height div 2); map.Zoom := 13; map.DrawTo( ImageEnView1.IEBitmap ); ImageEnView1.Update(); finally map.Free(); end; end; !!} procedure TIESlippyMap.DrawTo(destBitmap: TIEBitmap); var x, y: integer; t: TPoint; maxTiles: integer; startPos: TPoint; startTile: TPoint; begin maxTiles := trunc(Power(2.0, m_zoom)); // get starting tile and pos CalcTopLeftTileAndPos(startTile, startPos); // draw tiles from top-left ClearLoadQueue(); t.Y := startTile.Y; y := startPos.Y; while (y < destBitmap.Height) and (t.Y < maxTiles) do begin t.X := startTile.X; x := startPos.X; while (x < destBitmap.Width) and (t.X < maxTiles) do begin if (t.X >= 0) and (t.Y >= 0) then AddTileToLoadQueue(t, destBitmap, Point(x, y)); inc(x, 256); inc(t.X); end; inc(y, 256); inc(t.Y); end; WaitLoadQueue(); end; {!! TIESlippyMap.BmpXToLongitude Declaration function BmpXToLongitude(X: integer): double; Description Converts from horizontal bitmap coordinates to longitude (decimal degrees). This conversion depends by current
, , and . Parameter Description X Bitmap column relative to top-left position.
Example // handles OnMouseMove and gets latitude and longitude under the mouse position procedure TForm1.ImageEnView1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var bmpX, bmpY: integer; longitude, latitude: double; begin bmpX := ImageEnView1.XScr2Bmp(X); bmpY := ImageEnView1.YScr2Bmp(Y); longitude := TIESlippyMap(ImageEnView1.IEBitmap.VirtualBitmapProvider).BmpXToLongitude(bmpX); latitude := TIESlippyMap(ImageEnView1.IEBitmap.VirtualBitmapProvider).BmpYToLatitude(bmpY); end; See Also -
- - !!} function TIESlippyMap.BmpXToLongitude(X: integer): double; var startTile, startPos: TPoint; begin CalcTopLeftTileAndPos(startTile, startPos); result := CoordXToLongitude(X - startPos.X, startTile.X, m_zoom) end; {!! TIESlippyMap.BmpYToLatitude Declaration function BmpYToLatitude(Y: integer): double; Description Converts from vertical bitmap coordinates to latitude (decimal degrees). This conversion depends by current , , and . Parameter Description Y Bitmap row relative to top-left position.
Example // handles OnMouseMove and gets latitude and longitude under the mouse position procedure TForm1.ImageEnView1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var bmpX, bmpY: integer; longitude, latitude: double; begin bmpX := ImageEnView1.XScr2Bmp(X); bmpY := ImageEnView1.YScr2Bmp(Y); longitude := TIESlippyMap(ImageEnView1.IEBitmap.VirtualBitmapProvider).BmpXToLongitude(bmpX); latitude := TIESlippyMap(ImageEnView1.IEBitmap.VirtualBitmapProvider).BmpYToLatitude(bmpY); end; See Also -
- - !!} function TIESlippyMap.BmpYToLatitude(Y: integer): double; var startTile, startPos: TPoint; begin CalcTopLeftTileAndPos(startTile, startPos); result := CoordYToLatitude(Y - startPos.Y, startTile.Y, m_zoom) end; {!! TIESlippyMap.LongitudeToBmpX Declaration function LongitudeToBmpX(lon: double): integer; Description Converts from longitude to bitmap horizontal position. This conversion depends by current , , and . Parameter Description lon Longitude in decimal degrees.
See Also -
- - !!} function TIESlippyMap.LongitudeToBmpX(lon: double): integer; var startTile, startPos: TPoint; begin CalcTopLeftTileAndPos(startTile, startPos); result := (LongitudeToTileX(lon, m_zoom) - startTile.X) * 256 + startPos.X + LongitudeToCoordX(lon, m_zoom); end; {!! TIESlippyMap.LatitudeToBmpY Declaration function LatitudeToBmpY(lat: double): integer; Description Converts from latitude to bitmap vertical position. This conversion depends by current , , and . Parameter Description lat Latitude in decimal degrees.
See Also -
- - !!} function TIESlippyMap.LatitudeToBmpY(lat: double): integer; var startTile, startPos: TPoint; begin CalcTopLeftTileAndPos(startTile, startPos); result := (LatitudeToTileY(lat, m_zoom) - startTile.Y) * 256 + startPos.Y + LatitudeToCoordY(lat, m_zoom); end; constructor TIESlippyMapQueueItem.Create(tile_: TPoint; zoom_: integer; destBitmap_: TIEBitmap; destPos_: TPoint); begin inherited Create(); tile := tile_; zoom := zoom_; destBitmap := destBitmap_; destPos := destPos_; io := nil; bmp := TIEBitmap.Create(256, 256); state := iesmqWAIT; end; destructor TIESlippyMapQueueItem.Destroy(); begin io.Free(); bmp.Free(); inherited; end; {$endif} //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // TIEVCLStreamProvider {$ifdef IEVISION} constructor TIEVCLStreamProvider.Create(Stream: TStream); begin m_stream := Stream; end; destructor TIEVCLStreamProvider.Destroy; begin inherited; end; function TIEVCLStreamProvider.size(): int64; begin result := m_stream.Size; end; procedure TIEVCLStreamProvider.seek(offset: int64; whence: TIEVisionSeekOffset); begin case whence of // set absolute position ievSET: m_stream.Seek(offset, soBeginning); // set from current position ievCUR: m_stream.Seek(offset, soCurrent); // set from the end ievEND: m_stream.Seek(offset, soEnd); end; end; function TIEVCLStreamProvider.tell(): int64; begin result := m_stream.Position; end; function TIEVCLStreamProvider.silent_read(ptr: pointer; size: int64): int64; begin try result := m_stream.Read(pbyte(ptr)^, size); except result := 0; end; end; function TIEVCLStreamProvider.silent_write(ptr: pointer; size: int64): int64; begin try result := m_stream.Write(pbyte(ptr)^, size); except result := 0; end; end; function TIEVCLStreamProvider.silent_getc(): int32_t; var b: byte; begin try if m_stream.Read(b, 1) = 0 then result := -1 else result := b; except result := -1; end; end; function TIEVCLStreamProvider.eof(): bool32; begin result := (m_stream.Position = m_stream.Size); end; {$endif} // IEVISION //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // 0 = wrong tag type function IETIFFCalcTagSize(tagType: integer): word; const TIFFTAGSIZE: array [IETIFFTYPE_BYTE..IETIFFTYPE_IFD8] of word = ( 1, // 1 = IETIFFTYPE_BYTE 1, // 2 = IETIFFTYPE_ASCII 2, // 3 = IETIFFTYPE_SHORT 4, // 4 = IETIFFTYPE_LONG 8, // 5 = IETIFFTYPE_RATIONAL 1, // 6 = IETIFFTYPE_SBYTE 1, // 7 = IETIFFTYPE_UNDEFINED 2, // 8 = IETIFFTYPE_SSHORT 4, // 9 = IETIFFTYPE_SLONG 8, // 10 = IETIFFTYPE_SRATIONAL 4, // 11 = IETIFFTYPE_FLOAT 8, // 12 = IETIFFTYPE_DOUBLE 4, // 13 = IETIFFTYPE_IFDPOINTER 1, // 14 = IETIFFTYPE_UNICODE 1, // 15 = IETIFFTYPE_COMPLEX 8, // 16 = IETIFFTYPE_LONG8 8, // 17 = IETIFFTYPE_SLONG8 8 // 18 = IETIFFTYPE_IFD8 ); begin if (tagType >= IETIFFTYPE_BYTE) and (tagType <= IETIFFTYPE_IFD8) then result := TIFFTAGSIZE[tagType] else result := 0; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// {!! TIOParams.Create Declaration constructor Create(AttachTo: TObject = nil); Description A TIOParams object is automatically created by the TImageEnIO component and optionally by a TIEBitmap if is True. AttachTo can be a or !!} constructor TIOParams.Create(AttachTo: TObject = nil); begin inherited Create; if AttachTo is TImageEnIO then fAttachedTo := AttachTo else if AttachTo is TIEBitmap then fAttachedTo := AttachTo else fAttachedTo := nil; fDict := TIEDictionary.Create(); fColorMap := nil; fEXIF_Bitmap := nil; fJPEG_MarkerList := TIEMarkerList.Create; fIPTC_Info := TIEIPTCInfoList.Create; fPXM_Comments := TStringList.Create; fGIF_Comments := TStringList.Create; fPNG_TextKeys := TStringList.Create; fPNG_TextValues := TStringList.Create; {$ifdef IEINCLUDEDICOM} fDICOM_Tags := TIEDicomTags.Create; {$endif} {$ifdef IEINCLUDEIMAGINGANNOT} fImagingAnnot := nil; {$endif} fImageEnAnnot := TIEImageEnAnnot.Create(self); fInputICC := nil; fOutputICC := nil; fDefaultICC := nil; fEXIF_MakerNote := TIETagsHandler.Create; fEXIF_Tags := TList.Create; SetDefaultParams; end; destructor TIOParams.Destroy; begin FreeAndNil(fEXIF_Tags); FreeAndNil(fEXIF_MakerNote); if assigned(fEXIF_Bitmap) then FreeAndNil(fEXIF_Bitmap); if ColorMap <> nil then freemem(ColorMap); FreeAndNil(fJPEG_MarkerList); FreeAndNil(fIPTC_Info); {$ifdef IEINCLUDEIMAGINGANNOT} if assigned(fImagingAnnot) then FreeAndNil(fImagingAnnot); {$endif} FreeAndNil(fImageEnAnnot); FreeAndNil(fPXM_Comments); FreeAndNil(fGIF_Comments); FreeAndNil(fPNG_TextKeys); FreeAndNil(fPNG_TextValues); {$ifdef IEINCLUDEDICOM} FreeAndNil(fDICOM_Tags); {$endif} if assigned(fInputICC) then FreeAndNil(fInputICC); if assigned(fOutputICC) then FreeAndNil(fOutputICC); if assigned(fDefaultICC) then FreeAndNil(fDefaultICC); FreeAndNil(fDict); inherited; end; procedure TIOParams.FreeColorMap; begin if fColorMap <> nil then freemem(fColorMap); fColorMap := nil; fColorMapCount := 0; end; {!! TIOParams.ClearIPTCField Declaration procedure ClearIPTCField(iRecNo, iFieldIndex: Integer); Description Remove the specified field from the IPTC field list. Example // Clear all IPTC keywords of a file AnImageEnIO.Params.ClearIPTCField(PhotoShop_IPTC_Records, IPTC_PS_Keywords); See Also - Photoshop IPTC consts - - !!} procedure TIOParams.ClearIPTCField(iRecNo, iFieldIndex: Integer); var Idx: Integer; I: Integer; begin Idx := IPTC_Info.IndexOf(iRecNo, iFieldIndex); if Idx >= 0 then begin for I := IPTC_Info.count - 1 downto idx do begin if (IPTC_Info.RecordNumber[i] = iRecNo) and (IPTC_Info.DataSet[i] = iFieldIndex) then IPTC_Info.DeleteItem(i); end; end; end; {!! TidyIPTCStr Declaration function TidyIPTCStr(const Value: string): string; Description Removes the extraneous characters often found in IPTC data, such as null terminators. Examples sDescription := TidyIPTCStr( AnImageEnIO.Params.IPTC_Info.StringItem[iCaption] ); !!} function TidyIPTCStr(const Value: string): string; begin Result := Value; // Often includes a null terminator while (result <> '') and (result[length(result)] = #0) do setlength(result, length(result) - 1); // Remove #$D which appear in many photoshop descriptions result := StringReplace(Result, #$D, ' ', [rfReplaceAll]); end; {!! TIOParams.ReadIPTCField Declaration function ReadIPTCField(iRecNo, iFieldIndex: Integer): string; procedure ReadIPTCField(iRecNo, iFieldIndex: Integer; Dest: TStrings); Description Return a value from an IPTC field. Fields such as Photoshop's keyword field may have multiple instances. In this case the first method will return a comma separated string, whereas the second will add each instance to the TStrings object Example // Read the Photoshop description sDescription := AnImageEnIO.Params.ReadIPTCField(PhotoShop_IPTC_Records, IPTC_PS_Caption); // Read all the Photoshop keywords (comma-separated): sKeywords := AnImageEnIO.Params.ReadIPTCField(PhotoShop_IPTC_Records, IPTC_PS_Keywords); // Add all Photoshop keywords to a Listbox: AnImageEnIO.Params.ReadIPTCField(PhotoShop_IPTC_Records, IPTC_PS_Keywords, MyListBox.Items); See Also - Photoshop IPTC consts - - !!} function TIOParams.ReadIPTCField(iRecNo, iFieldIndex: Integer): string; var Idx: Integer; I: Integer; bExpectingMultiple: Boolean; begin result := ''; // get the field index Idx := IPTC_Info.IndexOf(iRecNo, iFieldIndex); if idx = -1 then Exit; bExpectingMultiple := (iRecNo = PhotoShop_IPTC_Records) and (iFieldIndex = IPTC_PS_KEYWORDS); if bExpectingMultiple = False then begin result := TidyIPTCStr(IPTC_Info.StringItem[idx]); end else begin // Have multiple instances of the field for I := idx to IPTC_Info.count - 1 do if (IPTC_Info.RecordNumber[i] = iRecNo) and (IPTC_Info.DataSet[i] = iFieldIndex) then Result := Result + TidyIPTCStr(IPTC_Info.StringItem[i]) + ', '; if result <> '' then SetLength(Result, Length(Result) - 2); // remove final comma and space end; end; procedure TIOParams.ReadIPTCField(iRecNo, iFieldIndex: Integer; Dest: TStrings); var Idx: Integer; I: Integer; begin Dest.Clear; // get the field index Idx := IPTC_Info.IndexOf(iRecNo, iFieldIndex); if idx = -1 then Exit; for I := idx to IPTC_Info.count - 1 do if (IPTC_Info.RecordNumber[i] = iRecNo) and (IPTC_Info.DataSet[i] = iFieldIndex) then Dest.Add(TidyIPTCStr(IPTC_Info.StringItem[i]));; end; {!! TIOParams.WriteIPTCField Declaration procedure WriteIPTCField(iRecNo, iFieldIndex: Integer; const Value: string); procedure WriteIPTCField(iRecNo, iFieldIndex: Integer; ssValues: TStrings); Description Write a value to an IPTC field. Note: Items that require multiple instances, such as Photoshop's keyword field, should be added using the TStrings overload method. Example // Write the Photoshop description: AnImageEnIO.Params.WriteIPTCField(PhotoShop_IPTC_Records, IPTC_PS_Caption, sDescription); // Write the Photoshop keywords (in a comma-separated string): ssList := TStringList.create; ssList.DelimitedText := sKeywords; AnImageEnIO.Params.WriteIPTCField(PhotoShop_IPTC_Records, IPTC_PS_Keywords, ssList); ssList.Free; See Also - Photoshop IPTC consts - - !!} procedure TIOParams.WriteIPTCField(iRecNo, iFieldIndex: Integer; const Value: string); var Idx: Integer; sKeywords: string; ssKeywords: TStringList; I: Integer; begin // Special handling for keywords, as they need to be added as multiple instances if (iRecNo = PhotoShop_IPTC_Records) and (iFieldIndex = IPTC_PS_Keywords) then begin ssKeywords := TStringList.Create; try sKeywords := StringReplace(Value, ',', #13#10, [rfReplaceAll]); ssKeywords.Text := sKeywords; for I := 0 to ssKeywords.Count - 1 do ssKeywords[I] := Trim(ssKeywords[I]); WriteIPTCField(iRecNo, iFieldIndex, ssKeywords); finally ssKeywords.free; end; end ELSE // REGULAR FIELDS begin // get the field index Idx := IPTC_Info.IndexOf(iRecNo, iFieldIndex); if idx < 0 then begin // Doesn't exist, so add it if Value <> '' then IPTC_Info.AddStringItem(iRecNo, iFieldIndex, AnsiString(Value)) end else begin // Exists... if Value = '' then IPTC_Info.DeleteItem(Idx) else if IPTC_Info.StringItem[Idx] <> Value then IPTC_Info.StringItem[Idx] := Value; end; end; end; procedure TIOParams.WriteIPTCField(iRecNo, iFieldIndex: Integer; ssValues: TStrings); var Value: string; I: Integer; begin // Clear existing entries ClearIPTCField(iRecNo, iFieldIndex); // Now add them for I := 0 to ssValues.Count - 1 do begin Value := ssValues[I]; if Value <> '' then IPTC_Info.AddStringItem(iRecNo, iFieldIndex, AnsiString(Value)); end; end; {!! TIOParams.IPTC_Photoshop Declaration property IPTC_Photoshop[FieldID: Integer]: string; Description Read or write a Photoshop compatible IPTC field. Note: This is the same as calling Params.ReadIPTCField(PhotoShop_IPTC_Records, FieldID) or Params.WriteIPTCField(PhotoShop_IPTC_Records, FieldID, Value) Acceptable values for FieldID: Const Description IPTC_PS_Title (5) Object name IPTC_PS_Edit_Status (7) Edit status IPTC_PS_Urgency (10) Urgency IPTC_PS_Category (15) Category IPTC_PS_Category_2 (20) Supplemental Category IPTC_PS_Fixture_Identifier (22) Fixture Identifier IPTC_PS_Keywords (25) Keywords IPTC_PS_Release_Date (30) Release Date IPTC_PS_Release_Time (35) Release Time IPTC_PS_Instructions (40) Special Instructions IPTC_PS_Reference_Service (45) Reference Service IPTC_PS_Reference_Date (47) Reference Date IPTC_PS_Reference_Number (50) Reference Number IPTC_PS_Date_Created (55) Date Created IPTC_PS_Time_Created (60) Time Created IPTC_PS_Originating_Program (65) Originating Program IPTC_PS_Program_Version (70) Program Version IPTC_PS_Object_Cycle (75) Object Cycle IPTC_PS_Byline_1 (80) By-line IPTC_PS_Byline_2 (85) By-line Title IPTC_PS_City (90) City IPTC_PS_State_Province (95) Province/State IPTC_PS_Country_Code (100) Country/Primary Location Code IPTC_PS_Country (101) Country/Primary Location Name IPTC_PS_Transmission_Reference (103) Original Transmission Reference IPTC_PS_Credit (110) Credit IPTC_PS_Source (115) Source IPTC_PS_Copyright_Notice (116) Copyright Notice IPTC_PS_Caption (120) Caption/Abstract IPTC_PS_Writer (122) Writer/Editor IPTC_PS_Image_Type (130) Image Type
Notes: - IPTC_PS_Keywords is stored with multiple instances. This will be returned as a comma-separated string, and can be set as a comma-separated or Linebreak-delimited string (or use the overloaded version of
) - IPTC_PS_Caption can contain linebreaks - All fields have maximum lengths Demo Demos\InputOutput\IPTC\IPTC.dpr Examples // Read the image description (written by PhotoShop) ImageEnView1.IO.LoadFromFile('C:\image.jpg'); Caption := ImageEnView1.IO.Params.IPTC_Photoshop[IPTC_PS_Caption]; // Write the image description (without resaving JPEG image) ImageEnView1.IO.Params.IPTC_Photoshop[IPTC_PS_Caption] := 'This is the new caption'; ImageEnView1.IO.InjectJpegIPTC('D:\image.jpg'); // Write keywords ImageEnView1.IO.Params.IPTC_Photoshop[IPTC_PS_Keywords] := Listbox1.Text; ImageEnView1.IO.SaveToFile('D:\image.jpg'); See Also - - Photoshop IPTC consts - - - !!} function TIOParams.GetIPTC_Photoshop(FieldID: Integer): string; begin Result := ReadIPTCField(PhotoShop_IPTC_Records, FieldID); end; procedure TIOParams.SetIPTC_Photoshop(FieldID: Integer; const Value: string); begin WriteIPTCField(PhotoShop_IPTC_Records, FieldID, Value); end; {!! TIOParams.ResetEXIF Declaration procedure ResetEXIF; Description Resets (nulls) all EXIF fields. This is useful to remove EXIF info from your files. Note: To remove all meta-data from a JPEG, it is better to call instead. !!} procedure TIOParams.ResetEXIF; var q: integer; begin fEXIF_Tags.Clear; fEXIF_HasEXIFData := false; if assigned(fEXIF_Bitmap) then FreeAndNil(fEXIF_Bitmap); fEXIF_Bitmap := nil; fEXIF_ImageDescription := ''; fEXIF_Make := ''; fEXIF_Model := ''; fEXIF_Orientation := 0; fEXIF_XResolution := 0; fEXIF_YResolution := 0; fEXIF_ResolutionUnit := 0; fEXIF_Software := ''; fEXIF_Artist := ''; fEXIF_DateTime := ''; fEXIF_WhitePoint[0] := -1; fEXIF_WhitePoint[1] := -1; for q := 0 to 5 do fEXIF_PrimaryChromaticities[q] := -1; for q := 0 to 2 do fEXIF_YCbCrCoefficients[q] := -1; fEXIF_YCbCrPositioning := -1; for q := 0 to 5 do fEXIF_ReferenceBlackWhite[q] := -1; fEXIF_Copyright := ''; fEXIF_ExposureTime := -1; fEXIF_FNumber := -1; fEXIF_ExposureProgram := -1; fEXIF_ISOSpeedRatings[0] := 0; fEXIF_ISOSpeedRatings[1] := 0; fEXIF_ExifVersion := ''; fEXIF_DateTimeOriginal := ''; fEXIF_DateTimeDigitized := ''; fEXIF_CompressedBitsPerPixel := 0; fEXIF_ShutterSpeedValue := -1; fEXIF_ApertureValue := -1; fEXIF_BrightnessValue := -1000; fEXIF_ExposureBiasValue := -1000; fEXIF_MaxApertureValue := -1000; fEXIF_SubjectDistance := -1; fEXIF_MeteringMode := -1; fEXIF_LightSource := -1; fEXIF_Flash := -1; fEXIF_FocalLength := -1; fEXIF_SubsecTime := ''; fEXIF_SubsecTimeOriginal := ''; fEXIF_SubsecTimeDigitized := ''; fEXIF_FlashPixVersion := ''; fEXIF_ColorSpace := -1; fEXIF_ExifImageWidth := 0; fEXIF_ExifImageHeight := 0; fEXIF_RelatedSoundFile := ''; fEXIF_FocalPlaneXResolution := -1; fEXIF_FocalPlaneYResolution := -1; fEXIF_FocalPlaneResolutionUnit := -1; fEXIF_ExposureIndex := -1; fEXIF_SensingMethod := -1; fEXIF_FileSource := -1; fEXIF_SceneType := -1; fEXIF_UserComment := ''; fEXIF_UserCommentCode := ''; fEXIF_MakerNote.Clear; fEXIF_XPRating := -1; fEXIF_XPTitle := ''; fEXIF_XPComment := ''; fEXIF_XPAuthor := ''; fEXIF_XPKeywords := ''; fEXIF_XPSubject := ''; fEXIF_ExposureMode := -1; fEXIF_WhiteBalance := -1; fEXIF_DigitalZoomRatio := -1; fEXIF_FocalLengthIn35mmFilm := -1; fEXIF_SceneCaptureType := -1; fEXIF_GainControl := -1; fEXIF_Contrast := -1; fEXIF_Saturation := -1; fEXIF_Sharpness := -1; fEXIF_SubjectDistanceRange := -1; fEXIF_ImageUniqueID := ''; fEXIF_GPSVersionID := ''; // ''=indicates that there aren't GPS info to write fEXIF_GPSLatitudeRef := ''; fEXIF_GPSLatitudeDegrees := 0; fEXIF_GPSLatitudeMinutes := 0; fEXIF_GPSLatitudeSeconds := 0; fEXIF_GPSLongitudeRef := ''; fEXIF_GPSLongitudeDegrees := 0; fEXIF_GPSLongitudeMinutes := 0; fEXIF_GPSLongitudeSeconds := 0; fEXIF_GPSAltitudeRef := ''; fEXIF_GPSAltitude := 0; fEXIF_GPSTimeStampHour := 0; fEXIF_GPSTimeStampMinute := 0; fEXIF_GPSTimeStampSecond := 0; fEXIF_GPSSatellites := ''; fEXIF_GPSStatus := ''; fEXIF_GPSMeasureMode := ''; fEXIF_GPSDOP := 0; fEXIF_GPSSpeedRef := ''; fEXIF_GPSSpeed := 0; fEXIF_GPSTrackRef := ''; fEXIF_GPSTrack := 0; fEXIF_GPSImgDirectionRef := ''; fEXIF_GPSImgDirection := 0; fEXIF_GPSMapDatum := ''; fEXIF_GPSDestLatitudeRef := ''; fEXIF_GPSDestLatitudeDegrees := 0; fEXIF_GPSDestLatitudeMinutes := 0; fEXIF_GPSDestLatitudeSeconds := 0; fEXIF_GPSDestLongitudeRef := ''; fEXIF_GPSDestLongitudeDegrees := 0; fEXIF_GPSDestLongitudeMinutes := 0; fEXIF_GPSDestLongitudeSeconds := 0; fEXIF_GPSDestBearingRef := ''; fEXIF_GPSDestBearing := 0; fEXIF_GPSDestDistanceRef := ''; fEXIF_GPSDestDistance := 0; fEXIF_GPSDateStamp := ''; fEXIF_InteropIndex := ''; fEXIF_InteropVersion := ''; fEXIF_CameraOwnerName := ''; fEXIF_BodySerialNumber := ''; fEXIF_LensMake := ''; fEXIF_LensModel := ''; fEXIF_LensSerialNumber := ''; fEXIF_Gamma := -1; for q := 0 to 3 do fEXIF_SubjectArea[ q ] := -1; fEXIF_SubjectLocationX := -1; fEXIF_SubjectLocationY := -1; // removes Jpeg EXIF tag with JPEG_MarkerList do for q := 0 to Count-1 do if (MarkerType[q]=JPEG_APP1) and CheckEXIFFromStandardBuffer(MarkerData[q], MarkerLength[q]) then begin DeleteMarker(q); break; end; end; {!! TIOParams.ResetInfo Declaration procedure ResetInfo; Description Resets IPTC information, imaging annotations, JPEG markers, EXIF, GIF comments, PNG comments, TIFF textual tags, TGA comments, PXM comments and any other loaded textual information. It also removes the input ICC profile. This can be used to reduce the size of images. The following operations are performed: - Resets - Clears - Clears - Clears - Calls - Clears - Resets - Resets DICOM position info - Clears - Clears - Clears - Clears - Clears - Clears - Clears - Clears - Clears - Clears - Resets Example ImageEnView1.IO.Params.ResetInfo; !!} // reset only info tags (EXIF, IPTC, JPEG_Tags, XMP and comments) procedure TIOParams.ResetInfo; begin IPTC_Info.Clear; {$ifdef IEINCLUDEIMAGINGANNOT} if assigned(fImagingAnnot) then FreeAndNil(fImagingAnnot); {$endif} fImageEnAnnot.Clear(); JPEG_MarkerList.Clear; ResetEXIF; GIF_Comments.Clear; {$ifdef IEINCLUDEDICOM} DICOM_Tags.Clear; fDICOM_RescaleIntercept := 0; fDICOM_RescaleSlope := 1; fDICOM_WindowCenter := 0; fDICOM_WindowWidth := 0; {$endif} PNG_TextKeys.Clear; PNG_TextValues.Clear; TIFF_DocumentName := ''; TIFF_ImageDescription := ''; TIFF_PageName := ''; TGA_Descriptor := ''; TGA_Author := ''; TGA_ImageName := ''; PXM_Comments.Clear; XMP_Info := ''; if assigned(fInputICC) then FreeAndNil(fInputICC); // do not reset output or Default ICC profile end; {!! TIOParams.SetDefaultParams Declaration procedure SetDefaultParams; Description Resets the parameters of the TIOParams object to their default (start-up values). !!} procedure TIOParams.SetDefaultParams; begin fDict.Clear(); FreeColorMap; // no colormap fFileName := ''; fFileType := ioUnknown; BitsPerSample := 8; // 8 BITS x SAMPLE SamplesPerPixel := 3; // 3 SAMPLES x PIXEL (RGB) IsNativePixelFOrmat := false; if assigned( fAttachedTo ) then begin try if ( fAttachedTo is TImageEnIO ) and assigned( TImageEnIO( fAttachedTo ).Bitmap) then begin fWidth := TImageEnIO( fAttachedTo ).Bitmap.Width; fHeight := TImageEnIO( fAttachedTo ).Bitmap.Height; end else if fAttachedTo is TIEBitmap then begin fWidth := TIEBitmap( fAttachedTo ).Width; fHeight := TIEBitmap( fAttachedTo ).Height; end; except // Unexpected error fWidth := 0; fHeight := 0; end; if fAttachedTo is TImageEnIO then begin SetDPIX( IEGlobalSettings().DefaultDPIX ); SetDPIY( IEGlobalSettings().DefaultDPIY ); end; end else begin SetDPIX( IEGlobalSettings().DefaultDPIX ); SetDPIY( IEGlobalSettings().DefaultDPIY ); end; fImageIndex := 0; fImageCount := 0; fGetThumbnail := false; fIsResource := false; fEnableAdjustOrientation := false; // GIF GIF_Version := 'GIF89a'; GIF_ImageIndex := 0; GIF_XPos := 0; GIF_YPos := 0; GIF_DelayTime := 0; GIF_FlagTranspColor := false; GIF_TranspColor := CreateRGB(0, 0, 0); GIF_Interlaced := false; GIF_WinWidth := 0; GIF_WinHeight := 0; GIF_Background := CreateRGB(0, 0, 0); GIF_Ratio := 0; GIF_LZWDecompFunc := IEGlobalSettings().DefGIF_LZWDecompFunc; GIF_LZWCompFunc := IEGlobalSettings().DefGIF_LZWCompFunc; fGIF_ImageCount := 0; GIF_Comments.Clear; GIF_Action := ioGIF_DrawBackground; GIF_RAWLoad := false; // DCX DCX_ImageIndex := 0; // TIFF TIFF_Compression := ioTIFF_UNCOMPRESSED; TIFF_PhotometInterpret := ioTIFF_RGB; TIFF_PlanarConf := 1; TIFF_ImageIndex := 0; TIFF_SubIndex := -1; TIFF_NewSubfileType := 0; TIFF_XPos := 0; TIFF_YPos := 0; TIFF_GetTile := -1; TIFF_DocumentName := ''; TIFF_ImageDescription := ''; TIFF_PageName := ''; TIFF_PageNumber := -1; TIFF_PageCount := -1; TIFF_Orientation := 1; TIFF_LZWDecompFunc := IEGlobalSettings().DefTIFF_LZWDecompFunc; TIFF_LZWCompFunc := IEGlobalSettings().DefTIFF_LZWCompFunc; fTIFF_ImageCount := 0; fTIFF_EnableAdjustOrientation := false; fTIFF_JPEGQuality := 80; fTIFF_JPEGColorSpace := ioJPEG_YCBCR; fTIFF_FillOrder := 1; fTIFF_ZIPCompression := 1; // normal (default) fTIFF_ByteOrder := ioLittleEndian; // Intel fTIFF_StripCount := 0; // 0 = automatic fTIFF_BigTIFF := false; SetLength(fTIFF_PhotoshopImageResources, 0); SetLength(fTIFF_PhotoshopImageSourceData, 0); // JPEG JPEG_ColorSpace := ioJPEG_YCbCr; JPEG_Quality := 80; JPEG_DCTMethod := ioJPEG_ISLOW; // 3.0.1 JPEG_CromaSubsampling := ioJPEG_HIGH; JPEG_OptimalHuffman := false; JPEG_Smooth := 0; JPEG_Progressive := false; JPEG_Scale := ioJPEG_FULLSIZE; JPEG_MarkerList.Clear; JPEG_Scale_Used := 1; OriginalWidth := 0; OriginalHeight := 0; JPEG_EnableAdjustOrientation := false; JPEG_GetExifThumbnail := false; // JPEG2000 {$IFDEF IEINCLUDEJPEG2000} fJ2000_ColorSpace := ioJ2000_RGB; fJ2000_Rate := 0.07; fJ2000_ScalableBy := ioJ2000_Rate; {$ENDIF} // BMP BMP_Compression := ioBMP_UNCOMPRESSED; BMP_Version := ioBMP_BM3; BMP_HandleTransparency := false; // PCX PCX_Version := 5; PCX_Compression := ioPCX_RLE; // ICO ICO_ImageIndex := 0; ICO_Background := CreateRGB(255, 255, 255); FillChar(ICO_Sizes[0], sizeof(TIOICOSizes), 0); ICO_Sizes[0].cx := 64; ICO_Sizes[0].cy := 64; FillChar(ICO_BitCount[0], sizeof(TIOICOBitCount), 0); ICO_BitCount[0] := 8; // CUR CUR_ImageIndex := 0; CUR_XHotSpot := 0; CUR_XHotSpot := 0; CUR_Background := CreateRGB(255, 255, 255); // PNG PNG_Interlaced := false; PNG_Background := CreateRGB(0, 0, 0); PNG_Filter := ioPNG_FILTER_NONE; PNG_Compression := 5; PNG_TextKeys.Clear; PNG_TextValues.Clear; // DICOM {$ifdef IEINCLUDEDICOM} DICOM_Tags.Clear; DICOM_WindowCenterOffset := 0; DICOM_Range := iedrAdjust; fDICOM_RescaleIntercept := 0; fDICOM_RescaleSlope := 1; SetDICOM_Compression(iedcUncompressed); fDICOM_JPEGQuality := 80; fDICOM_J2000Rate := 0.07; fDICOM_WindowCenter := 0; fDICOM_WindowWidth := 0; {$endif} // PSD PSD_LoadLayers := false; PSD_ReplaceLayers := true; fPSD_HasPremultipliedAlpha := false; fPSD_LargeDocumentFormat := false; fPSD_SelectLayer := ''; // HDP fHDP_ImageQuality := 0.9; fHDP_Lossless := false; // TGA TGA_XPos := 0; TGA_YPos := 0; TGA_Compressed := true; TGA_Descriptor := ''; TGA_Author := ''; TGA_Date := date; TGA_ImageName := ''; TGA_Background := CreateRGB(0, 0, 0); TGA_AspectRatio := 1; TGA_Gamma := 2.2; TGA_GrayLevel := false; // AVI AVI_FrameCount := 0; AVI_FrameDelayTime := 0.0; // IPTC IPTC_Info.Clear; // PXM PXM_Comments.Clear; // EXIF ResetEXIF; // PS PS_PaperWidth := 595; PS_PaperHeight := 842; PS_Compression := ioPS_G4FAX; PS_Title := 'No Title'; // PDF PDF_PaperWidth := 595; PDF_PaperHeight := 842; PDF_Compression := ioPDF_G4FAX; PDF_Title := ''; PDF_Author := ''; PDF_Subject := ''; PDF_Keywords := ''; PDF_Creator := ''; PDF_Producer := ''; {$ifdef IEINCLUDEIMAGINGANNOT} // Imaging Annotations if assigned(fImagingAnnot) then FreeAndNil(fImagingAnnot); {$endif} // ImageEn Annotations fImageEnAnnot.Clear(); // ICC if assigned(fInputICC) then FreeAndNil(fInputICC); if assigned(fOutputICC) then FreeAndNil(fOutputICC); if assigned(fDefaultICC) then FreeAndNil(fDefaultICC); // RAW {$ifdef IEINCLUDERAWFORMATS} fRAW_HalfSize := false; fRAW_Gamma := 2.222; fRAW_Bright := 1.0; fRAW_RedScale := 1.0; fRAW_BlueScale := 1.0; fRAW_QuickInterpolate := true; fRAW_UseAutoWB := false; fRAW_UseCameraWB := false; fRAW_FourColorRGB := false; fRAW_Camera := ''; fRAW_GetExifThumbnail := false; fRAW_AutoAdjustColors := false; fRAW_ExtraParams := ''; {$endif} // real RAW fBMPRAW_ChannelOrder := coRGB; fBMPRAW_Planes := plInterleaved; fBMPRAW_RowAlign := 8; fBMPRAW_HeaderSize := 0; fBMPRAW_DataFormat := dfBinary; // XMP fXMP_Info := ''; // IEN fIEN_Compression := -1; fIEN_Description := ''; fIEN_LayerCount := 0; fIEN_Version := 0; fIEN_GetThumbnail := false; fSVG_ImageCompression := ioPNG; end; {!! TIOParams.Assign Declaration procedure Assign(Source: ); Description Copy all image format parameters from Source to this object. Example ImageEnView1.IO.Params.Assign( ImageEnView2.IO.Params ); !!} procedure TIOParams.Assign(Source: TIOParams); begin fDict.Assign(Source.fDict); fFileName := Source.FileName; fFileType := Source.FileType; BitsPerSample := Source.BitsPerSample; SamplesPerPixel := Source.SamplesPerPixel; fWidth := Source.Width; fHeight := Source.Height; DpiX := Source.DpiX; DpiY := Source.DpiY; fColorMapCount := Source.ColorMapCount; IsNativePixelFormat := Source.IsNativePixelFormat; FreeColorMap; if Source.ColorMap <> nil then begin getmem(fColorMap, ColorMapCount * sizeof(TRGB)); copymemory(ColorMap, Source.ColorMap, ColorMapCount * sizeof(TRGB)); end; fImageIndex := Source.fImageIndex; fImageCount := Source.fImageCount; fGetThumbnail := Source.fGetThumbnail; fIsResource := Source.fIsResource; fEnableAdjustOrientation := Source.fEnableAdjustOrientation; OriginalWidth := Source.OriginalWidth; OriginalHeight := Source.OriginalHeight; // TIFF TIFF_Compression := Source.TIFF_Compression; TIFF_ImageIndex := Source.TIFF_ImageIndex; TIFF_SubIndex := Source.TIFF_SubIndex; TIFF_PhotometInterpret := Source.TIFF_PhotometInterpret; TIFF_PlanarConf := Source.TIFF_PlanarConf; TIFF_NewSubfileType := Source.TIFF_NewSubfileType; TIFF_XPos := Source.TIFF_XPos; TIFF_YPos := Source.TIFF_YPos; TIFF_GetTile := Source.TIFF_GetTile; TIFF_DocumentName := Source.TIFF_DocumentName; TIFF_ImageDescription := Source.TIFF_ImageDescription; TIFF_PageName := Source.TIFF_PageName; TIFF_PageNumber := Source.TIFF_PageNumber; TIFF_PageCount := Source.TIFF_PageCount; TIFF_Orientation := Source.TIFF_Orientation; TIFF_LZWDecompFunc := Source.TIFF_LZWDecompFunc; TIFF_LZWCompFunc := Source.TIFF_LZWCompFunc; fTIFF_ImageCount := Source.TIFF_ImageCount; fTIFF_EnableAdjustOrientation := Source.TIFF_EnableAdjustOrientation; fTIFF_JPEGQuality := Source.fTIFF_JPEGQuality; fTIFF_JPEGColorSpace := Source.fTIFF_JPEGColorSpace; fTIFF_FillOrder := Source.fTIFF_FillOrder; fTIFF_ZIPCompression := Source.fTIFF_ZIPCompression; fTIFF_ByteOrder := Source.fTIFF_ByteOrder; fTIFF_StripCount := Source.fTIFF_StripCount; fTIFF_PhotoshopImageResources := IECopyArrayOfByte(Source.fTIFF_PhotoshopImageResources); fTIFF_PhotoshopImageSourceData := IECopyArrayOfByte(Source.fTIFF_PhotoshopImageSourceData); fTIFF_BigTIFF := Source.fTIFF_BigTIFF; // GIF GIF_Version := Source.GIF_Version; GIF_ImageIndex := Source.GIF_ImageIndex; GIF_XPos := Source.GIF_XPos; GIF_YPos := Source.GIF_YPos; GIF_DelayTime := Source.GIF_DelayTime; GIF_FlagTranspColor := Source.GIF_FlagTranspColor; GIF_TranspColor := Source.GIF_TranspColor; GIF_Interlaced := Source.GIF_Interlaced; GIF_WinWidth := Source.GIF_WinWidth; GIF_WinHeight := Source.GIF_WinHeight; GIF_Background := Source.GIF_Background; GIF_Ratio := Source.GIF_Ratio; GIF_LZWDecompFunc := Source.GIF_LZWDecompFunc; GIF_LZWCompFunc := Source.GIF_LZWCompFunc; fGIF_ImageCount := Source.GIF_ImageCount; GIF_Comments.Assign(Source.GIF_Comments); GIF_Action := Source.GIF_Action; GIF_RAWLoad := Source.GIF_RAWLoad; // DCX DCX_ImageIndex := Source.DCX_ImageIndex; // JPEG JPEG_ColorSpace := Source.JPEG_ColorSpace; JPEG_Quality := Source.JPEG_Quality; JPEG_DCTMethod := Source.JPEG_DCTMethod; JPEG_CromaSubsampling := Source.JPEG_CromaSubsampling; JPEG_OptimalHuffman := Source.JPEG_OptimalHuffman; JPEG_Smooth := Source.JPEG_Smooth; JPEG_Progressive := Source.JPEG_Progressive; JPEG_Scale := Source.JPEG_Scale; JPEG_MarkerList.Assign(Source.JPEG_MarkerList); JPEG_Scale_Used := Source.JPEG_Scale_Used; JPEG_EnableAdjustOrientation := Source.JPEG_EnableAdjustOrientation; JPEG_GetExifThumbnail := Source.JPEG_GetExifThumbnail; // JPEG2000 {$IFDEF IEINCLUDEJPEG2000} fJ2000_ColorSpace := Source.J2000_ColorSpace; fJ2000_Rate := Source.J2000_Rate; fJ2000_ScalableBy := Source.J2000_ScalableBy; {$ENDIF} // PCX PCX_Version := Source.PCX_Version; PCX_Compression := Source.PCX_Compression; // BMP BMP_Version := Source.BMP_Version; BMP_Compression := Source.BMP_Compression; BMP_HandleTransparency := Source.BMP_HandleTransparency; // ICO ICO_ImageIndex := Source.ICO_ImageIndex; ICO_Background := Source.ICO_Background; move(Source.ICO_Sizes[0], ICO_Sizes[0], sizeof(TIOICOSizes)); move(Source.ICO_BitCount[0], ICO_BitCount[0], sizeof(TIOICOBitCount)); // CUR CUR_ImageIndex := Source.CUR_ImageIndex; CUR_XHotSpot := Source.CUR_XHotSpot; CUR_YHotSpot := Source.CUR_YHotSpot; CUR_Background := Source.CUR_Background; // PNG PNG_Interlaced := Source.PNG_Interlaced; PNG_Background := Source.PNG_Background; PNG_Filter := Source.PNG_Filter; PNG_Compression := Source.PNG_Compression; PNG_TextKeys.Assign( Source.PNG_TextKeys ); PNG_TextValues.Assign( Source.PNG_TextValues ); // DICOM {$ifdef IEINCLUDEDICOM} DICOM_Tags.Assign( Source.DICOM_Tags ); DICOM_WindowCenterOffset := Source.DICOM_WindowCenterOffset; DICOM_Range := Source.DICOM_Range; SetDICOM_Compression(Source.DICOM_Compression); fDICOM_JPEGQuality := Source.fDICOM_JPEGQuality; fDICOM_J2000Rate := Source.fDICOM_J2000Rate; fDICOM_RescaleIntercept := Source.fDICOM_RescaleIntercept; fDICOM_RescaleSlope := Source.fDICOM_RescaleSlope; fDICOM_WindowCenter := Source.fDICOM_WindowCenter; fDICOM_WindowWidth := Source.fDICOM_WindowWidth; {$endif} // PSD PSD_LoadLayers := Source.PSD_LoadLayers; PSD_ReplaceLayers := Source.PSD_ReplaceLayers; fPSD_HasPremultipliedAlpha := Source.PSD_HasPremultipliedAlpha; fPSD_LargeDocumentFormat := Source.PSD_LargeDocumentFormat; fPSD_SelectLayer := Source.PSD_SelectLayer; // HDP fHDP_ImageQuality := Source.fHDP_ImageQuality; fHDP_Lossless := Source.fHDP_Lossless; // TGA TGA_XPos := Source.TGA_XPos; TGA_YPos := Source.TGA_YPos; TGA_Compressed := Source.TGA_Compressed; TGA_Descriptor := Source.TGA_Descriptor; TGA_Author := Source.TGA_Author; TGA_Date := Source.TGA_Date; TGA_ImageName := Source.TGA_ImageName; TGA_Background := Source.TGA_Background; TGA_AspectRatio := Source.TGA_AspectRatio; TGA_Gamma := Source.TGA_Gamma; TGA_GrayLevel := Source.TGA_GrayLevel; // AVI AVI_FrameCount := Source.AVI_FrameCount; AVI_FrameDelayTime := Source.AVI_FrameDelayTime; // IPTC IPTC_Info.Assign(Source.IPTC_Info); {$ifdef IEINCLUDEIMAGINGANNOT} // Imaging annotations if assigned(Source.fImagingAnnot) then ImagingAnnot.Assign(Source.ImagingAnnot) else if assigned(fImagingAnnot) then FreeAndNil(fImagingAnnot); {$endif} // ImageEn annotations fImageEnAnnot.Assign(Source.fImageEnAnnot); // ICC if assigned(Source.fInputICC) then InputICCProfile.Assign(Source.InputICCProfile) else if assigned(fInputICC) then FreeAndNil(fInputICC); if assigned(Source.fOutputICC) then OutputICCProfile.Assign(Source.OutputICCProfile) else if assigned(fOutputICC) then FreeAndNil(fOutputICC); if assigned(Source.fDefaultICC) then DefaultICCProfile.Assign(Source.DefaultICCProfile) else if assigned(fDefaultICC) then FreeAndNil(fDefaultICC); // PXM PXM_Comments.Assign(Source.PXM_Comments); // EXIF IECopyEXIF(Source, self, true); fTIFF_Orientation := Source.fTIFF_Orientation; // because IECopyEXIF will overwrite it // PS fPS_PaperWidth := Source.fPS_PaperWidth; fPS_PaperHeight := Source.fPS_PaperHeight; fPS_Compression := Source.fPS_Compression; fPS_Title := Source.fPS_Title; // PDF fPDF_PaperWidth := Source.fPDF_PaperWidth; fPDF_PaperHeight := Source.fPDF_PaperHeight; fPDF_Compression := Source.fPDF_Compression; fPDF_Title := Source.fPDF_Title; fPDF_Author := Source.fPDF_Author; fPDF_Subject := Source.fPDF_Subject; fPDF_Keywords := Source.fPDF_Keywords; fPDF_Creator := Source.fPDF_Creator; fPDF_Producer := Source.fPDF_Producer; // RAW {$ifdef IEINCLUDERAWFORMATS} fRAW_HalfSize := Source.fRAW_HalfSize; fRAW_Gamma := Source.fRAW_Gamma; fRAW_Bright := Source.fRAW_Bright; fRAW_RedScale := Source.fRAW_RedScale; fRAW_BlueScale := Source.fRAW_BlueScale; fRAW_QuickInterpolate := Source.fRAW_QuickInterpolate; fRAW_UseAutoWB := Source.fRAW_UseAutoWB; fRAW_UseCameraWB := Source.fRAW_UseCameraWB; fRAW_FourColorRGB := Source.fRAW_FourColorRGB; fRAW_Camera := Source.fRAW_Camera; fRAW_GetExifThumbnail := Source.fRAW_GetExifThumbnail; fRAW_AutoAdjustColors := Source.fRAW_AutoAdjustColors; fRAW_ExtraParams := Source.fRAW_ExtraParams; {$endif} // Real RAW fBMPRAW_ChannelOrder := Source.fBMPRAW_ChannelOrder; fBMPRAW_Planes := Source.fBMPRAW_Planes; fBMPRAW_RowAlign := Source.fBMPRAW_RowAlign; fBMPRAW_HeaderSize := Source.fBMPRAW_HeaderSize; fBMPRAW_DataFormat := Source.fBMPRAW_DataFormat; // XMP fXMP_Info := Source.fXMP_Info; // IEN fIEN_Compression := Source.fIEN_Compression; fIEN_Description := Source.fIEN_Description; fIEN_LayerCount := Source.fIEN_LayerCount; fIEN_Version := Source.fIEN_Version; fIEN_GetThumbnail := Source.fIEN_GetThumbnail; // SVG fSVG_ImageCompression := Source.fSVG_ImageCompression; end; // assign compression parameters procedure TIOParams.AssignCompressionInfo(Source: TIOParams); begin BitsPerSample := Source.BitsPerSample; SamplesPerPixel := Source.SamplesPerPixel; // TIFF TIFF_Compression := Source.TIFF_Compression; TIFF_PhotometInterpret := Source.TIFF_PhotometInterpret; TIFF_PlanarConf := Source.TIFF_PlanarConf; TIFF_Orientation := Source.TIFF_Orientation; TIFF_LZWDecompFunc := Source.TIFF_LZWDecompFunc; TIFF_LZWCompFunc := Source.TIFF_LZWCompFunc; fTIFF_EnableAdjustOrientation := Source.TIFF_EnableAdjustOrientation; fTIFF_JPEGQuality := Source.fTIFF_JPEGQuality; fTIFF_JPEGColorSpace := Source.fTIFF_JPEGColorSpace; fTIFF_FillOrder := Source.fTIFF_FillOrder; fTIFF_ZIPCompression := Source.fTIFF_ZIPCompression; fTIFF_StripCount := Source.fTIFF_StripCount; // GIF GIF_Interlaced := Source.GIF_Interlaced; GIF_LZWDecompFunc := Source.GIF_LZWDecompFunc; GIF_LZWCompFunc := Source.GIF_LZWCompFunc; // JPEG JPEG_ColorSpace := Source.JPEG_ColorSpace; JPEG_Quality := Source.JPEG_Quality; JPEG_DCTMethod := Source.JPEG_DCTMethod; JPEG_CromaSubsampling := Source.JPEG_CromaSubsampling; JPEG_OptimalHuffman := Source.JPEG_OptimalHuffman; JPEG_Smooth := Source.JPEG_Smooth; JPEG_Progressive := Source.JPEG_Progressive; // JPEG2000 {$IFDEF IEINCLUDEJPEG2000} fJ2000_ColorSpace := Source.J2000_ColorSpace; fJ2000_Rate := Source.J2000_Rate; fJ2000_ScalableBy := Source.J2000_ScalableBy; {$ENDIF} // PCX PCX_Version := Source.PCX_Version; PCX_Compression := Source.PCX_Compression; // BMP BMP_Version := Source.BMP_Version; BMP_Compression := Source.BMP_Compression; BMP_HandleTransparency := Source.BMP_HandleTransparency; // ICO // CUR // PNG PNG_Interlaced := Source.PNG_Interlaced; PNG_Filter := Source.PNG_Filter; PNG_Compression := Source.PNG_Compression; // TGA TGA_Compressed := Source.TGA_Compressed; TGA_GrayLevel := Source.TGA_GrayLevel; // AVI // IPTC // PXM // EXIF // PS PS_Compression := Source.PS_Compression; // PDF PDF_Compression := Source.PDF_Compression; // DICOM {$IFDEF IEINCLUDEDICOM} DICOM_Range := Source.DICOM_Range; SetDICOM_Compression(Source.DICOM_Compression); fDICOM_JPEGQuality := Source.fDICOM_JPEGQuality; fDICOM_J2000Rate := Source.fDICOM_J2000Rate; {$ENDIF} end; procedure TIOParams.SetEXIF_ISOSpeedRatings(index: integer; v: integer); begin fEXIF_ISOSpeedRatings[index] := v; end; function TIOParams.GetEXIF_ISOSpeedRatings(index: integer): integer; begin result := fEXIF_ISOSpeedRatings[index]; end; procedure TIOParams.SetEXIF_SubjectArea(index: integer; v: integer); begin fEXIF_SubjectArea[index] := v; end; function TIOParams.GetEXIF_SubjectArea(index: integer): integer; begin result := fEXIF_SubjectArea[index]; end; procedure TIOParams.SetEXIF_ReferenceBlackWhite(index: integer; v: double); begin fEXIF_ReferenceBlackWhite[index] := v; end; function TIOParams.GetEXIF_ReferenceBlackWhite(index: integer): double; begin result := fEXIF_ReferenceBlackWhite[index]; end; procedure TIOParams.SetEXIF_WhitePoint(index: integer; v: double); begin fEXIF_WhitePoint[index] := v; end; function TIOParams.GetEXIF_WhitePoint(index: integer): double; begin result := fEXIF_WhitePoint[index]; end; procedure TIOParams.SetEXIF_PrimaryChromaticities(index: integer; v: double); begin fEXIF_PrimaryChromaticities[index] := v; end; function TIOParams.GetEXIF_PrimaryChromaticities(index: integer): double; begin result := fEXIF_PrimaryChromaticities[index]; end; procedure TIOParams.SetEXIF_YCbCrCoefficients(index: integer; v: double); begin fEXIF_YCbCrCoefficients[index] := v; end; function TIOParams.GetEXIF_YCbCrCoefficients(index: integer): double; begin result := fEXIF_YCbCrCoefficients[index]; end; {!! TIOParams.SaveToFile Declaration procedure SaveToFile(const FileName: WideString); Description Saves the file format parameters to a custom meta-data file. CheckMagicString should always be True, unless you must maintain compatibility with earlier editions of ImageEn (prior to v6.3.1) Note: This does NOT write parameters to an existing image file. Use methods like , , instead. Example // Save default parameters ImageEnView1.IO.Params.TIFF_Compression := ioTIFF_LZW; ImageEnView1.IO.Params.SaveToFile('D:\default.params'); ... // Load default parameters ImageEnView1.IO.Params.LoadFromFile('D:\default.params'); !!} procedure TIOParams.SaveToFile(const FileName: WideString); var fs: TIEWideFileStream; begin fs := nil; try fs := TIEWideFileStream.Create(FileName, fmCreate); SaveToStream(fs); finally FreeAndNil(fs); end; end; {!! TIOParams.LoadFromFile Declaration procedure LoadFromFile(const FileName: WideString; CheckMagicString: Boolean = true); Description Load file formats parameters from a meta-data file (that was saved using ). CheckMagicString should always be True, unless you must maintain compatibility with files saved from earlier editions of ImageEn (prior to v6.3.1) Note: This does NOT read the parameters from an existing image file. See instead Example // Save default parameters ImageEnView1.IO.Params.TIFF_Compression := ioTIFF_LZW; ImageEnView1.IO.Params.SaveToFile('D:\default.params'); ... // Load default parameters ImageEnView1.IO.Params.LoadFromFile('D:\default.params'); !!} procedure TIOParams.LoadFromFile(const FileName: WideString; CheckMagicString: Boolean = true); var fs: TIEWideFileStream; begin fs := nil; try fs := TIEWideFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); LoadFromStream(fs, CheckMagicString); finally FreeAndNil(fs); end; end; {!! TIOParams.Dpi Declaration property Dpi: Integer; Description Specifies the resolution (dots per inch) of the acquired image. If the horizontal and vertical resolutions aren't equal, Dpi is the horizontal resolution (the same as ). See Also - - - !!} procedure TIOParams.SetDpi(Value: integer); begin DpiX := Value; DpiY := Value; end; {!! TIOParams.DpiX Declaration property DpiX: integer; Description Specifies the horizontal Dpi (dots per inch) of the image. Example // Show the width of the current image in inches/mm lblWidth.Caption := IntToStr( Trunc( ImageEnView1.IO.Params.Width / ImageEnView1.IO.Params.DpiX )) + ' inches'; lblWidth.Caption := IntToStr( Trunc( ImageEnView1.IO.Params.Width / ImageEnView1.IO.Params.DpiX * 25.4 )) + ' mm'; See Also - - !!} procedure TIOParams.SetDpiX(Value: integer); begin fDpiX := Value; fEXIF_XResolution := Value; // Update scale if attached to a TImageEnVect if assigned( fAttachedTo ) and ( fAttachedTo is TImageEnIO ) and assigned( TImageEnIO( fAttachedTo ).AttachedImageEn) and ( TImageEnIO( fAttachedTo ).AttachedImageEn is TImageEnVect) then with TImageEnIO( fAttachedTo ).AttachedImageEn as TImageEnVect do UpdateDpi(); end; {!! TIOParams.DpiY Declaration property DpiY: integer; Description Specifies the vertical Dpi (dots per inch) of the image. Example // Show the height of the current image in inches/mm lblHeight.Caption := IntToStr( Trunc( ImageEnView1.IO.Params.Height / ImageEnView1.IO.Params.DpiY )) + ' inches'; lblHeight.Caption := IntToStr( Trunc( ImageEnView1.IO.Params.Height / ImageEnView1.IO.Params.DpiY * 25.4 )) + ' mm'; See Also - - !!} procedure TIOParams.SetDpiY(Value: integer); begin fDpiY := Value; fEXIF_YResolution := Value; // Update scale if attached to a TImageEnVect if assigned( fAttachedTo ) and ( fAttachedTo is TImageEnIO ) and assigned( TImageEnIO( fAttachedTo ).AttachedImageEn) and ( TImageEnIO( fAttachedTo ).AttachedImageEn is TImageEnVect) then with TImageEnIO( fAttachedTo ).AttachedImageEn as TImageEnVect do UpdateDpi(); end; procedure TIOParams.SetImageIndex(value: Integer); begin fImageIndex := value; fTIFF_ImageIndex := value; fDCX_ImageIndex := value; fGIF_ImageIndex := value; fICO_ImageIndex := value; fCUR_ImageIndex := value; end; procedure TIOParams.SetEnableAdjustOrientation(value: Boolean); begin fEnableAdjustOrientation := value; fTIFF_EnableAdjustOrientation := value; fJPEG_EnableAdjustOrientation := value; end; procedure TIOParams.SetImageCount(value: Integer); begin fImageCount := value; fTIFF_ImageCount := value; fAVI_FrameCount := value; fGIF_ImageCount := value; {$IFDEF IEINCLUDEDIRECTSHOW} fMEDIAFILE_FrameCount := value; {$ENDIF} end; procedure TIOParams.SetGetThumbnail(value: Boolean); begin fGetThumbnail := value; fJPEG_GetExifThumbnail := value; {$ifdef IEINCLUDERAWFORMATS} fRAW_GetExifThumbnail := value; {$endif} fIEN_GetThumbnail := Value; end; procedure TIOParams.SetIsResource(value: Boolean); begin fIsResource := value; end; procedure TIOParams.SetJPEG_GetExifThumbnail(value: Boolean); begin fGetThumbnail := value; fJPEG_GetExifThumbnail := value; end; {$ifdef IEINCLUDERAWFORMATS} procedure TIOParams.SetRAW_GetExifThumbnail(value: Boolean); begin fRAW_GetExifThumbnail := value; end; {$endif} procedure TIOParams.SetTIFF_Orientation(Value: integer); begin fTIFF_Orientation := Value; fEXIF_Orientation := Value; end; procedure TIOParams.SetEXIF_Orientation(Value: integer); begin fEXIF_Orientation := Value; fTIFF_Orientation := Value; end; procedure TIOParams.SetEXIF_XResolution(Value: double); begin SetDpiX(trunc(Value)); fEXIF_XResolution := Value; // because SetDpiX assign truncated value end; procedure TIOParams.SetEXIF_YResolution(Value: double); begin SetDpiY(trunc(Value)); fEXIF_YResolution := Value; // because SetDpiX assign truncated value end; function TIOParams.GetImageDelayTime: integer; var iFrameRate : Integer; begin Result := 0; case FileType of ioAVI : Result := Round(AVI_FrameDelayTime); ioGIF : Result := GIF_DelayTime * 10; {$ifdef IEINCLUDEDICOM} ioDICOM : begin //iFrameRate := 0; // Try Cine-Rate iFrameRate := IEStrToIntDef(DICOM_Tags.GetTagString($0018, $0040), 0); if iFrameRate > 0 then Result := Round(1000 / iFrameRate); if Result = 0 then begin // Try Recommended Display Frame Rate iFrameRate := IEStrToIntDef(DICOM_Tags.GetTagString($0008, $2144), 0); if iFrameRate > 0 then Result := Round(1000 / iFrameRate); end; if Result = 0 then begin // Try Frame Time Result := Trunc(IEStrToFloatDefA(DICOM_Tags.GetTagString($0018, $1063), 0)); end; end; {$endif} {$ifdef IEINCLUDEDIRECTSHOW} ioWMV, ioMPEG : Result := Round(MEDIAFILE_FrameDelayTime); {$endif} end; end; function TIOParams.GetImageEnIO: TObject; begin Result := nil; if assigned( fAttachedTo ) and ( fAttachedTo is TImageEnIO ) then Result := fAttachedTo; end; {!! TIOParams.InputICCProfile Declaration property InputICCProfile: ; Description Provides access to the ICC profile associated with the current image. If is True and ImageEn has a CMS, the and are applied when you load the image. !!} function TIOParams.GetInputICC: TIEICC; begin if not assigned(fInputICC) then fInputICC := TIEICC.Create(); result := fInputICC; end; {!! TIOParams.DefaultICCProfile Declaration property DefaultICCProfile: ; Description Specifies a default ICC profile associated with the loaded image. Note: A default ICC profile is used only when the loaded image does not have its own ICC profile. Example ImageEnView1.IO.Params.DefaultICCProfile.LoadFromFile('C:\Windows\System32\spool\drivers\color\AdobeRGB1998.icc'); ImageEnView1.IO.LoadFromFile('C:\input.tif'); !!} function TIOParams.GetDefaultICC: TIEICC; begin if not assigned(fDefaultICC) then fDefaultICC := TIEICC.Create; result := fDefaultICC; end; {!! TIOParams.OutputICCProfile Declaration property OutputICCProfile: ; Description Specifies the ICC profile associated with the current display system. The default profile is sRGB. If is True and ImageEn has a CMS, the and are applied when you load the image. !!} function TIOParams.GetOutputICC: TIEICC; begin if not assigned(fOutputICC) then begin fOutputICC := TIEICC.Create; fOutputICC.Assign_sRGBProfile; end; result := fOutputICC; end; {!! TIOParams.ImagingAnnot Declaration property ImagingAnnot: ; Description Provides access to the (Wang) imaging annotations loaded (or to be saved) from a TIFF. Using the object you can create new objects, copy to or from a (as vectorial objects) or (as layers), or just draw onto the bitmap. ImagingAnnot vs ImageEnAnnot ImagingAnnot handles annotations that are supported by other third party applications, but does not support all objects of TImageEnVect. supports all objects of TImageEnVect, but are not understood by other applications. Example // Load an image and all annotations from input.tif . This allows the annotations to be edited: ImageEnVect1.IO.LoadFromFile('C:\input.tif'); ImageEnVect1.IO.Params.ImagingAnnot.CopyToTImageEnVect( ImageEnVect1 ); // Load an image and all annotations from input.tif, but just draw annotation on the image (display only, cannot be edited): ImageEnVect1.IO.LoadFromFile('C:\input.tif'); ImageEnVect1.IO.Params.ImagingAnnot.DrawToBitmap( ImageEnVect1.IEBitmap, True ); ImageEnVect1.Update; !!} {$ifdef IEINCLUDEIMAGINGANNOT} function TIOParams.GetImagingAnnot: TIEImagingAnnot; begin if not assigned(fImagingAnnot) then begin fImagingAnnot := TIEImagingAnnot.Create; fImagingAnnot.Parent := self; end; result := fImagingAnnot; end; {$endif} {!! TIOParams.SaveToStream Declaration procedure SaveToStream(Stream: TStream); Description Saves the file format parameters to stream in a custom meta-data format. CheckMagicString should always be True, unless you must maintain compatibility with earlier editions of ImageEn (prior to v6.3.1) Note: This does NOT save the parameters from an existing image file stream. !!} // the first integer is the version: // 44: 4.0.2 // 45: 4.0.3 // 46: 4.1.1 // 47: 4.1.1-C // 48: 4.3.0 // 49: 4.3.1 // 50: 5.0.0 // 51: 5.0.6 // 52: 5.2.0 // 62: 6.2.2 // 70: 7.0.0 procedure TIOParams.SaveToStream(Stream: TStream); const IOP_VERSION: integer = 70; var i32: integer; ms: TMemoryStream; ab: boolean; NullProgress: TProgressRec; dicomCompression: TIEDicomCompression; begin // magic string IESaveStringToStream(Stream, IEIOPARAMSMAGIC); // version Stream.Write(IOP_VERSION, sizeof(integer)); // Dictionary IESaveStringToStreamW(Stream, fDict.Dump(ieplJSON)); // EXIF (embedded in a TIFF). Must be the first loading so next tags can be set correctly ms := TMemoryStream.Create; try NullProgress := NullProgressRec( ab ); TIFFWriteStream(ms, false, nil, self, NullProgress); i32 := ms.Size; Stream.Write(i32, sizeof(integer)); IECopyFrom(Stream, ms, 0); finally ms.Free; end; // Generics IESaveStringToStream(Stream, AnsiString(fFileName)); Stream.Write(fFileType, sizeof(TIOFileType)); Stream.Write(fBitsPerSample, sizeof(integer)); Stream.Write(fSamplesPerPixel, sizeof(integer)); Stream.Write(fWidth, sizeof(integer)); Stream.Write(fHeight, sizeof(integer)); Stream.Write(fDpiX, sizeof(integer)); Stream.Write(fDpiY, sizeof(integer)); Stream.Write(fColorMapCount, sizeof(integer)); if fColorMapCount > 0 then Stream.Write(fColorMap^, fColorMapCount * sizeof(TRGB)); Stream.Write(fImageIndex, sizeof(integer)); Stream.Write(fImageCount, sizeof(integer)); Stream.Write(fGetThumbnail, sizeof(boolean)); Stream.Write(fEnableAdjustOrientation, sizeof(boolean)); Stream.Write(fIsResource, sizeof(boolean)); // TIFF Stream.Write(fTIFF_Compression, sizeof(TIOTIFFCompression)); Stream.Write(fTIFF_ImageIndex, sizeof(integer)); Stream.Write(fTIFF_PhotometInterpret, sizeof(TIOTIFFPhotometInterpret)); Stream.Write(fTIFF_PlanarConf, sizeof(integer)); Stream.Write(fTIFF_NewSubfileType, sizeof(integer)); Stream.Write(fTIFF_XPos, sizeof(integer)); Stream.Write(fTIFF_YPos, sizeof(integer)); IESaveStringToStream(Stream, fTIFF_DocumentName); IESaveStringToStream(Stream, fTIFF_ImageDescription); IESaveStringToStream(Stream, fTIFF_PageName); Stream.Write(fTIFF_PageNumber, sizeof(integer)); Stream.Write(fTIFF_PageCount, sizeof(integer)); Stream.Write(fTIFF_ImageCount, sizeof(integer)); Stream.Write(fTIFF_Orientation, sizeof(integer)); Stream.Write(fTIFF_JPEGQuality, sizeof(integer)); Stream.Write(fTIFF_JPEGColorSpace, sizeof(TIOJPEGColorSpace)); Stream.Write(fTIFF_FillOrder, sizeof(integer)); Stream.Write(fTIFF_ZIPCompression, sizeof(integer)); Stream.Write(fTIFF_SubIndex, sizeof(integer)); Stream.Write(fTIFF_ByteOrder, sizeof(TIOByteOrder)); Stream.Write(fTIFF_GetTile, sizeof(integer)); Stream.Write(fTIFF_StripCount, sizeof(integer)); Stream.Write(fTIFF_BigTIFF, sizeof(boolean)); // i32 := length(fTIFF_PhotoshopImageResources); Stream.Write(i32, sizeof(integer)); Stream.Write(fTIFF_PhotoshopImageResources[0], i32); // i32 := length(fTIFF_PhotoshopImageSourceData); Stream.Write(i32, sizeof(integer)); Stream.Write(fTIFF_PhotoshopImageSourceData[0], i32); // GIF IESaveStringToStream(Stream, fGIF_Version); Stream.Write(fGIF_ImageIndex, sizeof(integer)); Stream.Write(fGIF_XPos, sizeof(integer)); Stream.Write(fGIF_YPos, sizeof(integer)); Stream.Write(fGIF_DelayTime, sizeof(integer)); Stream.Write(fGIF_FlagTranspColor, sizeof(boolean)); Stream.Write(fGIF_TranspColor, sizeof(TRGB)); Stream.Write(fGIF_Interlaced, sizeof(boolean)); Stream.Write(fGIF_WinWidth, sizeof(integer)); Stream.Write(fGIF_WinHeight, sizeof(integer)); Stream.Write(fGIF_Background, sizeof(TRGB)); Stream.Write(fGIF_Ratio, sizeof(integer)); Stream.Write(fGIF_ImageCount, sizeof(integer)); IESaveStringListToStream(Stream, fGIF_Comments); Stream.Write(fGIF_Action, sizeof(TIEGIFAction)); Stream.Write(fGIF_RAWLoad, sizeof(boolean)); // JPEG Stream.Write(fJPEG_ColorSpace, sizeof(TIOJPEGColorSpace)); Stream.Write(fJPEG_Quality, sizeof(integer)); Stream.Write(fJPEG_DCTMethod, sizeof(TIOJPEGDCTMethod)); Stream.Write(fJPEG_OptimalHuffman, sizeof(boolean)); Stream.Write(fJPEG_Smooth, sizeof(integer)); Stream.Write(fJPEG_Progressive, sizeof(boolean)); Stream.Write(fJPEG_Scale, sizeof(TIOJPEGScale)); fJPEG_MarkerList.SaveToStream(Stream); Stream.Write(fOriginalWidth, sizeof(integer)); // since 3.0.2 common to all formats (file position invaried due file compatibility) Stream.Write(fOriginalHeight, sizeof(integer)); // since 3.0.2 common to all formats (file position invaried due file compatibility) Stream.Write(fJPEG_EnableAdjustOrientation, sizeof(boolean)); Stream.Write(fJPEG_GetExifThumbnail, sizeof(boolean)); Stream.Write(fJPEG_CromaSubsampling, sizeof(TIOJPEGCromaSubsampling)); // JPEG2000 {$IFDEF IEINCLUDEJPEG2000} Stream.Write(fJ2000_ColorSpace, sizeof(TIOJ2000ColorSpace)); Stream.Write(fJ2000_Rate, sizeof(double)); Stream.Write(fJ2000_ScalableBy, sizeof(TIOJ2000ScalableBy)); {$ENDIF} // PCX Stream.Write(fPCX_Version, sizeof(integer)); Stream.Write(fPCX_Compression, sizeof(TIOPCXCompression)); // BMP Stream.Write(fBMP_Version, sizeof(TIOBMPVersion)); Stream.Write(fBMP_Compression, sizeof(TIOBMPCompression)); Stream.Write(fBMP_HandleTransparency, sizeof(boolean)); // ICO Stream.Write(fICO_ImageIndex, sizeof(integer)); Stream.Write(fICO_Background, sizeof(TRGB)); Stream.Write(ICO_Sizes[0], sizeof(TIOICOSizes)); Stream.Write(ICO_BitCount[0], sizeof(TIOICOBitCount)); // CUR Stream.Write(fCUR_ImageIndex, sizeof(integer)); Stream.Write(fCUR_XHotSpot, sizeof(integer)); Stream.Write(fCUR_YHotSpot, sizeof(integer)); Stream.Write(fCUR_Background, sizeof(TRGB)); // PNG Stream.Write(fPNG_Interlaced, sizeof(boolean)); Stream.Write(fPNG_Background, sizeof(TRGB)); Stream.Write(fPNG_Filter, sizeof(TIOPNGFilter)); Stream.Write(fPNG_Compression, sizeof(integer)); IESaveStringListToStream(Stream, fPNG_TextKeys); IESaveStringListToStream(Stream, fPNG_TextValues); // DICOM {$ifdef IEINCLUDEDICOM} DICOM_Tags.SaveToStream(Stream); Stream.Write(fDICOM_WindowCenterOffset, sizeof(double)); Stream.Write(fDICOM_Range, sizeof(TIEDicomRange)); dicomCompression := DICOM_Compression; Stream.Write(dicomCompression, sizeof(TIEDicomCompression)); Stream.Write(fDICOM_JPEGQuality, sizeof(integer)); Stream.Write(fDICOM_J2000Rate, sizeof(double)); Stream.Write(fDICOM_RescaleIntercept, sizeof(double)); Stream.Write(fDICOM_RescaleSlope, sizeof(double)); Stream.Write(fDICOM_WindowCenter, sizeof(double)); Stream.Write(fDICOM_WindowWidth, sizeof(double)); {$endif} // PSD Stream.Write(fPSD_LoadLayers, sizeof(boolean)); Stream.Write(fPSD_ReplaceLayers, sizeof(boolean)); Stream.Write(fPSD_HasPremultipliedAlpha, sizeof(boolean)); Stream.Write(fPSD_LargeDocumentFormat, sizeof(boolean)); IESaveStringToStream(Stream, fPSD_SelectLayer); // HDP Stream.Write(fHDP_ImageQuality, sizeof(double)); Stream.Write(fHDP_Lossless, sizeof(boolean)); // TGA Stream.Write(fTGA_XPos, sizeof(integer)); Stream.Write(fTGA_YPos, sizeof(integer)); Stream.Write(fTGA_Compressed, sizeof(boolean)); IESaveStringToStream(Stream, fTGA_Descriptor); IESaveStringToStream(Stream, fTGA_Author); Stream.Write(fTGA_Date, sizeof(TDateTime)); IESaveStringToStream(Stream, fTGA_ImageName); Stream.Write(fTGA_Background, sizeof(TRGB)); Stream.Write(fTGA_AspectRatio, sizeof(double)); Stream.Write(fTGA_Gamma, sizeof(double)); Stream.Write(fTGA_GrayLevel, sizeof(boolean)); // IPTC fIPTC_Info.SaveToStream(Stream); // PXM IESaveStringListToStream(Stream, fPXM_Comments); // AVI Stream.Write(fAVI_FrameCount, sizeof(integer)); Stream.Write(fAVI_FrameDelayTIme, sizeof(double)); // PS Stream.Write(fPS_PaperWidth, sizeof(integer)); Stream.Write(fPS_PaperHeight, sizeof(integer)); Stream.Write(fPS_Compression, sizeof(TIOPSCompression)); IESaveStringToStream(Stream, fPS_Title); // PDF Stream.Write(fPDF_PaperWidth, sizeof(integer)); Stream.Write(fPDF_PaperHeight, sizeof(integer)); Stream.Write(fPDF_Compression, sizeof(TIOPDFCompression)); IESaveStringToStream(Stream, fPDF_Title); IESaveStringToStream(Stream, fPDF_Author); IESaveStringToStream(Stream, fPDF_Subject); IESaveStringToStream(Stream, fPDF_Keywords); IESaveStringToStream(Stream, fPDF_Creator); IESaveStringToStream(Stream, fPDF_Producer); // DCX Stream.Write(fDCX_ImageIndex, sizeof(integer)); {$ifdef IEINCLUDEIMAGINGANNOT} // imaging annotations ImagingAnnot.SaveToStream(Stream); {$endif} // ImageEn Annotations ImageEnAnnot.SaveToStream(Stream); // ICC InputICCProfile.SaveToStream(Stream, false); OutputICCProfile.SaveToStream(Stream, false); DefaultICCProfile.SaveToStream(Stream, false); // RAW {$ifdef IEINCLUDERAWFORMATS} Stream.Write(fRAW_HalfSize, sizeof(boolean)); Stream.Write(fRAW_Gamma, sizeof(double)); Stream.Write(fRAW_Bright, sizeof(double)); Stream.Write(fRAW_RedScale, sizeof(double)); Stream.Write(fRAW_BlueScale, sizeof(double)); Stream.Write(fRAW_QuickInterpolate, sizeof(boolean)); Stream.Write(fRAW_UseAutoWB, sizeof(boolean)); Stream.Write(fRAW_UseCameraWB, sizeof(boolean)); Stream.Write(fRAW_FourColorRGB, sizeof(boolean)); IESaveStringToStream(Stream, fRAW_Camera); Stream.Write(fRAW_GetExifThumbnail, sizeof(boolean)); Stream.Write(fRAW_AutoAdjustColors, sizeof(boolean)); IESaveStringToStream(Stream, fRAW_ExtraParams); {$endif} {$ifdef IEINCLUDEDIRECTSHOW} Stream.Write(fMEDIAFILE_FrameCount, sizeof(integer)); Stream.Write(fMEDIAFILE_FrameDelayTime, sizeof(double)); {$endif} // real RAW Stream.Write(fBMPRAW_ChannelOrder, sizeof(TIOBMPRAWChannelOrder)); Stream.Write(fBMPRAW_Planes, sizeof(TIOBMPRAWPlanes)); Stream.Write(fBMPRAW_RowAlign, sizeof(integer)); Stream.Write(fBMPRAW_HeaderSize, sizeof(integer)); Stream.Write(fBMPRAW_DataFormat, sizeof(TIOBMPRAWDataFormat)); // IEN Stream.Write(fIEN_Compression, sizeof(Integer)); IESaveStringToStreamW(Stream, fIEN_Description); Stream.Write(fIEN_LayerCount, sizeof(integer)); Stream.Write(fIEN_Version, sizeof(integer)); Stream.Write(fIEN_GetThumbnail, sizeof(boolean)); // SVG Stream.Write(fSVG_ImageCompression, sizeof(Integer)); end; {!! TIOParams.LoadFromStream Declaration procedure LoadFromStream(Stream: TStream; CheckMagicString: Boolean = true); Description Load file formats parameters from a stream that was filled using . CheckMagicString should always be True, unless you must maintain compatibility with streams saved from earlier editions of ImageEn (prior to v6.3.1) Note: This does NOT read the parameters from an existing image file stream. See instead. !!} // read params stream procedure TIOParams.LoadFromStream(Stream: TStream; CheckMagicString: Boolean); var ver, i32: integer; b: byte; i: integer; idummy: integer; ss: AnsiString; ms: TMemoryStream; ab: boolean; NullProgress: TProgressRec; alpha: TIEMask; dicomCompression: TIEDicomCompression; ws: WideString; magicStr: AnsiString; begin // check magic string if CheckMagicString then begin IELoadStringFromStream(Stream, magicStr); if magicStr <> IEIOPARAMSMAGIC then begin raise EIEException.create('Invalid TIOParams stream. You cannot use TIOParams.LoadFromStream or LoadFromFile to load parameters from image files.'); end; end; // read version Stream.Read(ver, sizeof(integer)); // Dictionary fDict.Clear(); if ver >= 51 then begin IELoadStringFromStreamW(Stream, ws); fDict.Parse(ws); end; if ver >= 43 then begin alpha := nil; ms := TMemoryStream.Create; try Stream.Read(i32, sizeof(integer)); if i32 > 0 then ms.CopyFrom(Stream, i32); ms.Position := 0; NullProgress := NullProgressRec( ab ); alpha := TIEMask.Create; TIFFReadStream(nil, ms, i32, self, NullProgress, true, alpha, false, true, false, false); finally alpha.Free; ms.Free; end; end; // generics IELoadStringFromStream(Stream, ss); fFileName := WideString(ss); if ver < 2 then begin // in versions 0 and 1, TIOFileType was a byte Stream.Read(b, 1); fFileType := TIOFileType(b); end else Stream.Read(fFileType, sizeof(TIOFileType)); Stream.Read(fBitsPerSample, sizeof(integer)); Stream.Read(fSamplesPerPixel, sizeof(integer)); Stream.Read(fWidth, sizeof(integer)); Stream.Read(fHeight, sizeof(integer)); Stream.Read(fDpiX, sizeof(integer)); Stream.Read(fDpiY, sizeof(integer)); FreeColorMap; Stream.Read(fColorMapCount, sizeof(integer)); if fColorMapCount > 0 then begin getmem(fColorMap, fColorMapCount * sizeof(TRGB)); Stream.Read(fColorMap^, fColorMapCount * sizeof(TRGB)); end; if ver >= 25 then begin Stream.Read(fImageIndex, sizeof(integer)); Stream.Read(fImageCount, sizeof(integer)); Stream.Read(fGetThumbnail, sizeof(boolean)); end; if ver >= 38 then Stream.Read(fEnableAdjustOrientation, sizeof(boolean)); if ver >= 44 then Stream.Read(fIsResource, sizeof(boolean)); // TIFF Stream.Read(fTIFF_Compression, sizeof(TIOTIFFCompression)); Stream.Read(fTIFF_ImageIndex, sizeof(integer)); Stream.Read(fTIFF_PhotometInterpret, sizeof(TIOTIFFPhotometInterpret)); Stream.Read(fTIFF_PlanarConf, sizeof(integer)); if ver >= 47 then Stream.Read(fTIFF_NewSubfileType, sizeof(integer)); Stream.Read(fTIFF_XPos, sizeof(integer)); Stream.Read(fTIFF_YPos, sizeof(integer)); IELoadStringFromStream(Stream, fTIFF_DocumentName); IELoadStringFromStream(Stream, fTIFF_ImageDescription); IELoadStringFromStream(Stream, fTIFF_PageName); Stream.Read(fTIFF_PageNumber, sizeof(integer)); Stream.Read(fTIFF_PageCount, sizeof(integer)); if ver >= 4 then begin Stream.Read(fTIFF_ImageCount, sizeof(integer)); if ver >= 6 then Stream.Read(fTIFF_Orientation, sizeof(integer)); end; if ver >= 10 then Stream.Read(fTIFF_JPEGQuality, sizeof(integer)); if ver >= 16 then Stream.Read(fTIFF_JPEGColorSpace, sizeof(TIOJpegColorSpace)); if ver >= 26 then Stream.Read(fTIFF_FillOrder, sizeof(integer)); if ver >= 30 then Stream.Read(fTIFF_ZIPCompression, sizeof(integer)); if ver >= 31 then Stream.Read(fTIFF_SubIndex, sizeof(integer)); if ver >= 32 then Stream.Read(fTIFF_ByteOrder, sizeof(TIOByteOrder)); if ver >= 40 then Stream.Read(fTIFF_GetTile, sizeof(integer)); if ver >= 46 then Stream.Read(fTIFF_StripCount, sizeof(integer)); if ver >= 50 then begin Stream.Read(i32, sizeof(integer)); SetLength(fTIFF_PhotoshopImageResources, i32); Stream.Read(fTIFF_PhotoshopImageResources[0], i32); Stream.Read(i32, sizeof(integer)); SetLength(fTIFF_PhotoshopImageSourceData, i32); Stream.Read(fTIFF_PhotoshopImageSourceData[0], i32); end; if ver >= 51 then Stream.Read(fTIFF_BigTIFF, sizeof(boolean)); // GIF IELoadStringFromStream(Stream, fGIF_Version); Stream.Read(fGIF_ImageIndex, sizeof(integer)); Stream.Read(fGIF_XPos, sizeof(integer)); Stream.Read(fGIF_YPos, sizeof(integer)); Stream.Read(fGIF_DelayTime, sizeof(integer)); Stream.Read(fGIF_FlagTranspColor, sizeof(boolean)); Stream.Read(fGIF_TranspColor, sizeof(TRGB)); Stream.Read(fGIF_Interlaced, sizeof(boolean)); Stream.Read(fGIF_WinWidth, sizeof(integer)); Stream.Read(fGIF_WinHeight, sizeof(integer)); Stream.Read(fGIF_Background, sizeof(TRGB)); Stream.Read(fGIF_Ratio, sizeof(integer)); if ver >= 4 then Stream.Read(fGIF_ImageCount, sizeof(integer)); if ver >= 9 then IELoadStringListFromStream(Stream, fGIF_Comments); if ver >= 12 then Stream.Read(fGIF_Action, sizeof(TIEGIFAction)); if ver >= 49 then Stream.Read(fGIF_RAWLoad, sizeof(boolean)); // JPEG Stream.Read(fJPEG_ColorSpace, sizeof(TIOJPEGColorSpace)); Stream.Read(fJPEG_Quality, sizeof(integer)); Stream.Read(fJPEG_DCTMethod, sizeof(TIOJPEGDCTMethod)); Stream.Read(fJPEG_OptimalHuffman, sizeof(boolean)); Stream.Read(fJPEG_Smooth, sizeof(integer)); Stream.Read(fJPEG_Progressive, sizeof(boolean)); if ver >= 1 then Stream.Read(fJPEG_Scale, sizeof(TIOJPEGScale)); if ver >= 4 then fJPEG_MarkerList.LoadFromStream(Stream); if ver >= 7 then begin Stream.Read(fOriginalWidth, sizeof(integer)); // 3.0.2: common to all file formats Stream.Read(fOriginalHeight, sizeof(integer)); // 3.0.2: common to all file formats end; if ver >= 20 then begin Stream.Read(fJPEG_EnableAdjustOrientation, sizeof(boolean)); Stream.Read(fJPEG_GetExifThumbnail, sizeof(boolean)); end; if ver >= 39 then Stream.Read(fJPEG_CromaSubsampling, sizeof(TIOJPEGCromaSubsampling)); // JPEG2000 {$IFDEF IEINCLUDEJPEG2000} if ver >= 8 then begin Stream.Read(fJ2000_ColorSpace, sizeof(TIOJ2000ColorSpace)); Stream.Read(fJ2000_Rate, sizeof(double)); Stream.Read(fJ2000_ScalableBy, sizeof(TIOJ2000ScalableBy)); end; {$ENDIF} // PCX Stream.Read(fPCX_Version, sizeof(integer)); Stream.Read(fPCX_Compression, sizeof(TIOPCXCompression)); // BMP Stream.Read(fBMP_Version, sizeof(TIOBMPVersion)); Stream.Read(fBMP_Compression, sizeof(TIOBMPCompression)); if ver>=28 then Stream.Read(fBMP_HandleTransparency, sizeof(boolean)); // ICO if ver = 0 then begin Stream.Read(idummy, sizeof(integer)); Stream.Read(idummy, sizeof(integer)); fICO_ImageIndex := 0; end else begin Stream.Read(fICO_ImageIndex, sizeof(integer)); if ver >= 3 then Stream.Read(fICO_Background, sizeof(TRGB)); if ver >= 11 then begin Stream.Read(ICO_Sizes[0], sizeof(TIOICOSizes)); Stream.Read(ICO_BitCount[0], sizeof(TIOICOBitCount)); end; end; // CUR if ver = 0 then begin Stream.Read(idummy, sizeof(integer)); Stream.Read(idummy, sizeof(integer)); fCUR_ImageIndex := 0; fCUR_XHotSpot := 0; fCUR_YHotSpot := 0; end else begin Stream.Read(fCUR_ImageIndex, sizeof(integer)); Stream.Read(fCUR_XHotSpot, sizeof(integer)); Stream.Read(fCUR_YHotSpot, sizeof(integer)); if ver >= 3 then Stream.Read(fCUR_Background, sizeof(TRGB)); end; // PNG Stream.Read(fPNG_Interlaced, sizeof(boolean)); Stream.Read(fPNG_Background, sizeof(TRGB)); Stream.Read(fPNG_Filter, sizeof(TIOPNGFilter)); Stream.Read(fPNG_Compression, sizeof(integer)); if ver >= 23 then begin IELoadStringListFromStream(Stream, fPNG_TextKeys); IELoadStringListFromStream(Stream, fPNG_TextValues); end; // DICOM {$ifdef IEINCLUDEDICOM} if ver >= 37 then DICOM_Tags.LoadFromStream(Stream); if ver >= 48 then begin Stream.Read(fDICOM_WindowCenterOffset, sizeof(double)); Stream.Read(fDICOM_Range, sizeof(TIEDicomRange)); end; if ver >= 50 then begin Stream.Read(dicomCompression, sizeof(TIEDicomCompression)); SetDICOM_Compression(dicomCompression); Stream.Read(fDICOM_JPEGQuality, sizeof(integer)); Stream.Read(fDICOM_J2000Rate, sizeof(double)); end; if ver >= 52 then begin Stream.Read(fDICOM_RescaleIntercept, sizeof(double)); Stream.Read(fDICOM_RescaleSlope, sizeof(double)); end; if ver >= 62 then begin Stream.Read(fDICOM_WindowCenter, sizeof(double)); Stream.Read(fDICOM_WindowWidth, sizeof(double)); end; {$endif} // PSD if ver >= 27 then begin Stream.Read(fPSD_LoadLayers, sizeof(boolean)); if ver >= 34 then Stream.Read(fPSD_ReplaceLayers, sizeof(boolean)); if ver >= 36 then Stream.Read(fPSD_HasPremultipliedAlpha, sizeof(boolean)); if ver >= 51 then begin Stream.Read(fPSD_LargeDocumentFormat, sizeof(boolean)); IELoadStringFromStream(Stream, fPSD_SelectLayer); end; end; // HDP if ver >=41 then begin Stream.Read(fHDP_ImageQuality, sizeof(double)); Stream.Read(fHDP_Lossless, sizeof(boolean)); end; // TGA if ver >= 3 then begin Stream.Read(fTGA_XPos, sizeof(integer)); Stream.Read(fTGA_YPos, sizeof(integer)); Stream.Read(fTGA_Compressed, sizeof(boolean)); IELoadStringFromStream(Stream, fTGA_Descriptor); IELoadStringFromStream(Stream, fTGA_Author); Stream.Read(fTGA_Date, sizeof(TDateTime)); IELoadStringFromStream(Stream, fTGA_ImageName); Stream.Read(fTGA_Background, sizeof(TRGB)); Stream.Read(fTGA_AspectRatio, sizeof(double)); Stream.Read(fTGA_Gamma, sizeof(double)); Stream.Read(fTGA_GrayLevel, sizeof(boolean)); end; // IPTC if ver >= 4 then fIPTC_Info.LoadFromStream(Stream); // PXM if ver >= 5 then IELoadStringListFromStream(Stream, fPXM_Comments); // AVI if ver >= 6 then begin Stream.Read(fAVI_FrameCount, sizeof(integer)); if ver >= 45 then Stream.Read(fAVI_FrameDelayTime, sizeof(double)) else begin Stream.Read(i, sizeof(integer)); fAVI_FrameDelayTime := i; end; end; // PS if ver >= 14 then begin Stream.Read(fPS_PaperWidth, sizeof(integer)); Stream.Read(fPS_PaperHeight, sizeof(integer)); Stream.Read(fPS_Compression, sizeof(TIOPSCompression)); IELoadStringFromStream(Stream, fPS_Title); end; // PDF if ver >= 14 then begin Stream.Read(fPDF_PaperWidth, sizeof(integer)); Stream.Read(fPDF_PaperHeight, sizeof(integer)); Stream.Read(fPDF_Compression, sizeof(TIOPDFCompression)); if ver >= 15 then begin IELoadStringFromStream(Stream, fPDF_Title); IELoadStringFromStream(Stream, fPDF_Author); IELoadStringFromStream(Stream, fPDF_Subject); IELoadStringFromStream(Stream, fPDF_Keywords); IELoadStringFromStream(Stream, fPDF_Creator); IELoadStringFromStream(Stream, fPDF_Producer); end; end; // DCX if ver >= 18 then Stream.Read(fDCX_ImageIndex, sizeof(integer)); {$ifdef IEINCLUDEIMAGINGANNOT} // Imagning annotations if ver >= 13 then ImagingAnnot.LoadFromStream(Stream); {$endif} // ImageEn annotations if ver >= 51 then ImageEnAnnot.LoadFromStream(Stream); // ICC if ver >=17 then begin InputICCProfile.LoadFromStream(Stream, false); OutputICCProfile.LoadFromStream(Stream, false); if ver >=33 then DefaultICCProfile.LoadFromStream(Stream, false); end; // RAW if ver >= 18 then begin {$ifdef IEINCLUDERAWFORMATS} Stream.Read(fRAW_HalfSize, sizeof(boolean)); Stream.Read(fRAW_Gamma, sizeof(double)); Stream.Read(fRAW_Bright, sizeof(double)); Stream.Read(fRAW_RedScale, sizeof(double)); Stream.Read(fRAW_BlueScale, sizeof(double)); Stream.Read(fRAW_QuickInterpolate, sizeof(boolean)); Stream.Read(fRAW_UseAutoWB, sizeof(boolean)); Stream.Read(fRAW_UseCameraWB, sizeof(boolean)); Stream.Read(fRAW_FourColorRGB, sizeof(boolean)); IELoadStringFromStream(Stream, fRAW_Camera); Stream.Read(fRAW_GetExifThumbnail, sizeof(boolean)); if ver>=22 then Stream.Read(fRAW_AutoAdjustColors, sizeof(boolean)); if ver>=35 then IELoadStringFromStream(Stream, fRAW_ExtraParams); {$endif} end; // Media File {$ifdef IEINCLUDEDIRECTSHOW} if ver>=21 then begin Stream.Read(fMEDIAFILE_FrameCount, sizeof(integer)); if ver >= 45 then Stream.Read(fMEDIAFILE_FrameDelayTime, sizeof(double)) else begin Stream.Read(i, sizeof(integer)); fMEDIAFILE_FrameDelayTime := i; end; end; {$endif} // Real RAW if ver >= 23 then begin Stream.Read(fBMPRAW_ChannelOrder, sizeof(TIOBMPRAWChannelOrder)); Stream.Read(fBMPRAW_Planes, sizeof(TIOBMPRAWPlanes)); Stream.Read(fBMPRAW_RowAlign, sizeof(integer)); Stream.Read(fBMPRAW_HeaderSize, sizeof(integer)); if ver>=42 then Stream.Read(fBMPRAW_DataFormat, sizeof(TIOBMPRAWDataFormat)); end; // IEN if ver >= 70 then begin Stream.Read(fIEN_Compression, sizeof(Integer)); IELoadStringFromStreamW(Stream, fIEN_Description); Stream.Read(fIEN_LayerCount, sizeof(integer)); Stream.Read(fIEN_Version, sizeof(integer)); Stream.Read(fIEN_GetThumbnail, sizeof(Boolean)); Stream.Read(fSVG_ImageCompression, sizeof(Integer)); end; end; {!! TIOParams.FileTypeStr Declaration property FileTypeStr: String; (Read-only) Description Returns a textual description of the current file type and other file format specific properties. For example, if is ioTIFF and is ioTIFF_G4FAX, FileTypeStr returns the string: 'TIFF Bitmap (TIFF) Group 4 Fax'. Example if OpenImageEnDialog1.Execute then begin ImageEnView1.IO.LoadFromFile(OpenImageEnDialog1.FileName); ShowMessage( ImageEnView1.IO.Params.FileTypeStr ); end; !!} // returns the type of last loaded file function TIOParams.GetFileTypeStr: string; var fi: TIEFileFormatInfo; begin // main fi := IEFileFormatGetInfo(fFileType); if assigned(fi) then with fi do result := FullName + ' (' + UpperCase(SuitableExtension) + ')' else result := ''; // sub formats case fFileType of ioTIFF: case TIFF_Compression of ioTIFF_UNCOMPRESSED: result := result + ' Uncompressed'; ioTIFF_CCITT1D: result := result + ' Huffman'; ioTIFF_G3FAX1D: result := result + ' Group 3 Fax'; ioTIFF_G3FAX2D: result := result + ' Group 3 Fax 2D'; ioTIFF_G4FAX: result := result + ' Group 4 Fax'; ioTIFF_LZW: result := result + ' LZW'; ioTIFF_OLDJPEG: result := result + ' Jpeg v.5'; ioTIFF_JPEG: result := result + ' Jpeg'; ioTIFF_PACKBITS: result := result + ' PackBits RLE'; ioTIFF_ZIP: result := result + ' ZIP'; ioTIFF_DEFLATE: result := result+' Deflate'; end; ioJPEG: case JPEG_ColorSpace of ioJPEG_GRAYLEV: result := result + ' Gray level'; ioJPEG_YCbCr: result := result + ' YCbCr'; ioJPEG_CMYK: result := result + ' CMYK'; ioJPEG_YCbCrK: result := result + ' YCbCrK'; end; {$IFDEF IEINCLUDEJPEG2000} ioJP2, ioJ2k: case fJ2000_ColorSpace of ioJ2000_GRAYLEV: result := result + ' Gray level'; ioJ2000_RGB: result := result + ' RGB'; ioJ2000_YCbCr: result := result + ' YCbCr'; end; {$ENDIF} ioPCX: if PCX_Compression = ioPCX_UNCOMPRESSED then result := result + ' Uncompressed'; ioBMP: case BMP_Version of ioBMP_BM: result := result + ' ver.1'; ioBMP_BM3: result := result + ' ver.3'; ioBMP_BMOS2V1: result := result + ' OS/2 v.1'; ioBMP_BMOS2V2: result := result + ' OS/2 v.2'; end; ioGIF: if GIF_Interlaced then result := result + ' Interlaced'; {$IFDEF IEINCLUDEPNG} ioPNG: if PNG_Interlaced then result := result + ' Interlaced'; {$ENDIF} ioTGA: if TGA_Compressed then result := result + ' Compressed' else result := result + ' Uncompressed'; {$ifdef IEINCLUDERAWFORMATS} ioRAW: result := result+' ('+string(RAW_Camera)+')'; {$endif} end; end; function TIOParams.GetProperty(const Prop: WideString): WideString; var ss : WideString; q : integer; begin ss := UpperCase(IERemoveCtrlCharsW(Prop)); if ss = 'FILENAME' then result := FileName else if ss = 'FILETYPESTR' then result := WideString(FileTypeStr) else if ss = 'FILETYPE' then result := IntToStr(FileType) else if ss = 'BITSPERSAMPLE' then result := IntToStr(BitsPerSample) else if ss = 'SAMPLESPERPIXEL' then result := IntToStr(SamplesPerPixel) else if ss = 'WIDTH' then result := IntToStr(Width) else if ss = 'HEIGHT' then result := IntToStr(Height) else if ss = 'DPIX' then result := IntToStr(DpiX) else if ss = 'DPIY' then result := IntToStr(DpiY) else if Copy(ss, 1, 12)='COLORMAPITEM' then begin q := StrToIntDef(Copy(ss, 13, length(ss)), 0); result := IERGB2StrW(ColorMap^[q]); end else if ss = 'COLORMAPCOUNT' then result := IntToStr(ColorMapCount) else if ss = 'ISNATIVEPIXELFORMAT' then result := IEBool2StrW(IsNativePixelFormat) else if ss = 'ENABLEADJUSTORIENTATION' then result := IEBool2StrW(EnableAdjustOrientation) else if ss = 'ABORTING' then begin Result := ''; if assigned( fAttachedTo ) and ( fAttachedTo is TImageEnIO ) then result := IEBool2StrW( TImageEnIO( fAttachedTo ).Aborting) end else if ss = 'TIFF_COMPRESSIONSTR' then begin case TIFF_Compression of ioTIFF_UNCOMPRESSED: result := 'UNCOMPRESSED'; ioTIFF_CCITT1D: result := 'CCITT1D'; ioTIFF_G3FAX1D: result := 'G3FAX1D'; ioTIFF_G3FAX2D: result := 'G3FAX2D'; ioTIFF_G4FAX: result := 'G4FAX'; ioTIFF_LZW: result := 'LZW'; ioTIFF_OLDJPEG: result := 'OLDJPEG'; ioTIFF_JPEG: result := 'JPEG'; ioTIFF_PACKBITS: result := 'PACKBITS'; ioTIFF_ZIP: result := 'ZIP'; ioTIFF_DEFLATE: result := 'DEFLATE'; else result := 'UNKNOWN'; end; end else if ss = 'TIFF_COMPRESSION' then result := IntToStr(integer(TIFF_Compression)) else if ss = 'TIFF_IMAGEINDEX' then result := IntToStr(TIFF_ImageIndex) else if ss = 'TIFF_SUBINDEX' then result := IntToStr(TIFF_SubIndex) else if ss = 'TIFF_IMAGECOUNT' then result := IntToStr(TIFF_ImageCount) else if ss = 'TIFF_JPEGQUALITY' then result := IntToStr(TIFF_JpegQuality) else if ss = 'TIFF_ZIPCOMPRESSION' then result := IntToStr(TIFF_ZIPCompression) else if ss = 'TIFF_STRIPCOUNT' then result := IntToStr(TIFF_StripCount) else if ss = 'TIFF_PHOTOMETINTEPRETSTR' then begin case TIFF_PhotometInterpret of ioTIFF_WHITEISZERO: result := 'WB'; ioTIFF_BLACKISZERO: result := 'BW'; ioTIFF_RGB: result := 'RGB'; ioTIFF_RGBPALETTE: result := 'RGBPAL'; ioTIFF_TRANSPMASK: result := 'TRANSPMASK'; ioTIFF_CMYK: result := 'CMYK'; ioTIFF_YCBCR: result := 'YCBCR'; ioTIFF_CIELAB: result := 'CIELAB'; end; end else if ss = 'TIFF_PHOTOMETINTEPRET' then result := IntToStr(integer(TIFF_PhotometInterpret)) else if ss = 'TIFF_PLANARCONF' then result := IntToStr(TIFF_PlanarConf) else if ss = 'TIFF_NEWSUBFILETYPE' then result := IntToStr(TIFF_NewSubfileType) else if ss = 'TIFF_XPOS' then result := IntToStr(TIFF_XPos) else if ss = 'TIFF_YPOS' then result := IntToStr(TIFF_YPos) else if ss = 'TIFF_GETTILE' then result := IntToStr(TIFF_GetTile) else if ss = 'TIFF_DOCUMENTNAME' then result := WideString(TIFF_DocumentName) else if ss = 'TIFF_IMAGEDESCRIPTION' then result := WideString(TIFF_ImageDescription) else if ss = 'TIFF_PAGENAME' then result := WideString(TIFF_PageName) else if ss = 'TIFF_PAGENUMBER' then result := IntToStr(TIFF_PageNumber) else if ss = 'TIFF_PAGECOUNT' then result := IntToStr(TIFF_PageCount) else if ss = 'TIFF_JPEGCOLORSPACE' then result := IntToStr(integer(TIFF_JPEGColorSpace)) else if ss = 'TIFF_FILLORDER' then result := IntToStr(TIFF_FillOrder) else if ss = 'TIFF_ORIENTATION' then result := IntToStr(TIFF_Orientation) else if ss = 'TIFF_ENABLEADJUSTORIENTATION' then result := IEBool2StrW(TIFF_EnableAdjustOrientation) else if ss = 'TIFF_BYTEORDER' then result := IntToStr(integer(TIFF_ByteOrder)) else if ss = 'DCX_IMAGEINDEX' then result := IntToStr(DCX_ImageIndex) else if ss = 'AVI_FRAMECOUNT' then result := IntToStr(AVI_FrameCount) else if ss = 'AVI_FRAMEDELAYTIME' then result := IEFloatToStrW(AVI_FrameDelayTime) else if ss = 'GIF_VERSION' then result := WideString(GIF_Version) else if ss = 'GIF_IMAGEINDEX' then result := IntToStr(GIF_ImageIndex) else if ss = 'GIF_IMAGECOUNT' then result := IntToStr(GIF_ImageCount) else if ss = 'GIF_XPOS' then result := IntToStr(GIF_XPos) else if ss = 'GIF_YPOS' then result := IntToStr(GIF_YPos) else if ss = 'GIF_DELAYTIME' then result := IntToStr(GIF_DelayTime) else if ss = 'GIF_TRANSPARENT' then result := IEBool2StrW(GIF_FlagTranspColor) else if ss = 'GIF_TRANSPCOLOR' then result := IERGB2StrW(GIF_TranspColor) else if ss = 'GIF_INTERLACED' then result := IEBool2StrW(GIF_Interlaced) else if ss = 'GIF_WINWIDTH' then result := IntToStr(GIF_WinWidth) else if ss = 'GIF_WINHEIGHT' then result := IntToStr(GIF_WinHeight) else if ss = 'GIF_BACKGROUND' then result := IERGB2StrW(GIF_Background) else if ss = 'GIF_RATIO' then result := IntToStr(GIF_Ratio) else if ss = 'JPEG_COLORSPACE' then result := IntToStr(integer(JPEG_ColorSpace)) else if ss = 'JPEG_QUALITY' then result := IntToStr(JPEG_Quality) else if ss = 'JPEG_DCTMETHOD' then result := IntToStr(integer(JPEG_DCTMethod)) else if ss = 'JPEG_OPTIMALHUFFMAN' then result := IEBool2StrW(JPEG_OptimalHuffman) else if ss = 'JPEG_SMOOTH' then result := IntToStr(JPEG_Smooth) else if ss = 'JPEG_PROGRESSIVE' then result := IEBool2StrW(JPEG_Progressive) else if ss = 'JPEG_SCALE_USED' then result := IntToStr(JPEG_Scale_Used) else if ss = 'JPEG_SCALE' then result := IntToStr(integer(JPEG_Scale)) else if ss = 'JPEG_ENABLEADJUSTORIENTATION' then result := IEBool2StrW(JPEG_EnableAdjustOrientation) else if ss = 'JPEG_GETEXIFTHUMBNAIL' then result := IEBool2StrW(JPEG_GetExifThumbnail) else if ss = 'JPEG_WARNINGTOT' then result := IntToStr(JPEG_WarningTot) else if ss = 'JPEG_WARNINGCODE' then result := IntToStr(JPEG_WarningCode) else if ss = 'JPEG_ORIGINALWIDTH' then result := IntToStr(OriginalWidth) else if ss = 'JPEG_ORIGINALHEIGHT' then result := IntToStr(OriginalHeight) else if ss = 'ORIGINALWIDTH' then result := IntToStr(OriginalWidth) else if ss = 'ORIGINALHEIGHT' then result := IntToStr(OriginalHeight) else if ss = 'JPEG_CROMASUBSAMPLING' then result := IntToStr(integer(JPEG_CromaSubsampling)) else if ss = 'PCX_VERSION' then result := IntToStr(PCX_Version) else if ss = 'PCX_COMPRESSION' then result := IntToStr(integer(PCX_Compression)) else if ss = 'BMP_VERSION' then result := IntToStr(integer(BMP_Version)) else if ss = 'BMP_COMPRESSION' then result := IntToStr(integer(BMP_Compression)) else if ss = 'BMP_HANDLETRANSPARENCY' then result := IEBool2StrW(BMP_HandleTransparency) else if ss = 'BMPRAW_CHANNELORDER' then result := IntToStr(integer(BMPRAW_ChannelOrder)) else if ss = 'BMPRAW_PLANES' then result := IntToStr(integer(BMPRAW_Planes)) else if ss = 'BMPRAW_ROWALIGN' then result := IntToStr(BMPRAW_RowAlign) else if ss = 'BMPRAW_HEADERSIZE' then result := IntToStr(BMPRAW_HeaderSize) else if ss = 'BMPRAW_DATAFORMAT' then result := IntToStr(integer(BMPRAW_DataFormat)) else if ss = 'ICO_IMAGEINDEX' then result := IntToStr(ICO_ImageIndex) else if ss = 'ICO_BACKGROUND' then result := IERGB2StrW(ICO_Background) else if ss = 'CUR_IMAGEINDEX' then result := IntToStr(CUR_ImageIndex) else if ss = 'CUR_XHOTSPOT' then result := IntToStr(CUR_XHotSpot) else if ss = 'CUR_YHOTSPOT' then result := IntToStr(CUR_YHotSpot) else if ss = 'CUR_BACKGROUND' then result := IERGB2StrW(CUR_Background) else if ss = 'PNG_INTERLACED' then result := IEBool2StrW(PNG_Interlaced) else if ss = 'PNG_BACKGROUND' then result := IERGB2StrW(PNG_Background) else if ss = 'PNG_FILTER' then result := IntToStr(integer(PNG_Filter)) else if ss = 'PNG_COMPRESSION' then result := IntToStr(PNG_Compression) else if ss = 'PSD_LOADLAYERS' then result := IEBool2StrW(PSD_LoadLayers) else if ss = 'PSD_REPLACELAYERS' then result := IEBool2StrW(PSD_ReplaceLayers) else if ss = 'PSD_HASPREMULTIPLIEDALPHA' then result := IEBool2StrW(PSD_HasPremultipliedAlpha) else if ss = 'HDP_IMAGEQUALITY' then result := IEFloatToStrW(HDP_ImageQuality) else if ss = 'HDP_LOSSLESS' then result := IEBool2StrW(HDP_Lossless) else if ss = 'TGA_XPOS' then result := IntToStr(TGA_XPos) else if ss = 'TGA_YPOS' then result := IntToStr(TGA_YPos) else if ss = 'TGA_COMPRESSED' then result := IEBool2StrW(TGA_Compressed) else if ss = 'TGA_DESCRIPTOR' then result := WideString(TGA_Descriptor) else if ss = 'TGA_AUTHOR' then result := WideString(TGA_Author) else if ss = 'TGA_DATE' then result := datetostr(TGA_Date) else if ss = 'TGA_IMAGENAME' then result := WideString(TGA_ImageName) else if ss = 'TGA_BACKGROUND' then result := IERGB2StrW(TGA_Background) else if ss = 'TGA_ASPECTRATIO' then result := IEFloatToStrW(TGA_AspectRatio) else if ss = 'TGA_GAMMA' then result := IEFloatToStrW(TGA_Gamma) else if ss = 'TGA_GRAYLEVEL' then result := IEBool2StrW(TGA_GrayLevel) {$ifdef IEINCLUDEJPEG2000} else if ss = 'J2000_COLORSPACE' then result := IntToStr(integer(J2000_ColorSpace)) else if ss = 'J2000_RATE' then result := IEFloatToStrW(J2000_Rate) else if ss = 'J2000_SCALABLEBY' then result := IntToStr(integer(J2000_ScalableBy)) {$endif} else if ss = 'PS_PAPERWIDTH' then result := IntToStr(PS_PaperWidth) else if ss = 'PS_PAPERHEIGHT' then result := IntToStr(PS_PaperHeight) else if ss = 'PS_COMPRESSION' then result := IntToStr(integer(PS_Compression)) else if ss = 'PS_TITLE' then result := WideString(PS_Title) else if ss = 'PDF_PAPERWIDTH' then result := IntToStr(PDF_PaperWidth) else if ss = 'PDF_PAPERHEIGHT' then result := IntToStr(PDF_PaperHeight) else if ss = 'PDF_COMPRESSION' then result := IntToStr(integer(PDF_Compression)) else if ss = 'PDF_TITLE' then result := WideString(PDF_Title) else if ss = 'PDF_AUTHOR' then result := WideString(PDF_Author) else if ss = 'PDF_SUBJECT' then result := WideString(PDF_Subject) else if ss = 'PDF_KEYWORDS' then result := WideString(PDF_Keywords) else if ss = 'PDF_CREATOR' then result := WideString(PDF_Creator) else if ss = 'PDF_PRODUCER' then result := WideString(PDF_Producer) else if ss = 'EXIF_HASEXIF' then result := IEBool2StrW(EXIF_HasEXIFData) else if ss = 'EXIF_IMAGEDESCRIPTION' then result := WideString(EXIF_ImageDescription) else if ss = 'EXIF_MAKE' then result := WideString(EXIF_Make) else if ss = 'EXIF_MODEL' then result := WideString(EXIF_Model) else if ss = 'EXIF_ORIENTATION' then result := IntToStr(EXIF_Orientation) else if ss = 'EXIF_XRESOLUTION' then result := IEFloatToStrW(EXIF_XResolution) else if ss = 'EXIF_YRESOLUTION' then result := IEFloatToStrW(EXIF_YResolution) else if ss = 'EXIF_RESOLUTIONUNIT' then result := IntToStr(EXIF_ResolutionUnit) else if ss = 'EXIF_SOFTWARE' then result := WideString(EXIF_Software) else if ss = 'EXIF_DATETIME' then result := WideString(EXIF_Datetime) else if ss = 'EXIF_COPYRIGHT' then result := WideString(EXIF_Copyright) else if ss = 'EXIF_EXPOSURETIME' then result := IEFloatToStrW(EXIF_ExposureTime) else if ss = 'EXIF_FNUMBER' then result := IEFloatToStrW(EXIF_FNumber) else if ss = 'EXIF_EXPOSUREPROGRAM' then result := IntToStr(EXIF_ExposureProgram) else if ss = 'EXIF_EXIFVERSION' then result := WideString(EXIF_EXIFVersion) else if ss = 'EXIF_DATETIMEORIGINAL' then result := WideString(EXIF_DateTimeOriginal) else if ss = 'EXIF_DATETIMEDIGITIZED' then result := WideString(EXIF_DateTimeDigitized) else if ss = 'EXIF_COMPRESSEDBITSPERPIXEL' then result := IEFloatToStrW(EXIF_CompressedBitsPerPixel) else if ss = 'EXIF_SHUTTERSPEEDVALUE' then result := IEFloatToStrW(EXIF_ShutterSpeedValue) else if ss = 'EXIF_APERTUREVALUE' then result := IEFloatToStrW(EXIF_ApertureValue) else if ss = 'EXIF_BRIGHTNESSVALUE' then result := IEFloatToStrW(EXIF_BrightNessValue) else if ss = 'EXIF_EXPOSUREBIASVALUE' then result := IEFloatToStrW(EXIF_ExposureBiasValue) else if ss = 'EXIF_MAXAPERTUREVALUE' then result := IEFloatToStrW(EXIF_MaxApertureValue) else if ss = 'EXIF_SUBJECTDISTANCE' then result := IEFloatToStrW(EXIF_SubjectDistance) else if ss = 'EXIF_METERINGMODE' then result := IntToStr(EXIF_MeteringMode) else if ss = 'EXIF_LIGHTSOURCE' then result := IntToStr(EXIF_LightSource) else if ss = 'EXIF_FLASH' then result := IntToStr(EXIF_Flash) else if ss = 'EXIF_FOCALLENGTH' then result := IEFloatToStrW(EXIF_FocalLength) else if ss = 'EXIF_SUBSECTIME' then result := WideString(EXIF_SubsecTime) else if ss = 'EXIF_SUBSECTIMEORIGINAL' then result := WideString(EXIF_SubsecTimeOriginal) else if ss = 'EXIF_SUBSECTIMEDIGITIZED' then result := WideString(EXIF_SubsecTimeDigitized) else if ss = 'EXIF_FLASHPIXVERSION' then result := WideString(EXIF_FlashPixVersion) else if ss = 'EXIF_COLORSPACE' then result := IntToStr(EXIF_ColorSpace) else if ss = 'EXIF_EXIFIMAGEWIDTH' then result := IntToStr(EXIF_EXIFImageWidth) else if ss = 'EXIF_EXIFIMAGEHEIGHT' then result := IntToStr(EXIF_EXIFImageHeight) else if ss = 'EXIF_RELATEDSOUNDFILE' then result := WideString(EXIF_RelatedSoundFile) else if ss = 'EXIF_FOCALPLANEXRESOLUTION' then result := IEFloatToStrW(EXIF_FocalPlaneXResolution) else if ss = 'EXIF_FOCALPLANEYRESOLUTION' then result := IEFloatToStrW(EXIF_FocalPlaneYResolution) else if ss = 'EXIF_FOCALPLANERESOLUTIONUNIT' then result := IntToStr(EXIF_FocalPlaneResolutionUnit) else if ss = 'EXIF_EXPOSUREINDEX' then result := IEFloatToStrW(EXIF_ExposureIndex) else if ss = 'EXIF_SENSINGMETHOD' then result := IntToStr(EXIF_SensingMethod) else if ss = 'EXIF_FILESOURCE' then result := IntToStr(EXIF_FileSource) else if ss = 'EXIF_SCENETYPE' then result := IntToStr(EXIF_SceneType) else if ss = 'EXIF_USERCOMMENT' then result := EXIF_UserComment else if ss = 'EXIF_USERCOMMENTCODE' then result := WideString(EXIF_UserCommentCode) else if ss = 'EXIF_EXPOSUREMODE' then result := IntToStr(fEXIF_ExposureMode) else if ss = 'EXIF_WHITEBALANCE' then result := IntToStr(fEXIF_WhiteBalance) else if ss = 'EXIF_DIGITALZOOMRATIO' then result := IEFloatToStrW(fEXIF_DigitalZoomRatio) else if ss = 'EXIF_FOCALLENGTHIN35MMFILM' then result := IntToStr(fEXIF_FocalLengthIn35mmFilm) else if ss = 'EXIF_SCENECAPTURETYPE' then result := IntToStr(fEXIF_SceneCaptureType) else if ss = 'EXIF_GAINCONTROL' then result := IntToStr(fEXIF_GainControl) else if ss = 'EXIF_CONTRAST' then result := IntToStr(fEXIF_Contrast) else if ss = 'EXIF_SATURATION' then result := IntToStr(fEXIF_Saturation) else if ss = 'EXIF_SHARPNESS' then result := IntToStr(fEXIF_Sharpness) else if ss = 'EXIF_SUBJECTDISTANCERANGE' then result := IntToStr(fEXIF_SubjectDistanceRange) else if ss = 'EXIF_IMAGEUNIQUEID' then result := WideString(fEXIF_ImageUniqueID) else if ss = 'EXIF_ARTIST' then result := WideString(fEXIF_Artist) else if ss = 'EXIF_ISOSPEEDRATINGS0' then result := IntToStr(EXIF_ISOSpeedRatings[0]) else if ss = 'EXIF_ISOSPEEDRATINGS1' then result := IntToStr(EXIF_ISOSpeedRatings[1]) else if ss = 'EXIF_XPRATING' then result := IntToStr(fEXIF_XPRating) else if ss = 'EXIF_XPTITLE' then result := fEXIF_XPTitle else if ss = 'EXIF_XPCOMMENT' then result := fEXIF_XPComment else if ss = 'EXIF_XPAUTHOR' then result := fEXIF_XPAuthor else if ss = 'EXIF_XPKEYWORDS' then result := fEXIF_XPKeywords else if ss = 'EXIF_XPSUBJECT' then result := fEXIF_XPSubject else if ss = 'EXIF_WHITEPOINT0' then result := IEFloatToStrW(fEXIF_WhitePoint[0]) else if ss = 'EXIF_WHITEPOINT1' then result := IEFloatToStrW(fEXIF_WhitePoint[1]) else if ss = 'EXIF_YCBCRCOEFFICIENTS0' then result := IEFloatToStrW(fEXIF_YCbCrCoefficients[0]) else if ss = 'EXIF_YCBCRCOEFFICIENTS1' then result := IEFloatToStrW(fEXIF_YCbCrCoefficients[1]) else if ss = 'EXIF_YCBCRCOEFFICIENTS2' then result := IEFloatToStrW(fEXIF_YCbCrCoefficients[2]) else if ss = 'EXIF_YCBCRPOSITIONING' then result := IntToStr(EXIF_YCbCrPositioning) else if ss = 'EXIF_GPSVERSIONID' then result := WideString(fEXIF_GPSVersionID) else if ss = 'EXIF_GPSLATITUDE' then result := IEFloatToStrW(EXIF_GPSLatitude) else if ss = 'EXIF_GPSLATITUDEREF' then result := WideString(fEXIF_GPSLatitudeRef) else if ss = 'EXIF_GPSLATITUDEDEGREES' then result := IEFloatToStrW(fEXIF_GPSLatitudeDegrees) else if ss = 'EXIF_GPSLATITUDEMINUTES' then result := IEFloatToStrW(fEXIF_GPSLatitudeMinutes) else if ss = 'EXIF_GPSLATITUDESECONDS' then result := IEFloatToStrW(fEXIF_GPSLatitudeSeconds) else if ss = 'EXIF_GPSLONGITUDE' then result := IEFloatToStrW(EXIF_GPSLongitude) else if ss = 'EXIF_GPSLONGITUDEREF' then result := WideString(fEXIF_GPSLONGITUDEREF) else if ss = 'EXIF_GPSLONGITUDEDEGREES' then result := IEFloatToStrW(fEXIF_GPSLongitudeDegrees) else if ss = 'EXIF_GPSLONGITUDEMINUTES' then result := IEFloatToStrW(fEXIF_GPSLongitudeMinutes) else if ss = 'EXIF_GPSLONGITUDESECONDS' then result := IEFloatToStrW(fEXIF_GPSLongitudeSeconds) else if ss = 'EXIF_GPSALTITUDEREF' then result := WideString(fEXIF_GPSAltitudeRef) else if ss = 'EXIF_GPSALTITUDE' then result := IEFloatToStrW(fEXIF_GPSAltitude) else if ss = 'EXIF_GPSTIMESTAMPHOUR' then result := IEFloatToStrW(fEXIF_GPSTimeStampHour) else if ss = 'EXIF_GPSTIMESTAMPMINUTE' then result := IEFloatToStrW(fEXIF_GPSTimeStampMinute) else if ss = 'EXIF_GPSTIMESTAMPSECOND' then result := IEFloatToStrW(fEXIF_GPSTimeStampSecond) else if ss = 'EXIF_GPSSATELLITES' then result := WideString(fEXIF_GPSSatellites) else if ss = 'EXIF_GPSSTATUS' then result := WideString(fEXIF_GPSStatus) else if ss = 'EXIF_GPSMEASUREMODE' then result := WideString(fEXIF_GPSMeasureMode) else if ss = 'EXIF_GPSDOP' then result := IEFloatToStrW(fEXIF_GPSDOP) else if ss = 'EXIF_GPSSPEEDREF' then result := WideString(fEXIF_GPSSpeedRef) else if ss = 'EXIF_GPSSPEED' then result := IEFloatToStrW(fEXIF_GPSSpeed) else if ss = 'EXIF_GPSTRACKREF' then result := WideString(fEXIF_GPSTrackRef) else if ss = 'EXIF_GPSTRACK' then result := IEFloatToStrW(fEXIF_GPSTrack) else if ss = 'EXIF_GPSIMGDIRECTIONREF' then result := WideString(fEXIF_GPSImgDirectionRef) else if ss = 'EXIF_GPSIMGDIRECTION' then result := IEFloatToStrW(fEXIF_GPSImgDirection) else if ss = 'EXIF_GPSMAPDATUM' then result := WideString(fEXIF_GPSMapDatum) else if ss = 'EXIF_GPSDESTLATITUDEREF' then result := WideString(fEXIF_GPSDestLatitudeRef) else if ss = 'EXIF_GPSDESTLATITUDEDEGREES' then result := IEFloatToStrW(fEXIF_GPSDestLatitudeDegrees) else if ss = 'EXIF_GPSDESTLATITUDEMINUTES' then result := IEFloatToStrW(fEXIF_GPSDestLatitudeMinutes) else if ss = 'EXIF_GPSDESTLATITUDESECONDS' then result := IEFloatToStrW(fEXIF_GPSDestLatitudeSeconds) else if ss = 'EXIF_GPSDESTLONGITUDEREF' then result := WideString(fEXIF_GPSDestLongitudeRef) else if ss = 'EXIF_GPSDESTLONGITUDEDEGREES' then result := IEFloatToStrW(fEXIF_GPSDestLongitudeDegrees) else if ss = 'EXIF_GPSDESTLONGITUDEMINUTES' then result := IEFloatToStrW(fEXIF_GPSDestLongitudeMinutes) else if ss = 'EXIF_GPSDESTLONGITUDESECONDS' then result := IEFloatToStrW(fEXIF_GPSDestLongitudeSeconds) else if ss = 'EXIF_GPSDESTBEARINGREF' then result := WideString(fEXIF_GPSDestBearingRef) else if ss = 'EXIF_GPSDESTBEARING' then result := IEFloatToStrW(fEXIF_GPSDestBearing) else if ss = 'EXIF_GPSDESTDISTANCEREF' then result := WideString(fEXIF_GPSDestDistanceRef) else if ss = 'EXIF_GPSDESTDISTANCE' then result := IEFloatToStrW(fEXIF_GPSDestDistance) else if ss = 'EXIF_GPSDATESTAMP' then result := WideString(fEXIF_GPSDateStamp) else if ss = 'EXIF_CAMERAOWNERNAME' then result := WideString(fEXIF_CameraOwnerName) else if ss = 'EXIF_BODYSERIALNUMBER' then result := WideString(fEXIF_BodySerialNumber) else if ss = 'EXIF_LENSMAKE' then result := WideString(fEXIF_LensMake) else if ss = 'EXIF_LENSMODEL' then result := WideString(fEXIF_LensModel) else if ss = 'EXIF_LENSSERIALNUMBER' then result := WideString(fEXIF_LensSerialNumber) else if ss = 'EXIF_GAMMA' then result := IEFloatToStrW(fEXIF_Gamma) else { x 4 if ss = 'EXIF_SUBJECTAREA' then result := IntToStr(fEXIF_SubjectArea) else } if ss = 'EXIF_SUBJECTLOCATIONX' then result := IntToStr(fEXIF_SubjectLocationX) else if ss = 'EXIF_SUBJECTLOCATIONY' then result := IntToStr(fEXIF_SubjectLocationY) {$ifdef IEINCLUDERAWFORMATS} else if ss = 'RAW_HALFSIZE' then result := IEBool2StrW(RAW_HalfSize) else if ss = 'RAW_GAMMA' then result := IEFloatToStrW(RAW_Gamma) else if ss = 'RAW_BRIGHT' then result := IEFloatToStrW(RAW_Bright) else if ss = 'RAW_REDSCALE' then result := IEFloatToStrW(RAW_RedScale) else if ss = 'RAW_BLUESCALE' then result := IEFloatToStrW(RAW_BlueScale) else if ss = 'RAW_QUICKINTERPOLATE' then result := IEBool2StrW(RAW_QuickInterpolate) else if ss = 'RAW_USEAUTOWB' then result := IEBool2StrW(RAW_UseAutoWB) else if ss = 'RAW_USECAMERAWB' then result := IEBool2StrW(RAW_UseCameraWB) else if ss = 'RAW_FOURCOLORRGB' then result := IEBool2StrW(RAW_FourColorRGB) else if ss = 'RAW_CAMERA' then result := WideString(RAW_Camera) else if ss = 'RAW_GETEXIFTHUMBNAIL' then result := IEBool2StrW(RAW_GetExifThumbnail) else if ss = 'RAW_AUTOADJUSTCOLORS' then result := IEBool2StrW(RAW_AutoAdjustColors) else if ss = 'RAW_EXTRAPARAMS' then result := WideString(RAW_ExtraParams) {$endif} {$IFDEF IEINCLUDEDIRECTSHOW} else if ss = 'MEDIAFILE_FRAMECOUNT' then result := IntToStr(MEDIAFILE_FrameCount) else if ss = 'MEDIAFILE_FRAMEDELAYTIME' then result := IEFloatToStrW(MEDIAFILE_FrameDelayTime) {$ENDIF} else if ss = 'IMAGEINDEX' then result := IntToStr(ImageIndex) else if ss = 'IMAGECOUNT' then result := IntToStr(ImageCount) else if ss = 'GETTHUMBNAIL' then result := IEBool2StrW(GetThumbnail) else if ss = 'ISRESOURCE' then result := IEBool2StrW(IsResource) else if ss = 'XMP_INFO' then result := WideString(XMP_Info) // IEN else if ss = 'IEN_COMPRESSION' then result := IntToStr( fIEN_Compression ) else if ss = 'IEN_DESCRIPTION' then result := fIEN_Description else if ss = 'IEN_LAYERCOUNT' then result := IntToStr( fIEN_LayerCount ) else if ss = 'IEN_VERSION' then result := IntToStr( fIEN_Version) else if ss = 'IEN_GETTHUMBNAIL' then result := BoolToStr( fIEN_GetThumbnail ) // SVG else if ss = 'SVG_IMAGECOMPRESSION' then result := IntToStr( fSVG_ImageCompression ) else result := 'INVALID PROPERTY'; end; procedure TIOParams.SetProperty(Prop, Value: WideString); var ss : WideString; q : integer; begin ss := UpperCase(IERemoveCtrlCharsW(Prop)); Value := IERemoveCtrlCharsW(Value); if ss = 'BITSPERSAMPLE' then BitsPerSample := StrToIntDef(Value, 8) else if ss = 'SAMPLESPERPIXEL' then SamplesPerPixel := StrToIntDef(Value, 8) else if ss = 'WIDTH' then Width := StrToIntDef(Value, 1) else if ss = 'HEIGHT' then Height := StrToIntDef(Value, 1) else if ss = 'DPIX' then DpiX := StrToIntDef(Value, 1) else if ss = 'DPIY' then DpiY := StrToIntDef(Value, 1) else if Copy(ss, 1, 12)='COLORMAPITEM' then begin q := StrToIntDef(Copy(ss, 13, length(ss)), 0); ColorMap^[q] := IEStr2RGBW(Value); end // else // if ss = 'COLORMAPCOUNT' then // readonly else if ss = 'ISNATIVEPIXELFORMAT' then IsNativePixelFormat := IEStr2BoolW(value) else if ss = 'ENABLEADJUSTORIENTATION' then EnableAdjustOrientation := IEStr2BoolW(value) else if ss = 'ABORTING' then begin if assigned( fAttachedTo ) and ( fAttachedTo is TImageEnIO ) then TImageEnIO( fAttachedTo ).Aborting := IEStr2BoolW(value) end else if ss = 'TIFF_COMPRESSION' then TIFF_Compression := TIOTIFFCompression(StrToIntDef(value, 0)) else if ss = 'TIFF_IMAGEINDEX' then TIFF_ImageIndex := StrToIntDef(value, 0) else if ss = 'TIFF_SUBINDEX' then TIFF_SubIndex := StrToIntDef(value, 0) //else // if ss = 'TIFF_IMAGECOUNT' then // readonly else if ss = 'TIFF_PHOTOMETINTEPRET' then TIFF_PhotometInterpret := TIOTIFFPhotometInterpret(StrToIntDef(value, 0)) else if ss = 'TIFF_PLANARCONF' then TIFF_PlanarConf := StrToIntDef(value, 0) else if ss = 'TIFF_NEWSUBFILETYPE' then TIFF_NewSubfileType := StrToIntDef(value, 0) else if ss = 'TIFF_XPOS' then TIFF_XPos := StrToIntDef(value, 0) else if ss = 'TIFF_YPOS' then TIFF_YPos := StrToIntDef(value, 0) else if ss = 'TIFF_GETTILE' then TIFF_GetTile := StrToIntDef(value, -1) else if ss = 'TIFF_JPEGQUALITY' then TIFF_JPEGQuality := StrToIntDef(value, 0) else if ss = 'TIFF_ZIPCOMPRESSION' then TIFF_ZIPCompression := StrToIntDef(value, 0) else if ss = 'TIFF_STRIPCOUNT' then TIFF_StripCount := StrToIntDef(value, 0) else if ss = 'TIFF_DOCUMENTNAME' then TIFF_DocumentName := AnsiString(value) else if ss = 'TIFF_IMAGEDESCRIPTION' then TIFF_ImageDescription := AnsiString(value) else if ss = 'TIFF_PAGENAME' then TIFF_PageName := AnsiString(value) else if ss = 'TIFF_PAGENUMBER' then TIFF_PageNumber := StrToIntDef(value, 0) else if ss = 'TIFF_PAGECOUNT' then TIFF_PageCount := StrToIntDef(value, 0) else if ss = 'TIFF_JPEGCOLORSPACE' then TIFF_JPEGColorSpace := TIOJPEGColorSpace(StrToIntDef(value, 0)) else if ss = 'TIFF_FILLORDER' then TIFF_FillOrder := StrToIntDef(value, 1) else if ss = 'TIFF_ORIENTATION' then TIFF_Orientation := StrToIntDef(value, 1) else if ss = 'TIFF_ENABLEADJUSTORIENTATION' then TIFF_EnableAdjustOrientation := IEStr2BoolW(value) else if ss = 'TIFF_BYTEORDER' then TIFF_ByteOrder := TIOByteOrder(StrToIntDef(value, 1)) else if ss = 'DCX_IMAGEINDEX' then DCX_ImageIndex := StrToIntDef(value, 0) else if ss = 'AVI_FRAMECOUNT' then AVI_FrameCount := StrToIntDef(value, 0) else if ss = 'AVI_FRAMEDELAYTIME' then AVI_FrameDelayTime := IEStrToFloatDefW(value, 0) else if ss = 'GIF_VERSION' then GIF_Version := AnsiString(value) else if ss = 'GIF_IMAGEINDEX' then GIF_ImageIndex := StrToIntDef(value, 0) // else // if ss = 'GIF_IMAGECOUNT' then // read-only else if ss = 'GIF_XPOS' then GIF_XPos := StrToIntDef(value, 0) else if ss = 'GIF_YPOS' then GIF_YPos := StrToIntDef(value, 0) else if ss = 'GIF_DELAYTIME' then GIF_DelayTime := StrToIntDef(value, 0) else if ss = 'GIF_TRANSPARENT' then GIF_FlagTranspColor := IEStr2BoolW(value) else if ss = 'GIF_TRANSPCOLOR' then GIF_TranspColor := IEStr2RGBW(value) else if ss = 'GIF_INTERLACED' then GIF_Interlaced := IEStr2BoolW(value) else if ss = 'GIF_WINWIDTH' then GIF_WinWidth := StrToIntDef(value, 0) else if ss = 'GIF_WINHEIGHT' then GIF_WinHeight := StrToIntDef(value, 0) else if ss = 'GIF_BACKGROUND' then GIF_Background := IEStr2RGBW(value) else if ss = 'GIF_RATIO' then GIF_Ratio := StrToIntDef(value, 0) else if ss = 'JPEG_COLORSPACE' then JPEG_ColorSpace := TIOJPEGColorSpace(StrToIntDef(value, 0)) else if ss = 'JPEG_QUALITY' then JPEG_Quality := StrToIntDef(value, 0) else if ss = 'JPEG_DCTMETHOD' then JPEG_DCTMethod := TIOJPEGDCTMethod(StrToIntDef(value, 0)) else if ss = 'JPEG_OPTIMALHUFFMAN' then JPEG_OptimalHuffman := IEStr2BoolW(value) else if ss = 'JPEG_SMOOTH' then JPEG_Smooth := StrToIntDef(value, 0) else if ss = 'JPEG_PROGRESSIVE' then JPEG_Progressive := IEStr2BoolW(value) else if ss = 'JPEG_SCALE_USED' then JPEG_Scale_Used := StrToIntDef(value, 0) else if ss = 'JPEG_SCALE' then JPEG_Scale := TIOJPEGScale(StrToIntDef(value, 0)) else if ss = 'JPEG_ENABLEADJUSTORIENTATION' then JPEG_EnableAdjustOrientation := IEStr2BoolW(value) else if ss = 'JPEG_GETEXIFTHUMBNAIL' then JPEG_GetExifThumbnail := IEStr2BoolW(value) else if ss = 'JPEG_WARNINGTOT' then JPEG_WarningTot := StrToIntDef(value, 0) else if ss = 'JPEG_WARNINGCODE' then JPEG_WarningCode := StrToIntDef(value, 0) else if ss = 'JPEG_ORIGINALWIDTH' then OriginalWidth := StrToIntDef(value, 0) else if ss = 'JPEG_ORIGINALHEIGHT' then OriginalHeight := StrToIntDef(value, 0) else if ss = 'ORIGINALWIDTH' then OriginalWidth := StrToIntDef(value, 0) else if ss = 'ORIGINALHEIGHT' then OriginalHeight := StrToIntDef(value, 0) else if ss = 'JPEG_CROMASUBSAMPLING' then JPEG_CromaSubsampling := TIOJPEGCROMASUBSAMPLING(StrToIntDef(value, 1)) else if ss = 'PCX_VERSION' then PCX_Version := StrToIntDef(value, 0) else if ss = 'PCX_COMPRESSION' then PCX_Compression := TIOPCXCompression(StrToIntDef(value, 0)) else if ss = 'BMP_VERSION' then BMP_Version := TIOBMPVersion(StrToIntDef(value, 0)) else if ss = 'BMP_COMPRESSION' then BMP_Compression := TIOBMPCompression(StrToIntDef(value, 0)) else if ss = 'BMP_HANDLETRANSPARENCY' then BMP_HandleTransparency := IEStr2BoolW(value) else if ss = 'BMPRAW_CHANNELORDER' then BMPRAW_ChannelOrder := TIOBMPRAWChannelOrder(StrToIntDef(value, 0)) else if ss = 'BMPRAW_PLANES' then BMPRAW_Planes := TIOBMPRAWPlanes(StrToIntDef(value, 0)) else if ss = 'BMPRAW_ROWALIGN' then BMPRAW_RowAlign := StrToIntDef(value, 8) else if ss = 'BMPRAW_HEADERSIZE' then BMPRAW_HeaderSize := StrToIntDef(value, 0) else if ss = 'BMPRAW_DATAFORMAT' then BMPRAW_DataFormat := TIOBMPRAWDataFormat(StrToIntDef(value, 0)) else if ss = 'ICO_IMAGEINDEX' then ICO_ImageIndex := StrToIntDef(value, 0) else if ss = 'ICO_BACKGROUND' then ICO_Background := IEStr2RGBW(value) else if ss = 'CUR_IMAGEINDEX' then CUR_ImageIndex := StrToIntDef(value, 0) else if ss = 'CUR_XHOTSPOT' then CUR_XHotSpot := StrToIntDef(value, 0) else if ss = 'CUR_YHOTSPOT' then CUR_YHotSpot := StrToIntDef(value, 0) else if ss = 'CUR_BACKGROUND' then CUR_Background := IEStr2RGBW(value) else if ss = 'PNG_INTERLACED' then PNG_Interlaced := IEStr2BoolW(value) else if ss = 'PNG_BACKGROUND' then PNG_Background := IEStr2RGBW(value) else if ss = 'PNG_FILTER' then PNG_Filter := TIOPNGFilter(StrToIntDef(value, 0)) else if ss = 'PNG_COMPRESSION' then PNG_Compression := StrToIntDef(value, 1) else if ss = 'PSD_LOADLAYERS' then PSD_LoadLayers := IEStr2BoolW(value) else if ss = 'PSD_REPLACELAYERS' then PSD_ReplaceLayers := IEStr2BoolW(value) // else // if ss = 'PSD_HASPREMULTIPLIEDALPHA' then // readonly, PSD_HasPremultipliedAlpha := IEStr2BoolW(value) else if ss = 'HDP_IMAGEQUALITY' then HDP_ImageQuality := IEStrToFloatDefW(value, 0.9) else if ss = 'HDP_LOSSLESS' then HDP_Lossless := IEStr2BoolW(value) else if ss = 'TGA_XPOS' then TGA_XPos := StrToIntDef(value, 0) else if ss = 'TGA_YPOS' then TGA_YPos := StrToIntDef(value, 0) else if ss = 'TGA_COMPRESSED' then TGA_Compressed := IEStr2BoolW(value) else if ss = 'TGA_DESCRIPTOR' then TGA_Descriptor := AnsiString(value) else if ss = 'TGA_AUTHOR' then TGA_Author := AnsiString(value) else if ss = 'TGA_DATE' then try TGA_Date := strtodate(value) except end else if ss = 'TGA_IMAGENAME' then TGA_ImageName := AnsiString(value) else if ss = 'TGA_BACKGROUND' then TGA_Background := IEStr2RGBW(value) else if ss = 'TGA_ASPECTRATIO' then try TGA_AspectRatio := IEStrToFloatDefW(value, 0) except end else if ss = 'TGA_GAMMA' then try TGA_Gamma := IEStrToFloatDefW(value, 0) except end else if ss = 'TGA_GRAYLEVEL' then TGA_GrayLevel := IEStr2BoolW(value) {$ifdef IEINCLUDEJPEG2000} else if ss = 'J2000_COLORSPACE' then J2000_ColorSpace := TIOJ2000ColorSpace(StrToIntDef(value, 0)) else if ss = 'J2000_RATE' then try J2000_Rate := IEStrToFloatDefW(value, 0) except end else if ss = 'J2000_SCALABLEBY' then J2000_ScalableBy := TIOJ2000ScalableBy(StrToIntDef(value, 0)) {$endif} else if ss = 'PS_PAPERWIDTH' then PS_PaperWidth := StrToIntDef(value, 595) else if ss = 'PS_PAPERHEIGHT' then PS_PaperHeight := StrToIntDef(value, 842) else if ss = 'PS_COMPRESSION' then PS_Compression := TIOPSCompression(StrToIntDef(value, 0)) else if ss = 'PS_TITLE' then PS_Title := AnsiString(value) else if ss = 'PDF_PAPERWIDTH' then PDF_PaperWidth := StrToIntDef(value, 595) else if ss = 'PDF_PAPERHEIGHT' then PDF_PaperHeight := StrToIntDef(value, 842) else if ss = 'PDF_COMPRESSION' then PDF_Compression := TIOPDFCompression(StrToIntDef(value, 0)) else if ss = 'PDF_TITLE' then PDF_Title := AnsiString(value) else if ss = 'PDF_AUTHOR' then PDF_Author := AnsiString(value) else if ss = 'PDF_SUBJECT' then PDF_Subject := AnsiString(value) else if ss = 'PDF_KEYWORDS' then PDF_Keywords := AnsiString(value) else if ss = 'PDF_CREATOR' then PDF_Creator := AnsiString(value) else if ss = 'PDF_PRODUCER' then PDF_Producer := AnsiString(value) else if ss = 'EXIF_HASEXIF' then EXIF_HasEXIFData := IEStr2BoolW(value) else if ss = 'EXIF_IMAGEDESCRIPTION' then EXIF_ImageDescription := AnsiString(value) else if ss = 'EXIF_MAKE' then EXIF_Make := AnsiString(value) else if ss = 'EXIF_MODEL' then EXIF_Model := AnsiString(value) else if ss = 'EXIF_ORIENTATION' then EXIF_Orientation := StrToIntDef(value, 0) else if ss = 'EXIF_XRESOLUTION' then try EXIF_XResolution := IEStrToFloatDefW(value, 0); except end else if ss = 'EXIF_YRESOLUTION' then try EXIF_YResolution := IEStrToFloatDefW(value, 0); except end else if ss = 'EXIF_RESOLUTIONUNIT' then EXIF_ResolutionUnit := StrToIntDef(value, 0) else if ss = 'EXIF_SOFTWARE' then EXIF_Software := AnsiString(value) else if ss = 'EXIF_DATETIME' then EXIF_Datetime := AnsiString(value) else if ss = 'EXIF_COPYRIGHT' then EXIF_Copyright := AnsiString(value) else if ss = 'EXIF_EXPOSURETIME' then try EXIF_ExposureTime := IEStrToFloatDefW(value, 0) except end else if ss = 'EXIF_FNUMBER' then try EXIF_FNumber := IEStrToFloatDefW(value, -1) except end else if ss = 'EXIF_EXPOSUREPROGRAM' then EXIF_ExposureProgram := StrToIntDef(value, -1) else if ss = 'EXIF_EXIFVERSION' then EXIF_EXIFVersion := AnsiString(value) else if ss = 'EXIF_DATETIMEORIGINAL' then EXIF_DateTimeOriginal := AnsiString(value) else if ss = 'EXIF_DATETIMEDIGITIZED' then EXIF_DateTimeDigitized := AnsiString(value) else if ss = 'EXIF_COMPRESSEDBITSPERPIXEL' then try EXIF_CompressedBitsPerPixel := IEStrToFloatDefW(value, 0) except end else if ss = 'EXIF_SHUTTERSPEEDVALUE' then try EXIF_ShutterSpeedValue := IEStrToFloatDefW(value, -1); except end else if ss = 'EXIF_APERTUREVALUE' then try EXIF_ApertureValue := IEStrToFloatDefW(value, -1); except end else if ss = 'EXIF_BRIGHTNESSVALUE' then try EXIF_BrightNessValue := IEStrToFloatDefW(value, -1000); except end else if ss = 'EXIF_EXPOSUREBIASVALUE' then try EXIF_ExposureBiasValue := IEStrToFloatDefW(value, -1000); except end else if ss = 'EXIF_MAXAPERTUREVALUE' then try EXIF_MaxApertureValue := IEStrToFloatDefW(value, -1000); except end else if ss = 'EXIF_SUBJECTDISTANCE' then try EXIF_SubjectDistance := IEStrToFloatDefW(value, -1); except end else if ss = 'EXIF_METERINGMODE' then EXIF_MeteringMode := StrToIntDef(value, -1) else if ss = 'EXIF_LIGHTSOURCE' then EXIF_LightSource := StrToIntDef(value, -1) else if ss = 'EXIF_FLASH' then EXIF_Flash := StrToIntDef(value, -1) else if ss = 'EXIF_FOCALLENGTH' then try EXIF_FocalLength := IEStrToFloatDefW(value, -1) except end else if ss = 'EXIF_SUBSECTIME' then EXIF_SubsecTime := AnsiString(value) else if ss = 'EXIF_SUBSECTIMEORIGINAL' then EXIF_SubsecTimeOriginal := AnsiString(value) else if ss = 'EXIF_SUBSECTIMEDIGITIZED' then EXIF_SubsecTimeDigitized := AnsiString(value) else if ss = 'EXIF_FLASHPIXVERSION' then EXIF_FlashPixVersion := AnsiString(value) else if ss = 'EXIF_COLORSPACE' then EXIF_ColorSpace := StrToIntDef(value, -1) else if ss = 'EXIF_EXIFIMAGEWIDTH' then EXIF_EXIFImageWidth := StrToIntDef(value, 0) else if ss = 'EXIF_EXIFIMAGEHEIGHT' then EXIF_EXIFImageHeight := StrToIntDef(value, 0) else if ss = 'EXIF_RELATEDSOUNDFILE' then EXIF_RelatedSoundFile := AnsiString(value) else if ss = 'EXIF_FOCALPLANEXRESOLUTION' then try EXIF_FocalPlaneXResolution := IEStrToFloatDefW(value, -1) except end else if ss = 'EXIF_FOCALPLANEYRESOLUTION' then try EXIF_FocalPlaneYResolution := IEStrToFloatDefW(value, -1) except end else if ss = 'EXIF_FOCALPLANERESOLUTIONUNIT' then EXIF_FocalPlaneResolutionUnit := StrToIntDef(value, -1) else if ss = 'EXIF_EXPOSUREINDEX' then try EXIF_ExposureIndex := IEStrToFloatDefW(value, -1) except end else if ss = 'EXIF_SENSINGMETHOD' then EXIF_SensingMethod := StrToIntDef(value, -1) else if ss = 'EXIF_FILESOURCE' then EXIF_FileSource := StrToIntDef(value, -1) else if ss = 'EXIF_SCENETYPE' then EXIF_SceneType := StrToIntDef(value, -1) else if ss = 'EXIF_USERCOMMENT' then EXIF_UserComment := value else if ss = 'EXIF_USERCOMMENTCODE' then EXIF_UserCommentCode := AnsiString(value) else if ss = 'EXIF_EXPOSUREMODE' then fEXIF_ExposureMode := StrToIntDef(value, -1) else if ss = 'EXIF_WHITEBALANCE' then fEXIF_WhiteBalance := StrToIntDef(value, -1) else if ss = 'EXIF_DIGITALZOOMRATIO' then fEXIF_DigitalZoomRatio := IEStrToFloatDefW(value, -1) else if ss = 'EXIF_FOCALLENGTHIN35MMFILM' then fEXIF_FocalLengthIn35mmFilm := StrToIntDef(value, -1) else if ss = 'EXIF_SCENECAPTURETYPE' then fEXIF_SceneCaptureType := StrToIntDef(value, -1) else if ss = 'EXIF_GAINCONTROL' then fEXIF_GainControl := StrToIntDef(value, -1) else if ss = 'EXIF_CONTRAST' then fEXIF_Contrast := StrToIntDef(value, -1) else if ss = 'EXIF_SATURATION' then fEXIF_Saturation := StrToIntDef(value, -1) else if ss = 'EXIF_SHARPNESS' then fEXIF_Sharpness := StrToIntDef(value, -1) else if ss = 'EXIF_SUBJECTDISTANCERANGE' then fEXIF_SubjectDistanceRange := StrToIntDef(value, -1) else if ss = 'EXIF_IMAGEUNIQUEID' then fEXIF_ImageUniqueID := AnsiString(value) else if ss = 'EXIF_GPSVERSIONID' then fEXIF_GPSVersionID := AnsiString(value) else if ss = 'EXIF_GPSLATITUDE' then EXIF_GPSLatitude := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSLATITUDEREF' then fEXIF_GPSLatitudeRef := AnsiString(value) else if ss = 'EXIF_GPSLATITUDEDEGREES' then fEXIF_GPSLatitudeDegrees := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSLATITUDEMINUTES' then fEXIF_GPSLatitudeMinutes := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSLATITUDESECONDS' then fEXIF_GPSLatitudeSeconds := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSLONGITUDE' then EXIF_GPSLongitude := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSLONGITUDEREF' then fEXIF_GPSLONGITUDEREF := AnsiString(value) else if ss = 'EXIF_GPSLONGITUDEDEGREES' then fEXIF_GPSLongitudeDegrees := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSLONGITUDEMINUTES' then fEXIF_GPSLongitudeMinutes := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSLONGITUDESECONDS' then fEXIF_GPSLongitudeSeconds := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSALTITUDEREF' then fEXIF_GPSAltitudeRef := AnsiString(value) else if ss = 'EXIF_GPSALTITUDE' then fEXIF_GPSAltitude := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSTIMESTAMPHOUR' then fEXIF_GPSTimeStampHour := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSTIMESTAMPMINUTE' then fEXIF_GPSTimeStampMinute := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSTIMESTAMPSECOND' then fEXIF_GPSTimeStampSecond := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSSATELLITES' then fEXIF_GPSSatellites := AnsiString(value) else if ss = 'EXIF_GPSSTATUS' then fEXIF_GPSStatus := AnsiString(value) else if ss = 'EXIF_GPSMEASUREMODE' then fEXIF_GPSMeasureMode := AnsiString(value) else if ss = 'EXIF_GPSDOP' then fEXIF_GPSDOP := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSSPEEDREF' then fEXIF_GPSSpeedRef := AnsiString(value) else if ss = 'EXIF_GPSSPEED' then fEXIF_GPSSpeed := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSTRACKREF' then fEXIF_GPSTrackRef := AnsiString(value) else if ss = 'EXIF_GPSTRACK' then fEXIF_GPSTrack := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSIMGDIRECTIONREF' then fEXIF_GPSImgDirectionRef := AnsiString(value) else if ss = 'EXIF_GPSIMGDIRECTION' then fEXIF_GPSImgDirection := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSMAPDATUM' then fEXIF_GPSMapDatum := AnsiString(value) else if ss = 'EXIF_GPSDESTLATITUDEREF' then fEXIF_GPSDestLatitudeRef := AnsiString(value) else if ss = 'EXIF_GPSDESTLATITUDEDEGREES' then fEXIF_GPSDestLatitudeDegrees := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSDESTLATITUDEMINUTES' then fEXIF_GPSDestLatitudeMinutes := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSDESTLATITUDESECONDS' then fEXIF_GPSDestLatitudeSeconds := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSDESTLONGITUDEREF' then fEXIF_GPSDestLongitudeRef := AnsiString(value) else if ss = 'EXIF_GPSDESTLONGITUDEDEGREES' then fEXIF_GPSDestLongitudeDegrees := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSDESTLONGITUDEMINUTES' then fEXIF_GPSDestLongitudeMinutes := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSDESTLONGITUDESECONDS' then fEXIF_GPSDestLongitudeSeconds := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSDESTBEARINGREF' then fEXIF_GPSDestBearingRef := AnsiString(value) else if ss = 'EXIF_GPSDESTBEARING' then fEXIF_GPSDestBearing := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSDESTDISTANCEREF' then fEXIF_GPSDestDistanceRef := AnsiString(value) else if ss = 'EXIF_GPSDESTDISTANCE' then fEXIF_GPSDestDistance := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_GPSDATESTAMP' then fEXIF_GPSDateStamp := AnsiString(value) else if ss = 'EXIF_ISOSPEEDRATINGS0' then fEXIF_ISOSpeedRatings[0] := StrToIntDef(value, 0) else if ss = 'EXIF_ISOSPEEDRATINGS1' then fEXIF_ISOSpeedRatings[1] := StrToIntDef(value, 0) else if ss = 'EXIF_ARTIST' then fEXIF_Artist := AnsiString(value) else if ss = 'EXIF_XPRATING' then fEXIF_XPRating := StrToIntDef(value, -1) else if ss = 'EXIF_XPTITLE' then fEXIF_XPTitle := value else if ss = 'EXIF_XPCOMMENT' then fEXIF_XPComment := value else if ss = 'EXIF_XPAUTHOR' then fEXIF_XPAuthor := value else if ss = 'EXIF_XPKEYWORDS' then fEXIF_XPKeywords := value else if ss = 'EXIF_XPSUBJECT' then fEXIF_XPSubject := value else if ss = 'EXIF_WHITEPOINT0' then fEXIF_WhitePoint[0] := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_WHITEPOINT1' then fEXIF_WhitePoint[1] := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_YCBCRCOEFFICIENTS0' then fEXIF_YCbCrCoefficients[0] := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_YCBCRCOEFFICIENTS1' then fEXIF_YCbCrCoefficients[1] := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_YCBCRCOEFFICIENTS2' then fEXIF_YCbCrCoefficients[2] := IEStrToFloatDefW(value, 0) else if ss = 'EXIF_YCBCRPOSITIONING' then EXIF_YCbCrPositioning := StrToIntDef(value, 0) else if ss = 'EXIF_CAMERAOWNERNAME' then EXIF_CameraOwnerName := AnsiString(Value) else if ss = 'EXIF_BODYSERIALNUMBER' then EXIF_BodySerialNumber := AnsiString(Value) else if ss = 'EXIF_LENSMAKE' then EXIF_LensMake := AnsiString(Value) else if ss = 'EXIF_LENSMODEL' then EXIF_LensModel := AnsiString(Value) else if ss = 'EXIF_LENSSERIALNUMBER' then EXIF_LensSerialNumber := AnsiString(Value) else if ss = 'EXIF_GAMMA' then EXIF_Gamma := IEStrToFloatDefW(value, 0) else { x 4 if ss = 'EXIF_SUBJECTAREA' then EXIF_SubjectArea := StrToIntDef(value, 0) else } if ss = 'EXIF_SUBJECTLOCATIONX' then EXIF_SubjectLocationX := StrToIntDef(value, 0) else if ss = 'EXIF_SUBJECTLOCATIONY' then EXIF_SubjectLocationY := StrToIntDef(value, 0) {$ifdef IEINCLUDERAWFORMATS} else if ss = 'RAW_HALFSIZE' then RAW_HalfSize := IEStr2BoolW(value) else if ss = 'RAW_GAMMA' then RAW_Gamma := IEStrToFloatDefW(value, 0) else if ss = 'RAW_BRIGHT' then RAW_Bright := IEStrToFloatDefW(value, 0) else if ss = 'RAW_REDSCALE' then RAW_RedScale := IEStrToFloatDefW(value, 0) else if ss = 'RAW_BLUESCALE' then RAW_BlueScale := IEStrToFloatDefW(value, 0) else if ss = 'RAW_QUICKINTERPOLATE' then RAW_QuickInterpolate := IEStr2BoolW(value) else if ss = 'RAW_USEAUTOWB' then RAW_UseAutoWB := IEStr2BoolW(value) else if ss = 'RAW_USECAMERAWB' then RAW_UseCameraWB := IEStr2BoolW(value) else if ss = 'RAW_FOURCOLORRGB' then RAW_FourColorRGB := IEStr2BoolW(value) else if ss = 'RAW_CAMERA' then RAW_Camera := AnsiString(value) else if ss = 'RAW_GETEXIFTHUMBNAIL' then RAW_GetExifThumbnail := IEStr2BoolW(value) else if ss = 'RAW_AUTOADJUSTCOLORS' then RAW_AutoAdjustColors := IEStr2BoolW(value) else if ss = 'RAW_EXTRAPARAMS' then RAW_ExtraParams := AnsiString(value) {$endif} {$IFDEF IEINCLUDEDIRECTSHOW} else if ss = 'MEDIAFILE_FRAMECOUNT' then MEDIAFILE_FrameCount := StrToIntDef(value, 0) else if ss = 'MEDIAFILE_FRAMEDELAYTIME' then MEDIAFILE_FrameDelayTime := IEStrToFloatDefW(value, 0) {$ENDIF} else if ss = 'IMAGEINDEX' then ImageIndex := StrToIntDef(value, 0) else if ss = 'IMAGECOUNT' then ImageCount := StrToIntDef(value, 0) else if ss = 'GETTHUMBNAIL' then GetThumbnail := IEStr2BoolW(value) else if ss = 'ISRESOURCE' then IsResource := IEStr2BoolW(value) else if ss = 'XMP_INFO' then XMP_Info := AnsiString(value) // IEN else if ss = 'IEN_COMPRESSION' then fIEN_Compression := StrToIntDef(value, -1) else if ss = 'IEN_DESCRIPTION' then fIEN_Description := value else if ss = 'IEN_LAYERCOUNT' then fIEN_LayerCount := StrToIntDef(value, 0) else if ss = 'IEN_VERSION' then fIEN_Version := StrToIntDef(value, 0) else if ss = 'IEN_GETTHUMBNAIL' then fIEN_GetThumbnail := IEStr2BoolW(value) // SVG else if ss = 'SVG_IMAGECOMPRESSION' then fSVG_ImageCompression := StrToIntDef(value, ioPNG) end; {!! TIOParams.UpdateEXIFThumbnail Declaration procedure UpdateEXIFThumbnail(Width: integer = 160; Height: integer = -1; ResampleFilter: = rfTriangle); Description Updates the property with the content of current image. You should call this method just before saving a JPEG so the thumbnail is consistent with the saved image. Parameter Description Width Width of the thumbnail. Height Height of the thumbnail. ResampleFilter Interpolation filter to use when resampling.
Example ImageEnView1.IO.LoadFromFile('C:\input.jpg'); ImageEnView1.Proc.Negative; ImageEnView1.IO.Params.UpdateEXIFThumbnail; ImageEnView1.IO.SaveToFile('D:\output.jpg'); !!} procedure TIOParams.UpdateEXIFThumbnail(Width: integer = 160; Height: integer = -1; ResampleFilter: TResampleFilter = rfTriangle); var proc: TImageEnProc; begin if fEXIF_Bitmap = nil then fEXIF_Bitmap := TIEBitmap.Create; if assigned( fAttachedTo ) and ( fAttachedTo is TImageEnIO ) then proc := TImageEnProc.CreateFromBitmap( TImageEnIO( fAttachedTo ).IEBitmap ) else if assigned( fAttachedTo ) and ( fAttachedTo is TIEBitmap ) then proc := TImageEnProc.CreateFromBitmap( TIEBitmap( fAttachedTo )) else exit; try proc.ResampleTo(fEXIF_Bitmap, Width, Height, ResampleFilter); finally proc.free; end; end; procedure TIOParams.EXIFTagsAdd(tag: Integer); begin if fEXIF_Tags.IndexOf(pointer(tag))<0 then fEXIF_Tags.Add(pointer(tag)); end; procedure TIOParams.EXIFTagsDel(tag: Integer); var p: Integer; begin p := fEXIF_Tags.IndexOf(pointer(tag)); if p > -1 then fEXIF_Tags.Delete(p); end; procedure TIOParams.SetEXIF_ExposureTime(value: Double); begin fEXIF_ExposureTime := value; if value <> -1 then EXIFTagsAdd($829A) else EXIFTagsDel($829A); end; procedure TIOParams.SetEXIF_FNumber(value: Double); begin fEXIF_FNumber := value; if value <> -1 then EXIFTagsAdd($829D) else EXIFTagsDel($829D); end; procedure TIOParams.SetEXIF_ExposureProgram(value: Integer); begin fEXIF_ExposureProgram := value; if value <> -1 then EXIFTagsAdd($8822) else EXIFTagsDel($8822); end; procedure TIOParams.SetEXIF_CompressedBitsPerPixel(value: Double); begin fEXIF_CompressedBitsPerPixel := value; if value <> 0 then EXIFTagsAdd($9102) else EXIFTagsDel($9102); end; procedure TIOParams.SetEXIF_DateTime2(const Value: TDateTime); begin EXIF_DateTime := AnsiString(DateTimeToEXIFDate(Value)); end; procedure TIOParams.SetEXIF_DateTimeDigitized2(const Value: TDateTime); begin EXIF_DateTimeDigitized := AnsiString(DateTimeToEXIFDate(Value)); end; procedure TIOParams.SetEXIF_DateTimeOriginal2(const Value: TDateTime); begin EXIF_DateTimeOriginal := AnsiString(DateTimeToEXIFDate(Value)); end; procedure TIOParams.SetEXIF_ShutterSpeedValue(value: Double); begin fEXIF_ShutterSpeedValue := value; if value <> -1 then EXIFTagsAdd($9201) else EXIFTagsDel($9201); end; procedure TIOParams.SetEXIF_ApertureValue(value: Double); begin fEXIF_ApertureValue := value; if value <> -1 then EXIFTagsAdd($9202) else EXIFTagsDel($9202); end; procedure TIOParams.SetEXIF_BrightnessValue(value: Double); begin fEXIF_BrightnessValue := value; if value <> -1000 then EXIFTagsAdd($9203) else EXIFTagsDel($9203); end; procedure TIOParams.SetEXIF_ExposureBiasValue(value: Double); begin fEXIF_ExposureBiasValue := value; if value <> -1000 then EXIFTagsAdd($9204) else EXIFTagsDel($9204); end; procedure TIOParams.SetEXIF_MaxApertureValue(value: Double); begin fEXIF_MaxApertureValue := value; if value <> -1000 then EXIFTagsAdd($9205) else EXIFTagsDel($9205); end; procedure TIOParams.SetEXIF_SubjectDistance(value: Double); begin fEXIF_SubjectDistance := value; if value <> -1 then EXIFTagsAdd($9206) else EXIFTagsDel($9206); end; procedure TIOParams.SetEXIF_MeteringMode(value: Integer); begin fEXIF_MeteringMode := value; if value <> -1 then EXIFTagsAdd($9207) else EXIFTagsDel($9207); end; procedure TIOParams.SetEXIF_LightSource(value: Integer); begin fEXIF_LightSource := value; if value <> -1 then EXIFTagsAdd($9208) else EXIFTagsDel($9208); end; procedure TIOParams.SetEXIF_Flash(value: Integer); begin fEXIF_Flash := value; if value <> -1 then EXIFTagsAdd($9209) else EXIFTagsDel($9209); end; procedure TIOParams.SetEXIF_FocalLength(value: Double); begin fEXIF_FocalLength := value; if value <> -1 then EXIFTagsAdd($920A) else EXIFTagsDel($920A); end; procedure TIOParams.SetEXIF_ColorSpace(value: Integer); begin fEXIF_ColorSpace := value; if value <> -1 then EXIFTagsAdd($A001) else EXIFTagsDel($A001); end; procedure TIOParams.SetEXIF_ExifImageWidth(value: Integer); begin fEXIF_ExifImageWidth := value; if value <> 0 then EXIFTagsAdd($A002) else EXIFTagsDel($A002); end; procedure TIOParams.SetEXIF_ExifImageHeight(value: Integer); begin fEXIF_ExifImageHeight := value; if value <> 0 then EXIFTagsAdd($A003) else EXIFTagsDel($A003); end; procedure TIOParams.SetEXIF_FocalPlaneXResolution(value: Double); begin fEXIF_FocalPlaneXResolution := value; if value <> -1 then EXIFTagsAdd($A20E) else EXIFTagsDel($A20E); end; procedure TIOParams.SetEXIF_FocalPlaneYResolution(value: Double); begin fEXIF_FocalPlaneYResolution := value; if value <> -1 then EXIFTagsAdd($A20F) else EXIFTagsDel($A20F); end; procedure TIOParams.SetEXIF_FocalPlaneResolutionUnit(value: Integer); begin fEXIF_FocalPlaneResolutionUnit := value; if value <> -1 then EXIFTagsAdd($A210) else EXIFTagsDel($A210); end; procedure TIOParams.SetEXIF_ExposureIndex(value: Double); begin fEXIF_ExposureIndex := value; if value <> -1 then EXIFTagsAdd($A215) else EXIFTagsDel($A215); end; procedure TIOParams.SetEXIF_SensingMethod(value: Integer); begin fEXIF_SensingMethod := value; if value <> -1 then EXIFTagsAdd($A217) else EXIFTagsDel($A217); end; procedure TIOParams.SetEXIF_FileSource(value: Integer); begin fEXIF_FileSource := value; if value <> -1 then EXIFTagsAdd($A300) else EXIFTagsDel($A300); end; procedure TIOParams.SetEXIF_SceneType(value: Integer); begin fEXIF_SceneType := value; if value <> -1 then EXIFTagsAdd($A301) else EXIFTagsDel($A301); end; procedure TIOParams.SetEXIF_Gamma(value: Double); begin fEXIF_Gamma := value; end; procedure TIOParams.SetEXIF_SubjectLocationX(value: Integer); begin fEXIF_SubjectLocationX := value; end; procedure TIOParams.SetEXIF_SubjectLocationY(value: Integer); begin fEXIF_SubjectLocationY := value; end; function TIOParams.GetEXIF_DateTime2: TDateTime; begin Result := EXIFDateToDateTime(string(EXIF_DateTime)); end; function TIOParams.GetEXIF_DateTimeDigitized2: TDateTime; begin Result := EXIFDateToDateTime(string(EXIF_DateTimeDigitized)); end; function TIOParams.GetEXIF_DateTimeOriginal2: TDateTime; begin Result := EXIFDateToDateTime(string(EXIF_DateTimeOriginal)); end; {!! TIOParams.AdjustGPSCoordinates Declaration procedure AdjustGPSCoordinates(); Description Adjusts the GPS properties (ie
, , etc...) to fit into integer values (when possible). This method is automatically called when loading EXIF-GPS tags. !!} procedure TIOParams.AdjustGPSCoordinates(); procedure AdjustOne(dir: AnsiString; var degrees: Double; var minutes: Double; var seconds: Double; var ref: AnsiString); var v: Double; begin v := IEGPSConvertDMSToDegDec(degrees, minutes, seconds, ref); IEGPSConvertDegDecToDMS(dir, v, degrees, minutes, seconds, ref); end; begin AdjustOne('SN', fEXIF_GPSLatitudeDegrees, fEXIF_GPSLatitudeMinutes, fEXIF_GPSLatitudeSeconds, fEXIF_GPSLatitudeRef); AdjustOne('WE', fEXIF_GPSLongitudeDegrees, fEXIF_GPSLongitudeMinutes, fEXIF_GPSLongitudeSeconds, fEXIF_GPSLongitudeRef); AdjustOne('SN', fEXIF_GPSDestLatitudeDegrees, fEXIF_GPSDestLatitudeMinutes, fEXIF_GPSDestLatitudeSeconds, fEXIF_GPSDestLatitudeRef); AdjustOne('WE', fEXIF_GPSDestLongitudeDegrees, fEXIF_GPSDestLongitudeMinutes, fEXIF_GPSDestLongitudeSeconds, fEXIF_GPSDestLongitudeRef); end; function LatLongStr(const dGPSDegrees, dGPSMinutes, dGPSSeconds : Double; const sGPSReference : string) : string; // remove the null terminator from a string function RemoveNull(Value : string) : string; begin result := trim(Value); if (result <> '') and (result[length(result)] = #0) then SetLength(result, length(result) - 1); result := trim(result); end; var iOutDegrees : Integer; iOutMinutes : Integer; dOutSeconds : Double; begin Result := ''; if (dGPSDegrees <> 0) or (RemoveNull(sGPSReference)<>'') then begin iOutDegrees := Trunc(dGPSDegrees); iOutMinutes := Trunc(dGPSMinutes); dOutSeconds := dGPSSeconds; if dOutSeconds = 0 then dOutSeconds := Frac(dGPSMinutes) * 60; result := IntToStr(iOutDegrees) + '° ' + IntToStr(iOutMinutes) + ''' ' + IEFloatToFormatString(dOutSeconds, 2, True) + '" ' + Uppercase(RemoveNull(sGPSReference)); end; end; function TIOParams.GetEXIF_GPSLatitude_Str: string; begin Result := string( LatLongStr(EXIF_GPSLatitudeDegrees, EXIF_GPSLatitudeMinutes, EXIF_GPSLatitudeSeconds, string(EXIF_GPSLatitudeRef)) ); end; procedure TIOParams.SetEXIF_GPSLatitude(value: Double); begin IEGPSConvertDegDecToDMS('SN', value, fEXIF_GPSLatitudeDegrees, fEXIF_GPSLatitudeMinutes, fEXIF_GPSLatitudeSeconds, fEXIF_GPSLatitudeRef); end; function TIOParams.GetEXIF_GPSLatitude(): Double; begin result := IEGPSConvertDMSToDegDec(EXIF_GPSLatitudeDegrees, EXIF_GPSLatitudeMinutes, EXIF_GPSLatitudeSeconds, EXIF_GPSLatitudeRef); end; function TIOParams.GetEXIF_GPSLongitude(): Double; begin result := IEGPSConvertDMSToDegDec(EXIF_GPSLongitudeDegrees, EXIF_GPSLongitudeMinutes, EXIF_GPSLongitudeSeconds, EXIF_GPSLongitudeRef); end; function TIOParams.GetEXIF_GPSLongitude_Str: string; begin Result := string( LatLongStr(EXIF_GPSLongitudeDegrees, EXIF_GPSLongitudeMinutes, EXIF_GPSLongitudeSeconds, string(EXIF_GPSLongitudeRef)) ); end; procedure TIOParams.SetEXIF_GPSLongitude(value: Double); begin IEGPSConvertDegDecToDMS('WE', value, fEXIF_GPSLongitudeDegrees, fEXIF_GPSLongitudeMinutes, fEXIF_GPSLongitudeSeconds, fEXIF_GPSLongitudeRef); end; {!! TIOParams.Read Declaration function Read(const FileName: WideString; Format: = ioUnknown): Boolean; overload; function Read(const FileName: WideString; bUseExtension: Boolean): Boolean; overload; function Read(Stream: TStream; Format: = ioUnknown): Boolean; overload; function Read(Buffer: Pointer; BufferSize: Integer; Format: = ioUnknown): Boolean; overload; Description Reads the properties of an image. Result is false if a loading error is encountered due to a corrupt or unknown image format. FileName is the file name with full path. Format is the file format that the stream or file contains. If ioUnknown is specified then the file content is analyzed to determine the format. bUseExtension determines that the file format is based on the extension of the file, e.g. image.jpeg will be processed as ioJPEG format. Examples // Load the parameters of an image (which may be a BMP file, but we will examine the content to be sure) IOParams.Read( 'C:\alfa.bmp' ); Label1.Caption := 'alfa.bmp has ' + inttostr(IOParams.BitsPerSample) + ' bits per sample'; // Load the parameters of a BMP IOParams.Read( 'C:\alfa.bmp', ioBMP ); Label1.Caption := 'alfa.bmp has ' + inttostr(IOParams.BitsPerSample) + ' bits per sample'; // Load the parameters of a file. It will be assumed to a BMP because of the file extension IOParams.Read( 'C:\alfa.bmp', True ); Label1.Caption := 'alfa.bmp has ' + inttostr(IOParams.BitsPerSample) + ' bits per sample'; // Read the count of the images in a file (Same as IEGetFileFramesCount) function GetImageCount(const FileName: WideString): Integer; var iop : TIOParams; begin Result := -1; iop := TIOParams.Create( Nil ); If iop.Read( FileName ) then Result := iop.ImageCount; iop.Free; end; !!} function TIOParams.Read(const FileName: WideString; Format: TIOFileType = ioUnknown): Boolean; var io : TImageEnIO; begin io := TImageEnIO.Create( Nil ); Result := io.ParamsFromFile( FileName, Format ); Assign( io.Params ); io.Free; end; function TIOParams.Read(const FileName: WideString; bUseExtension: Boolean): Boolean; var io : TImageEnIO; begin io := TImageEnIO.Create( Nil ); Result := io.ParamsFromFile( FileName, bUseExtension ); Assign( io.Params ); io.Free; end; function TIOParams.Read(Stream: TStream; Format: TIOFileType = ioUnknown): Boolean; var io : TImageEnIO; begin io := TImageEnIO.Create( Nil ); Result := io.ParamsFromStream( Stream, Format ); Assign( io.Params ); io.Free; end; function TIOParams.Read(Buffer: Pointer; BufferSize: Integer; Format: TIOFileType): Boolean; var io : TImageEnIO; begin io := TImageEnIO.Create( Nil ); Result := io.ParamsFromBuffer( Buffer, BufferSize, Format ); Assign( io.Params ); io.Free; end; /// TIOParams ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function DICOMCompression2Str(Compression: TIEDicomCompression): AnsiString; { Note, do not use a conversion like this! Will cause AV on startup C++ apps with RunTime packages disabled const DICOM_TS2STR: array [TIEDicomCompression] of ^AnsiString = ( @IEDICOM_TRANSFERSYNTAX_UNCOMP_LITTLEENDIAN_IMPLICIT, @IEDICOM_TRANSFERSYNTAX_UNCOMP_LITTLEENDIAN_EXPLICIT, @IEDICOM_TRANSFERSYNTAX_UNCOMP_BIGENDIAN_EXPLICIT, @IEDICOM_TRANSFERSYNTAX_RLE, @IEDICOM_TRANSFERSYNTAX_LOSSLESSJPEG1, @IEDICOM_TRANSFERSYNTAX_LOSSLESSJPEG2, @IEDICOM_TRANSFERSYNTAX_LOSSYJPEG8BIT, @IEDICOM_TRANSFERSYNTAX_LOSSYJPEG12BIT, @IEDICOM_TRANSFERSYNTAX_JPEG2000, @IEDICOM_TRANSFERSYNTAX_LOSSLESSJPEG2000, @IEDICOM_TRANSFERSYNTAX_MPEG); } begin {$IFDEF IEINCLUDEDICOM} case Compression of iedcUncompressed_Implicit: result := IEDICOM_TRANSFERSYNTAX_UNCOMP_LITTLEENDIAN_IMPLICIT; iedcUncompressed: result := IEDICOM_TRANSFERSYNTAX_UNCOMP_LITTLEENDIAN_EXPLICIT; iedcUncompressed_BE: result := IEDICOM_TRANSFERSYNTAX_UNCOMP_BIGENDIAN_EXPLICIT; iedcRLE: result := IEDICOM_TRANSFERSYNTAX_RLE; iedcLSJPEG1: result := IEDICOM_TRANSFERSYNTAX_LOSSLESSJPEG1; iedcLSJPEG2: result := IEDICOM_TRANSFERSYNTAX_LOSSLESSJPEG2; iedcJPEG: result := IEDICOM_TRANSFERSYNTAX_LOSSYJPEG8BIT; iedcJPEG12Bit: result := IEDICOM_TRANSFERSYNTAX_LOSSYJPEG12BIT; iedcJPEG2000: result := IEDICOM_TRANSFERSYNTAX_LOSSYJPEG2000; iedcLosslessJPEG2000: result := IEDICOM_TRANSFERSYNTAX_LOSSLESSJPEG2000; iedcMPEG: result := IEDICOM_TRANSFERSYNTAX_MPEG; else result := ''; end; {$ELSE} result := ''; {$ENDIF} end; function TIOParams.GetDICOM_Compression(): TIEDicomCompression; var transfSyntax: AnsiString; begin {$IFDEF IEINCLUDEDICOM} transfSyntax := IETrim(DICOM_Tags.GetTagString($0002, $0010)); for result := iedcUncompressed_Implicit to iedcMPEG do if DICOMCompression2Str(result) = transfSyntax then exit; {$ENDIF} result := iedcUncompressed; // the default end; procedure TIOParams.SetDICOM_Compression(Value: TIEDicomCompression); begin {$IFDEF IEINCLUDEDICOM} DICOM_Tags.SetTagString($0002, $0010, DICOMCompression2Str(Value)); {$ENDIF} end; procedure TIOParams.SetXMP_Info(Value: AnsiString); var xmpDict: TIEDictionary; begin fXMP_Info := Value; xmpDict := TIEDictionary.Create(); try xmpDict.Parse(WideString(fXMP_Info)); finally if not xmpDict.IsEmpty() then Dict.Insert('XMP', xmpDict) else xmpDict.Free(); end; end; {!! TIOParams.PS_PaperSize Declaration property PS_PaperSize : Description Provides a quick way to set and or interpret their current values. Note: iepAuto CANNOT be used with PS format! Example // Save using "US Letter" paper size ImageEnView1.IO.Params.PS_PaperSize := iepLetter; ImageEnView1.IO.SaveToFile('D:\output.ps'); // Which is the same as... ImageEnView1.IO.Params.PS_PaperWidth := 612; ImageEnView1.IO.Params.PS_PaperHeight := 792; ImageEnView1.IO.SaveToFile('D:\output.ps'); See Also - - - !!} function TIOParams.GetPS_PaperSize : TIOPDFPaperSize; begin Result := IEPointsToPaperSize( PS_PaperWidth, PS_PaperHeight ); if Result = iepAuto then Result := iepUnknown; end; procedure TIOParams.SetPS_PaperSize(const value : TIOPDFPaperSize); var I: Integer; begin if value = iepAuto then exit; // Unsupported for PS for I := Low(IOPDFPaperSizes) to High(IOPDFPaperSizes) do if IOPDFPaperSizes[I].Size = Value then begin PS_PaperWidth := IOPDFPaperSizes[I].Width; PS_PaperHeight := IOPDFPaperSizes[I].Height; exit; end; end; {!! TIOParams.PDF_PaperSize Declaration property PDF_PaperSize : Description Provides a quick way to set and or interpret their current values. If this is set to iepAuto then each page will be output at the size of the image. Note: This may create huge pages! Example // Save using "US Letter" paper size ImageEnView1.IO.Params.PDF_PaperSize := iepLetter; ImageEnView1.IO.SaveToFile('D:\output.pdf'); // Which is the same as... ImageEnView1.IO.Params.PDF_PaperWidth := 612; ImageEnView1.IO.Params.PDF_PaperHeight := 792; ImageEnView1.IO.SaveToFile('D:\output.pdf'); See Also - - - !!} function TIOParams.GetPDF_PaperSize : TIOPDFPaperSize; begin Result := IEPointsToPaperSize( PDF_PaperWidth, PDF_PaperHeight ); end; procedure TIOParams.SetPDF_PaperSize(const value : TIOPDFPaperSize); var I: Integer; begin for I := Low(IOPDFPaperSizes) to High(IOPDFPaperSizes) do if IOPDFPaperSizes[I].Size = Value then begin PDF_PaperWidth := IOPDFPaperSizes[I].Width; PDF_PaperHeight := IOPDFPaperSizes[I].Height; exit; end; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// {!! IEPaperSizeToStr Declaration function IEPaperSizeToStr(const ASize : ) : string; Description Convert a value to a human-readible string. values can be specified for and . Example 1 Caption := IEPaperSizeToStr(iepLetter); // Caption becomes 'US Letter'; Example 2 procedure TMainForm.FormCreate(Sender: TObject); var a: TIOPDFPaperSize; begin // Fill combobox with available PDF paper sizes cmbPaperSize.Clear; for a := Low(TIOPDFPaperSize) to iepAuto do cmbPaperSize.Items.Add(IEPaperSizeToStr(a)); // Make "US Letter" the selected one cmbPaperSize.ItemIndex := cmbPaperSize.Items.IndexOf(IEPaperSizeToStr(iepLetter)); end; // Set PDF paper size to user's selection ImageEnView1.IO.Params.PDF_PaperSize := IEStrToPaperSize(cmbPaperSize.Text); See Also - - - !!} function IEPaperSizeToStr(const ASize : TIOPDFPaperSize) : string; var I: Integer; begin Result := ''; for I := Low(IOPDFPaperSizes) to High(IOPDFPaperSizes) do if IOPDFPaperSizes[I].Size = ASize then begin Result := IOPDFPaperSizes[I].Name; exit; end; end; {!! IEStrToPaperSize Declaration function IEStrToPaperSize(const sSize : string; aDefault : = iepUnknown) : ; Description Converts a paper size name (e.g. as returned by ) to a value. values are used by and . Example procedure TMainForm.FormCreate(Sender: TObject); var a: TIOPDFPaperSize; begin // Fill combobox with available PDF paper sizes cmbPaperSize.Clear; for a := Low(TIOPDFPaperSize) to iepAuto do cmbPaperSize.Items.Add(IEPaperSizeToStr(a)); // Make "US Letter" the selected one cmbPaperSize.ItemIndex := cmbPaperSize.Items.IndexOf(IEPaperSizeToStr(iepLetter)); end; // Set PDF paper size to user's selection ImageEnView1.IO.Params.PDF_PaperSize := IEStrToPaperSize(cmbPaperSize.Text); See Also - - - !!} function IEStrToPaperSize(const sSize : string; aDefault : TIOPDFPaperSize = iepUnknown) : TIOPDFPaperSize; var I: Integer; begin Result := aDefault; for I := Low(IOPDFPaperSizes) to High(IOPDFPaperSizes) do if SameText(IOPDFPaperSizes[I].Name, sSize) then begin Result := IOPDFPaperSizes[I].Size; exit; end; end; {!! IEPointsToPaperSize Declaration function IEPointsToPaperSize(const Width, Height : Integer) : ; Description Converts dimensions in Adobe PDF points (1 point = 1/72 of inch) to a value. values are used by and . !!} function IEPointsToPaperSize(const Width, Height : Integer) : TIOPDFPaperSize; var I: Integer; begin Result := iepUnknown; for I := Low( IOPDFPaperSizes ) to High( IOPDFPaperSizes ) do if ( Width = IOPDFPaperSizes[I].Width ) and ( Height = IOPDFPaperSizes[I].Height ) then begin Result := IOPDFPaperSizes[I].Size; exit; end; end; {!! IECalcPaperSize Declaration function IECalcPaperSize(const Width, Height : Double; Metric: Boolean) : ; Description Finds the largest paper type that will fit within the dimensions of Width and Height (specified in inches). If Metric is true, the result will be one of: iepA0, iepA1, iepA2, iepA3, iepA4, iepA5, iepA6, iepB5. Otherwise it will be a US value from: iepLetter, iepLegal, iepTabloid Result will be iepUnknown if the method fails. Example with ImageEnMView1.MIO do begin lblSizeM := 'Max Paper Size (Metric): + IEPaperSizeToStr( IECalcPaperSize( AcquireParams.PhysicalWidth, AcquireParams.PhysicalHeight, True )); lblSizeUS := 'Max Paper Size (US): + IEPaperSizeToStr( IECalcPaperSize( AcquireParams.PhysicalWidth, AcquireParams.PhysicalHeight, False )); end; See Also - - - !!} function IECalcPaperSize(const Width, Height : Double; Metric: Boolean) : TIOPDFPaperSize; var I: Integer; widthPt, heightPt: Integer; begin Result := iepUnknown; widthPt := Round( Width * 72 ); heightPt := Round( Height * 72 ); if widthPt > heightPt then IESwap( widthPt, heightPt ); if Metric then begin for i := ord( iepA0 ) to ord( iepB5 ) do if ( IOPDFPaperSizes[ i ].Width <= widthPt ) and ( IOPDFPaperSizes[ i ].Height <= heightPt ) then begin Result := TIOPDFPaperSize( i ); exit end; end else // US begin if ( IOPDFPaperSizes[ ord( iepTabloid ) ].Width <= widthPt ) and ( IOPDFPaperSizes[ ord( iepTabloid ) ].Height <= heightPt ) then Result := iepTabloid else if ( IOPDFPaperSizes[ ord( iepLegal ) ].Width <= widthPt ) and ( IOPDFPaperSizes[ ord( iepLegal ) ].Height <= heightPt ) then Result := iepLegal else if ( IOPDFPaperSizes[ ord( iepLetter ) ].Width <= widthPt ) and ( IOPDFPaperSizes[ ord( iepLetter ) ].Height <= heightPt ) then Result := iepLetter; end; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// // TIEImageInfo {$IFDEF IEINCLUDEMULTIVIEW} constructor TIEImageInfo.Create(Parent_: TObject); begin inherited Create; parent := Parent_; Filename := ''; ID := -1; tag := 0; userPointer := nil; userDict := nil; Background := clWhite; DTime := 0.0; image := nil; TopText := ''; BottomText := ''; InfoText := ''; cacheImage := nil; SourceType := iestDefault; Checked := False; CreateDate := 0; FileSize := 0; EditDate := 0; Hash := ''; end; destructor TIEImageInfo.Destroy(); begin if assigned(userDict) then userDict.Free(); inherited; end; // Load Caption from legacy TIEMText structure function _LoadLegacyCaptionFromStream(Stream: TStream): WideString; var ver: byte; acharset: TFontCharset; acolor: TColor; apitch: TFontPitch; astyle: TFontStyles; i32: Integer; s: AnsiString; aTruncSide: TIEMTruncSide; aBackground: TColor; aBackgroundStyle: TBrushStyle; aPos: TIEMTextPos; begin // version Stream.Read(ver, 1); // caption IELoadStringFromStreamW(Stream, Result); // Read old font values Stream.Read(acharset, SizeOf(TFontCharset)); Stream.Read(acolor, SizeOf(TColor)); Stream.Read(i32, SizeOf(integer)); IELoadStringFromStream(Stream, s); Stream.Read(apitch, SizeOf(TFontPitch)); Stream.Read(astyle, SizeOf(TFontStyles)); // Old background values Stream.Read(aBackground, SizeOf(TColor)); Stream.Read(aBackgroundStyle, SizeOf(TBrushStyle)); // Read pos Stream.Read(aPos, SizeOf(TIEMTextPos)); // Read old trunc side value Stream.Read(aTruncSide, SizeOf(TIEMTruncSide)); end; // StreamVersion is aligned to IEMVIEWSNAPSHOTVERSION class function TIEImageInfo.CreateFromStream(Parent: TObject; Stream: TStream; StreamVersion: Byte; LoadCache: Boolean; Images: TIEVirtualImageList; Caches: TIEVirtualImageList): TIEImageInfo; var a32, itemp: Integer; s: AnsiString; ws: WideString; begin result := TIEImageInfo.Create(Parent); try // image Stream.Read(a32, SizeOf(integer)); result.image := Images.GetImageFromIndex(a32); // cache if LoadCache then begin Stream.Read(a32, SizeOf(integer)); result.cacheImage := Caches.GetImageFromIndex(a32) end; // background Stream.Read( result.Background, SizeOf(TColor) ); // name if StreamVersion = 1 then begin IELoadStringFromStream(Stream, s); ws := WideString(s); end else IELoadStringFromStreamW(Stream, ws); result.Filename := ws; // ID Stream.Read( result.ID, SizeOf(integer) ); // DTime if StreamVersion >= 5 then Stream.Read( result.DTime, SizeOf(double) ) else begin Stream.Read( itemp, SizeOf(integer) ); result.DTime := itemp; end; // tag if StreamVersion >= 6 then Stream.Read( result.tag, SizeOf(integer) ); // Top Text if StreamVersion <= 7 then ws := _LoadLegacyCaptionFromStream(Stream) else IELoadStringFromStreamW(Stream, ws); result.TopText := ws; // Info Text if StreamVersion <= 7 then ws := _LoadLegacyCaptionFromStream(Stream) else IELoadStringFromStreamW(Stream, ws); result.InfoText := ws; // Bottom Text if StreamVersion <= 7 then ws := _LoadLegacyCaptionFromStream(Stream) else IELoadStringFromStreamW(Stream, ws); result.BottomText := ws; // Checked if StreamVersion >= 7 then Stream.Read( result.Checked, SizeOf(Boolean) ); // User dictionary if StreamVersion >= 9 then begin IELoadStringFromStreamW(Stream, ws); if ws <> '' then begin result.userDict := TIEDictionary.Create(); result.userDict.Parse(ws); end; end; // Don't need: Hash except result.Free(); raise; end; end; procedure TIEImageInfo.SaveToStream(Stream: TStream; SaveCache: Boolean; Images: TIEVirtualImageList; Caches: TIEVirtualImageList); var i32: Integer; begin // index of images i32 := Images.FindImageIndex( image ); Stream.Write(i32, SizeOf(integer)); // index of caches if SaveCache then begin i32 := Caches.FindImageIndex( cacheImage ); Stream.Write(i32, SizeOf(integer)); end; // background Stream.Write( Background, SizeOf(TColor) ); // name IESaveStringToStreamW(Stream, Filename); // ID Stream.Write( ID, SizeOf(integer) ); // DTime Stream.Write( DTime, SizeOf(double) ); // tag Stream.Write( tag, SizeOf(integer) ); // text IESaveStringToStreamW(Stream, TopText); IESaveStringToStreamW(Stream, InfoText); IESaveStringToStreamW(Stream, BottomText); // Checked Stream.Write( Checked, SizeOf(Boolean) ); // User Dictionary if assigned(userDict) then IESaveStringToStreamW(Stream, userDict.Dump(ieplJSON)) else IESaveStringToStreamW(Stream, ''); // Don't need: Hash end; {$ENDIF} ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// // TIECustomMultiBitmap {$IFDEF IEINCLUDEMULTIVIEW} constructor TIECustomMultiBitmap.Create(bCacheToDisk: Boolean); begin fImageCacheUseDisk := bCacheToDisk; Create(); end; constructor TIECustomMultiBitmap.Create(); begin inherited; fParamsList := nil; fImageInfo := TList.Create; fImageCacheSize := 10; fImageList := TIEVirtualImageList.Create('ILIST', fImageCacheUseDisk); fImageList.MaxImagesInMemory := fImageCacheSize; fBackground := clWindow; fLockUpdate := 0; fUpdatePending := True; fOnChanged := nil; fModified := False; end; {!! TIEMultiBitmap.Destroy Declaration destructor Destroy; Description Frees the object. !!} destructor TIECustomMultiBitmap.Destroy; var idx: Integer; begin for idx := GetImageCount - 1 downto 0 do FreeImageInfo( idx ); FreeAndNil(fImageList); FreeAndNil(fImageInfo); FreeAndNil(fParamsList); // inherited; end; // If this component has been filled "Virtually" then fImageInfo.Count has been set to the number of images available // Without fImageInfo items being assigned. In this case it must be assigned in CheckAllocated() procedure TIECustomMultiBitmap.CheckAllocated(idx: integer); begin // Overridden in descendent classes end; // Used to communicate changes in the selection of an owner control, TImageEnMView to underlying image sources, such as a database table procedure TIECustomMultiBitmap.SetActiveImage(idx: integer); begin // Overridden in descendent classes end; // Add Count NIL entries to the image list. Must handle CheckAllocated() procedure TIECustomMultiBitmap.AllocateVirtual(Count: integer); begin Clear; fImageInfo.Count := Count; UpdateParams( IEM_OP_ALLOCATE, -1, Count ); end; function TIECustomMultiBitmap.GetImageInfo(idx: integer): TIEImageInfo; begin result := nil; if (idx >= 0) and (idx < fImageInfo.Count) then begin CheckAllocated( idx ); Result := TIEImageInfo(fImageInfo[idx]); end; end; function TIECustomMultiBitmap.ValidateIndex(idx: integer): Boolean; begin result := (idx >= 0) and (idx < fImageInfo.Count); end; {!! TIEMultiBitmap.ImageWidth Declaration property ImageWidth[idx: Integer]: Integer; Description Return the width of the image, idx. See also: !!} function TIECustomMultiBitmap.GetImageWidth(idx: integer): integer; begin result := 0; if ValidateIndex( idx ) then begin CheckImageLoaded( idx ); if GetImageInfo( idx ).image <> nil then result := fImageList.GetImageWidth( GetImageInfo( idx ).image ); end; end; {!! TIEMultiBitmap.Params Declaration property Params[idx: integer]: ; Description If is true, then Params provides access to the object for the image idx. The parameters are updated when loading from files or streams. You can modify these parameters before saving images. If is false, an exception will be raised. Note: should only be used when TIEMultiBitmap is being used as a stand-alone object. When it is attached to a TImageEnMView or TImageEnMIO, use TImageEnMIO.Params instead. Example // Change the compression method for a TIFF file MBitmap := TIEMultiBitmap.create; MBitmap.ParamsEnabled := True; // Load params with the image MBitmap.Read( 'C:\MyImage.tiff' ); MBitmap.Params[ 0 ].TIFF_Compression := ioTIFF_G4FAX; MBitmap.DuplicateCompressionInfo; MBitmap.Write( 'C:\OutImage.tiff' ); MBitmap.Free; // Which is the same as: MBitmap := TIEMultiBitmap.create; MParams := TIOMultiParams.create; MBitmap.Read( 'C:\MyImage.tiff', MParams ); for I := 0 to MBitmap.count do MParams[ I ].TIFF_Compression := ioTIFF_G4FAX; MBitmap.Write( 'C:\OutImage.tiff', MParams ); MParams.free; MBitmap.Free; !!} function TIECustomMultiBitmap.GetParams(idx: integer): TIOParams; begin if GetParamsEnabled = False then Result := nil else result := fParamsList.GetParams( idx ); end; {!! TIEMultiBitmap.ParamsEnabled Declaration property ParamsEnabled: Boolean; Description If ParamsEnabled is true, then this object stores the Input/Output parameters (meta-data) for your images, which can be accessed via . Default: False Note: should only be used when TIEMultiBitmap is being used as a stand-alone object. When it is attached to a TImageEnMView or TImageEnMIO, use TImageEnMIO.Params instead. Example // Change the compression method for a TIFF file MBitmap := TIEMultiBitmap.create; MBitmap.ParamsEnabled := True; // Load params with the image MBitmap.Read( 'C:\MyImage.tiff' ); MBitmap.Params[ 0 ].TIFF_Compression := ioTIFF_G4FAX; MBitmap.DuplicateCompressionInfo; MBitmap.Write( 'C:\OutImage.tiff' ); MBitmap.Free; // Which is the same as: MBitmap := TIEMultiBitmap.create; MParams := TIOMultiParams.create; MBitmap.Read( 'C:\MyImage.tiff', MParams ); for I := 0 to MBitmap.count do MParams[ I ].TIFF_Compression := ioTIFF_G4FAX; MBitmap.Write( 'C:\OutImage.tiff', MParams ); MParams.free; MBitmap.Free; !!} function TIECustomMultiBitmap.GetParamsEnabled: Boolean; begin Result := assigned( fParamsList ); end; procedure TIECustomMultiBitmap.SetParamsEnabled(const Value: Boolean); begin if assigned( fParamsList ) = Value then exit; if Value then begin fParamsList := TIOMultiParams.create; fParamsList.Allocate( Count ); end else begin FreeAndNil( fParamsList ); end; end; // Operation is an IEM const such as IEM_OP_INSERT (1) or IEM_OP_DELETE (2) procedure TIECustomMultiBitmap.UpdateParams(Operation: integer; Idx: integer; ExtraParam: Integer); begin if GetParamsEnabled then fParamsList.UpdateEx( Operation, idx, ExtraParam ); if assigned( fOnUpdateParams ) then fOnUpdateParams( Self, Operation, idx, ExtraParam ); end; {!! TIEMultiBitmap.ImageHeight Declaration property ImageHeight[idx: Integer]: Integer; Description Return the height of the image, idx. See also: !!} function TIECustomMultiBitmap.GetImageHeight(idx: integer): integer; begin result := 0; if ValidateIndex( idx ) then begin CheckImageLoaded( idx ); if GetImageInfo( idx ).image <> nil then result := fImageList.GetImageHeight( GetImageInfo( idx ).image ); end; end; {!! TIEMultiBitmap.ImageHash Declaration property ImageHash[idx: Integer]: AnsiString; Description Returns the MD5 Hash of image, idx. See Also - - - !!} function TIECustomMultiBitmap.GetImageHash(idx: integer): AnsiString; var bmp: TIEBitmap; begin result := ''; if ValidateIndex( idx ) then begin CheckImageLoaded( idx ); with GetImageInfo( idx ) do begin if Hash = '' then begin bmp := GetTIEBitmap( idx ); Hash := bmp.GetHash(); ReleaseBitmap( idx, false ); end; result := Hash; end; end; end; function TIECustomMultiBitmap.GetImageOriginalWidth(idx: integer): integer; begin result := 0; if ValidateIndex( idx ) then begin CheckImageLoaded( idx ); if GetImageInfo( idx ).image <> nil then result := fImageList.GetImageOriginalWidth( GetImageInfo( idx ).image ); end; end; function TIECustomMultiBitmap.GetImageOriginalHeight(idx: integer): integer; begin result := 0; if ValidateIndex( idx ) then begin CheckImageLoaded( idx ); if GetImageInfo( idx ).image <> nil then result := fImageList.GetImageOriginalHeight( GetImageInfo( idx ).image ); end; end; procedure TIECustomMultiBitmap.SetImageOriginalWidth(idx: integer; Value: integer); begin if ValidateIndex( idx ) then begin if GetImageInfo( idx ).image <> nil then fImageList.SetImageOriginalWidth( GetImageInfo( idx ).image, Value ); end; end; procedure TIECustomMultiBitmap.SetImageOriginalHeight(idx: integer; Value: integer); begin if ValidateIndex( idx ) then begin if GetImageInfo( idx ).image <> nil then fImageList.SetImageOriginalHeight( GetImageInfo( idx ).image, Value ); end; end; {!! TIEMultiBitmap.ImageBitCount Declaration property ImageBitCount[idx: Integer]: Integer; Description Returns the bit count of the image, idx. It can be: 1 : Black/white image 24 : True color image !!} function TIECustomMultiBitmap.GetImageBitCount(idx: integer): integer; begin result := 0; if ValidateIndex( idx ) then begin CheckImageLoaded( idx ); if GetImageInfo( idx ).image <> nil then result := fImageList.GetImageBitCount( GetImageInfo( idx ).image ); end; end; procedure TIECustomMultiBitmap.SetImageTag(idx, v: integer); begin if ValidateIndex( idx ) then GetImageInfo( idx ).Tag := v; end; {!! TIEMultiBitmap.ImageTag Declaration property ImageTag[idx: Integer]: integer; Description Associates an integer value with the image, idx. Note: - This property is not used by TIEMultiBitmap in any way and is provided for custom use (similar to the Tag property of components). - The value is not loaded/saved from file and streams, or copied/pasted to clipboard. !!} function TIECustomMultiBitmap.GetImageTag(idx: integer): integer; begin result := -1; if ValidateIndex( idx ) then result := GetImageInfo( idx ).Tag; end; {!! TIEMultiBitmap.ImageFileName Declaration property ImageFileName[idx: Integer]: WideString; Description Specifies the image loaded at index, idx. If your TIEMultiBitmap has been filled with multiple images, then ImageFileName returns the name of the file at an index Example // Show the filename of the second image ShowMessage( MyIEMBitmap.ImageFileName[ 1 ]); !!} function TIECustomMultiBitmap.GetImageFileName(idx: integer): WideString; begin result := ''; if ValidateIndex( idx ) then result := GetImageInfo( idx ).Filename; end; {!! TIEMultiBitmap.ImageDictionary Declaration property ImageDictionary[idx: Integer]: ; Description Returns a dictionary associated with the specified image. User can insert data into this dictionary. The dictionary is saved and restored using and , or using related methods of . Example MyIEMBitmap.ImageDictionary[0].Insert('Name', 'Letizia'); MyIEMBitmap.ImageDictionary[1].Insert('Name', 'Minnie'); !!} function TIECustomMultiBitmap.GetImageDictionary(idx: integer): TIEDictionary; begin result := nil; if ValidateIndex( idx ) then with GetImageInfo(idx) do begin if not assigned(userDict) then userDict := TIEDictionary.Create(); result := userDict; end; end; // Note: set ID = -1 procedure TIECustomMultiBitmap.SetImageFileName(idx: integer; v: WideString); begin if ValidateIndex( idx ) then with GetImageInfo( idx ) do begin Filename := v; ID := -1; end; end; procedure TIECustomMultiBitmap.SetImageUserPointer(idx: Integer; v: pointer); begin if ValidateIndex( idx ) then GetImageInfo( idx ).userPointer := v; end; {!! TIEMultiBitmap.Modified Declaration property Modified: Boolean; Description Returns true if the image list has changed in any way since loading. This includes appending, insertion and deletion of frames, and manipulation of images within the frames, e.g. by rotation. It does not include changes to . Notes: - Modified is reset to false whenever the TIEMultiBitmap is loaded, i.e. using or via - Saving a TIEMultiBitmap does not reset Modified Example // Check the status of the animated GIF in our TImageEnMView on FormClose If ImageEnMView1.IEMBitmap.Modified then if MessageDlg( 'Save changes to your image?', mtConfirmation, [mbYes,mbNo], 0) = mrYes then ImageEnMView1.MIO.SaveToFile( ActiveFilename ); !!} procedure TIECustomMultiBitmap.SetModified(Value: Boolean); begin if Value then Changed( -1 ) else fModified := False; end; // Sets Modified and calls OnChanged procedure TIECustomMultiBitmap.Changed(idx: integer); begin fModified := True; if ValidateIndex( idx ) then GetImageInfo( idx ).Hash := ''; if assigned( fOnChanged ) then fOnChanged( Self, idx ); end; {!! TIEMultiBitmap.ImageUserPointer Declaration property ImageUserPointer[idx: Integer]: pointer; Description Associates a pointer with image, idx. Note: - This property is not used by TIEMultiBitmap in any way and is provided for custom use. - The value is not loaded/saved from file and streams, or copied/pasted to clipboard. !!} function TIECustomMultiBitmap.GetImageUserPointer(idx: Integer): pointer; begin result := nil; if ValidateIndex( idx ) then result := GetImageInfo( idx ).userPointer; end; function TIECustomMultiBitmap.GetImageBackground(idx: integer): TColor; begin result := 0; if ValidateIndex( idx ) then result := GetImageInfo( idx ).Background; end; procedure TIECustomMultiBitmap.SetImageBackground(idx: integer; v: TColor); begin if ValidateIndex( idx ) then GetImageInfo( idx ).Background := v; Changed( idx ); end; function TIECustomMultiBitmap.GetImageDelayTime(idx: integer): Double; begin result := 0.0; if ValidateIndex( idx ) then result := GetImageInfo( idx ).DTime; end; procedure TIECustomMultiBitmap.SetImageDelayTime(idx: integer; v: Double); begin if ValidateIndex( idx ) then GetImageInfo( idx ).DTime := v; Changed( idx ); end; {!! TIEMultiBitmap.InsertImage Declaration procedure InsertImage(idx: integer); procedure InsertImage(Idx : integer; Stream : TStream); procedure InsertImage(Idx : integer; Bitmap : ); procedure InsertImage(Idx : integer; Bitmap : TBitmap); procedure InsertImage(Idx : integer; MBitmap : ); procedure InsertImage(Idx : integer; Width, Height : integer; PixelFormat : = ie24RGB); procedure InsertImage(Idx : integer; const FileName : string); Description Inserts a new image at position, idx (0 is the first). Examples ImageEnView1.IO.LoadFromFile('C:\000.tif'); MBitmap.InsertImage(0); MBitmap.SetImage(0, ImageEnView1.Bitmap); // Which is the same as... MBitmap.InsertImage(0, 'C:\000.tif'); // Insert 256 x 256 bitmap MBitmap.InsertImage(0, 256, 256, ie24RGB); // Insert a file from the web MBitmap.InsertImage(0, 'http://www.imageen.com/graphics/imageen.gif'); // Show the first ten frames of a video file for I := 0 to 9 do MBitmap.InsertImage( I, 'D:\Temp\Cement.avi' + IEM_Path_Index_Delimiter + IntToStr( I * 10 )); See Also - !!} // NB: Equivalent to TImageEnMView.InsertImageEx procedure TIECustomMultiBitmap.InsertImage(idx: integer); var NewInfo: TIEImageInfo; begin NewInfo := TIEImageInfo.Create(self); NewInfo.Background := fBackground; if idx >= fImageInfo.Count then begin // Append fImageInfo.Add(newinfo); idx := fImageInfo.Count - 1; end else begin // Insert fImageInfo.Insert(idx, newinfo); end; UpdateParams( IEM_OP_INSERT, idx, -1 ); Changed( -1 ); end; procedure TIECustomMultiBitmap.InsertImage(Idx : integer; Stream : TStream); begin InsertImage( Idx ); SetImage( Idx, Stream ); end; procedure TIECustomMultiBitmap.InsertImage(Idx : integer; MBitmap : TIECustomMultiBitmap); var I: Integer; bmp: TIEBitmap; begin for I := 0 to MBitmap.Count - 1 do begin bmp := MBitmap.GetTIEBitmap( I ); InsertImage( Idx + I, bmp ); // Assign user dictionary with MBitmap.GetImageInfo( I ) do begin if assigned( userDict ) then ImageDictionary[ Idx + I ].Assign( userDict ); end; MBitmap.ReleaseBitmap( I, False ); end; end; procedure TIECustomMultiBitmap.InsertImage(Idx : integer; Bitmap : TIEBitmap); begin InsertImage( Idx ); SetImage( Idx, Bitmap ); if GetParamsEnabled and Bitmap.ParamsEnabled then GetParams( idx ).Assign( Bitmap.Params ); end; procedure TIECustomMultiBitmap.InsertImage(Idx : integer; Bitmap : TBitmap); begin InsertImage( Idx ); SetImage( Idx, Bitmap ); end; procedure TIECustomMultiBitmap.InsertImage(Idx : integer; Width, Height : integer; PixelFormat : TIEPixelFormat); var temp: TIEBitmap; begin InsertImage( Idx ); temp := TIEBitmap.Create; try temp.Allocate( Width, Height, PixelFormat ); temp.Fill( clBlack ); SetImage( Idx, temp ); finally temp.free; end; end; procedure TIECustomMultiBitmap.InsertImage(Idx : integer; const FileName : string); begin InsertImage( Idx ); if SetImage( Idx, FileName ) then ImageFileName[ idx ] := FileName; end; procedure TIECustomMultiBitmap.FreeImageInfo(idx: integer); begin if fImageInfo[ idx ] = nil then exit; TIEImageInfo(fImageInfo[ idx ]).Free(); fImageInfo[ idx ] := nil; end; {!! TIEMultiBitmap.DeleteImage Declaration procedure DeleteImage(idx: integer); Description Removes the image, idx from the image list (freeing its associated bitmap). !!} // NB: Equivalent to TImageEnMView.DeleteImageNU() procedure TIECustomMultiBitmap.DeleteImage(idx: integer); begin if ValidateIndex( idx ) = False then exit; if ( fImageInfo[ idx ] <> nil ) and ( TIEImageInfo( fImageInfo[ idx ] ).Image <> nil ) then fImageList.Delete( TIEImageInfo( fImageInfo[ idx ] ).Image ); FreeImageInfo( idx ); fImageInfo.Delete(idx); UpdateParams( IEM_OP_DELETE, idx, -1 ); Changed( -1 ); end; {!! TIEMultiBitmap.AppendImage Declaration function AppendImage: Integer; function AppendImage(Stream: TStream): integer; function AppendImage(Bitmap: ): integer; function AppendImage(Bitmap : TBitmap): integer; function AppendImage(MBitmap : ); function AppendImage(Width, Height: Integer; PixelFormat: = ie24RGB): Integer; function AppendImage(const FileName: String): integer; Description Appends a new image at last position in the list and returns the new image position. Examples ImageEnView1.IO.LoadFromFile( 'C:\MyImage.tif' ); idx := MBitmap.AppendImage; MBitmap.SetImage( idx, ImageEnView1.Bitmap ); // Which is the same as... MBitmap.AppendImage( 'C:\MyImage.tif' ); // Load the fifth image of MyImage.tif MBitmap.AppendImage( 'C:\MyImage.tif' + IEM_Path_Index_Delimiter + 4 ); // Append 256 x 256 bitmap MBitmap.AppendImage( 256, 256, ie24RGB ); // Append a file from the web MBitmap.AppendImage( 'http://www.imageen.com/graphics/imageen.gif' ); // Show ten frames of a video file for I := 0 to 9 do MBitmap.AppendImage( 'D:\Temp\Cement.avi' + IEM_Path_Index_Delimiter + IntToStr( I * 10 )); // Append all pages of a TIFF to the current content iPageCount := EnumTIFFIm( sFileName ); for I := 0 to iPageCount - 1 do MBitmap.AppendImage( sFileName + IEM_Path_Index_Delimiter + IntToStr( I )); See Also - !!} function TIECustomMultiBitmap.AppendImage(): integer; begin result := fImageInfo.Count; InsertImage( Result ); end; function TIECustomMultiBitmap.AppendImage(Stream: TStream): integer; begin result := fImageInfo.Count; InsertImage( Result, Stream ); end; function TIECustomMultiBitmap.AppendImage(MBitmap: TIECustomMultiBitmap): integer; begin result := fImageInfo.Count; InsertImage( Result, MBitmap ); end; function TIECustomMultiBitmap.AppendImage(Bitmap: TIEBitmap): integer; begin result := fImageInfo.Count; InsertImage( Result, Bitmap ); end; function TIECustomMultiBitmap.AppendImage(Bitmap : TBitmap): integer; begin result := fImageInfo.Count; InsertImage( Result, Bitmap ); end; function TIECustomMultiBitmap.AppendImage(Width, Height: Integer; PixelFormat: TIEPixelFormat): Integer; begin result := fImageInfo.Count; InsertImage( Result, Width, Height, PixelFormat ); end; function TIECustomMultiBitmap.AppendImage(const FileName: String): integer; begin result := fImageInfo.Count; InsertImage( Result, FileName ); end; {!! TIEMultiBitmap.SetImage Declaration procedure SetImage(idx: Integer; srcImage: ); overload; procedure SetImage(idx: Integer; srcImage: TBitmap); overload; procedure SetImage(idx: Integer; width, height: Integer; PixelFormat: ); overload; function SetImage(idx: integer; const FileName: WideString; SourceImageIndex: Integer = 0; FileFormat: = ioUnknown): boolean; overload; function SetImage(idx: Integer; Stream: TStream; SourceImageIndex: Integer = 0; FileFormat: = ioUnknown): Boolean; overload Description Sets the image assigned to index, idx. With overloads 2 and 3 the srcImage bitmap is copied internally; therefore you can free srcImage after calling SetImage. With overload 4 the image can be a local file or web page based image. With overloads 3 and 4 use SourceImageIndex to specify the image index if the source file is a multi-frame file (such as a TIFF or AVI). You can also specify the FileFormat if it cannot be determined by the file extension or content. Examples ImageEnView1.IO.LoadFromFile('C:\000.tif'); MBitmap.InsertImage( 0 ); MBitmap.SetImage(0, ImageEnView1.Bitmap); idx := ImageEnMView1.AppendImage; ImageEnMView1.SetImage(idx, stream); idx := ImageEnMView1.AppendImage; ImageEnMView1.SetImage(idx, 'D:\myfile.jpg'); idx := ImageEnMView1.AppendImage; ImageEnMView1.SetImage(idx, 'http://www.imageen.com/image.jpg'); !!} procedure TIECustomMultiBitmap.SetImageEx(idx: integer; srcImage: TIEBaseBitmap); begin if ( srcImage <> nil ) and ( idx > -1 ) and ( idx < fImageInfo.Count ) then begin CheckAllocated( idx ); if TIEImageInfo(fImageInfo[idx]).image <> nil then fImageList.Delete(TIEImageInfo(fImageInfo[idx]).image); TIEImageInfo(fImageInfo[idx]).image := fImageList.AddIEBitmapNoMap(srcImage); fImageList.SetImageOriginalWidth(TIEImageInfo(fImageInfo[idx]).image, srcImage.Width); fImageList.SetImageOriginalHeight(TIEImageInfo(fImageInfo[idx]).image, srcImage.Height); Changed( idx ); end; end; procedure TIECustomMultiBitmap.SetImage(idx: Integer; width, height: Integer; PixelFormat: TIEPixelFormat); var temp: TIEBitmap; begin temp := TIEBitmap.Create(Width, Height, PixelFormat); try SetImageEx( idx, temp ); finally temp.free; end; end; procedure TIECustomMultiBitmap.SetImage(idx: integer; srcImage: TBitmap); var tbmp: TIEBitmap; begin if srcImage <> nil then begin tbmp := TIEBitmap.Create; try tbmp.EncapsulateTBitmap(srcImage, true); SetImageEx( idx, tbmp ); finally FreeAndNil(tbmp); end; end; end; // NB: Equivalent to TImageEnMView.SetIEBitmapEx() and TImageEnMView.SetImage procedure TIECustomMultiBitmap.SetImage(idx: integer; srcImage: TIEBaseBitmap); begin SetImageEx( idx, srcImage ); end; // NB: Equivalent to TImageEnMView.SetImageFromFile function TIECustomMultiBitmap.SetImage(idx: integer; const FileName: WideString; SourceImageIndex: Integer = 0; FileFormat: TIOFileType = ioUnknown): boolean; begin result := SetImageFromStreamOrFile( idx, nil, FileName, SourceImageIndex, FileFormat ); end; // NB: Equivalent to TImageEnMView.SetImageFromStream function TIECustomMultiBitmap.SetImage(idx: integer; Stream: TStream; SourceImageIndex: Integer = 0; FileFormat: TIOFileType = ioUnknown): boolean; begin result := SetImageFromStreamOrFile( idx, Stream, '', SourceImageIndex, FileFormat ); end; function TIECustomMultiBitmap.SetImageFromStreamOrFile(idx: integer; Stream: TStream; const FileName: WideString; SourceImageIndex: Integer; FileFormat: TIOFileType; MIO: TObject = nil): Boolean; var bmp: TIEBitmap; info: TIEImageInfo; ASourceType : TIESourceType; IO: TImageEnIO; ms: TMemoryStream; bAborting: Boolean; FileExt: string; begin result := False; if idx >= fImageInfo.Count then exit; // URL HANDLING if ( Stream = nil ) and ( IEGetURLTypeW(FileName) <> ieurlUNKNOWN ) then begin // LOAD FROM URL ms := TMemoryStream.Create; try bAborting := False; if IEGetFromURL(FileName, ms, IEGlobalSettings().ProxyAddress, IEGlobalSettings().ProxyUser, IEGlobalSettings().ProxyPassword, nil, nil, @bAborting, FileExt) then begin ms.Position := 0; Result := SetImageFromStreamOrFile(Idx, ms, '', SourceImageIndex, FileFormat); end; finally FreeAndNil(ms); end; exit; end; info := GetImageInfo( idx ); ASourceType := info.SourceType; IO := TImageEnIO.Create( nil ); bmp := TIEBitmap.Create; try IO.Background := info.Background; IO.AttachedIEBitmap := bmp; IO.Params.ImageIndex := SourceImageIndex; try if Stream <> nil then IO.LoadFromStream( Stream, FileFormat ) else begin if FileFormat = ioUnknown then FileFormat := FindFileFormat( FileName, ffFallbackToExtension ); IO.LoadFromFile( FileName, FileFormat ); if ( not IO.Aborting ) and ( ImageFileName[ idx ] = '' ) then ImageFileName[ idx ] := FileName; end; except IO.Aborting := true; end; if IO.Aborting then exit; if GetParamsEnabled then fParamsList.Params[ idx ].assign( IO.Params ); if assigned( MIO ) and ( MIO is TImageEnMIO ) then TImageEnMIO( MIO ).fParamsList.Params[ idx ].assign( IO.Params ); info.Background := IO.Background; info.SourceType := ASourceType; SetImageEx( idx, bmp ); ImageOriginalWidth[idx] := IO.Params.OriginalWidth; ImageOriginalHeight[idx] := IO.Params.OriginalHeight; if IO.Params.EXIF_DateTimeOriginal2 > 0 then info.CreateDate := IO.Params.EXIF_DateTimeOriginal2; result := True; Changed( idx ); finally IO.AttachedIEBitmap := nil; FreeAndNil(bmp); FreeAndNil(IO); end; end; {!! TIEMultiBitmap.IndexOf Declaration function IndexOf(const Hash: AnsiString): Integer; overload; function IndexOf(Bitmap: TIEBitmap): Integer; overload; Description Returns the index of an image within the list (that matches the content or MD5 hash of an image). Example // Add images to a TImageEnMView if they are unique (same image is not already in the list) ImageEnMView1.LockUpdate; for sFilename in ssFiles do begin bmp.Read( sFilename ); if ImageEnMView1.IEMultiBitmap.IndexOf( bmp ) < 0 then ImageEnMView1.AppendImage( bmp ); end; ImageEnMView1.UnlockUpdate; See Also - - !!} function TIECustomMultiBitmap.IndexOf(const Hash: AnsiString): Integer; var I: Integer; begin Result := -1; if Hash = '' then exit; for I := 0 to Count - 1 do if SameText( string(ImageHash[ i ]), string(Hash) ) then begin Result := i; exit; end; end; function TIECustomMultiBitmap.IndexOf(Bitmap: TIEBitmap): Integer; begin Result := IndexOf( Bitmap.GetHash( iehaMD5 )); end; {!! TIEMultiBitmap.SaveSnapshot Declaration procedure SaveSnapshot(Stream: TStream; Options: = [iessoCompressed, iessoSaveIOParams]); overload; procedure SaveSnapshot(const FileName: WideString; Options: = [iessoCompressed, iessoSaveIOParams]); overload; Description Saves current object status (including images) to the specified stream or file. See also: . !!} procedure TIECustomMultiBitmap.SaveSnapshot(const FileName: WideString; Options: TIESaveSnapshotOptions); var fs: TIEWideFileStream; begin fs := TIEWideFileStream.Create(FileName, fmCreate); try SaveSnapshot(fs, Options); finally fs.Free(); end; end; procedure TIECustomMultiBitmap.SaveSnapshot(Stream: TStream; Options: TIESaveSnapshotOptions); var ver: byte; compressed: Boolean; saveParams: Boolean; i, i32: Integer; LZStream: TZCompressionStream; begin // magic IESaveStringToStream(Stream, 'MULTIBMPSNAPSHOT'); // version ver := IEMVIEWSNAPSHOTVERSION; Stream.Write(ver, SizeOf(byte)); // compressed flag compressed := iessoCompressed in Options; Stream.Write(compressed, SizeOf(compressed)); if compressed then begin LZStream := TZCompressionStream.Create(Stream, zcDefault, 15); Stream := LZStream; end else LZStream := nil; try // images count i32 := Count; Stream.Write(i32, SizeOf(i32)); // save IO parameters flag saveParams := (iessoSaveIOParams in Options) and ParamsEnabled; Stream.Write(saveParams, SizeOf(saveParams)); // images fImageList.SaveToStream(Stream); // info for i := 0 to Count - 1 do begin GetImageInfo( i ).SaveToStream(Stream, false, fImageList, nil); // I/O params if saveParams then Params[i].SaveToStream(Stream); end; finally if compressed then LZStream.Free(); end; end; {!! TIEMultiBitmap.LoadSnapshot Declaration function LoadSnapshot(Stream: TStream): Boolean; overload; function LoadSnapshot(const FileName: WideString): Boolean; overload; Description Loads the saved object status (including images) from the specified stream or file. See also: . !!} function TIECustomMultiBitmap.LoadSnapshot(const FileName: WideString): Boolean; var fs: TIEWideFileStream; begin fs := TIEWideFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try result := LoadSnapshot(fs); finally fs.Free(); end; end; function TIECustomMultiBitmap.LoadSnapshot(Stream: TStream): Boolean; var magicStr: AnsiString; ver: byte; i, i32: Integer; loadParams: Boolean; compressed: Boolean; LZStream: TZDecompressionStream; begin result := false; // magic IELoadStringFromStream(Stream, magicStr); if magicStr <> 'MULTIBMPSNAPSHOT' then exit; // version Stream.Read(ver, SizeOf(byte)); Clear(); // compressed flag Stream.Read(compressed, SizeOf(compressed)); if compressed then begin LZStream := TZDecompressionStream.Create(Stream); Stream := LZStream; end else LZStream := nil; try // images count Stream.Read(i32, SizeOf(i32)); // load IO parameters flag Stream.Read(loadParams, SizeOf(loadParams)); // images result := fImageList.LoadFromStream(Stream); if not result then exit; // info for i := 0 to i32 - 1 do begin fImageInfo.Add( TIEImageInfo.CreateFromStream(self, Stream, ver, false, fImageList, nil) ); // I/O params if loadParams then begin ParamsEnabled := True; UpdateParams( IEM_OP_INSERT, i, -1 ); Params[i].LoadFromStream(Stream); end; end; Changed( -1 ); finally if compressed then LZStream.Free(); end; result := true; end; {!! TIEMultiBitmap.CopyToIEBitmap Declaration procedure CopyToIEBitmap(idx: Integer; bmp: ); Description Copies the specified image, idx, to the destination object. !!} procedure TIECustomMultiBitmap.CopyToIEBitmap(idx: integer; bmp: TIEBitmap); begin With GetImageInfo( idx ) do begin if image = nil then raise EIEException.create('Invalid image'); fImageList.CopyToIEBitmap(image, bmp); end; end; {!! TIEMultiBitmap.GetBitmap Declaration function GetBitmap(idx: Integer): TBitmap; Description Creates a TBitmap object from the image at index, idx. You will need to call to free the TBitmap object. See also: . Example // Save the fifth image to file bmp := MBitmap.GetBitmap(4); bmp.SaveToFile('alfa.bmp'); MBitmap.ReleaseBitmap(4); !!} function TIECustomMultiBitmap.GetBitmap(idx: integer): TBitmap; begin result := nil; if ValidateIndex( idx ) = False then exit; CheckImageLoaded( idx ); if GetImageInfo( idx ).image <> nil then begin // image present result := fImageList.GetBitmap( GetImageInfo( idx ).image ).VclBitmap; end; end; {!! TIEMultiBitmap.GetTIEBitmap Declaration function GetTIEBitmap(idx: Integer): ; Description Creates a object from the image at index, idx. You will need to call to free the object. Note: If =True then the returned TIEBitmap will have . Example // Save the fifth image to file bmp := MBitmap.GetTIEBitmap(4); // Note: bmp must be TIEBitmap type bmp.Write('D:\alfa.png'); MBitmap.ReleaseBitmap(4); !!} function TIECustomMultiBitmap.GetTIEBitmap(idx: integer): TIEBitmap; begin result := nil; if ValidateIndex( idx ) = False then exit; CheckImageLoaded( idx ); if GetImageInfo( idx ).image <> nil then begin // image present result := fImageList.GetBitmap( GetImageInfo( idx ).image ); if GetParamsEnabled then begin Result.ParamsEnabled := True; Result.Params.Assign( GetParams( idx )); end; end; end; {!! TIEMultiBitmap.ReleaseBitmap Declaration procedure ReleaseBitmap(idx: Integer; SaveChanges: Boolean); Description Releases the bitmap created with or method. Parameter Description idx The image index to release. saveChanges If true (default) the bitmap will be written in the cache.
!!} procedure TIECustomMultiBitmap.ReleaseBitmap(idx: Integer; SaveChanges: Boolean); begin fImageList.ReleaseBitmapByImage(TIEImageInfo(fImageInfo[idx]).image, SaveChanges); if SaveChanges then Changed( idx ); end; // Load an image if it not yet available procedure TIECustomMultiBitmap.CheckImageLoaded(idx: Integer); var iebmp: TIEBitmap; info: TIEImageInfo; io : TImageEnIO; IOParams: TIOParams; begin info := GetImageInfo( idx ); if info.image <> nil then exit; try if assigned( fOwner ) and ( fOwner is TImageEnMView ) then TImageEnMView( fOwner ).ObtainImageNow( idx ) else if (info.ID > -1) and InternalLoadImageByID_Assigned() then begin // request by ID iebmp := nil; IOParams := nil; try if GetParamsEnabled then IOParams := TIOParams.Create; InternalLoadImageByID( self, idx, info.ID, iebmp, IOParams ); if iebmp = nil then raise EIEException.create( 'Load Error' ); if GetParamsEnabled then fParamsList.GetParams( idx ).Assign( IOParams ); Info.image := fImageList.AddIEBitmapNoMap( iebmp ); fImageList.SetImageOriginalWidth ( Info.image, iebmp.Width ); fImageList.SetImageOriginalHeight( Info.image, iebmp.Height ); if ( IOParams <> nil ) and ( IOParams.EXIF_DateTimeOriginal2 > 0 ) then Info.CreateDate := IOParams.EXIF_DateTimeOriginal2; finally FreeAndNil ( IOParams ); end; end else if info.Filename <> '' then begin io := TImageEnIO.Create( nil ); iebmp := TIEBitmap.Create; try io.Background := info.Background; io.AttachedIEBitmap := iebmp; io.LoadFromFileAuto( info.Filename ); if (iebmp.Width < 2) and (iebmp.Height < 2) then raise EIEException.create( 'Load Error' ); if GetParamsEnabled then fParamsList.GetParams( idx ).Assign( io.Params ); // set the image info.Background := io.Background; info.SourceType := iestDefault; Info.image := fImageList.AddIEBitmapNoMap( iebmp ); fImageList.SetImageOriginalWidth ( Info.image, iebmp.Width ); fImageList.SetImageOriginalHeight( Info.image, iebmp.Height ); if io.Params.EXIF_DateTimeOriginal2 > 0 then Info.CreateDate := io.Params.EXIF_DateTimeOriginal2; finally io.AttachedIEBitmap := nil; FreeAndNil( iebmp ); FreeAndNil( io ); end; end; except // LOAD ERROR end; end; {!! TIEMultiBitmap.GetImageToFile Declaration procedure GetImageToFile(idx: Integer; const FileName: WideString; IOParams:
= nil); Description Saves the image at index, idx, to file. The file format is determined by the file extension. Parameter Description idx The image index (0=first image) FileName The destination path and file name Params The save parameters
Example // Separate the pages of a multipage TIFF MBitmap.Read('multipage.tif'); MBitmap.GetImageToFile(0, 'page1.tif'); MBitmap.GetImageToFile(1, 'page2.tif'); !!} procedure TIECustomMultiBitmap.GetImageToFile(idx: Integer; const FileName: WideString; IOParams: TIOParams = nil); var IO: TImageEnIO; bmp: TIEBitmap; begin IO := TImageEnIO.Create( nil ); if assigned( IOParams ) then IO.Params.Assign( IOParams ) else if GetParamsEnabled() then IO.Params.Assign( Params[ idx ] ); bmp := GetTIEBitmap(idx); try if bmp = nil then raise EIEException.create( 'Bitmap not available' ); IO.AttachedIEBitmap := bmp; IO.SaveToFile(FileName); finally ReleaseBitmap(idx, false); FreeAndNil(IO); end; end; {!! TIEMultiBitmap.GetImageToStream Declaration procedure GetImageToStream(idx: Integer; Stream: TStream; ImageFormat:
; IOParams: = nil); Description Saves the image at index, idx, to a stream. Parameter Description idx The image index (Where 0 is the first image) Stream The destination stream ImageFormat The output file format (e.g. ioTiff or ioJpeg) Params The save parameters
Example // Save the first image to a stream in JPEG format MBitmap.GetImageToFile(0, MyStream, ioJPEG); !!} procedure TIECustomMultiBitmap.GetImageToStream(idx: Integer; Stream: TStream; ImageFormat: TIOFileType; IOParams: TIOParams = nil); var IO: TImageEnIO; bmp: TIEBitmap; begin IO := TImageEnIO.Create( nil ); if assigned( IOParams ) then IO.Params.Assign( IOParams ) else if GetParamsEnabled() then IO.Params.Assign( Params[ idx ] ); bmp := GetTIEBitmap(idx); try if bmp = nil then raise EIEException.create( 'Bitmap not available' ); IO.AttachedIEBitmap := bmp; IO.SaveToStream(Stream, ImageFormat); finally ReleaseBitmap(idx, false); FreeAndNil(IO); end; end; {!! TIEMultiBitmap.PrepareSpaceFor Declaration procedure PrepareSpaceFor(Width, Height: Integer; Bitcount: Integer; ImageCount: Integer); Description Allocates enough space within the temporary file for ImageCount> images of size Width * Height * BitCount. Use this method to improve performance only when planning to add many images of the same size. !!} procedure TIECustomMultiBitmap.PrepareSpaceFor(Width, Height: integer; Bitcount: integer; ImageCount: integer); begin fImageList.PrepareSpaceFor(Width, Height, Bitcount, ImageCount); end; {!! TIEMultiBitmap.ImageCacheSize Declaration property ImageCacheSize: Integer; Description Specifies the number of images to be stored in memory, rather than in a memory mapped file. For example, if you know that a TIEMultiBitmap will only contain 20 images then the ImageCacheSize could be set to 20 to disable all memory mapping. Default: 10 !!} procedure TIECustomMultiBitmap.SetImageCacheSize(v: integer); begin fImageCacheSize := v; fImageList.MaxImagesInMemory := fImageCacheSize; end; {!! TIEMultiBitmap.ImageCacheUseDisk Declaration property ImageCacheUseDisk: Boolean; Description When enabled, a disk file is used to cache the images and view. Otherwise only system memory is used. Disabling this option is useful if you have low disk space or don't want ImageEn to write to disk. Warning: Setting this property will also call
Default: True !!} procedure TIECustomMultiBitmap.SetImageCacheUseDisk(v: boolean); begin if fImageCacheUseDisk <> v then begin fImageCacheUseDisk := v; Clear; end; end; {!! TIEMultiBitmap.Clear Declaration procedure Clear; Description Removes all images from the TIEMultiBitmap and releases any associated memory. !!} procedure TIECustomMultiBitmap.Clear; var idx: Integer; begin for idx := GetImageCount - 1 downto 0 do FreeImageInfo( idx ); fImageInfo.Clear(); UpdateParams( IEM_OP_CLEAR, -1, -1 ); // this frees images referenced by TIEImageInfo(fImageInfo[]).Image (done by fImageList.Delete() in TIECustomMultiBitmap.DeleteImage) FreeAndNil(fImageList); fImageList := TIEVirtualImageList.Create('ILIST', fImageCacheUseDisk); fImageList.MaxImagesInMemory := fImageCacheSize; Changed( -1 ); end; {!! TIEMultiBitmap.Count Declaration property Count: integer; (Read-only) Description Returns the number of images stored in the TIEMultiBitmap. !!} function TIECustomMultiBitmap.GetImageCount: integer; begin result := fImageInfo.Count; end; {!! TIECustomMultiBitmap.LockUpdate Declaration procedure LockUpdate; Description Increments the lock update counter. While is greater than zero all updating is disabled. Use to unlock. Example // Disable updating MyDBMultiBitmap.LockUpdate; try ... Perform activities, e.g. appending many files to database finally // Re-enable Updating and refresh view MyDBMultiBitmap.UnlockUpdate; end; !!} procedure TIECustomMultiBitmap.LockUpdate; begin inc(fLockUpdate); end; {!! TIECustomMultiBitmap.UnlockUpdate Declaration function UnlockUpdate: integer; Description Decrement the lock update counter (use after calling ). If the lock count is zero, then is called to refresh the content and view. Returns the lock count. Example // Disable updating MyDBMultiBitmap.LockUpdate; try ... Perform activities, e.g. appending many files to database finally // Re-enable Updating and refresh view MyDBMultiBitmap.UnlockUpdate; end; !!} function TIECustomMultiBitmap.UnlockUpdate: integer; begin if fLockUpdate > 0 then dec( fLockUpdate ); if fLockUpdate = 0 then begin if fUpdatePending then UpdateEx( False ) else // This might have been called by TImageEnMView so ensure we call update if assigned( fOwner ) and ( fOwner is TImageEnMView ) then TImageEnMView( fOwner ).Update; end; result := fLockUpdate; end; // Not exposed in documentation {!! TIECustomMultiBitmap.Update Declaration procedure Update; Description Updates the if connected. !!} procedure TIECustomMultiBitmap.Update; begin UpdateEx( True ); end; // In TIECustomMultiBitmap bFullUpdate has no effect procedure TIECustomMultiBitmap.UpdateEx(bFullUpdate: Boolean = true); begin if fLockUpdate > 0 then begin fUpdatePending := True; exit; end; if assigned( fOwner ) and ( fOwner is TImageEnMView ) then TImageEnMView( fOwner ).Update; end; // If descendent classes need to load images by ID on demand, then InternalLoadImageByID must be used and InternalLoadImageByID_Assigned returns true function TIECustomMultiBitmap.InternalLoadImageByID_Assigned(): Boolean; begin Result := False; end; // If descendent classes need to load images by ID on demand, then InternalLoadImageByID must be used and InternalLoadImageByID_Assigned returns true procedure TIECustomMultiBitmap.InternalLoadImageByID(Sender: TObject; Index, ID: Integer; var Bitmap: TIEBitmap; var IOParams: TIOParams); begin { // } end; {!! TIEMultiBitmap.Flip Declaration procedure Flip(idx: integer; Dir: ); Description Flips (mirrors) a frame within the image across the horizontal or vertical axis. Examples // Flip the first image in a TIFF file top-to-bottom MBitmap := TIEMultiBitmap.create; MBitmap.Read( 'D:\Doc.Tiff' ); MBitmap.Flip( 0, fdVertical ); MBitmap.Write( 'D:\Doc.Tiff' ); MBitmap.Free; !!} procedure TIECustomMultiBitmap.Flip(idx: integer; Dir: TFlipDir); var bmp: TIEBitmap; begin bmp := GetTIEBitmap( idx ); bmp.Flip( Dir ); ReleaseBitmap( idx, True ); Update; end; {!! TIEMultiBitmap.Rotate Declaration procedure Rotate(idx: integer; Angle: double; AntialiasMode: = ierFast; BackgroundColor: TColor = clWhite); Description Rotates a frame of the current image by the specified angle (negative or positive degrees counter-clockwise). AntialiasMode specifies the anti-aliasing algorithm that is used to improve rotation quality: ierNone : No anti-aliasing (lowest quality) ierFast : Fast but lower quality ierBilinear : Bilinear, high quality ierBicubic : Bicubic, highest quality BackgroundColor specifies a background color to fill new regions (i.e. when not rotating at a 90 degree angle) Examples // Rotate the first frame of a TIFF file 90° counter-clockwise; MBitmap := TIEMultiBitmap.create; MBitmap.Read( 'D:\Doc.Tiff' ); MBitmap.Rotate( 0, 90 ); MBitmap.Write( 'D:\Doc.Tiff' ); MBitmap.Free; // Rotate the first frame of an image 45° clockwise at highest quality with a white background color MBitmap.Rotate( 0, 315, ierBicubic, clWhite ); See Also - !!} procedure TIECustomMultiBitmap.Rotate(idx: integer; Angle: double; AntialiasMode: TIEAntialiasMode = ierFast; BackgroundColor: TColor = clWhite); var bmp: TIEBitmap; begin bmp := GetTIEBitmap( idx ); bmp.Rotate( Angle, AntialiasMode, BackgroundColor ); ReleaseBitmap( idx, True ); Update; end; {!! TIEMultiBitmap.Resample Declaration procedure Resample(idx: integer; ScaleBy: Double; FilterType: = rfNone); Description Resizes a frame of the current image. The content of the image changes (stretched to new size). Parameter Description ScaleBy The amount to scale all images. E.g. 0.5 would halve the size of all images while respecting the proportions FilterType Resampling interpolation algorithm
Examples // Halve the size of the first image in a TImageEnMView with high quality smoothing ImageEnMView1.IEMBitmap.Resample( 0, 0.5, rfLanczos3 ); ImageEnMView1.Update; // Quarter the size of the first frame of a TIFF file with fast but good quality smoothing MBitmap := TIEMultiBitmap.create; MBitmap.Read( 'D:\Doc.Tiff' ); MBitmap.Resample( 0, 0.25, rfFastLinear ); MBitmap.Write( 'D:\Doc.Tiff' ); MBitmap.Free; !!} procedure TIECustomMultiBitmap.Resample(idx: integer; ScaleBy: Double; FilterType: TResampleFilter = rfNone); var bmp: TIEBitmap; begin bmp := GetTIEBitmap( idx ); bmp.Resample( ScaleBy, FilterType ); ReleaseBitmap( idx, True ); Update; end; {!! TIEMultiBitmap.FlipAll Declaration procedure FlipAll(Dir:
); Description Flips (mirrors) all frames within the image across the horizontal or vertical axis. Examples // Flip all images in a TImageEnMView right-to-left ImageEnMView1.IEMBitmap.Flip( fdHorizontal ); // Flip all images in a TIFF file top-to-bottom MBitmap := TIEMultiBitmap.create; MBitmap.Read( 'D:\Doc.Tiff' ); MBitmap.FlipAll( fdVertical ); MBitmap.Write( 'D:\Doc.Tiff' ); MBitmap.Free; !!} procedure TIECustomMultiBitmap.FlipAll(Dir: TFlipDir); var I: Integer; begin LockUpdate; for I := 0 to Count - 1 do Flip( I, Dir ); UnlockUpdate; end; {!! TIEMultiBitmap.RotateAll Declaration procedure RotateAll(Angle: double; AntialiasMode: = ierFast; BackgroundColor: TColor = clWhite); Description Rotates all frames within the current image by the specified angle (negative or positive degrees counter-clockwise). AntialiasMode specifies the anti-aliasing algorithm that is used to improve rotation quality: ierNone : No anti-aliasing (lowest quality) ierFast : Fast but lower quality ierBilinear : Bilinear, high quality ierBicubic : Bicubic, highest quality BackgroundColor specifies a background color to fill new regions (i.e. when not rotating at a 90 degree angle) Examples // Rotate all images in a TImageEnMView 90° clockwise (Note: AntialiasMode is irrelevant for 90 deg. rotates) ImageEnMView1.IEMBitmap.RotateAll( 270 ); // Rotate a TIFF file 90° counter-clockwise; MBitmap := TIEMultiBitmap.create; MBitmap.Read( 'D:\Doc.Tiff' ); MBitmap.RotateAll( 90 ); MBitmap.Write( 'D:\Doc.Tiff' ); MBitmap.Free; // Rotate the image 45° clockwise at highest quality with a white background color MBitmap.RotateAll( 315, ierBicubic, clWhite ); // Rotate the image 180° clockwise MBitmap.RotateAll( 180 ); See Also - !!} procedure TIECustomMultiBitmap.RotateAll(Angle: double; AntialiasMode: TIEAntialiasMode = ierFast; BackgroundColor: TColor = clWhite); var I: Integer; begin LockUpdate; for I := 0 to Count - 1 do Rotate( I, Angle, AntialiasMode, BackgroundColor ); UnlockUpdate; end; {!! TIEMultiBitmap.ResampleAll Declaration procedure ResampleAll(ScaleBy: Double; FilterType: = rfNone); Description Resizes (all frames of) the current image. The content of the image changes (stretched to new size). Parameter Description ScaleBy The amount to scale all images. E.g. 0.5 would halve the size of all images while respecting the proportions FilterType Resampling interpolation algorithm
Examples // Halve the size of all images in a TImageEnMView with high quality smoothing ImageEnMView1.IEMBitmap.ResampleAll( 0.5, rfLanczos3 ); // Quarter the size of all images in a TIFF file with fast but good quality smoothing MBitmap := TIEMultiBitmap.create; MBitmap.Read( 'D:\Doc.Tiff' ); MBitmap.ResampleAll( 0.25, rfFastLinear ); MBitmap.Write( 'D:\Doc.Tiff' ); MBitmap.Free; !!} procedure TIECustomMultiBitmap.ResampleAll(ScaleBy: Double; FilterType: TResampleFilter = rfNone); var I: Integer; begin LockUpdate; for I := 0 to Count - 1 do Resample( I, ScaleBy, FilterType ); UnlockUpdate; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// // TIEMultiBitmap {!! TIEMultiBitmap.Create Declaration constructor Create(); overload; constructor Create(ImageWidth, ImageHeight: integer; ImagePixelFormat:
= ie24RGB); overload; constructor Create(MBitmap: ); overload; constructor Create(const FileName: string); overload; Description Create a new TIEMultiBitmap object. Second overload creates the bitmap using specified parameters. Third overload creates a clone of an existing TIEMultiBitmap Fourth overload loads image from specified file. Examples // Create an empty image mbmp1 := TIEMultiBitmap.Create(); // Create 1000x1000, 24 bit RGB image with 5 pages mbmp2 := TIEMultiBitmap.Create(1000, 1000, 5, ie24RGB); // Create an image from file "input.gif" mbmp2 := TIEMultiBitmap.Create( 'input.gif' ); // Create a clone of mbmp2 mbmp3 := TIEMultiBitmap.Create(mbmp2); !!} constructor TIEMultiBitmap.Create(ImageWidth, ImageHeight: integer; PageCount: Integer; ImagePixelFormat: TIEPixelFormat = ie24RGB); var I: Integer; begin Create(); for I := 0 to PageCount - 1 do AppendImage( ImageWidth, ImageHeight, ImagePixelFormat ); fModified := False; end; constructor TIEMultiBitmap.Create(MBitmap: TIECustomMultiBitmap); begin Create(); Assign( MBitmap ); fModified := False; end; constructor TIEMultiBitmap.Create(const FileName: string); begin Create(); Read( FileName ); end; {!! TIEMultiBitmap.Assign Declaration procedure Assign(Source: TObject); Description Replace the existing content with the frames in TImageEnMView, , , TBitmap or TImageList. !!} procedure TIEMultiBitmap.Assign(Source: TObject); var I: Integer; iebmp: TIEBitmap; ico: TIcon; begin if Source is TIEBitmap then begin Clear; AppendImage( TIEBitmap( Source )); end else if Source is TBitmap then begin Clear; AppendImage( TBitmap( Source )); end else if Source is TIECustomMultiBitmap then begin Clear; AppendImage( TIECustomMultiBitmap( Source )); end else if Source is TImageEnMView then begin Clear; AppendImage( TImageEnMView( Source ).IEMBitmap ); // Assign params if GetParamsEnabled then ParamsList.Assign( TImageEnMView( Source ).MIO.ParamsList ); end else if Source is TImageList then begin Clear; for I := 0 to TImageList( Source ).Count - 1 do begin ico := TIcon.create; iebmp := TIEBitmap.create; TImageList( Source ).GetIcon( I , ico ); IEConvertIconToBitmap( ico.Handle, iebmp ); AppendImage( iebmp ); ico.Free; iebmp.Free; end; end else if Source <> nil then raise EIEException.create('Unrecognized source'); end; {!! TIEMultiBitmap.DuplicateCompressionInfo Declaration procedure DuplicateCompressionInfo; Description Clone the compression information from idx 0 to all indexes. Note: Only valid if = true Example // Change the compression method for a TIFF file MBitmap := TIEMultiBitmap.create; MBitmap.ParamsEnabled := True; // Load params with the image MBitmap.Read( 'C:\MyImage.tiff' ); MBitmap.Params[ 0 ].TIFF_Compression := ioTIFF_G4FAX; MBitmap.DuplicateCompressionInfo; MBitmap.Write( 'C:\OutImage.tiff' ); MBitmap.Free; // Which is the same as: MBitmap := TIEMultiBitmap.create; MParams := TIOMultiParams.create; MBitmap.Read( 'C:\MyImage.tiff', MParams ); for I := 0 to MBitmap.count do MParams[ I ].TIFF_Compression := ioTIFF_G4FAX; MBitmap.Write( 'C:\OutImage.tiff', MParams ); MParams.free; MBitmap.Free; !!} procedure TIEMultiBitmap.DuplicateCompressionInfo; begin if GetParamsEnabled then fParamsList.DuplicateCompressionInfo; end; {!! TIEMultiBitmap.RemoveBlankPages Declaration function RemoveBlankPages(Tolerance: Double = 0.0; Complete: boolean = true; LeftToRight: boolean = true): Integer; Description Locate images in the TIEMultiBitmap of a single color (i.e. blank images) and remove them. Parameter Description Tolerance Determines how tolerant to be in checking color variance (in the range 0.0 to 1.0). For example, if tolerance is 0.1 then 10% of pixels can be of different color and the image would still be considered "blank" Complete If true all images are checked. Otherwise the check stops once the first non blank image has been found and removed. LeftToRight If true the scan starts at the first image and proceeds to the last (otherwise it proceeds in reverse order)
Returns the number of removed pages. Example // Remove last blank pages MBitmap.RemoveBlankPages( 0.0, False, False ); // Remove any pages that are 95% blank MBitmap.RemoveBlankPages( 0.05 ); !!} function TIEMultiBitmap.RemoveBlankPages(Tolerance: Double = 0; Complete: boolean = true; LeftToRight: boolean = true): Integer; var proc: TImageEnProc; i: Integer; domValue: Double; domColor: TRGB; begin result := 0; proc := TImageEnProc.Create(nil); try if LeftToRight then i := 0 else i := GetImageCount - 1; while (LeftToRight and (i < GetImageCount)) or (not LeftToRight and (i >= 0)) do begin proc.AttachedIEBitmap := GetTIEBitmap(i); try domValue := proc.GetDominantColor(domColor) / 100; finally ReleaseBitmap(i, false); end; if 1 - domValue <= tolerance then begin DeleteImage(i); inc(result); if not LeftToRight then dec(i); end else begin if not Complete then // stop when a non-blank occurs break; if LeftToRight then inc(i) else dec(i); end; end; finally proc.Free; end; end; {!! TIEMultiBitmap.RemoveDuplicates Declaration function RemoveDuplicates(): Integer; Description Locate images with duplicate content in the TIEMultiBitmap and remove other instances (using an MD5 Hash). Returns the number of removed pages. Examples // Ensure there are no duplicate images in our TIEMultiBitmap after filling it from a folder MBitmap.Clear; MBitmap.FillFromDirectory('C:\Images'); MBitmap.RemoveDuplicates(); See Also -
- !!} function TIEMultiBitmap.RemoveDuplicates(): Integer; var ssHashes: TStringList; i: Integer; begin result := 0; ssHashes := TStringList.Create(); try ssHashes.Sorted := True; ssHashes.Duplicates := dupError; i := 0; while i < GetImageCount do try if ImageHash[ i ] <> '' then ssHashes.Add( string(ImageHash[ i ]) ); inc( i ); except // Hash found! DeleteImage( i ); inc( result ); end; finally ssHashes.Free; end; end; {!! TIEMultiBitmap.AppendSplit Declaration function AppendSplit(SourceGrid: ; cellWidth: Integer; cellHeight: Integer; maxCount: Integer = 0): Integer; Description Splits the source image into cells of the specified size and adds each cell to the TIEMultiBitmap Result is the count of added images. Parameter Description SourceGrid Source bitmap containing cells to split. cellWidth Width of a cell. cellHeight Height of a cell. maxCount Maximum number of cells to add. 0 = all suitable cells.
!!} function TIEMultiBitmap.AppendSplit(SourceGrid: TIEBitmap; cellWidth: Integer; cellHeight: Integer; maxCount: Integer): Integer; var x, y: Integer; idx: Integer; begin result := 0; y := 0; while y < SourceGrid.Height do begin x := 0; while x < SourceGrid.Width do begin idx := AppendImage; SetImageRect( idx, SourceGrid, x, y, x + cellWidth - 1, y + cellHeight - 1 ); inc(result); if (maxCount>0) and (maxCount=result) then exit; inc(x, cellWidth); end; inc(y, cellHeight); end; end; {!! TIEMultiBitmap.MoveImage Declaration procedure MoveImage(idx: Integer; destination: Integer); Description Moves an image from the index position idx to the destination position. If the destination index is greater than or equal to the image count, the image is moved to the position after the last image. Note: If you have images of the order ABCD, then calling MoveImage(0, 2) would change it to BCAD Example // Exchange first and second images MBitmap.MoveImage(0, 1); // Move first image to the end of the grid MBitmap.MoveImage(0, MBitmap.Count); !!} // move image idx to destination index procedure TIEMultiBitmap.MoveImage(idx: integer; destination: integer); begin if (idx >= 0) and (idx < fImageInfo.Count) and (destination >= 0) and (destination <> idx) then begin if destination >= fImageInfo.Count then begin fImageInfo.Add( fImageInfo[ idx ]); fImageInfo.Delete( idx ); end else fImageInfo.Move( idx, destination ); UpdateParams( IEM_OP_MOVE, idx, destination ); Changed( -1 ); end; end; {!! TIEMultiBitmap.SwapImages Declaration procedure TIEMultiBitmap.SwapImages(idx1, idx2: Integer); Description Moves two images to each others position. Example // Exchange first and last images MBitmap.MoveImage(0, MBitmap.Count - 1); !!} procedure TIEMultiBitmap.SwapImages(idx1, idx2: Integer); var tmp: pointer; begin tmp := fImageInfo[ idx1 ]; fImageInfo[ idx1 ] := fImageInfo[idx2]; fImageInfo[ idx2 ] := tmp; UpdateParams( IEM_OP_SWAP, idx1, idx2 ); Changed( -1 ); end; {!! TIEMultiBitmap.InsertTransitionFrames Declaration procedure InsertTransitionFrames(Idx : integer; iFrameCount : integer; Effect :
; iWidth : Integer = -1; iHeight : Integer = -1; BackgroundColor : TColor = clBlack; ResamplingFilter: = rfFastLinear); Description Create a series of transition frames from the image at Idx - 1 to the image at Idx (and insert them at position Idx). If Idx = 0 then the transition is from a blank frame to the first image. If Idx = Count then the transition is from the last image to a blank frame. Parameter Description Idx The insertion position iFrameCount The number of frames to insert Effect The desired transition effect iWidth, iHeight The size to create the transition bitmaps. If either of these are -1 then the size will be the larger of the two images in each dimension. Aspect Ratios will be maintained and any non-image area will be filled with BackgroundColor. BackgroundColor The color that will be used for blank frames or non-image area (default is clBlack) ResamplingFilter The algorithm that is used to improve quality when resizing images
Note: Use
if you need to create frames for an iettPanZoom transition Example // Create ten frames that use a cross dissolve transition from image 5 to image 6 MBitmap.InsertTransitionFrames(6, 10, iettCrossDissolve); See Also - !!} procedure TIEMultiBitmap.InsertTransitionFrames(Idx : integer; iFrameCount : integer; Effect : TIETransitionType; iWidth : Integer = -1; iHeight : Integer = -1; BackgroundColor : TColor = clBlack; ResamplingFilter: TResampleFilter = rfFastLinear); var ARect : TRect; begin ARect := Rect(0, 0, 0, 0); InsertTransitionFramesEx(Idx, iFrameCount, Effect, ARect, ARect, True, iWidth, iHeight, False, BackgroundColor, ResamplingFilter); end; {!! TIEMultiBitmap.InsertTransitionFramesEx Declaration procedure InsertTransitionFramesEx(Idx : Integer; iFrameCount : Integer; Effect : ; StartRect, EndRect : TRect; RectMaintainAspectRatio : boolean = True; iWidth : Integer = -1; iHeight : Integer = -1; bStretchSmall : Boolean = False; BackgroundColor : TColor = clBlack; ResamplingFilter : ; Smoothing: Integer = 96; Timing : = iettLinear); Description This is an extended version of that includes more parameters and is primarily used when you need to create a series of frames that show a Pan Zoom from StartRect to EndRect for the image specified at Idx - 1. Parameter Description Idx The insertion position iFrameCount The number of frames to insert Effect The desired transition effect StartRect When using an iettPanZoom effect this is the portion of the image that is shown at the start EndRect When using an iettPanZoom effect this is the portion of the image that is shown at the end RectMaintainAspectRatio ImageEn will ensure that the starting and ending rects are automatically adjusted to ensure the resultant image has the correct aspect ratio (iettPanZoom only) iWidth, iHeight The size to create the transition bitmaps. If either of these are -1 then the size will be the larger of the two images in each dimension. Aspect Ratios will be maintained and any non-image area will be filled with BackgroundColor. bStretchSmall If the images are smaller than the transition bitmap size (iWidth x iHeight) should they be stretched to fit (which can lead to distortion). BackgroundColor The color that will be used for blank frames or non-image area (Default is clBlack) ResamplingFilter The algorithm that is used to improve quality when resizing images Timing The rate at which the transition progresses Smoothing In order to reduce the "jumpiness" of pan zoom effects, transition frames are alpha blended. A low value will improve smoothness, but increase blurriness. A high value will improve clarity, but increase jumpiness. Typical range is 64 - 196. 255 means no alpha blending
Example // Create ten Pan Zoom frames for the image at index 5 // Top Left corner of image StartingRect := Rect(0, 0, MBitmap.ImageWidth[5] div 4, MBitmap.ImageHeight[5] div 4); // Bottom right corner of image EndingRect := Rect(MulDiv(MBitmap.ImageWidth[5], 3, 4), MulDiv(MBitmap.ImageHeight[5], 3, 4), MBitmap.ImageWidth[5], MBitmap.ImageHeight[5]); // Create frames MBitmap.InsertTransitionFramesEx(5, 10, iettPanZoom, StartRect, EndRect); See Also -
!!} procedure TIEMultiBitmap.InsertTransitionFramesEx(Idx : integer; iFrameCount : Integer; Effect : TIETransitionType; StartRect, EndRect : TRect; RectMaintainAspectRatio : boolean = True; iWidth : Integer = -1; iHeight : Integer = -1; bStretchSmall : Boolean = False; BackgroundColor : TColor = clBlack; ResamplingFilter: TResampleFilter = rfFastLinear; Smoothing: Integer = 96; Timing : TIETransitionTiming = iettLinear); var StartImage : TIEBitmap; EndImage : TIEBitmap; ATransBitmap : TBitmap; iSteps : Integer; EachStep : Single; TransLevel : Single; I : Integer; bWantFrame0 : Boolean; bWantFrame100 : Boolean; Proc : TImageEnProc; begin if iFrameCount < 1 then exit; if (Idx < 0) or (Idx > GetImageCount) then raise EIEException.create('Invalid Index'); if (Idx = 0) and (Effect = iettPanZoom) then raise EIEException.create('Invalid index for iettPanZoom'); // We don't want 0% or 100% for normal transitions as they will be identical to the before and after frames bWantFrame0 := False; bWantFrame100 := False; Proc := TImageEnProc.create( nil ); StartImage := TIEBitmap.create; EndImage := TIEBitmap.create; ATransBitmap := TBitmap.create; try If Idx = 0 then begin // Starting image is blank, Ending image is index 0 CopyToIEBitmap(idx, EndImage); if (iWidth < 0) or (iHeight < 0) then StartImage.Allocate(EndImage.Width, EndImage.Height) else StartImage.Allocate(iWidth, iHeight); StartImage.Fill(BackgroundColor); // We want the initial blank (0%) Frame bWantFrame0 := True; end else if Idx = GetImageCount then begin // Starting image is last frame, ending image is blank // Starting image is blank, Ending image is index 0 CopyToIEBitmap(idx - 1, StartImage); if (iWidth < 0) or (iHeight < 0) then EndImage.Allocate(StartImage.Width, StartImage.Height) else EndImage.Allocate(iWidth, iHeight); EndImage.Fill(BackgroundColor); // We want the ending blank (100%) Frame bWantFrame100 := True; end else begin // Both images are valid CopyToIEBitmap(idx - 1, StartImage); CopyToIEBitmap(idx, EndImage); end; if Effect = iettPanZoom then begin // We want both the start and end frames (i.e. the rects that the user specified) bWantFrame0 := True; bWantFrame100 := True; end; // Prepare the bitmaps Proc.PrepareTransitionBitmapsEx(StartImage.VclBitmap, EndImage.VclBitmap, Effect, StartRect, EndRect, RectMaintainAspectRatio, iWidth, iHeight, bStretchSmall, BackgroundColor, ResamplingFilter, Smoothing, Timing); for I := 1 to iFrameCount do begin iSteps := (iFrameCount + 1) - (Integer(bWantFrame0) + Integer(bWantFrame100)); EachStep := 100 / iSteps; if bWantFrame0 then TransLevel := (I - 1) * EachStep else TransLevel := I * EachStep; Proc.CreateTransitionBitmap(TransLevel, ATransBitmap); InsertImage(idx, ATransBitmap); Inc(idx); end; finally ATransBitmap.Free; StartImage.free; EndImage .free; Proc.Free; end; end; {!! TIEMultiBitmap.SetImageRect Declaration procedure SetImageRect(idx: Integer; srcImage: TBitmap; x1, y1, x2, y2: Integer); procedure SetImageRect(idx: Integer; srcImage: ; x1, y1, x2, y2: Integer); Description Sets the image assigned to index, idx. The rectangle x1, y1, x2, y2 of srcImage bitmap is copied internally. After calling SetImageRect you can free the srcImage bitmap. !!} // creates a new copy of "srcImage" (then srcImage can be freed) procedure TIEMultiBitmap.SetImageRect(idx: integer; srcImage: TBitmap; x1, y1, x2, y2: integer); begin if idx < fImageInfo.Count then begin CheckAllocated( idx ); x1 := imin(srcImage.width - 1, x1); y1 := imin(srcImage.height - 1, y1); x2 := imin(srcImage.width - 1, x2); y2 := imin(srcImage.height - 1, y2); if TIEImageInfo(fImageInfo[idx]).image <> nil then fImageList.Delete(TIEImageInfo(fImageInfo[idx]).image); TIEImageInfo(fImageInfo[idx]).image := fImageList.AddBitmapRect(srcImage, x1, y1, x2 - x1 + 1, y2 - y1 + 1); fImageList.SetImageOriginalWidth(TIEImageInfo(fImageInfo[idx]).image, srcImage.Width); fImageList.SetImageOriginalHeight(TIEImageInfo(fImageInfo[idx]).image, srcImage.Height); Changed( idx ); end; end; // creates a new copy of "srcImage" (then srcImage can be freed) procedure TIEMultiBitmap.SetImageRect(idx: integer; srcImage: TIEBitmap; x1, y1, x2, y2: integer); var temp: TIEBitmap; begin temp := TIEBitmap.Create; try temp.Allocate(x2 - x1 + 1, y2 - y1 + 1, srcImage.PixelFormat); srcImage.CopyRectTo(temp, x1, y1, 0, 0, temp.Width, temp.Height, true); SetImageEx( idx, temp ); finally temp.free; end; end; {!! TIEMultiBitmap.Read Declaration function Read(const FileName: string; IOParams: = nil; bCheckUnknown: Boolean = False): boolean; overload; function Read(Stream: TStream; FileType: = ioUnknown; IOParams: = nil): boolean; overload; function Read(Buffer: pointer; BufferSize: integer; FileType: = ioUnknown; IOParams: = nil): boolean; Description Load an image from file or stream. This method supports all formats supported by class. When reading from a stream you can optionally specify the Format. If it is not specified ImageEn will determine the file type automatically. You can optionally pass a object for the I/O parameters of the file (see also ). If bCheckUnknown is true and the file extension is not known or is incorrect (e.g. a GIF file named MyImage.jpg), then loading will be attempted by analyzing the file content (in the same way as ). Returns False on failure. Examples var mbmp: TIEMultiBitmap; begin mbmp := TIEMultiBitmap.Create; mbmp.Read('input.tiff'); mbmp.Write('output.tiff'); mbmp.Free; end; ...which is the same as: with TIEMultiBitmap.Create('input.tiff') do begin Write('output.tiff'); Free; end; ...And the same as: var mbmp: TIEMultiBitmap; mio: TImageEnMIO; begin mbmp := TIEMultiBitmap.Create; io := TImageEnMIO.CreateFromIEMBitmap(mbmp); io.LoadFromFile('input.tiff'); io.SaveToFile('output.tiff'); io.Free; mbmp.Free; end; !!} function TIEMultiBitmap.Read(const FileName: string; IOParams: TIOMultiParams = nil; bCheckUnknown: Boolean = False): boolean; var io: TImageEnMIO; begin io := TImageEnMIO.CreateFromIEMBitmap( Self ); try // Assign Params if assigned( IOParams ) then io.fParamsList.Assign( IOParams ) else if ParamsEnabled then io.fParamsList.Assign( fParamsList ); io.LoadFromFile( Filename, bCheckUnknown ); result := not io.Aborting; // Restore Params if assigned( IOParams ) then IOParams.Assign( io.fParamsList ); if ParamsEnabled then fParamsList.Assign( io.fParamsList ); finally io.Free; end; Update; end; function TIEMultiBitmap.Read(Stream: TStream; FileType: integer = 0; IOParams: TIOMultiParams = nil): boolean; var io: TImageEnMIO; begin io := TImageEnMIO.CreateFromIEMBitmap( self ); try // Assign Params if assigned( IOParams ) then io.fParamsList.Assign( IOParams ) else if ParamsEnabled then io.fParamsList.Assign( fParamsList ); io.LoadFromStream(Stream, FileType); result := not io.Aborting; // Restore Params if assigned( IOParams ) then IOParams.Assign( io.fParamsList ); if ParamsEnabled then fParamsList.Assign( io.fParamsList ); finally io.Free; end; Update; end; function TIEMultiBitmap.Read(Buffer: pointer; BufferSize: integer; FileType: integer = 0; IOParams: TIOMultiParams = nil): boolean; var io: TImageEnMIO; begin io := TImageEnMIO.CreateFromIEMBitmap( self ); try // Assign Params if assigned( IOParams ) then io.fParamsList.Assign( IOParams ) else if ParamsEnabled then io.fParamsList.Assign( fParamsList ); io.LoadFromBuffer(Buffer, BufferSize, FileType); result := not io.Aborting; // Restore Params if assigned( IOParams ) then IOParams.Assign( io.fParamsList ); if ParamsEnabled then fParamsList.Assign( io.fParamsList ); finally io.Free; end; Update; end; {!! TIEMultiBitmap.Write Declaration function Write(const FileName: string; IOParams: = nil): boolean; overload; function Write(Stream: TStream; FileType: ; IOParams: = nil): boolean; overload; Description Write an image to file or stream. This method supports all formats supported by class. If saving to a stream you must specify the FileType You can optionally specify an object containing the I/O parameters of the file (see also ). Returns true on success. Examples var mbmp: TIEMultiBitmap; begin mbmp := TIEMultiBitmap.Create; mbmp.Read('input.tiff'); mbmp.Write('output.tiff'); mbmp.Free; end; Which is the same as... with TIEMultiBitmap.Create('input.tiff') do begin Write('output.tiff'); Free; end; Also, the same as... var mbmp: TIEMultiBitmap; io: TImageEnMIO; begin mbmp := TIEMultiBitmap.Create; io := TImageEnMIO.CreateFromIEMBitmap(mbmp); io.LoadFromFile('input.tiff'); io.SaveToFile('output.tiff'); io.Free; mbmp.Free; end; !!} function TIEMultiBitmap.Write(const FileName: string; IOParams: TIOMultiParams = nil): boolean; var I: Integer; io: TImageEnMIO; bmp : TIEBitmap; iBitsPerSample, iSamplesPerPixel: Integer; begin io := TImageEnMIO.CreateFromIEMBitmap( Self ); try // Assign Params if assigned( IOParams ) then io.fParamsList.Assign( IOParams ) else if ParamsEnabled then io.fParamsList.Assign( fParamsList ) else for I := 0 to Count - 1 do begin // Assign some minimum params bmp := GetTIEBitmap( I ); if bmp.PixelFormat = ie8g then begin iBitsPerSample := 8; iSamplesPerPixel := 1; io.fParamsList.Params[ I ].JPEG_ColorSpace := ioJPEG_GRAYLEV; end else IEPixelFormatToBPSAndSPP( bmp.PixelFormat, iBitsPerSample, iSamplesPerPixel ); io.fParamsList.Params[ I ].BitsPerSample := iBitsPerSample; io.fParamsList.Params[ I ].SamplesPerPixel := iSamplesPerPixel; ReleaseBitmap( I, false ); end; io.SaveToFile(FileName); result := not io.Aborting; finally io.Free; end; end; function TIEMultiBitmap.Write(Stream: TStream; FileType: integer; IOParams: TIOMultiParams = nil): boolean; var io: TImageEnMIO; begin io := TImageEnMIO.CreateFromIEMBitmap( self ); try // Assign Params if assigned( IOParams ) then io.fParamsList.Assign( IOParams ) else if ParamsEnabled then io.fParamsList.Assign( fParamsList ); io.SaveToStream(Stream, FileType); result := not io.Aborting; finally io.Free; end; end; {!! TIEMultiBitmap.FillFromDirectory Declaration procedure FillFromDirectory(const Directory: WideString; Limit : integer = -1; AllowUnknownFormats : boolean = false; const ExcludeExtensions : WideString = ''; DetectFileFormat : boolean = false; const FilterMask : WideString = ''; IncludeVideoFiles : Boolean = False; LoadOnDemand : boolean = true; DefaultTopText : = iedtNone; DefaultInfoText : = iedtNone; DefaultBottomText : = iedtFilename; bShowHiddenFiles : Boolean = False; bShowFolders : Boolean = False); Description Fills the MultiBitmap with files from the specified Directory. For each file will be set with the full path. Parameter Description Directory The folder to search for files Limit The maximum number of images to load. Use -1 to retrieve all files AllowUnknownFormats If false (default) only known and supported file formats are loaded. Otherwise all files are loaded ExcludeExtensions A comma separated list of file extensions to skip (e.g. 'lyr,all,iev') DetectFileFormat If true then the image type is detected by reading the header (which can be slow). Otherwise ImageEn only checks the file extension FilterMask Limits the fill to file extensions found in a comma separated list (e.g. 'jpg,jpeg,jpe'). Specify an empty string to return all supported extensions bShowHiddenFiles Enable to include hidden and system files (default is false)
Note: Does NOT clear existing content. Use
first to replace existing content Example MultiBitmap1.Clear; MultiBitmap1.FillFromDirectory('C:\images'); !!} procedure TIEMultiBitmap.FillFromDirectory(const Directory: WideString; Limit : integer = -1; AllowUnknownFormats : boolean = false; const ExcludeExtensions : WideString = ''; DetectFileFormat : boolean = false; const FilterMask : WideString = ''; bGetHiddenFiles : Boolean = False); var l, idx: Integer; fpath, fname: WideString; iAdded: Integer; sep: WideString; excList: TStringList; mskList: TStringList; dir: TIEDirContent; ext: WideString; bInclude: Boolean; begin LockUpdate(); dir := nil; excList := TStringList.Create; mskList := TStringList.Create; try excList.CommaText := LowerCase( ExcludeExtensions ); mskList.CommaText := LowerCase( FilterMask ); l := length( Directory ); if ( l = 0 ) or ( Directory[ l ] = '\' ) then sep := '' else sep := '\'; iAdded := 0; dir := TIEDirContent.Create( Directory + sep + '*.*' ); while dir.GetItem( fname, True, False, bGetHiddenFiles ) do begin fpath := Directory + sep + fname; ext := IEExtractFileExtW( fname, false ); if dir.IsFolder then bInclude := True else bInclude := ( AllowUnknownFormats or ( DetectFileFormat and ( FindFileFormat( fpath, ffContentOnly ) <> ioUnknown )) or IsKnownFormat( fpath, False )) and ( excList.IndexOf( ext ) = -1) and (( mskList.Count = 0 ) or ( mskList.IndexOf( ext ) > -1 )); if bInclude then begin if ( Limit > -1 ) and ( iAdded = Limit ) then break; idx := AppendImage( fpath ); with GetImageInfo( idx ) do begin FileSize := dir.FileSizeBytes; CreateDate := dir.CreateDate; EditDate := dir.EditDate; end; inc(iAdded); end; end; finally dir.Free; mskList.Free; excList.Free; UnLockUpdate; end; end; {$ENDIF} // IEINCLUDEMULTIVIEW {$IFDEF IEINCLUDEMULTIVIEW} ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// TIOMultiParams constructor TIOMultiParams.Create; begin inherited Create; // fParamsList := TList.Create; end; destructor TIOMultiParams.Destroy; begin Clear; FreeAndNil( fParamsList ); // inherited; end; procedure TIOMultiParams.CheckAllocated(idx: integer); var iCopy: Integer; iop: TIOParams; begin if fParamsList[ idx ] <> nil then exit; iop := TIOParams.Create( nil ); // Copy compression info if ( fParamsList.Count > 0 ) and ( idx >= fParamsList.Count ) then iCopy := 0 // Appending: Get from first Params item else iCopy := Idx - 1; // Inserting: Get from previous Params item if ( iCopy >= 0 ) and ( fParamsList[ iCopy ] <> nil ) then iop.AssignCompressionInfo( TIOParams( fParamsList[ iCopy ] )); fParamsList[ idx ] := iop; end; procedure TIOMultiParams.RemoveParam(idx: integer); begin if idx < fParamsList.Count then begin if fParamsList[ idx ] <> nil then TIOParams( fParamsList[ idx ]).free; fParamsList.Delete( idx ); end; end; procedure TIOMultiParams.InsertParam(idx: integer); begin if idx < fParamsList.Count then // insert fParamsList.Insert( idx, nil ) else // add fParamsList.Add( nil ); end; procedure TIOMultiParams.MoveParam(idx: integer; Destination: integer); begin if (idx >= 0) and (idx < fParamsList.Count) and (Destination >= 0) and (Destination <> idx) then begin if destination >= fParamsList.Count then begin fParamsList.Add( fParamsList[ idx ]); fParamsList.Delete( idx ); end else fParamsList.Move( idx, Destination ); end; end; procedure TIOMultiParams.MoveParams(IndexGroup: TIEArrayOfInteger; Destination: integer); var mm: array of TIOParams; i: Integer; begin SetLength( mm, fParamsList.Count ); for i := 0 to fParamsList.Count - 1 do begin CheckAllocated( i ); // must pre-allocate all mm[ i ] := fParamsList[ i ]; end; for i := 0 to length(IndexGroup) - 1 do begin fParamsList[ fParamsList.IndexOf( mm[ IndexGroup[ i ] ] ) ] := nil; // mark as to remove fParamsList.Insert( Destination, mm[ IndexGroup[ i ] ] ); inc( Destination ); end; // Delete those marked as nil for i := fParamsList.Count - 1 downto 0 do if fParamsList[ i ] = nil then fParamsList.Delete( i ); end; procedure TIOMultiParams.SwapParams(idx1, idx2: integer); var tmp: pointer; begin tmp := fParamsList[ idx1 ]; fParamsList[ idx1 ] := fParamsList[ idx2 ]; fParamsList[ idx2 ] := tmp; end; {!! TIOMultiParams.Params Declaration property Params[idx: integer]: ; Description Provides access to the object for the image idx to modify image parameters (e.g. bits per sample, compression, etc). !!} function TIOMultiParams.GetParams(idx: integer): TIOParams; begin result := nil; if ( idx >= 0 ) and ( idx < fParamsList.Count ) then begin CheckAllocated( idx ); result := TIOParams( fParamsList[ idx ]) end; end; {!! TIOMultiParams.Count Declaration property Count: integer; Description Returns the number of elements in the list. Read-only !!} function TIOMultiParams.GetCount: integer; begin result := fParamsList.Count; end; {!! TIOMultiParams.Assign Declaration procedure Assign(Source: TObject); Description Assign params of another TIOMultiParams object. !!} procedure TIOMultiParams.Assign(Source: TObject); var I: Integer; begin if not (Source is TIOMultiParams) then raise EIEException.create( 'Not a TIOMultiParams' ); Allocate( TIOMultiParams( Source ).Count ); for I := 0 to TIOMultiParams( Source ).Count - 1 do begin CheckAllocated( I ); TIOParams( fParamsList[ I ] ).Assign( TIOMultiParams( Source ).Params[ I ] ); end; end; {!! TIOMultiParams.Clear Declaration procedure Clear(); Description Empty the params list !!} procedure TIOMultiParams.Clear; var I: Integer; begin for I := fParamsList.Count - 1 downto 0 do if fParamsList[ i ] <> nil then TIOParams( fParamsList[ I ]).free; fParamsList.Clear(); end; procedure TIOMultiParams.Allocate(Count : Integer); begin fParamsList.Capacity := fParamsList.Count + Count; if fParamsList.Count = 0 then fParamsList.Count := Count else while fParamsList.Count < Count do InsertParam( fParamsList.Count ); end; {!! TIOMultiParams.DuplicateCompressionInfo Declaration procedure DuplicateCompressionInfo; Description Clone the compression information from idx 0 to all indexes. Example // Change the compression method for a TIFF file MBitmap := TIEMultiBitmap.create; MBitmap.ParamsEnabled := True; // Load params with the image MBitmap.Read( 'C:\MyImage.tiff' ); MBitmap.Params[ 0 ].TIFF_Compression := ioTIFF_G4FAX; MBitmap.DuplicateCompressionInfo; MBitmap.Write( 'C:\OutImage.tiff' ); MBitmap.Free; !!} procedure TIOMultiParams.DuplicateCompressionInfo; var i: integer; tmp: TIOParams; begin tmp := TIOParams.Create( nil ); tmp.AssignCompressionInfo(Params[0]); for i := 1 to Count - 1 do Params[i].AssignCompressionInfo(tmp); FreeAndNil(tmp); end; procedure TIOMultiParams.UpdateEx(Operation: integer; // last operation of insert(1)/delete(2)/move(3)/swap(4) (0=no op) Idx: integer; // index of processed image by fLastImOp ExtraParam: Integer); // param 1 var IndexGroup: TIEArrayOfInteger; begin SetLength(IndexGroup, 0); UpdateEx(Operation, Idx, ExtraParam, IndexGroup); end; procedure TIOMultiParams.UpdateEx(Operation: integer; // last operation of insert(1)/delete(2)/move(3)/swap(4) (0=no op) Idx: integer; // index of processed image by fLastImOp ExtraParam: Integer; // param 1 IndexGroup: TIEArrayOfInteger); begin if assigned( fParamsList ) = False then exit; case Operation of IEM_OP_INSERT : // Inserting Idx InsertParam( Idx ); IEM_OP_DELETE : // deleting Idx RemoveParam( Idx ); IEM_OP_MOVE : // moving Idx to ExtraParam MoveParam( Idx, ExtraParam ); IEM_OP_SWAP : // swap Idx with ExtraParam SwapParams( Idx, ExtraParam ); IEM_OP_MOVEGROUP : // move group of indexes to ExtraParam MoveParams( IndexGroup, ExtraParam ); IEM_OP_CLEAR : // Clear all items in list Clear; IEM_OP_ALLOCATE : // Add items to the list Allocate( ExtraParam ); end; end; {!! TIOMultiParams.Read Declaration function Read(const FileName: WideString; Format: = ioUnknown): Boolean; overload; function Read(const FileName: WideString; bUseExtension: Boolean): Boolean; overload; function Read(Stream: TStream; Format: = ioUnknown): Boolean; overload; function Read(Buffer: Pointer; BufferSize: Integer; Format: = ioUnknown): Boolean; overload; Description Reads the properties from an image file. Result is false if a loading error is encountered due to a corrupt or unknown image format. FileName is the file name with full path. Format is the file format that the stream or file contains. If ioUnknown is specified then the file content is analyzed to determine the format. bUseExtension determines that the file format is based on the extension of the file, e.g. image.jpeg will be processed as ioJPEG format. Examples // Load the parameters of an image (which may be a TIFF file, but we will examine the content to be sure) IOParams.Read( 'C:\alfa.tiff' ); Label1.Caption := 'alfa.tiff contains ' + inttostr(IOParams[0].ImageCount) + ' images'; // Load the parameters of a TIFF IOParams.Read( 'C:\alfa.tiff', ioTIFF ); Label1.Caption := 'alfa.tiff contains ' + inttostr(IOParams[0].ImageCount) + ' images'; // Load the parameters of a file. It will be assumed to a TIFF because of the file extension IOParams.Read( 'C:\alfa.tiff', True ); Label1.Caption := 'alfa.tiff contains ' + inttostr(IOParams[0].ImageCount) + ' images'; !!} function TIOMultiParams.Read(const FileName: WideString; Format: TIOFileType = ioUnknown): Boolean; var mio : TImageEnMIO; begin mio := TImageEnMIO.Create( Nil ); Result := mio.ParamsFromFile( FileName, Format); Assign( mio.fParamsList ); mio.Free; end; function TIOMultiParams.Read(const FileName: WideString; bUseExtension: Boolean): Boolean; var mio : TImageEnMIO; begin mio := TImageEnMIO.Create( Nil ); Result := mio.ParamsFromFile( FileName, bUseExtension ); Assign( mio.fParamsList ); mio.Free; end; function TIOMultiParams.Read(Stream: TStream; Format: TIOFileType = ioUnknown): Boolean; var mio : TImageEnMIO; begin mio := TImageEnMIO.Create( Nil ); Result := mio.ParamsFromStream( Stream, Format ); Assign( mio.fParamsList ); mio.Free; end; function TIOMultiParams.Read(Buffer: Pointer; BufferSize: Integer; Format: TIOFileType): Boolean; var mio : TImageEnMIO; begin mio := TImageEnMIO.Create( Nil ); Result := mio.ParamsFromBuffer( Buffer, BufferSize, Format ); Assign( mio.fParamsList ); mio.Free; end; /// TIOMultiParams ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {$ENDIF} // IEINCLUDEMULTIVIEW procedure IESwapIEBitmaps(var a: TIEBitmap; var b: TIEBitmap); var t: TIEBitmap; begin t := a; a := b; b := t; end; {!! JpegLosslessTransformStream Declaration function JpegLosslessTransformStream(SourceStream, DestStream: TStream; Transform: ; GrayScale: Boolean; CopyMarkers: ; CutRect: Trect; UpdateEXIF: Boolean = False): Boolean; Description Losslessly rotates, flips or crops (cuts) a JPEG in a stream. Description Parameter Description SourceStream A TStream object that contains the jpeg source stream DestStream A TStream object that will receive the jpeg result stream Transform The transformation to perform GrayScale True force grayscale output CopyMarkers How comments and markers (e.g. IPTC info) should be copied CutRect Specifies the rectangle to retain when Transform = jtCut UpdateEXIF Updates the EXIF thumbnail and orientation tags
Returns false if the operation failed. Lossless Information Whenever you save a JPEG by regular methods it needs to re-encoded, so after multiple re-saves the quality can become quite degraded. Lossless JPEG operations, on the other hand, work by rearranging the compressed data, without ever fully decoding the image, therefore there is no degration in quality. Note, however, that lossless operations can only work on full DCT blocks, so when cutting/cropping the resulting image may contain at least a part of the area outside CutRect depending on the need to align with to the nearest DCT block boundary (or multiple blocks, depending on the sampling factors). !!} function JpegLosslessTransformStream(SourceStream, DestStream: TStream; Transform: TIEJpegTransform; GrayScale: boolean; CopyMarkers: TIEJpegCopyMarkers; CutRect: TRect; UpdateEXIF: Boolean): boolean; var xp: TProgressRec; ab: boolean; begin ab := false; xp.Aborting := @ab; IEJpegLosslessTransform(SourceStream, DestStream, xp, integer(Transform), GrayScale, integer(CopyMarkers), CutRect, UpdateEXIF); result := not ab; end; {!! JpegLosslessTransform Declaration function JpegLosslessTransform(const SourceFile, DestFile: WideString; Transform:
; GrayScale: Boolean; CopyMarkers: ; CutRect: TRect; UpdateEXIF: Boolean = False): Boolean; function JpegLosslessTransform(const SourceFile, DestFile: WideString; Transform: ): boolean; overload; Description Losslessly rotates, flips or crops (cuts) a JPEG file. Description Parameter Description SourceFile The full path and filename of the source file DestFile The full path and filename for the resulting file Transform The transformation to perform GrayScale True force grayscale output CopyMarkers How comments and markers (e.g. IPTC info) should be copied CutRect Specifies the rectangle to retain when Transform = jtCut UpdateEXIF Updates the EXIF thumbnail and orientation tags
Returns false if the operation failed. See also:
which works with a single file. Lossless Information Whenever you save a JPEG by regular methods it needs to re-encoded, so after multiple re-saves the quality can become quite degraded. Lossless JPEG operations, on the other hand, work by rearranging the compressed data, without ever fully decoding the image, therefore there is no degration in quality. Note, however, that lossless operations can only work on full DCT blocks, so when cutting/cropping the resulting image may contain at least a part of the area outside CutRect depending on the need to align with to the nearest DCT block boundary (or multiple blocks, depending on the sampling factors). Demo Demos\ImageEditing\LosslessCrop\LosslessCut.dpr Example // Rotate input.jpg 90° clockwise and save to output.jpg JpegLosslessTransform('D:\input.jpg', 'D:\output.jpg', jtRotate90, false, jcCopyAll, Rect(0, 0, 0, 0)); !!} function JpegLosslessTransform(const SourceFile, DestFile: WideString; Transform: TIEJpegTransform; GrayScale: boolean; CopyMarkers: TIEJpegCopyMarkers; CutRect: TRect; UpdateEXIF: Boolean): boolean; var fr, fw: TIEWideFileStream; begin try fr := TIEWideFileStream.Create(SourceFile, fmOpenRead or fmShareDenyWrite); except result := false; exit; end; try fw := TIEWideFileStream.Create(DestFile, fmCreate); except FreeAndNil(fr); result := false; exit; end; result := JpegLosslessTransformStream(fr, fw, Transform, GrayScale, CopyMarkers, CutRect, UpdateEXIF); FreeAndNil(fw); FreeAndNil(fr); end; function JpegLosslessTransform(const SourceFile, DestFile: WideString; Transform: TIEJpegTransform): boolean; overload; begin result := JpegLosslessTransform(SourceFile, DestFile, Transform, false, jcCopyAll, Rect(0, 0, 0, 0), true); end; {!! JpegLosslessTransform2 Declaration function JpegLosslessTransform2(const FileName: WideString; Transform: ; GrayScale: boolean; CopyMarkers: ; CutRect: TRect; UpdateEXIF: Boolean = False): boolean; overload; function JpegLosslessTransform2(const FileName: WideString; Transform: ): boolean; overload; Description Losslessly rotates, flips or crops (cuts) a JPEG file. Same as , but the source file is overwritten with the transformed image. Description Parameter Description FileName The full path and filename of the file to transform Transform The transformation to perform GrayScale True force grayscale output CopyMarkers How comments and markers (e.g. IPTC info) should be copied CutRect Specifies the rectangle to retain when Transform = jtCut UpdateEXIF Updates the EXIF thumbnail and orientation tags
Returns false if the operation failed. Lossless Information Whenever you save a JPEG by regular methods it needs to re-encoded, so after multiple re-saves the quality can become quite degraded. Lossless JPEG operations, on the other hand, work by rearranging the compressed data, without ever fully decoding the image, therefore there is no degration in quality. Note, however, that lossless operations can only work on full DCT blocks, so when cutting/cropping the resulting image may contain at least a part of the area outside CutRect depending on the need to align with to the nearest DCT block boundary (or multiple blocks, depending on the sampling factors). Demo Demos\ImageEditing\LosslessCrop\LosslessCut.dpr Example // Rotate MyImage.jpg 90° clockwise JpegLosslessTransform('D:\MyImage.jpg', jtRotate90); !!} function JpegLosslessTransform2(const FileName: WideString; Transform: TIEJpegTransform; GrayScale: boolean; CopyMarkers: TIEJpegCopyMarkers; CutRect: TRect; UpdateEXIF: Boolean): boolean; var i: Integer; SrcFileName: WideString; begin i := 0; repeat SrcFileName := FileName+IntToStr(i); inc(i); until not IEFileExistsW(SrcFileName); MoveFileW(PWideChar(FileName), PWideChar(SrcFileName)); result := JpegLosslessTransform(SrcFileName, FileName, Transform, GrayScale, CopyMarkers, CutRect, UpdateEXIF); if not result then begin if IEFileExistsW(FileName) then DeleteFileW(PWideChar(FileName)); MoveFileW(PWideChar(SrcFileName), PWideChar(FileName)); end else DeleteFileW(PWideChar(SrcFileName)); end; function JpegLosslessTransform2(const FileName: WideString; Transform: TIEJpegTransform): boolean; begin result := JpegLosslessTransform2(FileName, Transform, False, jcCopyAll, Rect(0, 0, 0, 0), true); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // CMYK/RGB conversions var CMYKProfile: TIEICC; SRGBProfile: TIEICC; function InitCMYKConversion: Boolean; begin result := True; if CMYKProfile = nil then begin CMYKProfile := TIEICC.Create(false); CMYKProfile.Assign_CMYKProfile(); if CMYKProfile.IsValid then begin SRGBProfile := TIEICC.Create(false); SRGBProfile.Assign_sRGBProfile(); CMYKProfile.InitTransform(SRGBProfile, integer(iecmsCMYK), integer(iecmsBGR), 0, 0); SRGBProfile.InitTransform(CMYKProfile, integer(iecmsBGR), integer(iecmsCMYK), 0, 0); end else result := False; end; end; // CMYK to RGB function IECMYK2RGB(cmyk: TCMYK): TRGB; var src: TIECMSCOLOR; dst: TIECMSCOLOR; begin if IEGlobalSettings().UseCMYKProfile and InitCMYKConversion then begin src.cmyk.cyan := (255 - cmyk.c) * 257; src.cmyk.magenta := (255 - cmyk.m) * 257; src.cmyk.yellow := (255 - cmyk.y) * 257; src.cmyk.black := (255 - cmyk.k) * 257; IE_TranslateColors(CMYKProfile.MSTransform, @src, 1, IE_CS2IF[integer(iecmsCMYK)], @dst, IE_CS2IF[integer(iecmsBGR)]); result.r := dst.rgb.red shr 8; result.g := dst.rgb.green shr 8; result.b := dst.rgb.blue shr 8; end else begin with cmyk, result do begin r := k * c div 255; g := k * m div 255; b := k * y div 255; end; end; end; // colorProfile must be initialized with the destination profile using TIEICC.InitTransform call function IECMYK2RGBROW(inrow: PCMYK; outrow: PRGB; width: Integer; alphaRow: pinteger; colorProfile: TIEICC): TRGB; var buf_src: array of TIECMSCOLOR; buf_dst: array of TIECMSCOLOR; src : PIECMSCOLOR; dst: PIECMSCOLOR; i: integer; begin SetLength(buf_src, width); src := @buf_src[0]; for i := 1 to width do begin src^.cmyk.cyan := (255 - inrow^.c) * 257; src^.cmyk.magenta := (255 - inrow^.m) * 257; src^.cmyk.yellow := (255 - inrow^.y) * 257; src^.cmyk.black := (255 - inrow^.k) * 257; inc(src); inc(inrow); end; SetLength(buf_dst, width); dst := @buf_dst[0]; IE_TranslateColors(colorProfile.MSTransform, @buf_src[0], width, IE_CS2IF[integer(iecmsCMYK)], @buf_dst[0], IE_CS2IF[integer(iecmsBGR)]); if alphaRow = nil then begin // no alpha channel for i := 1 to width do begin outrow^.r := dst^.rgb.red shr 8; outrow^.g := dst^.rgb.green shr 8; outrow^.b := dst^.rgb.blue shr 8; inc(dst); inc(outrow); end; end else begin // with alpha channel for i := 1 to width do begin outrow^.r := alphaRow^ * (dst^.rgb.red shr 8 - outrow^.r) shr 18 + outrow^.r; outrow^.g := alphaRow^ * (dst^.rgb.green shr 8 - outrow^.g) shr 18 + outrow^.g; outrow^.b := alphaRow^ * (dst^.rgb.blue shr 8 - outrow^.b) shr 18 + outrow^.b; inc(dst); inc(outrow); inc(alphaRow); end; end; end; // CMYK to RGB, a whole row // alpha is shift-left 10 function IECMYK2RGBROW(inrow: PCMYK; outrow: PRGB; width: Integer; alphaRow: pinteger = nil): TRGB; var i: integer; begin if IEGlobalSettings().UseCMYKProfile and InitCMYKConversion then begin IECMYK2RGBROW(inrow, outrow, width, alphaRow, CMYKProfile); end else begin if alphaRow = nil then begin // no alpha channel for i := 1 to width do begin outrow^.r := inrow^.k * inrow^.c div 255; outrow^.g := inrow^.k * inrow^.m div 255; outrow^.b := inrow^.k * inrow^.y div 255; inc(inrow); inc(outrow); end; end else begin // with alpha channel for i := 1 to width do begin outrow^.r := alphaRow^ * (inrow^.k * inrow^.c div 255 - outrow^.r) shr 18 + outrow^.r; outrow^.g := alphaRow^ * (inrow^.k * inrow^.m div 255 - outrow^.g) shr 18 + outrow^.g; outrow^.b := alphaRow^ * (inrow^.k * inrow^.y div 255 - outrow^.b) shr 18 + outrow^.b; inc(inrow); inc(outrow); inc(alphaRow); end; end; end; end; // RGB to CMYK function IERGB2CMYK(const rgb: TRGB): TCMYK; var src: TIECMSCOLOR; dst: TIECMSCOLOR; begin if IEGlobalSettings().UseCMYKProfile and InitCMYKConversion then begin src.rgb.red := rgb.r * 257; src.rgb.green := rgb.g * 257; src.rgb.blue := rgb.b * 257; IE_TranslateColors(SRGBProfile.MSTransform, @src, 1, IE_CS2IF[integer(iecmsBGR)], @dst, IE_CS2IF[integer(iecmsCMYK)]); result.c := 255 - dst.cmyk.cyan shr 8; result.m := 255 - dst.cmyk.magenta shr 8; result.y := 255 - dst.cmyk.yellow shr 8; result.k := 255 - dst.cmyk.black shr 8; end else with rgb, result do begin K := imax(r, imax(g, b)); if K = 0 then begin C := 255; M := 255; Y := 255; end else begin C := r * 255 div K; M := g * 255 div K; Y := b * 255 div K; end; end; end; // end of CMYK/RGB conversions //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure IEDefaultConvertColorFunction(InputScanline: pointer; InputColorSpace: TIEColorSpace; OutputScanline: pointer; OutputColorSpace: TIEColorSpace; ImageWidth: integer; IOParams: TIOParams); {$ifdef IEINCLUDECMS} const CCTOCMS: array [iecmsRGB..iecmsYCBCR] of integer = (TYPE_RGB_8, TYPE_BGR_8, TYPE_CMYK_8_REV, TYPE_CMYKcm_8, TYPE_Lab_8, TYPE_GRAY_8, TYPE_RGB_16, TYPE_RGB_16_SE, TYPE_YCbCr_8); {$endif} var x8g: pbyte; xlab: PCIELAB; xcmyk: PCMYK; xbgr: PRGB; xgray8: pbyte; xrgb48: PRGB48; xycbcr: PYCBCR; i: integer; InputProfile: TIEICC; RedToGrayCoef, GreenToGrayCoef, BlueToGrayCoef: integer; begin InputProfile := nil; if assigned(IOParams) then begin if assigned(IOParams.fDefaultICC) and ((IOParams.fInputICC = nil) or (not IOParams.fInputICC.IsValid)) then InputProfile := IOParams.fDefaultICC else InputProfile := IOParams.fInputICC; end; {$ifdef IEINCLUDECMS} if IEGlobalSettings().EnableCMS and (IOParams <> nil) and assigned(InputProfile) and InputProfile.IsValid and not InputProfile.IsApplied and IOParams.OutputICCProfile.IsValid then begin // use CMS if InputProfile.Transform(IOParams.OutputICCProfile, CCTOCMS[InputColorSpace], CCTOCMS[OutputColorSpace], INTENT_PERCEPTUAL, 0 , InputScanline, OutputScanline, ImageWidth) then exit; // sucessful end; {$else} // use mscms if IEGlobalSettings().EnableCMS and (IOParams <> nil) and assigned(InputProfile) and InputProfile.IsValid and not InputProfile.IsApplied and IOParams.OutputICCProfile.IsValid and InputProfile.CheckTransform(integer(InputColorSpace)) and InputProfile.Transform(IOParams.OutputICCProfile, integer(InputColorSpace), integer(OutputColorSpace), 0, 0, InputScanline, OutputScanline, ImageWidth) then begin exit; // sucessful end; {$endif} case InputColorSpace of iecmsGray8: case OutputColorSpace of iecmsBGR: begin // Gray8->BGR x8g := pbyte(InputScanline); xbgr := PRGB(OutputScanline); for i := 0 to ImageWidth - 1 do begin xbgr^.r := x8g^; xbgr^.g := x8g^; xbgr^.b := x8g^; inc(xbgr); inc(x8g); end; end; end; iecmsRGB: case OutputColorSpace of iecmsBGR: begin // RGB->BGR _CopyBGR_RGB(OutputScanline, InputScanline, ImageWidth); end; end; iecmsRGB48: case OutputColorSpace of iecmsBGR: begin // RGB48->BGR xrgb48 := PRGB48(InputScanline); xbgr := PRGB(OutputScanline); for i := 0 to ImageWidth - 1 do begin xbgr^.r := xrgb48^.r shr 8; xbgr^.g := xrgb48^.g shr 8; xbgr^.b := xrgb48^.b shr 8; inc(xbgr); inc(xrgb48); end; end; end; iecmsRGB48_SE: case OutputColorSpace of iecmsBGR: begin // RGB48->BGR xrgb48 := PRGB48(InputScanline); xbgr := PRGB(OutputScanline); for i := 0 to ImageWidth - 1 do begin xbgr^.r := xrgb48^.r and $FF; xbgr^.g := xrgb48^.g and $FF; xbgr^.b := xrgb48^.b and $FF; inc(xbgr); inc(xrgb48); end; end; end; iecmsBGR: case OutputColorSpace of iecmsCMYK: begin // BGR->CMYK xbgr := PRGB(InputScanline); xcmyk := PCMYK(OutputScanline); for i := 0 to ImageWidth - 1 do begin xcmyk^ := IERGB2CMYK(xbgr^); inc(xbgr); inc(xcmyk); end; end; iecmsCIELab: begin // BGR->CIELab xbgr := PRGB(InputScanline); xlab := PCIELAB(OutputScanline); for i := 0 to ImageWidth - 1 do begin xlab^ := IERGB2CIELAB(xbgr^); inc(xbgr); inc(xlab); end; end; iecmsGray8: begin // BGR->Gray8 RedToGrayCoef := IEGlobalSettings().RedToGrayCoef; GreenToGrayCoef := IEGlobalSettings().GreenToGrayCoef; BlueToGrayCoef := IEGlobalSettings().BlueToGrayCoef; xbgr := PRGB(InputScanline); xgray8 := pbyte(OutputScanline); for i := 0 to ImageWidth - 1 do begin with xbgr^ do xgray8^ := (r * RedToGrayCoef + g * GreenToGrayCoef + b * BlueToGrayCoef) div 100; inc(xbgr); inc(xgray8); end; end; iecmsBGR: begin // BGR->BGR copymemory(OutputScanline, InputScanline, ImageWidth*3); end; end; iecmsCMYK: case OutputColorSpace of iecmsBGR: begin // CMYK->BGR (* xcmyk := PCMYK(InputScanline); xbgr := OutputScanline; for i := 0 to ImageWidth - 1 do begin xbgr^ := IECMYK2RGB(xcmyk^); inc(xbgr); inc(xcmyk); end; //*) IECMYK2RGBROW(PCMYK(InputScanline), OutputScanline, ImageWidth); end; end; iecmsCMYK6: case OutputColorSpace of iecmsBGR: begin // CMYK->BGR xcmyk := PCMYK(InputScanline); xbgr := OutputScanline; for i := 0 to ImageWidth - 1 do begin with xcmyk^ do begin c := 255-c; m := 255-m; y := 255-y; k := 255-k; end; xbgr^ := IECMYK2RGB(xcmyk^); inc(xbgr); inc(xcmyk); inc(pbyte(xcmyk), 2); end; end; end; iecmsCIELab: case OutputColorSpace of iecmsBGR: begin // ieCIELab->BGR xlab := PCIELAB(InputScanline); xbgr := OutputScanline; for i := 0 to ImageWidth - 1 do begin xbgr^ := IECIELAB2RGB(xlab^); inc(xlab); inc(xbgr); end; end; end; iecmsYCbCr: case OutputColorSpace of iecmsBGR: begin // ieYCbCr->BGR xycbcr := PYCBCR(InputScanline); xbgr := OutputScanline; for i := 0 to ImageWidth - 1 do begin IEYCbCr2RGB(xbgr^, xycbcr^.y, xycbcr^.Cb, xycbcr^.Cr); inc(xycbcr); inc(xbgr); end; end; end; end; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// {!! IEAVISelectCodec Declaration function IEAVISelectCodec: AnsiString; Description Displays the Windows Codec Selection dialog. If the user selects a code it is returned as a FourCC codec string. Otherwise '' is returned. This can then be used in methods such as
. !!} function IEAVISelectCodec(): AnsiString; var AVI_avf: pointer; AVI_avs1: pointer; AVI_popts: pointer; psi: TAviStreamInfo; tempfilename: String; begin if not gAVIFILEinit then begin AVIFileInit; gAVIFILEinit := true; end; AVI_avs1 := nil; AVI_avf := nil; AVI_popts := nil; tempfilename := IEGetTempFileName('avitemp', IEGlobalSettings().DefTEMPPATH)+'.avi'; if IEFileExists(tempfilename) then DeleteFile(tempfilename); if AVIFileOpen(PAVIFILE(AVI_avf), PChar(tempfilename), OF_WRITE or OF_CREATE, nil) <> 0 then raise EInvalidGraphic.Create('unable to create AVI file'); try ZeroMemory(@psi, sizeof(psi)); psi.fccType := streamtypeVIDEO; psi.dwScale := 1; psi.dwRate := 15; psi.dwQuality := $FFFFFFFF; AVI_popts := AllocMem(sizeof(TAVICOMPRESSOPTIONS)); psi.dwSuggestedBufferSize := 0; psi.rcFrame := rect(0, 0, 640, 480); AVIFileCreateStream(PAVIFILE(AVI_avf), PAVISTREAM(AVI_avs1), psi); if AVISaveOptions(0, 0, 1, @AVI_avs1, @AVI_popts) then result := PAnsiChar(@PAVICOMPRESSOPTIONS(AVI_popts)^.fccHandler) else result := ''; finally if AVI_popts <> nil then begin AVISaveOptionsFree(1, PAVICOMPRESSOPTIONS(AVI_popts)); freemem(AVI_popts); end; if AVI_avs1 <> nil then AVIStreamRelease(AVI_avs1); if AVI_avf <> nil then AVIFileRelease(AVI_avf); if IEFileExists(tempfilename) then DeleteFile(tempfilename); end; end; type TICINFO = packed record dwSize: DWORD; fccType: DWORD; fccHandler: DWORD; dwFlags: DWORD; dwVersion: DWORD; dwVersionICM: DWORD; szName: array [0..16 - 1] of WCHAR; szDescription: array [0..128 - 1] of WCHAR; szDriver: array [0..128 - 1] of WCHAR; end; PICINFO = ^TICINFO; function ICInfo(fccType: DWORD; fccHandler: DWORD; lpicinfo: PICINFO): Boolean; stdcall; external 'MsVfW32.dll' name 'ICInfo'; function ICGetInfo(hic: THandle; lpicinfo: PICINFO; cb: DWORD): LRESULT; stdcall; external 'MsVfW32.dll' name 'ICGetInfo'; function ICOpen(fccType: DWORD; fccHandler: DWORD; wMode: UINT): THandle; stdcall; external 'MsVfW32.dll' name 'ICOpen'; function ICClose(hic: THandle): LRESULT; stdcall; external 'MsVfW32.dll' name 'ICClose'; {!! IEAVIGetCodecs Declaration function IEAVIGetCodecs: TStringList; Description Returns a list of Windows codec as FourCC codec strings. These can then be used for methods such as . To obtain a description of codecs use . !!} function IEAVIGetCodecs: TStringList; var i: Integer; ic: TICINFO; fourcc: AnsiString; begin result := TStringList.Create; FillChar(ic, sizeof(ic), 0); SetLength(fourcc, 4); i := 0; while true do begin if not ICInfo(0, i, @ic) then break; Move(ic.fccHandler, fourcc[1], 4); result.Add( string(fourcc) ); inc(i); end; end; {!! IEAVIGetCodecsDescription Declaration function IEAVIGetCodecsDescription: TStringList; Description Returns a list of Windows codec descriptions. It will align with FourCC codec strings returned by . !!} function IEAVIGetCodecsDescription: TStringList; var i: Integer; ic: TICINFO; hic: THandle; begin result := TStringList.Create; FillChar(ic, sizeof(ic), 0); i := 0; while true do begin if not ICInfo(0, i, @ic) then break; hic := ICOpen(ic.fccType, ic.fccHandler, 4); ICGetInfo(hic, @ic, sizeof(TICINFO)); result.Add( ic.szDescription ); ICClose(hic); inc(i); end; end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // input/output plugins const // IEX_GetInfo/IEX_SetInfo: available after IEX_ExecuteRead IEX_IMAGEWIDTH = $00; IEX_IMAGEHEIGHT = $01; IEX_PIXELFORMAT = $02; // IEX_1G, IEX_8G etc IEX_FORMATDESCRIPTOR = $03; // could be the same as IEX_PLUGINDESCRIPTOR plus specific file format info IEX_IMAGEDATA = $04; // RGB data. R,G,B are interlaced and the alignment is 8 bit. First channel is Red. IEX_IMAGEPALETTE = $05; // an array of 256x8 bit RGB triplets, only when format is IEX_8P IEX_IMAGEDATELENGTH = $06; // length of IEX_IMAGEDATA buffer IEX_ORIGINALIMAGEWIDTH = $07; IEX_ORIGINALIMAGEHEIGHT = $08; // IEX_GetInfo/IEX_SetInfo: always available after IEX_Initialize IEX_PLUGINCAPABILITY = $0101; // IEX_FILEREADER and/or IEX_FILEWRITER and/or IEX_MULTITHREAD IEX_PLUGINDESCRIPTOR = $0102; // ex. "Camera RAW" IEX_FILEEXTENSIONS = $0103; // ex. "CRW;CR2;NEF;RAW;PEF;RAF;X3F;BAY;ORF;SRF;MRW;DCR" IEX_AUTOSEARCHEXIF = $0104; // plugin provides this value. You should use only with IEX_GetInfo. If true ImageEn will search automatically for EXIF in file IEX_FORMATSCOUNT = $0105; // >1 if the plugin supports multiple formats // IEX_GetInfo/IEX_SetInfo: values for IEX_CAPABILITY IEX_FILEREADER = $0001; IEX_FILEWRITER = $0010; IEX_MULTITHREAD = $0100; // IEX_GetInfo/IEX_SetInfo: values for IEX_PIXELFORMAT IEX_INVALID = 0; IEX_1G = 1; IEX_8P = 2; IEX_8G = 3; IEX_16G = 4; IEX_24RGB = 5; IEX_32F = 6; IEX_CMYK = 7; IEX_48RGB = 8; type // callbacks (stdcall) TIEX_Progress = procedure(percentage: Integer; UserData: Pointer); stdcall; TIEX_Read = function(buffer: Pointer; bufferLength: Integer; UserData: Pointer): Integer; stdcall; TIEX_Write = function(buffer: Pointer; bufferLength: Integer; UserData: Pointer): Integer; stdcall; TIEX_PositionSet = procedure(position: Integer; UserData: Pointer); stdcall; TIEX_PositionGet = function(UserData: Pointer): Integer; stdcall; TIEX_Length = function(UserData: Pointer): Integer; stdcall; TIEX_GetParameter = procedure(Param: PAnsiChar; value: PAnsiChar; UserData: Pointer); stdcall; TIEX_SetParameter = procedure(Param: PAnsiChar; value: PAnsiChar; UserData: Pointer); stdcall; // callbacks (cdecl) TIEX_Progress_cdecl = procedure(percentage: Integer; UserData: Pointer); cdecl; TIEX_Read_cdecl = function(buffer: Pointer; bufferLength: Integer; UserData: Pointer): Integer; cdecl; TIEX_Write_cdecl = function(buffer: Pointer; bufferLength: Integer; UserData: Pointer): Integer; cdecl; TIEX_PositionSet_cdecl = procedure(position: Integer; UserData: Pointer); cdecl; TIEX_PositionGet_cdecl = function(UserData: Pointer): Integer; cdecl; TIEX_Length_cdecl = function(UserData: Pointer): Integer; cdecl; TIEX_GetParameter_cdecl = procedure(Param: PAnsiChar; value: PAnsiChar; UserData: Pointer); cdecl; TIEX_SetParameter_cdecl = procedure(Param: PAnsiChar; value: PAnsiChar; UserData: Pointer); cdecl; // dll exported (stdcall) TIEX_GetInfo = function(handle: Pointer; info: Integer): Pointer; stdcall; TIEX_SetInfo = procedure(handle: Pointer; info: Integer; value: Pointer); stdcall; TIEX_ExecuteRead = procedure(handle: Pointer; parametersOnly: longbool); stdcall; TIEX_ExecuteWrite = procedure(handle: Pointer); stdcall; TIEX_ExecuteTry = function(handle: Pointer): longbool; stdcall; TIEX_AddParameter = procedure(handle: Pointer; param: PAnsiChar); stdcall; TIEX_SetCallBacks = procedure(handle: Pointer; progressfun: TIEX_Progress; readfun: TIEX_Read; writefun: TIEX_Write; posset: TIEX_PositionSet; posget: TIEX_PositionGet; lenfun: TIEX_Length; getparam: TIEX_GetParameter; setparam: TIEX_SetParameter; userData: Pointer ); stdcall; TIEX_Initialize = function(format: Integer): Pointer; stdcall; TIEX_Finalize = procedure(handle: Pointer); stdcall; // dll exported (cdecl) TIEX_GetInfo_cdecl = function(handle: Pointer; info: Integer): Pointer; cdecl; TIEX_SetInfo_cdecl = procedure(handle: Pointer; info: Integer; value: Pointer); cdecl; TIEX_ExecuteRead_cdecl = procedure(handle: Pointer; parametersOnly: longbool); cdecl; TIEX_ExecuteWrite_cdecl = procedure(handle: Pointer); cdecl; TIEX_ExecuteTry_cdecl = function(handle: Pointer): longbool; cdecl; TIEX_AddParameter_cdecl = procedure(handle: Pointer; param: PAnsiChar); cdecl; TIEX_SetCallBacks_cdecl = procedure(handle: Pointer; progressfun: TIEX_Progress_cdecl; readfun: TIEX_Read_cdecl; writefun: TIEX_Write_cdecl; posset: TIEX_PositionSet_cdecl; posget: TIEX_PositionGet_cdecl; lenfun: TIEX_Length_cdecl; getparam: TIEX_GetParameter_cdecl; setparam: TIEX_SetParameter_cdecl; userData: Pointer ); cdecl; TIEX_Initialize_cdecl = function(format: Integer): Pointer; cdecl; TIEX_Finalize_cdecl = procedure(handle: Pointer); cdecl; TIEIOPlugin=record libhandle: THandle; // stdcall IEX_ExecuteRead_std: TIEX_ExecuteRead; IEX_ExecuteWrite_std: TIEX_ExecuteWrite; IEX_ExecuteTry_std: TIEX_ExecuteTry; IEX_AddParameter_std: TIEX_AddParameter; IEX_SetCallBacks_std: TIEX_SetCallBacks; IEX_Initialize_std: TIEX_Initialize; IEX_Finalize_std: TIEX_Finalize; IEX_GetInfo_std: TIEX_GetInfo; IEX_SetInfo_std: TIEX_SetInfo; // cdecl IEX_ExecuteRead_cdecl: TIEX_ExecuteRead_cdecl; IEX_ExecuteWrite_cdecl: TIEX_ExecuteWrite_cdecl; IEX_ExecuteTry_cdecl: TIEX_ExecuteTry_cdecl; IEX_AddParameter_cdecl: TIEX_AddParameter_cdecl; IEX_SetCallBacks_cdecl: TIEX_SetCallBacks_cdecl; IEX_Initialize_cdecl: TIEX_Initialize_cdecl; IEX_Finalize_cdecl: TIEX_Finalize_cdecl; IEX_GetInfo_cdecl: TIEX_GetInfo_cdecl; IEX_SetInfo_cdecl: TIEX_SetInfo_cdecl; FileType: TIOFileType; PluginsCS: TCriticalSection; // protect non multithreaded plugin Capability: Integer; pluginFormat: Integer; // the index of format inside the plugin DLLFileName: String; use_cdecl: Boolean; end; PIEIOPlugin=^TIEIOPlugin; var ioplugins: TList; function IEGetIOPlugin(fileType: TIOFileType): PIEIOPlugin; var i: Integer; begin for i := 0 to ioplugins.Count - 1 do begin result := PIEIOPlugin( ioplugins[i] ); if result^.FileType=fileType then exit; end; result := nil; end; type TIECallbackRecord = record OnProgress: TIEProgressEvent; OnProgressSender: TObject; Stream: TStream; Params: TIOParams; end; PIECallBackRecord = ^TIECallBackRecord; procedure CallBack_Progress_std(percentage: Integer; userdata: Pointer); stdcall; begin with PIECallBackRecord(userdata)^ do if assigned(OnProgress) then OnProgress( OnProgressSender, percentage ); end; procedure CallBack_Progress_cdecl(percentage: Integer; userdata: Pointer); cdecl; begin CallBack_Progress_std(percentage, userdata); end; function CallBack_Read_std(buffer: Pointer; bufferLength: Integer; userdata: Pointer): Integer; stdcall; begin result := PIECallBackRecord(userdata)^.Stream.Read(pbyte(buffer)^, bufferLength); end; function CallBack_Read_cdecl(buffer: Pointer; bufferLength: Integer; userdata: Pointer): Integer; cdecl; begin result := CallBack_Read_std(buffer, bufferLength, userdata); end; function CallBack_Write_std(buffer: Pointer; bufferLength: Integer; userdata: Pointer): Integer; stdcall; begin result := PIECallBackRecord(userdata)^.Stream.Write(pbyte(buffer)^, bufferLength); end; function CallBack_Write_cdecl(buffer: Pointer; bufferLength: Integer; userdata: Pointer): Integer; cdecl; begin result := CallBack_Write_std(buffer, bufferLength, userdata); end; procedure CallBack_PositionSet_std(position: Integer; UserData: Pointer); stdcall; begin PIECallBackRecord(userdata)^.Stream.Position := position; end; procedure CallBack_PositionSet_cdecl(position: Integer; UserData: Pointer); cdecl; begin CallBack_PositionSet_std(position, UserData); end; function CallBack_PositionGet_std(UserData: Pointer): Integer; stdcall; begin result := PIECallBackRecord(userdata)^.Stream.Position; end; function CallBack_PositionGet_cdecl(UserData: Pointer): Integer; cdecl; begin result := CallBack_PositionGet_std(UserData); end; function CallBack_Length_std(UserData: Pointer): Integer; stdcall; begin result := PIECallBackRecord(userdata)^.Stream.Size; end; function CallBack_Length_cdecl(UserData: Pointer): Integer; cdecl; begin result := CallBack_Length_std(UserData); end; procedure CallBack_GetParameter_std(Param: PAnsiChar; Value: PAnsiChar; UserData: Pointer); stdcall; begin if assigned( PIECallBackRecord(userdata)^.Params ) then IEStrCopy( Value, PAnsiChar(AnsiString(PIECallBackRecord(userdata)^.Params.GetProperty(WideString(Param)))) ); end; procedure CallBack_GetParameter_cdecl(Param: PAnsiChar; Value: PAnsiChar; UserData: Pointer); cdecl; begin CallBack_GetParameter_std(Param, Value, UserData); end; procedure CallBack_SetParameter_std(Param: PAnsiChar; Value: PAnsiChar; UserData: Pointer); stdcall; begin if assigned( PIECallBackRecord(userdata)^.Params ) then PIECallBackRecord(userdata)^.Params.SetProperty(WideString(Param), WideString(Value)); end; procedure CallBack_SetParameter_cdecl(Param: PAnsiChar; Value: PAnsiChar; UserData: Pointer); cdecl; begin CallBack_SetParameter_std(Param, Value, UserData); end; function IEX_GetInfo(p: PIEIOPlugin; handle: Pointer; info: Integer): Pointer; begin if p^.use_cdecl then result := p^.IEX_GetInfo_cdecl(handle, info) else result := p^.IEX_GetInfo_std(handle, info); end; procedure IEX_SetInfo(p: PIEIOPlugin; handle: Pointer; info: Integer; value: Pointer); begin if p^.use_cdecl then p^.IEX_SetInfo_cdecl(handle, info, value) else p^.IEX_SetInfo_std(handle, info, value); end; procedure IEX_ExecuteRead(p: PIEIOPlugin; handle: Pointer; parametersOnly: longbool); begin if p^.use_cdecl then p^.IEX_ExecuteRead_cdecl(handle, parametersOnly) else p^.IEX_ExecuteRead_std(handle, parametersOnly); end; procedure IEX_ExecuteWrite(p: PIEIOPlugin; handle: Pointer); begin if p^.use_cdecl then p^.IEX_ExecuteWrite_cdecl(handle) else p^.IEX_ExecuteWrite_std(handle); end; function IEX_ExecuteTry(p: PIEIOPlugin; handle: Pointer): longbool; begin if p^.use_cdecl then result := p^.IEX_ExecuteTry_cdecl(handle) else result := p^.IEX_ExecuteTry_std(handle); end; procedure IEX_AddParameter(p: PIEIOPlugin; handle: Pointer; param: PAnsiChar); begin if p^.use_cdecl then p^.IEX_AddParameter_cdecl(handle, param) else p^.IEX_AddParameter_std(handle, param); end; procedure IEX_SetCallBacks(p: PIEIOPlugin; handle: Pointer; userData: Pointer); begin if p^.use_cdecl then p^.IEX_SetCallBacks_cdecl(handle, CallBack_Progress_cdecl, CallBack_Read_cdecl, CallBack_Write_cdecl, CallBack_PositionSet_cdecl, CallBack_PositionGet_cdecl, CallBack_Length_cdecl, CallBack_GetParameter_cdecl, CallBack_SetParameter_cdecl, userData) else p^.IEX_SetCallBacks_std(handle, CallBack_Progress_std, CallBack_Read_std, CallBack_Write_std, CallBack_PositionSet_std, CallBack_PositionGet_std, CallBack_Length_std, CallBack_GetParameter_std, CallBack_SetParameter_std, userData) end; function IEX_Initialize(p: PIEIOPlugin; format: Integer): Pointer; begin if p^.use_cdecl then result := p^.IEX_Initialize_cdecl(format) else result := p^.IEX_Initialize_std(format); end; procedure IEX_Finalize(p: PIEIOPlugin; handle: Pointer); begin if p^.use_cdecl then p^.IEX_Finalize_cdecl(handle) else p^.IEX_Finalize_std(handle); end; // invert swap low-high bytes (only for 48bit RGB images) procedure BGRHL(row: PRGB48; width: Integer); var i: Integer; begin for i := 0 to width - 1 do begin with row^ do begin r := IESwapWord(r); g := IESwapWord(g); b := IESwapWord(b); end; inc(row); end; end; procedure IEPlgInREAD(InputStream: TStream; Bitmap: TIEBitmap; var IOParams: TIOParams; var Progress: TProgressRec; Preview: boolean); type plongbool = ^longbool; var p: PIEIOPlugin; rec: TIECallbackRecord; handle: pointer; srcformat: integer; width, height, row: integer; image: pbyte; imagelen: integer; rl: integer; tempBitmap: TIEBitmap; q: integer; Stream: TIEBufferedReadStream; dd: double; tempio: TImageEnIO; memstream: TIEMemStream; begin p := IEGetIOPlugin( IOParams.FileType ); if p = nil then exit; if IOParams.GetThumbnail then begin // try to load the (EXIF?) thumbnail if IOParams.EXIF_Bitmap <> nil then IOParams.EXIF_Bitmap.FreeImage(true); IOParams.GetThumbnail := false; IEPlgInREAD(InputStream, Bitmap, IOParams, Progress, true); IOParams.GetThumbnail := true; if assigned(IOParams.EXIF_Bitmap) and not IOParams.EXIF_Bitmap.IsEmpty then begin // success, exit Bitmap.Assign( IOParams.EXIF_Bitmap ); exit; end; // continue loading the full image InputStream.Position := 0; end; if (p^.Capability and IEX_MULTITHREAD) = 0 then p^.PluginsCS.Enter(); if Preview then Stream := TIEBufferedReadStream.Create(InputStream, 8192, IEGlobalSettings().UseRelativeStreams) else Stream := TIEBufferedReadStream.Create(InputStream, 1024 * 1024, IEGlobalSettings().UseRelativeStreams); rec.OnProgress := Progress.fOnProgress; rec.OnProgressSender := Progress.Sender; rec.Stream := Stream; rec.Params := IOParams; Progress.Aborting^ := false; handle := IEX_Initialize(p, p^.pluginFormat); IEX_SetCallBacks(p, handle, @rec); try if plongbool(IEX_GetInfo(p, handle, IEX_AUTOSEARCHEXIF))^ then begin // ImageEn will search EXIF info inside the file Stream.Position := 0; q := IESearchEXIFInfo(Stream); if q >= 0 then begin Stream.Position := q; if IELoadEXIFFromTIFF(Stream, IOParams, true) then begin // use dpi of the Exif if IOParams.EXIF_ResolutionUnit = 3 then dd := CM_per_Inch else dd := 1; IOParams.DpiX := trunc(IOParams.EXIF_XResolution * dd); IOParams.DpiY := trunc(IOParams.EXIF_YResolution * dd); end; end else begin // is this a CRW? (with CIFF instead of EXIF?) Stream.Position := 0; {$ifdef IEINCLUDERAWFORMATS} IECRWGetCIFFAsExif(Stream, IOParams); {$endif} end; // look for IPTC Stream.Position := 0; tempio := TImageEnIO.Create(nil); try tempio.ParamsFromStream(Stream, ioTIFF); IOParams.IPTC_Info.Assign( tempio.Params.IPTC_Info ); if not IOParams.EXIF_HasEXIFData and tempio.Params.EXIF_HasEXIFData then IECopyEXIF(tempio.Params, IOParams, true); finally tempio.Free(); end; // reset position Stream.Position := 0; end; IEX_ExecuteRead(p, handle, Preview); width := pinteger(IEX_GetInfo(p, handle, IEX_IMAGEWIDTH))^; height := pinteger(IEX_GetInfo(p, handle, IEX_IMAGEHEIGHT))^; srcformat := pinteger(IEX_GetInfo(p, handle, IEX_PIXELFORMAT))^; image := IEX_GetInfo(p, handle, IEX_IMAGEDATA); // set ioparams IOParams.Width := width; IOParams.Height := height; if assigned(IEX_GetInfo(p, handle, IEX_ORIGINALIMAGEWIDTH)) then begin IOParams.OriginalWidth := pinteger(IEX_GetInfo(p, handle, IEX_ORIGINALIMAGEWIDTH))^; IOParams.OriginalHeight := pinteger(IEX_GetInfo(p, handle, IEX_ORIGINALIMAGEHEIGHT))^; end else begin IOParams.OriginalWidth := width; IOParams.OriginalHeight := height; end; case srcformat of IEX_1G : begin IOParams.BitsPerSample := 1; IOParams.SamplesPerPixel := 1; end; IEX_8G : begin IOParams.BitsPerSample := 8; IOParams.SamplesPerPixel := 1; end; IEX_8P : begin IOParams.BitsPerSample := 8; IOParams.SamplesPerPixel := 1; end; IEX_16G : begin IOParams.BitsPerSample := 16; IOParams.SamplesPerPixel := 1; end; IEX_24RGB : begin IOParams.BitsPerSample := 8; IOParams.SamplesPerPixel := 3; end; IEX_48RGB : begin IOParams.BitsPerSample := 16; IOParams.SamplesPerPixel := 3; end; IEX_32F : begin IOParams.BitsPerSample := 32; IOParams.SamplesPerPixel := 1; end; IEX_CMYK : begin IOParams.BitsPerSample := 8; IOParams.SamplesPerPixel := 4; end; end; IOParams.FreeColorMap(); if (image <> nil) and (width <> 0) and (height <> 0) and not Preview then begin tempBitmap := nil; if IOParams.IsNativePixelFormat then begin // native pixel format Bitmap.Allocate(width, height, TIEPixelFormat(srcformat)); end else begin // convert to ie1g or ie24RGB if (srcformat = IEX_1G) then Bitmap.Allocate(width, height, ie1g) else if srcFormat = IEX_24RGB then Bitmap.Allocate(width, height, ie24RGB) else begin Bitmap.Allocate(width, height, ie24RGB); tempBitmap := TIEBitmap.Create(); tempBitmap.Allocate(width, height, TIEPixelFormat(srcformat)); end; end; for row := 0 to height - 1 do begin if tempBitmap = nil then begin // native pixel format of ie1g or ie24RGB rl := IEBitmapRowLen(width, Bitmap.BitCount, 8); CopyMemory( Bitmap.Scanline[row], image, rl ); if Bitmap.PixelFormat = ie24RGB then _BGR2RGB( Bitmap.Scanline[row], width ); if Bitmap.PixelFOrmat = ie48RGB then BGRHL( Bitmap.Scanline[row], width ); inc(image, rl); end else begin // non-nativepixelformat or other pixel formats to convert to ie1g or ie24RGB rl := IEBitmapRowLen(width, tempBitmap.BitCount, 8); CopyMemory( tempBitmap.Scanline[row], image, rl ); inc(image, rl); end; end; if tempBitmap <> nil then begin Bitmap.CopyAndConvertFormat(tempBitmap); FreeAndNil(tempBitmap); end; if IOParams.EXIF_HasEXIFData and IOParams.EnableAdjustOrientation then begin IEAdjustEXIFOrientation(Bitmap, IOParams.EXIF_Orientation); IOParams.EXIF_Orientation := 1; // 3.0.3 end; end; if (image <> nil) and not Preview and (srcFormat = IEX_INVALID) then begin // try to load using known format (in case it is jpeg thumbnail) memstream := nil; tempio := TImageEnIO.CreateFromBitmap(Bitmap); try imagelen := pinteger(IEX_GetInfo(p, handle, IEX_IMAGEDATELENGTH))^; memstream := TIEMemStream.Create(image, imagelen); tempio.LoadFromStream(memstream); IOParams.Assign(tempio.Params); finally memstream.Free(); tempio.Free(); end; end; if (image = nil) and not Preview then Progress.Aborting^ := true; finally IEX_Finalize(p, handle); if Stream <> nil then FreeAndNil(Stream); if (p^.Capability and IEX_MULTITHREAD) = 0 then p^.PluginsCS.Leave(); end; end; function IEPlgInTRY(Stream: TStream; TryingFormat: TIOFileType): boolean; var p: PIEIOPlugin; rec: TIECallbackRecord; handle: pointer; begin p := IEGetIOPlugin( TryingFormat ); if p = nil then begin result := false; exit; end; rec.OnProgress := nil; rec.OnProgressSender := nil; rec.Stream := Stream; rec.Params := nil; if (p^.Capability and IEX_MULTITHREAD) = 0 then p^.PluginsCS.Enter(); handle := IEX_Initialize(p, p^.pluginFormat); IEX_SetCallBacks(p, handle, @rec); try result := IEX_ExecuteTry(p, handle); finally IEX_Finalize(p, handle); if (p^.Capability and IEX_MULTITHREAD) = 0 then p^.PluginsCS.Leave(); end; end; procedure IEPlgInWRITE(Stream: TStream; Bitmap: TIEBitmap; var IOParams: TIOParams; var Progress: TProgressRec); var p: PIEIOPlugin; rec: TIECallbackRecord; handle: pointer; i, rl, row: integer; mem: array of byte; pd: pbyte; begin p := IEGetIOPlugin( IOParams.FileType ); if p = nil then exit; rec.OnProgress := Progress.fOnProgress; rec.OnProgressSender := Progress.Sender; rec.Stream := Stream; rec.Params := IOParams; Progress.Aborting^ := false; if (p^.Capability and IEX_MULTITHREAD) = 0 then p^.PluginsCS.Enter(); handle := IEX_Initialize(p, p^.pluginFormat); IEX_SetCallBacks(p, handle, @rec); i := Bitmap.Width; IEX_SetInfo(p, handle, IEX_IMAGEWIDTH, @i); i := Bitmap.Height; IEX_SetInfo(p, handle, IEX_IMAGEHEIGHT, @i); i := integer(Bitmap.PixelFormat); IEX_SetInfo(p, handle, IEX_PIXELFORMAT, @i); rl := IEBitmapRowLen(Bitmap.Width, Bitmap.BitCount, 8); // 8 bit aligned try SetLength(mem, rl * Bitmap.Height); pd := @mem[0]; for row := 0 to Bitmap.Height - 1 do begin CopyMemory(pd, Bitmap.Scanline[row], rl); if Bitmap.PixelFormat = ie24RGB then _BGR2RGB( PRGB(pd), Bitmap.Width ); inc(pd, rl); end; IEX_SetInfo(p, handle, IEX_IMAGEDATA, @mem[0]); IEX_ExecuteWrite(p, handle); finally IEX_Finalize(p, handle); if (p^.Capability and IEX_MULTITHREAD) = 0 then p^.PluginsCS.Leave(); end; end; // return true if the specified plugins is already loaded // does not compare file path function IEIsExtIOPluginLoaded(const FileName: String): Boolean; var p: PIEIOPlugin; i: integer; begin result := false; for i := 0 to ioplugins.Count - 1 do begin p := ioplugins[i]; if ExtractFileName(p^.DLLFileName) = ExtractFileName(string(FileName)) then begin result := true; break; end; end; end; {!! IEAutoLoadIOPlugins Declaration function IEAutoLoadIOPlugins : Integer; Description Checks the application folder for any of the following plug-ins: jbiglib.dll and imagemagick.dll and automatically adds them by calling . Also checks for an installed version of ImageMagick (and optionally Ghostscript) using . Result is the number of plug-ins that were loaded, or -1 in case of unexpected error. Note: From v6.1.0, dcrawlib.dll is no longer used for Camera Raw format support, use ielib instead. Example procedure TMainForm.FormCreate(Sender: TObject); begin IEAutoLoadIOPlugins; end; See Also - - !!} function IEAutoLoadIOPlugins : Integer; const Jbiglib_dll = 'jbiglib.dll'; Imagemagick_dll = 'imagemagick.dll'; var sAppFolder: string; begin Result := 0; try sAppFolder := IEAddBackSlash(ExtractFilePath(Application.Exename)); // JBIG if IEFileExists(sAppFolder + Jbiglib_dll) then begin IEAddExtIOPlugIn(sAppFolder + Jbiglib_dll); inc(Result); end; // IMAGEMAGICK DLL (OLDER) if IEFileExists(sAppFolder + Imagemagick_dll) then begin IEAddExtIOPlugIn(sAppFolder + Imagemagick_dll); inc(Result); end; // INSTALLED IMAGEMAGICK (NEWER) {$ifdef IEINCLUDEMISCPLUGINS} if TIEMiscPluginsImageMagick.IsAvailable then begin TIEMiscPluginsImageMagick.RegisterPlugin; inc(Result); end; {$endif} except Result := -1; end; end; {!! IEAddExtIOPlugin Declaration function IEAddExtIOPlugin(const FileName : string) : Integer; Description Adds support for extra file formats using the ImageEn input/output plug-ins (DLL's) that can be downloaded from the Registered Users download page. Available plug-ins allow you to load and save JBIG and other formats. All include source code if you need help to you write your own plug-ins. Result is the FileType for the added formats, e.g. ioOtherDLLPlugIns, ioOtherDLLPlugIns + 1, etc. This can be used by methods such as . Note: From v6.1.0, dcrawlib.dll is no longer used for Camera Raw format support, use ielib instead. Example IEAddExtIOPlugIn('jbiglib.dll'); IEAddExtIOPlugIn('imagemagick.dll'); A plugin can include more than one file format. For example, imagemagick.dll adds PCD, DICOM, FITS and many others. Please read license terms for each plugin downloaded from imageen.com web site. See Also - !!} function IEAddExtIOPlugin(const FileName: String): Integer; const Legacy_Camera_Raw_DLL = 'dcrawlib.dll'; // Used prior to v6.1.0 for camera raw formats. Now handled by ielib var h: THandle; p: PIEIOPlugin; FileFormatInfo: TIEFileFormatInfo; formatsCount: integer; formatIndex: integer; done: boolean; ph: pointer; iPos: Integer; sExtensions: string; sSuitableExtension: string; begin result := 0; if IEIsExtIOPluginLoaded(FileName) then exit; // already loaded // Trying to load legacy DCRAW DLL? if SameText( ExtractFilename( Filename ), Legacy_Camera_Raw_DLL ) then begin // User may be unaware that raw formats no longer supported // May also have try to call ieFileformatRemove( ioRAW ) which would remove all raw support raise EIEException.create('dcrawlib.dll is no longer supported. Use ielib32.dll instead!'); end; formatIndex := 0; repeat done := true; h := LoadLibrary(PChar(FileName)); if h <> 0 then begin new( p ); p^.use_cdecl := GetProcAddress(h, 'IEX_UseCDECL') <> nil; // this is a flag not a function! if p^.use_cdecl then begin p^.IEX_ExecuteRead_cdecl := GetProcAddress(h, 'IEX_ExecuteRead'); p^.IEX_ExecuteWrite_cdecl := GetProcAddress(h, 'IEX_ExecuteWrite'); p^.IEX_ExecuteTry_cdecl := GetProcAddress(h, 'IEX_ExecuteTry'); p^.IEX_AddParameter_cdecl := GetProcAddress(h, 'IEX_AddParameter'); p^.IEX_SetCallBacks_cdecl := GetProcAddress(h, 'IEX_SetCallBacks'); p^.IEX_Initialize_cdecl := GetProcAddress(h, 'IEX_Initialize'); p^.IEX_Finalize_cdecl := GetProcAddress(h, 'IEX_Finalize'); p^.IEX_GetInfo_cdecl := GetProcAddress(h, 'IEX_GetInfo'); p^.IEX_SetInfo_cdecl := GetProcAddress(h, 'IEX_SetInfo'); end else begin // stdcall p^.IEX_ExecuteRead_std := GetProcAddress(h, 'IEX_ExecuteRead'); p^.IEX_ExecuteWrite_std := GetProcAddress(h, 'IEX_ExecuteWrite'); p^.IEX_ExecuteTry_std := GetProcAddress(h, 'IEX_ExecuteTry'); p^.IEX_AddParameter_std := GetProcAddress(h, 'IEX_AddParameter'); p^.IEX_SetCallBacks_std := GetProcAddress(h, 'IEX_SetCallBacks'); p^.IEX_Initialize_std := GetProcAddress(h, 'IEX_Initialize'); p^.IEX_Finalize_std := GetProcAddress(h, 'IEX_Finalize'); p^.IEX_GetInfo_std := GetProcAddress(h, 'IEX_GetInfo'); p^.IEX_SetInfo_std := GetProcAddress(h, 'IEX_SetInfo'); end; if ((@p^.IEX_ExecuteRead_std = nil) or (@p^.IEX_ExecuteWrite_std = nil) or (@p^.IEX_AddParameter_std = nil) or (@p^.IEX_SetCallBacks_std = nil) or (@p^.IEX_Initialize_std = nil) or (@p^.IEX_Finalize_std = nil) or (@p^.IEX_GetInfo_std = nil) or (@p^.IEX_SetInfo_std = nil) or (@p^.IEX_ExecuteTry_std = nil)) and ((@p^.IEX_ExecuteRead_cdecl = nil) or (@p^.IEX_ExecuteWrite_cdecl = nil) or (@p^.IEX_AddParameter_cdecl = nil) or (@p^.IEX_SetCallBacks_cdecl = nil) or (@p^.IEX_Initialize_cdecl = nil) or (@p^.IEX_Finalize_cdecl = nil) or (@p^.IEX_GetInfo_cdecl = nil) or (@p^.IEX_SetInfo_cdecl = nil) or (@p^.IEX_ExecuteTry_cdecl = nil)) then begin // this is not a plugin dll FreeLibrary(h); dispose( p ); end else begin // this is OK ph := IEX_Initialize(p, formatIndex); formatsCount := pinteger(IEX_GetInfo(p, ph, IEX_FORMATSCOUNT))^; p^.libhandle := h; p^.DLLFileName := FileName; p^.FileType := ioOtherDLLPlugIns + ioplugins.Count; p^.pluginFormat := formatIndex; FileFormatInfo := TIEFileFormatInfo.Create(); FileFormatInfo.FileType := p^.FileType; FileFormatInfo.FullName := string(PAnsiChar(IEX_GetInfo(p, ph, IEX_PLUGINDESCRIPTOR))); // plugins can send only ansichars sExtensions := string(PAnsiChar(IEX_GetInfo(p, ph, IEX_FILEEXTENSIONS))); // plugins can send only ansichars FileFormatInfo.Extensions := sExtensions; sSuitableExtension := sExtensions; iPos := Pos(';', sSuitableExtension); if iPos > 0 then delete(sSuitableExtension, iPos, Length(sSuitableExtension) - iPos + 1); FileFormatInfo.SuitableExtension := sSuitableExtension; FileFormatInfo.DialogPage := []; FileFormatInfo.InternalFormat := false; p^.Capability := pinteger( IEX_GetInfo(p, ph, IEX_PLUGINCAPABILITY) )^; if (p^.Capability and IEX_FILEREADER) <> 0 then FileFormatInfo.ReadFunction := IEPlgInREAD; if (p^.Capability and IEX_FILEREADER) <> 0 then FileFormatInfo.TryFunction := IEPlgInTRY; if (p^.Capability and IEX_FILEWRITER) <> 0 then FileFormatInfo.WriteFunction := IEPlgInWRITE; if (p^.Capability and IEX_MULTITHREAD) = 0 then p^.PluginsCS := TCriticalSection.Create(); ioplugins.Add( p ); IEFileFormatAdd( FileFormatInfo ); result := p^.FileType; inc(formatIndex); done := formatIndex = formatsCount; IEX_Finalize(p, ph); end; end; until done; end; procedure IEUnLoadIOPlugins; var i: integer; p: PIEIOPlugin; begin for i := 0 to ioplugins.Count - 1 do begin p := ioplugins[i]; IEFileFormatRemove( p^.FileType ); if (p^.Capability and IEX_MULTITHREAD) = 0 then FreeAndNil(p^.PluginsCS); FreeLibrary( p^.libhandle ); dispose( p ); end; ioplugins.Clear(); end; // input/output plugins /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {!! IEOptimizeGIF Declaration procedure IEOptimizeGIF(const InputFile, OutputFile: WideString); Description Optimizes a GIF animation (or multi-page GIF) by detecting differences between each frame and removing any data that is duplicated. The resulting file will only include differences between frames and can be significantly smaller. Demo Demos\ImageEditing\AnimatedGIF\AnimatedGIF.dpr Example ImageEnMView1.MIO.SaveToFile('D:\temp.gif'); IEOptimizeGIF('D:\temp.gif', 'D:\output.gif'); !!} procedure IEOptimizeGIF(const InputFile, OutputFile: WideString); var i: Integer; ie: TImageEnView; prev: TIEBitmap; x, y, w, h: Integer; p1, p2: PRGB; x1, y1, x2, y2: Integer; a1, a2: pbyte; ielist: TList; begin ielist := TList.Create; prev := TIEBitmap.Create; i := 0; repeat ie := TImageEnView.Create(nil); ielist.Add(ie); ie.IO.Params.GIF_ImageIndex := i; ie.IO.LoadFromFileGIF(InputFile); if i = 0 then begin // this is the first frame, save as is ie.IO.Params.GIF_Action := ioGIF_DontRemove; prev.Assign( ie.IEBitmap ); end else begin // this is not first frame, check differences with "prev" bitmap x1 := 1000000; y1 := 1000000; x2 := 0; y2 := 0; w := imin(prev.Width, ie.IEBitmap.Width); h := imin(prev.Height, ie.IEBitmap.Height); y := 0; while yp2^.r) or (p1^.g<>p2^.g) or (p1^.b<>p2^.b) then begin if x < x1 then x1 := x; if x > x2 then x2 := x; if y < y1 then y1 := y; if y > y2 then y2 := y; end; if (a2^ = 0) and (a1^=255) then begin x1 := 1000000; y1 := 1000000; x2 := 0; y2 := 0; y := h; break; end; inc(p1); inc(p2); inc(a1); inc(a2); end; inc(y); end; prev.Assign( ie.IEBitmap ); if (x1 <> 1000000) and (y1 <> 1000000) and (x2 <> 0) and (y2 <> 0) then begin ie.Proc.Crop(x1, y1, x2, y2); ie.IO.Params.GIF_XPos := x1; ie.IO.Params.GIF_YPos := y1; ie.IO.Params.GIF_WinWidth := prev.Width; ie.IO.Params.GIF_WinHeight := prev.Height; ie.IO.Params.GIF_Action := ioGIF_DontRemove; end else ie.IO.Params.GIF_Action := ioGIF_DrawBackground; end; inc(i); until i=ie.IO.Params.GIF_ImageCount; for i := 0 to ielist.Count - 1 do begin ie := ielist[i]; if i < ielist.Count - 1 then ie.IO.Params.GIF_Action := TImageEnView(ielist[i + 1]).IO.Params.GIF_Action; if i = 0 then ie.IO.SaveToFileGIF(OutputFile) else ie.IO.InsertToFileGIF(OutputFile); FreeAndNil(ie); end; FreeAndNil(prev); FreeAndNil(ielist); end; constructor TIEFileFormatInfo.Create(); begin end; constructor TIEFileFormatInfo.Create(FileType: TIOFileType; FullName: string; Extensions: string; SuitableExtension : string; InternalFormat: Boolean; DialogPage: TPreviewParams; ReadFunction: TIEReadImageStream; WriteFunction: TIEWriteImageStream; TryFunction: TIETryImageStream); begin self.FileType := FileType; self.FullName := FullName; self.Extensions := Extensions; self.SuitableExtension := SuitableExtension; self.InternalFormat := InternalFormat; self.DialogPage := DialogPage; self.ReadFunction := ReadFunction; self.WriteFunction := WriteFunction; self.TryFunction := TryFunction end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// // Registered File formats support ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// {!! IEFileFormatGetInfo Declaration function IEFileFormatGetInfo(FileType: ): ; Description Returns a TIEFileFormatInfo object which contains details about the specified file format. See also: Example // Get a suitable file extension for saving a JPEG sExt := IEFileFormatGetInfo(ioJPEG).SuitableExtension; // returns 'jpeg' // Get a description of JPEG files sFormatName := IEFileFormatGetInfo(ioJPEG).FullName; // returns 'JPEG Bitmap' !!} // ret nil if FileType doesn't exists function IEFileFormatGetInfo(FileType: TIOFileType): TIEFileFormatInfo; var q: integer; begin result := nil; if FileType = ioUnknown then exit; for q := 0 to IEGlobalSettings().FileFormats.Count - 1 do begin result := TIEFileFormatInfo(IEGlobalSettings().FileFormats[q]); if result.FileType = FileType then exit; end; result := nil; end; // ret extension count function IEFileFormatGetExtCount(FileType: TIOFileType): integer; begin result := 0; while IEFileFormatGetExt(FileType, result) <> '' do inc(result); end; // ret extension // example: for Extensions='jpg;jpeg' idx=1 is 'jpeg' function IEFileFormatGetExt(FileType: TIOFileType; idx: integer): string; var fi: TIEFileFormatInfo; ss: string; // function ExtractNext: string; var q: integer; begin q := Pos(';', ss); if q = 0 then begin result := ss; ss := ''; end else begin result := Copy(ss, 1, q - 1); ss := Copy(ss, q + 1, length(ss) - q); end; end; // var i: integer; begin fi := IEFileFormatGetInfo(FileType); if assigned(fi) then begin ss := fi.Extensions; i := 0; while length(ss) > 0 do begin result := ExtractNext; if i = idx then exit; inc(i); end; end; result := ''; end; {!! IEFileFormatGetInfo2 Declaration function IEFileFormatGetInfo2(Extension: string): ; Description Returns a TIEFileFormatInfo object which contains details about the specified file format. The format is specified by its extension (example '.gif' or 'gif'). See also: Example // Get a description of .JPEG files sFormatName := IEFileFormatGetInfo2('.JPEG').FullName; // returns 'JPEG Bitmap' !!} // ret nil if Extension doesn't exists (accept '.xxx' or 'xxx') function IEFileFormatGetInfo2(Extension: string): TIEFileFormatInfo; var q, i, c: integer; begin Extension := LowerCase(Extension); if (Length(Extension) > 0) and (Extension[1] = '.') then Delete(Extension, 1, 1); for q := 0 to IEGlobalSettings().FileFormats.Count - 1 do begin result := TIEFileFormatInfo(IEGlobalSettings().FileFormats[q]); c := IEFileFormatGetExtCount(result.FileType); for i := 0 to c - 1 do if LowerCase(IEFileFormatGetExt(result.FileType, i)) = Extension then exit; end; result := nil; end; {!! IEFileFormatAdd Declaration procedure IEFileFormatAdd(FileFormatInfo: ); Description Adds a new file format to ImageEn. The object FileFormatInfo specifies file format information and read/write functions. Note: You do not need to free the FileFormatInfo object. Demo Demos\InputOutput\FileFormatPlugins\FPlug.dpr Example var FileFormatInfo: TIEFileFormatInfo; begin FileFormatInfo := TIEFileFormatInfo.Create; with FileFormatInfo do begin FileType := ioUNC; FullName := 'Uncompressed Bitmap'; Extensions := 'unc;ucp'; SuitableExtension := 'unc'; // Optional. It is automatically set if not specified InternalFormat := False; DialogPage := []; ReadFunction := ReadUNC; WriteFunction := WriteUNC; TryFunction := TryUNC; end; IEFileFormatADD(FileFormatInfo); end; !!} procedure IEFileFormatAdd(FileFormatInfo: TIEFileFormatInfo); var sSuitableExtension: string; iPos: Integer; begin if FileFormatInfo.SuitableExtension = '' then begin sSuitableExtension := FileFormatInfo.Extensions; iPos := Pos(';', sSuitableExtension); if iPos > 0 then delete(sSuitableExtension, iPos, Length(sSuitableExtension) - iPos + 1); FileFormatInfo.SuitableExtension := sSuitableExtension; end; IEGlobalSettings().FileFormats.Add(FileFormatInfo); end; {!! IEFileFormatRemove Declaration procedure IEFileFormatRemove(FileType: ); Description Removes a file format added using . !!} procedure IEFileFormatRemove(FileType: TIOFileType); var r: TIEFileFormatInfo; begin r := IEFileFormatGetInfo(FileType); if assigned( r ) then begin IEGlobalSettings().FileFormats.Remove(r); r.Free; end; end; procedure DumpReadImageStream(Stream: TStream; Bitmap: TIEBitmap; var IOParams: TIOParams; var Progress: TProgressRec; Preview: boolean); begin end; procedure DumpWriteImageStream(Stream: TStream; Bitmap: TIEBitmap; var IOParams: TIOParams; var Progress: TProgressRec); begin end; function DumpTryImageStream(Stream: TStream; TryingFormat: TIOFileType): boolean; begin result := false; end; // Alloc TIEImageEnGlobalSettings.FileFormats global variable and embedded file formats procedure IEInitFileFormats; var fi: TIEFileFormatInfo; {$ifNdef Delphi7orNewer} L3118: TImageEnIO; {$endif} begin // So that the linker includes all obj files, avoiding the Delphi error, "Internal Error L3118" {$ifNdef Delphi7orNewer} L3118 := TImageEnIO.Create(nil); FreeAndNil(L3118); {$endif} IEGlobalSettings().FileFormats := TList.Create; // TIFF fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioTIFF; FullName := 'TIFF Image'; Extensions := 'TIF;TIFF;FAX;G3N;G3F;XIF'; SuitableExtension := 'tiff'; DialogPage := [ppTIFF]; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // GIF fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioGIF; FullName := 'GIF Image'; Extensions := 'GIF'; SuitableExtension := 'gif'; DialogPage := [ppGIF]; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // JPEG fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioJPEG; FullName := 'JPEG Image'; Extensions := 'JPG;JPEG;JPE;JIF'; SuitableExtension := 'jpeg'; DialogPage := [ppJPEG]; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // PCX with fi do begin fi := TIEFileFormatInfo.Create; FileType := ioPCX; FullName := 'PaintBrush'; Extensions := 'PCX'; SuitableExtension := 'pcx'; DialogPage := [ppPCX]; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // BMP fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioBMP; FullName := 'Windows Bitmap'; Extensions := 'BMP;DIB;RLE'; SuitableExtension := 'bmp'; DialogPage := [ppBMP]; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // BMPRAW fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioBMPRAW; FullName := 'Raw Bitmap'; Extensions := ''; // in this way this format will not be included in open/save dialog SuitableExtension := ''; DialogPage := []; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // ICO fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioICO; FullName := 'Windows Icon'; Extensions := 'ICO'; SuitableExtension := 'ico'; DialogPage := []; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // CUR fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioCUR; FullName := 'Windows Cursor'; Extensions := 'CUR'; SuitableExtension := 'cur'; DialogPage := []; ReadFunction := DumpReadImageStream; WriteFunction := nil; // cannot write TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; {$IFDEF IEINCLUDEPNG} // PNG fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioPNG; FullName := 'Portable Network Graphics'; Extensions := 'PNG'; SuitableExtension := 'png'; DialogPage := [ppPNG]; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; {$ENDIF} {$ifdef IEINCLUDEDICOM} // DICOM fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioDICOM; FullName := 'DICOM Medical Image'; Extensions := 'DCM;DIC;DICOM;V2'; SuitableExtension := 'dicom'; DialogPage := []; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; {$endif} // WMF fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioWMF; FullName := 'Windows Metafile'; Extensions := 'WMF'; SuitableExtension := 'wmf'; DialogPage := []; ReadFunction := DumpReadImageStream; WriteFunction := nil; // cannot write TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // EMF fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioEMF; FullName := 'Enhanced Windows Metafile'; Extensions := 'EMF'; SuitableExtension := 'emf'; DialogPage := []; ReadFunction := DumpReadImageStream; WriteFunction := nil; // cannot write TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // TGA fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioTGA; FullName := 'Targa Image'; Extensions := 'TGA;TARGA;VDA;ICB;VST;PIX'; SuitableExtension := 'targa'; DialogPage := [ppTGA]; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // PXM fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioPXM; FullName := 'Portable Pixmap, Graymap, Bitmap'; Extensions := 'PXM;PPM;PGM;PBM'; SuitableExtension := 'pxm'; DialogPage := []; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // WBMP fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioWBMP; FullName := 'Wireless Bitmap'; Extensions := 'WBMP'; SuitableExtension := 'wbmp'; DialogPage := []; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; {$IFDEF IEINCLUDEJPEG2000} // JP2 fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioJP2; FullName := 'JPEG2000'; Extensions := 'JP2'; SuitableExtension := 'jp2'; DialogPage := [ppJ2000]; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // J2K fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioJ2K; FullName := 'JPEG2000 Code Stream'; Extensions := 'J2K;JPC;J2C'; SuitableExtension := 'j2k'; DialogPage := [ppJ2000]; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; {$ENDIF} // PostScript (PS) fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioPS; FullName := 'PostScript'; Extensions := 'PS;EPS'; SuitableExtension := 'eps'; DialogPage := []; ReadFunction := nil; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // Adobe PDF fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioPDF; FullName := 'Adobe PDF'; Extensions := 'PDF'; SuitableExtension := 'pdf'; DialogPage := []; ReadFunction := nil; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // DCX fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioDCX; FullName := 'Multipage PCX'; Extensions := 'DCX'; SuitableExtension := 'dcx'; DialogPage := []; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // RAW {$ifdef IEINCLUDERAWFORMATS} fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioRAW; FullName := 'Camera Raw Image'; Extensions := 'CRW;CR2;DNG;NEF;RAW;RAF;X3F;ORF;SRF;MRW;DCR;BAY;PEF;SR2;ARW;KDC;MEF;3FR;K25;ERF;CAM;CS1;DC2;DCS;FFF;MDC;MOS;NRW;PTX;PXN;RDC;RW2;RWL;IIQ;SRW'; SuitableExtension := 'raw'; DialogPage := []; ReadFunction := DumpReadImageStream; WriteFunction := nil; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; {$endif} // PSD fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioPSD; FullName := 'Photoshop PSD'; Extensions := 'PSD;PSB'; SuitableExtension := 'psd'; DialogPage := []; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // IEV fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioIEV; FullName := 'Vectorial Objects'; Extensions := 'IEV'; SuitableExtension := 'iev'; DialogPage := []; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // IEN fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioIEN; FullName := 'ImageEn Layers'; Extensions := 'IEN;IMAGEEN;LYR'; SuitableExtension := 'ien'; DialogPage := []; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // ALL fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioALL; FullName := 'Layers and Objects'; Extensions := 'ALL'; SuitableExtension := 'all'; DialogPage := []; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; // HDP {$ifdef IEINCLUDEWIC} if IEWICAvailable() then begin fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioHDP; FullName := 'Microsoft HD Photo'; Extensions := 'WDP;HDP;JXR'; SuitableExtension := 'hdp'; DialogPage := []; ReadFunction := DumpReadImageStream; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := true; IEFileFormatAdd(fi); end; end; {$endif} // Scalable Vector Graphics fi := TIEFileFormatInfo.Create; with fi do begin FileType := ioSVG; FullName := 'Scalable Vector Graphics'; Extensions := 'SVG'; SuitableExtension := 'svg'; DialogPage := []; ReadFunction := nil; WriteFunction := DumpWriteImageStream; TryFunction := DumpTryimageStream; InternalFormat := True; IEFileFormatAdd(fi); end; end; // update GIF WriteFunction and ReadFunction regarding to DefGIF_LZWCOMPFUNC and DefGIF_LZWDECOMPFUNC procedure IEUpdateGIFStatus; var fi: TIEFileFormatInfo; begin fi := IEFileFormatGetInfo(ioGIF); if assigned(fi) then begin if assigned(IEGlobalSettings().DefGIF_LZWDECOMPFUNC) then fi.ReadFunction := DumpReadImageStream else fi.ReadFunction := nil; if assigned(IEGlobalSettings().DefGIF_LZWCOMPFUNC) then fi.WriteFunction := DumpWriteImageStream else fi.WriteFunction := nil; end; end; // Free TIEImageEnGlobalSettings.FileFormats global variable procedure IEFreeFileFormats; var q: integer; begin for q := 0 to IEGlobalSettings().FileFormats.Count - 1 do TIEFileFormatInfo(IEGlobalSettings().FileFormats[q]).Free; IEGlobalSettings().FileFormats.Free(); IEGlobalSettings().FileFormats := nil; end; {!! IsKnownFormat Declaration function IsKnownFormat(const FileName : WideString; bIncludeVideoFiles : Boolean = False) : boolean; Description Returns true if the specified filename is a supported file format. By default, this only includes image formats. Set bIncludeVideoFiles to true to include AVI, MPEG and WMV Note: This method only checks that file extension is recognized (e.g. .JPEG of image.jpeg). To examine the content of the image to determine if it is readable use See also: Example If IsKnownFormat('C:\test.fax') then ShowMessage('ok, I can load it'); !!} function IsKnownFormat(const FileName: WideString; bIncludeVideoFiles : Boolean = False): boolean; var fpi: TIEFileFormatInfo; sExt: string; begin sExt := Lowercase(string(IEExtractFileExtW(FileName))); if IEFileExtInExtensions(sExt, Supported_Video_File_Extensions) then begin Result := bIncludeVideoFiles; end else begin fpi := IEFileFormatGetInfo2(sExt); result := assigned(fpi) and (@fpi.ReadFunction <> nil); end; end; {!! IsKnownSaveFormat Declaration function IsKnownSaveFormat(const FileName : WideString) : boolean; Description Returns true if the specified filename is a file format that ImageEn supports saving (by checking its file extension). Note: There are a variety of formats (such as WMF) which ImageEn can load but not save. See also: Example If IsKnownSaveFormat('test.dcm') then ShowMessage('ok, I can save it'); !!} function IsKnownSaveFormat(const FileName: WideString): boolean; var fpi: TIEFileFormatInfo; sExt: string; begin sExt := Lowercase(string(IEExtractFileExtW(FileName))); fpi := IEFileFormatGetInfo2(sExt); result := assigned(fpi) and (@fpi.WriteFunction <> nil); end; {!! FindFileFormat Declaration function FindFileFormat(const FileName: WideString; FindMethod: = ffContentOnly): ; Description Returns the file format of the specified file by reading the file and trying to recognize the file header. FindMethod determines how the file extension is used to aid or confirm format detection: Value Description ffContentOnly Only the content of the file is examined. The filename is ignored (No extension checking) ffVerifyByExtension The content is examined to determine the type. This is then compared to the file extension and ioUnknown is returned if the type does not match (Strict extension checking) ffFallbackToExtension The content is examined to determine the type. If it cannot be determined (which can happen with some Dicom and Raw formats), then the type is guessed by the file extension (Optimistic extension checking)
Some formats cannot be detected by content alone. Sony ARW and Kodak DCR are TIFF internally so will return as ioTIFF. WBMP and Implicit Dicom will return as ioUnknown. Note: FindFileFormat uses
to detect the image format. Examples // Determine the file type only by examining the file header/content if FindFileFormat( sFilename, ffContentOnly ) = ioJPEG then ShowMessage( 'File content is JPEG' ); // Determine the file type by examining the file header/content, check it has the correct file extension if FindFileFormat( sFilename, ffVerifyByExtension ) = ioJPEG then ShowMessage( 'File content is JPEG and it has a JPEG extension' ); // Determine the file type by examining the file header/content. If that fails use the correct file extension if FindFileFormat( sFilename, ffFallbackToExtension ) = ioDICOM then ShowMessage( 'File appears to be a DICOM' ); var ss: TIOFileType; begin ss := FindFileFormat('C:\myfile.dat', ffContentOnly); if ss = ioGIF then ImageEnView1.IO.LoadFromFileGIF('C:\myfile.dat') else if ss = ioJPEG then ImageEnView1.IO.LoadFromFileJpeg('C:\myfile.dat'); end; !!} // Recognizes: JPG, GIF, PCX, DCX, BMP, TIF, PNG, ICO, CUR, TGA, PXM, JP2, JPC, J2C, J2K, RAW, PSD, HDP // supports registered file formats function FindFileFormat(const FileName: WideString; FindMethod: TIEFindFormatMethod = ffContentOnly): TIOFileType; var fs: TIEWideFileStream; fpi: TIEFileFormatInfo; ext: string; begin result := ioUnknown; if (FileName='') or not IEFileExistsW(FileName) then exit; // verify stream try fs := TIEWideFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try result := FindStreamFormat(fs); finally FreeAndNil(fs); end; except end; ext := string(IEExtractFileExtW(FileName)); fpi := IEFileFormatGetInfo2( ext ); // raw formats cannot be confused with TIFF, then we must check the extension if (fpi <> nil) and (fpi.FileType = ioRAW) and (result = ioTIFF) then result := ioRAW else // If user has created own reader for this type, then use that instead if (fpi <> nil) and not fpi.InternalFormat then result := fpi.FileType else // For strict checking, ensure the extension matches the type if ( FindMethod = ffVerifyByExtension) and ( result <> ioUnknown ) then begin // verify extension if assigned( fpi ) then begin if (result <> ioICO) and (result <> ioCUR) then begin if result <> fpi.FileType then result := ioUnknown; end else result := fpi.FileType; end else if not (( Result = ioAVI ) and ( ext = '.avi' )) then result := ioUnknown; end else // For optimistic checking, see if we can determine the format using the extension if ( FindMethod = ffFallbackToExtension) and ( result = ioUnknown ) and assigned( fpi ) then result := fpi.FileType; end; {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 6.3.1 (2015-06-16) function FindFileFormat(const FileName: WideString; VerifyExtension: boolean): TIOFileType; begin if VerifyExtension then Result := FindFileFormat( FileName, ffVerifyByExtension ) else Result := FindFileFormat( FileName, ffContentOnly ) end; {$endif} function AVITryStream(Stream: TStream): boolean; var l: int64; s1, s2: array[0..3] of AnsiChar; begin l := Stream.Position; Stream.Read(s1[0], 4); Stream.Seek(4, soCurrent); Stream.Read(s2[0], 4); result := (s1 = 'RIFF') and (s2 = 'AVI '); Stream.Position := l; end; // Return true if this is a stream of SOME known Raw file formats // Not an extensive test! Just used to eliminate false positives { Works for: - Olympus ORF - Fujifilm RAF - Minolta MRW - Canon CR2 - Some Canon CRW } function IsRAWStream(fs: TStream): boolean; var id: array[0..15] of AnsiChar; lp: int64; begin Result := False; lp := fs.Position; try if fs.Size > 16 then begin fs.Read(id, 16); // Olympus ORF if (( Copy( id, 1, 2 ) = 'MM' ) or ( Copy( id, 1, 2 ) = 'II' )) and (( Copy( id, 3, 2 ) = 'RO' ) or ( Copy( id, 3, 2 ) = 'OR' ) or ( Copy( id, 3, 2 ) = 'RS' )) then result := True else // Fujifilm RAF if Copy( id, 1, 8 ) = 'FUJIFILM' then result := True else // Minolta MRW if Copy( id, 2, 3 ) = 'MRM' then result := True else // Canon CR2 if (( Copy( id, 1, 2 ) = 'MM' ) or ( Copy( id, 1, 2 ) = 'II' )) and (( id[ 8 ] = 'C' ) and ( id[ 9 ] = 'R' )) then result := True else // Canon CRW if (( Copy( id, 1, 2 ) = 'MM' ) or ( Copy( id, 1, 2 ) = 'II' )) and // HEAPCCDR (( id[ 6 ] = 'H' ) and ( id[ 11 ] = 'C' ) and ( id[ 12 ] = 'D' ) and ( id[ 13 ] = 'R' )) then result := True; end; finally fs.Position := lp; end; end; {!! FindStreamFormat Declaration function FindStreamFormat(Stream: TStream): ; Description Returns the format of the file found in a stream by reading the file header. Some formats cannot be detected by content alone. Sony ARW and Kodak DCR are TIFF internally so will return as ioTIFF. WBMP and Implicit Dicom will return as ioUnknown. !!} function FindStreamFormat(Stream: TStream): TIOFileType; var Size: integer; HeaderJpegStream: TStreamJpegHeader; HeaderGIF: TGIFHeader; HeaderPcx: PCXSHead; HeaderPcx2: TPcxHeader; HeaderBmp: TBITMAPFILEHEADER; HeaderTIFF: TIFFSHead; id: array[0..3] of AnsiChar; lp: int64; q: integer; begin result := ioUnknown; try lp := Stream.Position; Size := Stream.Size; try // try jpeg (with extra header) if Size > sizeof(TStreamJpegHeader) then begin Stream.Read(HeaderJpegStream, sizeof(HeaderJpegStream)); Stream.Position := lp; if HeaderJpegStream.ID = 'JFIF' then begin result := ioJPEG; exit; end; end; // try GIF (no extra header) if Size > sizeof(TGIFHeader) then begin Stream.Read(HeaderGIF, sizeof(HeaderGIF)); Stream.Position := lp; if (headergif.id[0] = 'G') and (headergif.id[1] = 'I') and (headergif.id[2] = 'F') then begin result := ioGIF; exit; end; end; // try PCX (with extra header - ver.2) if Size > sizeof(PCXSHead) then begin Stream.Read(HeaderPCX, sizeof(HeaderPCX)); Stream.Position := lp; if HeaderPCX.id = 'PCX2' then begin result := ioPCX; exit; end; end; // try PCX (with extra header - ver.1) if Size > 4 then begin Stream.Read(id, 4); Stream.Position := lp; if id = 'PCX' then begin result := ioPCX; exit; end; end; // try BMP (no extra header) if Size > sizeof(HeaderBmp) then begin Stream.Read(HeaderBmp, sizeof(HeaderBmp)); Stream.Position := lp; if HeaderBmp.bfType = 19778 then begin result := ioBMP; exit; end; end; // try PCX (no extra header) if Size > sizeof(TPcxHeader) then begin Stream.Read(HeaderPcx2, sizeof(HeaderPcx2)); Stream.Position := lp; if (HeaderPcx2.Manufacturer = $0A) and (HeaderPcx2.Version <= 5) then begin result := ioPCX; exit; end; end; // try TIFF (with extra header) if Size > sizeof(TIFFSHead) then begin Stream.Read(HeaderTIFF, sizeof(HeaderTIFF)); Stream.Position := lp; if HeaderTIFF.ID = 'TIFF' then begin result := ioTIFF; exit; end; end; {$ifdef IEINCLUDEWIC} // try HDP (Microsoft PhotoHD) if IsHDPStream(Stream) then begin result := ioHDP; exit; end; {$endif} // try TIFF (no extra header) if IsTIFFStream(Stream) and not IsDNGStream( Stream ) then begin if IsRAWStream( Stream ) then result := ioRAW else result := ioTIFF; exit; end; // try PNG {$IFDEF IEINCLUDEPNG} if Size > 8 then begin if IsPNGStream(Stream) then begin result := ioPNG; exit; end; end; {$ENDIF} // try DICOM {$ifdef IEINCLUDEDICOM} if IEDicomTryStream(Stream) then begin result := ioDICOM; exit; end; {$endif} // try ICO if IcoTryStream(Stream) then begin result := ioICO; exit; end; // try CUR if CurTryStream(Stream) then begin result := ioCUR; exit; end; // try TGA if TryTGA(Stream) then begin result := ioTGA; exit; end; // try PXM if tryPXM(Stream) then begin result := ioPXM; exit; end; {$IFDEF IEINCLUDEJPEG2000} // try jp2 if J2KTryStreamJP2(Stream) then begin result := ioJP2; exit; end; // try j2k, jpc, j2c if J2KTryStreamJ2K(Stream) then begin result := ioJ2K; exit; end; {$ENDIF} // try AVI if AVITryStream(Stream) then begin result := ioAVI; exit; end; // try DCX if IEDCXTryStream(Stream) then begin result := ioDCX; exit; end; // try WMF if IEWMFTryStream(Stream) then begin result := ioWMF; exit; end; // try EMF if IEEMFTryStream(Stream) then begin result := ioEMF; exit; end; {$ifdef IEINCLUDEPSD} // try PSD if IETryPSD(Stream) then begin result := ioPSD; exit; end; {$endif} // try IEV if IETryIEV(Stream) then begin result := ioIEV; exit; end; // try IEN if IETryIEN(Stream) then begin result := ioIEN; exit; end; // try ALL (IEN+IEV) if IETryALL(Stream) then begin result := ioALL; exit; end; // try jpeg (without extra header) // Check header is not raw, because RAF files resemble JPEG stream if ( IsRAWStream( Stream ) = False ) and ( JpegTryStream(Stream, true) >= 0 ) then begin result := ioJPEG; exit; end; // try user registered file formats for q := 0 to IEGlobalSettings().FileFormats.Count - 1 do with TIEFileFormatInfo(IEGlobalSettings().FileFormats[q]) do if assigned(TryFunction) then begin Stream.Position := lp; if TryFunction(Stream, FileType) then begin result := FileType; break; end; end; Stream.Position := lp; if result <> ioUnknown then exit; // try RAW {$ifdef IEINCLUDERAWFORMATS} if IELibAvailable() and IERAWTryStream(Stream) then begin result := ioRAW; exit; end; {$endif} finally Stream.Position := lp; end; except end; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // load from url type HINTERNET = Pointer; INTERNET_PORT = Word; LPINTERNET_BUFFERS=^INTERNET_BUFFERS; INTERNET_BUFFERS = record dwStructSize: DWORD; Next: LPINTERNET_BUFFERS; lpcszHeader: PAnsiChar; dwHeadersLength: DWORD; dwHeadersTotal: DWORD; lpvBuffer: Pointer; dwBufferLength: DWORD; dwBufferTotal: DWORD; dwOffsetLow: DWORD; dwOffsetHigh: DWORD; end; TInternetCloseHandle = function(hInet: HINTERNET): BOOL; stdcall; TInternetOpen = function(lpszAgent: PAnsiChar; dwAccessType: DWORD; lpszProxy, lpszProxyBypass: PAnsiChar; dwFlags: DWORD): HINTERNET; stdcall; TInternetConnect = function(hInet: HINTERNET; lpszServerName: PAnsiChar; nServerPort: INTERNET_PORT; lpszUsername: PAnsiChar; lpszPassword: PAnsiChar; dwService: DWORD; dwFlags: DWORD; dwContext: DWORD): HINTERNET; stdcall; THttpOpenRequest = function(hConnect: HINTERNET; lpszVerb: PAnsiChar; lpszObjectName: PAnsiChar; lpszVersion: PAnsiChar; lpszReferrer: PAnsiChar; lplpszAcceptTypes: PAnsiChar; dwFlags: DWORD; dwContext: DWORD): HINTERNET; stdcall; THttpSendRequest = function(hRequest: HINTERNET; lpszHeaders: PAnsiChar; dwHeadersLength: DWORD; lpOptional: Pointer; dwOptionalLength: DWORD): BOOL; stdcall; TInternetReadFile = function(hFile: HINTERNET; lpBuffer: Pointer; dwNumberOfBytesToRead: DWORD; var lpdwNumberOfBytesRead: DWORD): BOOL; stdcall; TInternetReadFileEx = function(hFile: HINTERNET; lpBuffersOut: LPINTERNET_BUFFERS; dwFlags: DWORD; dwContext: DWORD): BOOL; stdcall; THttpQueryInfo = function(hRequest: HINTERNET; dwInfoLevel: DWORD; lpvBuffer: Pointer; lpdwBufferLength: PDWORD; lpdwIndex: PDWORD): BOOL; stdcall; TInternetQueryOption = function(hInternet: HINTERNET; dwOption: DWORD; lpBuffer: Pointer; var lpdwBufferLength: DWORD): BOOL; stdcall; TInternetSetOption = function(hInternet: HINTERNET; dwOption: DWORD; lpBuffer: Pointer; dwBufferLength: DWORD): BOOL; stdcall; TInternetGetLastResponseInfo = function(lpdwError: PDWORD; lpszBuffer: PAnsiChar; lpdwBufferLength: PDWORD): BOOL; stdcall; TFtpOpenFile = function(hConnect: HINTERNET; lpszFileName: PAnsiChar; dwAccess: DWORD; dwFlags: DWORD; dwContext: PDWORD): HINTERNET; stdcall; const INTERNET_OPEN_TYPE_DIRECT = 1; INTERNET_SERVICE_FTP = 1; INTERNET_SERVICE_HTTP = 3; INTERNET_OPEN_TYPE_PROXY = 3; INTERNET_FLAG_NO_CACHE_WRITE = $04000000; INTERNET_FLAG_DONT_CACHE = INTERNET_FLAG_NO_CACHE_WRITE; INTERNET_FLAG_KEEP_CONNECTION = $00400000; INTERNET_FLAG_RELOAD = $80000000; HTTP_QUERY_CONTENT_LENGTH = 5; IRF_NO_WAIT = 8; INTERNET_FLAG_ASYNC = $10000000; INTERNET_FLAG_SECURE = $00800000; INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP = $00008000; // ex: https:// to http:// INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS = $00004000; // ex: http:// to https:// INTERNET_FLAG_IGNORE_CERT_DATE_INVALID = $00002000; // expired X509 Cert. INTERNET_FLAG_IGNORE_CERT_CN_INVALID = $00001000; // bad common name in X509 Cert. INTERNET_OPEN_TYPE_PRECONFIG = 0; INTERNET_FLAG_NO_AUTH = $00040000; INTERNET_OPTION_SECURITY_FLAGS = 31; SECURITY_FLAG_IGNORE_REVOCATION = $00000080; SECURITY_FLAG_IGNORE_UNKNOWN_CA = $00000100; SECURITY_FLAG_IGNORE_WRONG_USAGE = $00000200; HTTP_QUERY_CONTENT_TYPE = 1; FTP_TRANSFER_TYPE_BINARY = $00000002; var wininet: THandle; InternetOpen: TInternetOpen; InternetCloseHandle: TInternetCloseHandle; InternetConnect: TInternetConnect; HttpOpenRequest: THttpOpenRequest; HttpSendRequest: THttpSendRequest; HttpQueryInfo: THttpQueryInfo; InternetReadFile: TInternetReadFile; InternetReadFileEx: TInternetReadFileEx; InternetQueryOption: TInternetQueryOption; InternetSetOption: TInternetSetOption; InternetGetLastResponseInfo: TInternetGetLastResponseInfo; FtpOpenFile : TFtpOpenFile; procedure IEInitWinINet; begin if wininet = 0 then begin // try to load the wininet.dll dynamic library wininet := LoadLibrary('wininet.dll'); if wininet <> 0 then begin InternetOpen := GetProcAddress(wininet, 'InternetOpenA'); InternetCloseHandle := GetProcAddress(wininet, 'InternetCloseHandle'); InternetConnect := GetProcAddress(wininet, 'InternetConnectA'); HttpOpenRequest := GetProcAddress(wininet, 'HttpOpenRequestA'); HttpSendRequest := GetProcAddress(wininet, 'HttpSendRequestA'); HttpQueryInfo := GetProcAddress(wininet, 'HttpQueryInfoA'); InternetReadFile := GetProcAddress(wininet, 'InternetReadFile'); InternetReadFileEx := GetProcAddress(wininet, 'InternetReadFileExA'); InternetQueryOption := GetProcAddress(wininet, 'InternetQueryOptionA'); InternetSetOption := GetProcAddress(wininet, 'InternetSetOptionA'); InternetGetLastResponseInfo := GetProcAddress(wininet, 'InternetGetLastResponseInfoA'); FtpOpenFile := GetProcAddress(wininet, 'FtpOpenFileA'); end; end; end; procedure IEFreeWinINet; begin if wininet <> 0 then begin FreeLibrary(wininet); wininet := 0; end; end; // URL: 'http://domain[:port]/resource' (example 'http://www.imageen.com/test.jpg' ) // URL: 'https://domain[:port]/resource' // URL: 'ftp://user:password@domain[:port]/resource' (example 'ftp://user:password@ftp.imageen.com/Pictures/test.jpg') // ProxyAddress: 'domain:port' (example '10.2.7.2:8080' ) function IEGetFromURL(const URL: WideString; OutStream: TStream; const ProxyAddress: WideString; const ProxyUser: WideString; const ProxyPassword: WideString; OnProgress: TIEProgressEvent; Sender: TObject; Aborting: pboolean; var FileExt: String): Boolean; var hint: HINTERNET; hcon: HINTERNET; hreq: HINTERNET; buffer: array of AnsiChar; Host, Page: AnsiString; Port, i, j: integer; ib: INTERNET_BUFFERS; t1: dword; ConnType: TIEURLType; Service: dword; flags: cardinal; OptionsBuffer, OptionsBufferLen: DWORD; bx: cardinal; filetype: AnsiString; userid, password: AnsiString; AURL: AnsiString; tempString: AnsiString; procedure FreeHandles; begin if hreq <> nil then InternetCloseHandle(hreq); if hcon <> nil then InternetCloseHandle(hcon); if hint <> nil then internetCloseHandle(hint); end; begin result := false; ConnType := IEGetURLTypeW(URL); AURL := AnsiString(URL); // remove protocol part and set service type case ConnType of ieurlHTTP: begin delete(AURL, 1, 7); Service := INTERNET_SERVICE_HTTP; end; ieurlHTTPS: begin delete(AURL, 1, 8); Service := INTERNET_SERVICE_HTTP; end; ieurlFTP: begin delete(AURL, 1, 6); Service := INTERNET_SERVICE_FTP; end; else exit; end; userid := ''; password := ''; // extract userid/password, Host, Port and Resource (Page) i := IEPos('/', AURL); if i < 1 then exit; Host := IECopy(AURL, 1, i - 1); Page := IECopy(AURL, i, length(AURL)); Port := 0; i := IEPos('@', Host); if i > 0 then begin // userid/password j := IEPos(':',Host); if j = 0 then exit; userid := IECopy(Host, 1, j-1); password := IECopy(Host, j+1, i-j-1); Host := IECopy(Host, i+1, length(Host)); end; i := IEPos(':', Host); if i > 0 then begin Port := IEStrToIntDef(IECopy(Host, i + 1, length(Host)), 80); Host := IECopy(Host, 1, i - 1); end else begin // default port case ConnType of ieurlHTTP: Port := 80; ieurlHTTPS: Port := 443; ieurlFTP: Port := 21; end; end; hreq := nil; hcon := nil; hint := nil; try if ProxyAddress = '' then begin hint := InternetOpen('Mozilla/4.*', INTERNET_OPEN_TYPE_DIRECT, nil, nil, 0); hcon := InternetConnect(hint, PAnsiChar(AnsiString(Host)), Port, PAnsiChar(AnsiString(userid)), PAnsiChar(AnsiString(password)), Service, 0, 0); end else begin hint := InternetOpen('Mozilla/4.*', INTERNET_OPEN_TYPE_PROXY, PAnsiChar(AnsiString(ProxyAddress)), nil, 0); hcon := InternetConnect(hint, PAnsiChar(AnsiString(Host)), Port, PAnsiChar(AnsiString(ProxyUser)), PAnsiChar(AnsiString(ProxyPassword)), Service, 0, 0); end; if hcon = nil then exit; if (ConnType = ieurlHTTP) or (ConnType = ieurlHTTPS) then begin flags := INTERNET_FLAG_DONT_CACHE or INTERNET_FLAG_KEEP_CONNECTION or INTERNET_FLAG_RELOAD; if ConnType=ieurlHTTPS then flags := flags or INTERNET_FLAG_SECURE or INTERNET_FLAG_IGNORE_CERT_CN_INVALID or INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP or INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS or INTERNET_FLAG_IGNORE_CERT_DATE_INVALID; hreq := HttpOpenRequest(hcon, 'GET', PAnsiChar(AnsiString(Page)), 'HTTP/1.1', nil, nil, flags, 0); if hreq = nil then exit; OptionsBufferLen := sizeof(OptionsBuffer); InternetQueryOption(hreq, INTERNET_OPTION_SECURITY_FLAGS, @OptionsBuffer, OptionsBufferLen); OptionsBuffer := OptionsBuffer or SECURITY_FLAG_IGNORE_UNKNOWN_CA or SECURITY_FLAG_IGNORE_REVOCATION or SECURITY_FLAG_IGNORE_WRONG_USAGE; InternetSetOption(hreq, INTERNET_OPTION_SECURITY_FLAGS, @OptionsBuffer, sizeof(OptionsBuffer)); SetLength(buffer, 65536); HttpSendRequest(hreq, nil, 0, nil, 0); // get file type fileExt := ''; t1 := 65536; if HttpQueryInfo(hreq, HTTP_QUERY_CONTENT_TYPE, @buffer[0], @t1, nil) then begin buffer[t1] := #0; IESetStringA(fileType, @buffer[0], t1); t1 := IEPos('/', fileType); if t1 > 0 then fileExt := string(IECopy(fileType, t1+1, length(fileType))); end; // get file length t1 := 65536; if HttpQueryInfo(hreq, HTTP_QUERY_CONTENT_LENGTH, @buffer[0], @t1, nil) then begin buffer[t1] := #0; IESetStringA(tempString, @buffer[0], t1); t1 := IEStrToIntDef(tempString, 0); end else t1 := 0; end else if (ConnType=ieurlFTP) then begin Page := IECopy(Page, 2, length(Page)); hreq := FtpOpenFile(hcon, PAnsiChar(Page), GENERIC_READ, FTP_TRANSFER_TYPE_BINARY, nil); if hreq = nil then exit; fileExt := string(IECopy(IEExtractFileExtA(Page), 2, 10)); t1 := 0; SetLength(buffer, 65536); end; if t1 <> 0 then begin // we know the size, can load in async mode fillchar(ib, sizeof(ib), 0); ib.dwStructSize := sizeof(ib); repeat ib.lpvBuffer := @buffer[0]; ib.dwBufferLength := 65536; if not InternetReadFileEx(hreq, @ib, IRF_NO_WAIT, 0) then break; if ib.dwBufferLength = 0 then break else begin OutStream.Write(pbyte(ib.lpvBuffer)^, ib.dwBufferLength); if assigned(OnProgress) then OnProgress(Sender, trunc(100 / t1 * OutStream.Size)); end; until (dword(OutStream.Size)>=t1) or (assigned(Aborting) and Aborting^); end else begin // sync mode repeat InternetReadFile(hreq, @buffer[0], 1024, bx); OutStream.Write(buffer[0], bx); until (bx = 0) or (assigned(Aborting) and Aborting^); end; finally FreeHandles; end; result := true; end; {!! DeleteGIFIm Declaration function DeleteGIFIm(const FileName: WideString; idx: Integer): Integer; Description Removes an image at index, idx (zero-based), from a multi-frame GIF file. Returns the remaining number of frames that the file contains. If the FileName doesn't exists or doesn't contain images, it returns 0. Example // Delete the second image in a multipage GIF, named 'multipage.gif'. DeleteGIFIm('C:\multipage.gif', 1); See Also - !!} // Remove the image idx from the specified GIF // returns the remaining images count function DeleteGIFIm(const FileName: WideString; idx: integer): integer; begin result := _DeleteGIFIm(FileName, idx, true); end; {!! DeleteTIFFIm Declaration function DeleteTIFFIm(const FileName: WideString; idx: Integer): Integer; Description Removes an image at index, idx (zero-based), from a multi-frame TIFF file. Returns the remaining number of frames that the file contains. If the FileName doesn't exists or doesn't contain images, it returns 0. Example // Delete the second image in a multipage TIFF, named 'multipage.tif'. DeleteTIFFIm('C:\multipage.tif', 1); See Also - !!} // removes the image idx from the specified tiff // returns the remained images function DeleteTIFFIm(const FileName: WideString; idx: integer): integer; var fs: TIEWideFileStream; begin fs := TIEWideFileStream.Create(FileName, fmOpenReadWrite); try result := TIFFDeleteImStream(fs, idx); finally FreeAndNil(fs); end; end; {!! DeleteDCXIm Declaration procedure DeleteDCXIm(const FileName: WideString; idx: integer); Description Removes an image at index, idx (zero-based), from a multi-frame DCX file. Returns the remaining number of frames that the file contains. If the FileName doesn't exists or doesn't contain images, it returns 0. Example // Delete the second image in a multipage DCX, named 'multipage.dcx'. DeleteDCXIm('C:\multipage.dcx', 1); See Also - !!} procedure DeleteDCXIm(const FileName: WideString; idx: integer); var fs: TIEWideFileStream; begin fs := TIEWideFileStream.Create(FileName, fmOpenReadWrite); try IEDCXDeleteStream(fs, idx); finally FreeAndNil(fs); end; end; {!! DeleteTIFFImGroup Declaration function DeleteTIFFImGroup(const FileName: WideString; Indexes: array of integer): Integer; Description Removes the specified group of pages from the specified file. Indexes is an array of page indexes to remove. Returns the remaining number of frames that FileName file contains. If the FileName doesn't exists or doesn't contain images, it returns 0. !!} function DeleteTIFFImGroup(const FileName: WideString; Indexes: array of integer): integer; var fs: TIEWideFileStream; begin fs := TIEWideFileStream.Create(FileName, fmOpenReadWrite); try result := TIFFDeleteImStreamGroup(fs, @Indexes, high(Indexes) + 1); finally FreeAndNil(fs); end; end; // Enumerates images in the specified GIF {!! EnumGIFIm Declaration function EnumGIFIm(const FileName: WideString): Integer; Description Returns the number of frames (images) that the specified file contains. If the FileName doesn't exist or doesn't contain images, it returns 0. Note: A GIF can contain multiple images even if it is not marked as animated. !!} function EnumGIFIm(const FileName: WideString): integer; begin try result := _DeleteGIFIm(FileName, -1, false); except result := 0; end; end; {!! EnumTIFFIm Declaration function EnumTIFFIm(const FileName: WideString): Integer; Description Returns the number of frames (images) that the specified file contains. If the FileName doesn't exist or doesn't contain images, it returns 0. !!} // Enumerates images in the specified TIFF function EnumTIFFIm(const FileName: WideString): integer; var fs: TIEWideFileStream; begin fs := TIEWideFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try result := TIFFEnumImages(fs); finally FreeAndNil(fs); end; end; {!! EnumDCXIm Declaration function EnumDCXIm(const FileName: WideString): Integer; Description Returns the number of frames (images) that the specified file contains. If the FileName doesn't exist or doesn't contain images, it returns 0. See Also - !!} function EnumDCXIm(const FileName: WideString): integer; var fs: TIEWideFileStream; begin fs := TIEWideFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try result := IEDCXCountStream(fs); finally FreeAndNil(fs); end; end; {!! EnumTIFFStream Declaration function EnumTIFFStream(Stream: TStream): Integer; Description Returns the number of frames (images) that the TIFF Stream contains. !!} function EnumTIFFStream(Stream: TStream): integer; begin result := TIFFEnumImages(Stream); end; {!! EnumICOIm Declaration function EnumICOIm(const FileName: WideString): Integer; Description Returns the number of images inside an ICO file. If the FileName doesn't exist or doesn't contain images, it returns 0. !!} function EnumICOIm(const FileName: WideString): integer; var fs: TIEWideFileStream; begin fs := TIEWideFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try result := _EnumICOImStream(fs); finally FreeAndNil(fs); end; end; {!! CheckAniGIF Declaration function CheckAniGIF(const FileName: WideString): Boolean; Description Returns True if the specified GIF file has the animated flag set (i.e. the "NETSCAPE2.0" string). If the file doesn't exist or if the image hasn't set the flag, it returns False. !!} // Returns True if the specified GIF is animated function CheckAniGIF(const FileName: WideString): boolean; begin try result := _CheckGIFAnimate(string(FileName)); except result := false; end; end; {!! IEWriteICOImages Declaration procedure IEWriteICOImages(const fileName: WideString; images: array of TObject); Description Provides an alternate method to save ICO files (instead of using or ). It allows you to specify the origin of each frame of ICO to be saved. IEWriteICOImages doesn't look at and , but only ... and TImageEnView.IO.Params.. Example // Suppose we have three images, each in a TImageEnView component (e.g. ImageEnView1, ImageEnView2, ImageEnView3) // we want to create an icon of these three images at 32 bit, 8 bit and 4 bit. // 32 bit (24 for colors and 8 for alpha channel) ImageEnView1.IO.Params.BitsPerSample := 4; ImageEnView1.IO.Params.SamplesPerPixel := 3; // 8 bit (256 colors) ImageEnView2.IO.Params.BitsPerSample := 8; ImageEnView2.IO.Params.SamplesPerPixel := 1; // 4 bit (16 colors) ImageEnView3.IO.Params.BitsPerSample := 4; ImageEnView3.IO.Params.SamplesPerPixel := 1; // save all inside a single ICO IEWriteICOImages('output.ico', [ImageEnView1, ImageEnView2, ImageEnView3]); !!} procedure IEWriteICOImages(const fileName: WideString; images: array of TObject); var NullProgress: TProgressRec; fs: TIEWideFileStream; Aborting: boolean; begin NullProgress := NullProgressRec( Aborting ); fs := TIEWideFileStream.Create(fileName, fmCreate); try ICOWriteStream2(fs, images, NullProgress); finally FreeAndNil(fs); end; end; {!! ExtractTIFFImageStream Declaration procedure ExtractTIFFImageStream(SourceStream, OutStream: TStream; idx: Integer); Description Extracts the page, idx, (starting at 0) from SourceStream and saves it to OutStream. It doesn't remove the page from source file; also it doesn't decompress the image resulting in a very quick process. Example // extract first page fr := TFileStream.Create('input_multipage.tif', fmOpenRead); fw := TFileStream.Create('page0.tif', fmCreate); ExtractTIFFImageFile( fr , fw, 0 ); fw.free; fr.free; !!} procedure ExtractTIFFImageStream(SourceStream, OutStream: TStream; idx: integer); begin TIFFExtractImStream(SourceStream, idx, OutStream); end; {!! ExtractTIFFImageFile Declaration procedure ExtractTIFFImageFile(const SourceFileName, OutFileName: WideString; idx: Integer); Description Extracts the page, idx, (starting at 0) from SourceFileName and saves it to OutFileName. It doesn't remove the page from source file; also it doesn't decompress the image resulting in a very quick process. Example ExtractTIFFImageFile( 'input_multipage.tif' , 'page0.tif', 0 ); // extract first page !!} procedure ExtractTIFFImageFile(const SourceFileName, OutFileName: WideString; idx: integer); var SourceStream, OutStream: TIEWideFileStream; begin SourceStream := TIEWideFileStream.Create(SourceFileName, fmOpenRead or fmShareDenyWrite); OutStream := nil; try OutStream := TIEWideFileStream.Create(OutFileName, fmCreate); TIFFExtractImStream(SourceStream, idx, OutStream); finally FreeAndNil(OutStream); end; FreeAndNil(SourceStream); end; {!! InsertTIFFImageStream Declaration procedure InsertTIFFImageStream(SourceStream, InsertingStream, OutStream: TStream; idx: Integer); Description Inserts the TIFF stream InsertingStream into SourceStream, saving the result to OutStream. Idx is the page where to insert the file. As both source and destination images are not de-compressed the operation is very quick. Note: Both TIFFs must have the same byte order. You can check it by reading the image parameters and checking property. !!} procedure InsertTIFFImageStream(SourceStream, InsertingStream, OutStream: TStream; idx: integer); begin TIFFInsertImStream(SourceStream, InsertingStream, idx, OutStream); end; {!! InsertTIFFImageFile Declaration procedure InsertTIFFImageFile(const SourceFileName, InsertingFileName, OutFileName: WideString; idx: Integer); Description Inserts the file InsertingFileName into SourceFileName, saving the result to OutFileName. Idx is the page where to insert the file. As both source and destination images are not de-compressed the operation is very quick. Note: Both TIFFs must have the same byte order. You can check it reading image parameters and checking property. Example // this inserts pagetoinsert.tif in old.tif as first page and save all to new.tif InsertingTIFFImageFile( 'old.tif' , 'pagetoinsert.tif', 'new.tif', 0 ); !!} // InsertingFileName is the page to insert procedure InsertTIFFImageFile(const SourceFileName, InsertingFileName, OutFileName: WideString; idx: integer); var SourceStream, InsertingStream, OutStream: TIEWideFileStream; begin SourceStream := TIEWideFileStream.Create(SourceFileName, fmOpenRead or fmShareDenyWrite); InsertingStream := nil; OutStream := nil; try InsertingStream := TIEWideFileStream.Create(InsertingFileName, fmOpenRead or fmShareDenyWrite); try OutStream := TIEWideFileStream.Create(OutFileName, fmCreate); TIFFInsertImStream(SourceStream, InsertingStream, idx, OutStream); finally FreeAndNil(OutStream); end; finally FreeAndNil(InsertingStream); end; FreeAndNil(SourceStream); end; function IEAdjustDPI(bmp: TIEBitmap; Params: TIOParams; FilteredAdjustDPI: boolean): TIEBitmap; var new_w, new_h: integer; begin result := bmp; with Params do if (DpiX <> DpiY) and (DpiX > 0) and (DpiY > 0) and (bmp.Width > 0) and (bmp.Height > 0) then begin result := TIEBitmap.Create; if Width > Height then begin new_h := trunc((Height / DpiY) * DpiX); new_w := Width; DpiY := DpiX; Height := new_h; end else begin new_w := trunc((Width / DpiX) * DpiY); new_h := Height; DpiX := DpiY; Width := new_w; end; if FilteredAdjustDPI then begin result.Allocate(new_w, new_h, ie24RGB); if bmp.PixelFormat <> ie24RGB then bmp.PixelFormat := ie24RGB; _ResampleEx(bmp, result, nil, IEGlobalSettings().DefaultResampleFilter, nil, nil); end else begin result.Allocate(new_w, new_h, bmp.PixelFormat); _IEBmpStretchEx(bmp, result, nil, nil); end; end; end; {!! IEGetFileFramesCount Declaration function IEGetFileFramesCount(const FileName: WideString): Integer; Description A generic method to get the number of frames in a multi-page images and supported videos (GIF, TIFF, AVI, MPEG...). Notes: - It will work with single page files too (such as JPEG) by returning 1. - The file content is analyzed to determine the image type See Also - !!} function IEGetFileFramesCount(const FileName: WideString): Integer; var ff: Integer; io: TImageEnIO; begin ff := FindFileFormat(FileName, ffFallbackToExtension); if ( ff <> ioAVI ) and ( ff <> ioUnknown ) then begin case ff of ioGIF: result := EnumGifIm(FileName); ioTIFF: result := EnumTIFFIm(FileName); ioICO: result := EnumICOIm(FileName); ioDCX: result := EnumDCXIm(FileName); {$ifdef IEINCLUDEDICOM} ioDICOM: result := IEDicomImageCount(string(FileName)); {$endif} {$ifdef IEINCLUDEWIC} ioHDP: result := IEHDPFrameCount(FileName); {$endif} ioPDF: result := IEPDFFrameCount(FileName); {$ifdef IEINCLUDEMISCPLUGINS} iomscPDF, iomscWPPDF: result := IEPDFFrameCount(FileName); {$endif} else result := 1; // a single page file (jpeg, bmp...) end; end else begin // AVI or multimedia files (Mpeg,...) io := TImageEnIO.Create(nil); try {$ifdef IEINCLUDEDIRECTSHOW} result := io.OpenMediaFile(FileName); io.CloseMediaFile; {$else} // only AVI supported result := io.OpenAVIFile(FileName); io.CloseAVIFile; {$endif} finally FreeAndNil(io); end; end; end; {!! IEFindNumberWithKnownFormat Declaration function IEFindNumberWithKnownFormat( const Directory: WideString ): integer; Description Returns the number of images in a specified folder that are of a format supported by ImageEn. !!} // Returns the number of Images with KnownFormat in a Folder function IEFindNumberWithKnownFormat( const Directory: WideString ): integer; var Found: integer; SR: TSearchRec; FPath: TFileName; begin Result := 0; Found := FindFirst ( Directory + '\*.*', $00000020, SR ); // $00000020=faArchive if Found = 0 then begin while Found = 0 do begin FPath := Directory + '\' + SR.Name; if IsKnownFormat ( FPath ) and ( SR.Attr and $10 = 0 ) then inc ( Result ); Found := FindNext ( SR ); end; FindClose ( SR ); end; end; {!! IECalcJpegFileQuality Declaration function IECalcJpegFileQuality(const FileName: WideString): Integer; Description Estimates the quality that was used for saving a Jpeg file. The returned value can then be used for the property (to maintain a similar quality level). Example ImageEnView1.LoadFromFile('C:\input.jpg'); // do image processing here... ImageEnView1.IO.Params.JPEG_Quality := IECalcJpegFileQuality('C:\input.jpg'); ImageEnView1.IO.SaveToFile('D:\output.jpg'); !!} function IECalcJpegFileQuality(const FileName: WideString): integer; var fs: TIEWideFileStream; begin fs := TIEWideFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try result := IECalcJpegStreamQuality(fs); finally FreeAndNil(fs); end; end; {!! IECalcJpegStreamQuality Declaration function IECalcJpegStreamQuality(Stream: TStream): Integer; Description Estimates the quality that was used for saving a Jpeg file. The returned value can then be used for the property (to maintain a similar quality level). Example ImageEnView1.LoadFromFile('C:\input.jpg'); // do image processing here... ImageEnView1.IO.Params.JPEG_Quality := IECalcJpegFileQuality('C:\input.jpg'); ImageEnView1.IO.SaveToFile('D:\output.jpg'); !!} function IECalcJpegStreamQuality(Stream: TStream): integer; var qt: Pointer; QTables: pintegerarray; QTablesCount: integer; i: integer; begin QTablesCount := IEGetJpegQuality(Stream, qt); QTables := qt; // returns the average of all qtables result := 0; for i := 0 to QTablesCount - 1 do result := result + QTables[i]; result := result div QTablesCount; // freemem(qt); end; {!! GetAllSupportedFileExtensions Declaration function GetAllSupportedFileExtensions(bLoadFormats, bSaveFormats : Boolean; bVideoFormats: Boolean = True) : string Description Returns the extensions of all file formats that are supported by ImageEn in the format "*.jpeg;*.jpg;*.gif;...' Parameter Description bLoadFormats Include formats that ImageEn can load bSaveFormats Include formats that ImageEn can save bVideoFormats Include video formats that ImageEn supports
Example // Get all image and video formats that ImageEn can read sLoadExtensions := GetAllSupportedFileExtensions( True, False, True ); // Get the image formats that ImageEn can save (not videos) sSaveExtensions := GetAllSupportedFileExtensions( False, True, False ); // Create a file filter for JPEG, GIF and all supported files types FilterComboBox1.Filter := 'JPEG Files|' + GetFileExtensionsOfType( ioJPEG ) + '|' + 'GIF Files|' + GetFileExtensionsOfType(i oGIF ) + '|' + 'All Images|' + GetAllSupportedFileExtensions( True, False, False ) + '|' + 'All Files|*.*'; See Also -
!!} function GetAllSupportedFileExtensions(bLoadFormats, bSaveFormats : Boolean; bVideoFormats: Boolean = True) : string; var q: integer; begin result := ''; for q := 0 to IEGlobalSettings().FileFormats.Count - 1 do with TIEFileFormatInfo(IEGlobalSettings().FileFormats[q]) do begin if (Extensions <> '') and ((bSaveFormats and (@WriteFunction <> nil)) or (bLoadFormats and (@ReadFunction <> nil))) then Result := Result + GetFileExtensionsOfType(FileType) + ';'; end; // Video files if bVideoFormats then begin {$ifdef IEINCLUDEDIRECTSHOW} if bLoadFormats then result := result + Supported_Video_File_Extensions else {$endif} result := result + Supported_AVI_File_Extensions; end; // Remove trailing semicolon if Result <> '' then SetLength(Result, Length(Result) - 1); end; {!! GetFileExtensionsOfType Declaration function GetFileExtensionsOfType(FileType: ) : string; Description Returns the extensions of an ImageEn file type in the format "*.jpeg;*.jpg' Example // Create a file filter for JPEG, GIF and all supported files types FilterComboBox1.Filter := 'JPEG Files|' + GetFileExtensionsOfType(ioJPEG) + '|' + 'GIF Files|' + GetFileExtensionsOfType(ioGIF) + '|' + 'All Images|' + GetAllSupportedFileExtensions(True, False, False) + '|' + 'All Files|*.*'; See Also - !!} function GetFileExtensionsOfType(FileType: TIOFileType) : string; var i, cc: integer; begin result := ''; cc := IEFileFormatGetExtCount(FileType); for i := 0 to cc - 1 do Result := Result + '*.' + LowerCase(IEFileFormatGetExt(FileType, i)) + ';'; // Remove trailing semicolon if Result <> '' then SetLength(Result, Length(Result) - 1); end; {!! IEExtToFileFormat Declaration function IEExtToFileFormat(ex: String): ; Description Converts a file extension to a type. See Also - !!} // See also: SingleImageFilenameToFileType function IEExtToFileFormat(const ext: String): TIOFileType; var fpi: TIEFileFormatInfo; begin fpi := IEFileFormatGetInfo2( LowerCase(ext) ); if assigned(fpi) then result := fpi.FileType else if IEFileExtInExtensions(ext, Supported_MPEG_File_Extensions) then result := ioMPEG else if IEFileExtInExtensions(ext, Supported_WMV_File_Extensions) then result := ioWMV else result := ioUnknown; end; function IEFilenameToFileFormat(const FileName: String): TIOFileType; begin Result := IEExtToFileFormat( ExtractFileExt( FileName )); end; {!! IEFileIsOfFormat Declaration function IEFileIsOfFormat(const sFilename : string; aFormat : TIOFileType) : Boolean; Description Returns true if the file has the extension of the specified type. For example: IEFileIsOfFormat('C:\File.avi', ioAVI) would return true See Also - !!} function IEFileIsOfFormat(const sFilename : string; aFormat : TIOFileType) : Boolean; var Ex : string; c: integer; i: Integer; begin if aFormat = ioAVI then result := IEFilenameInExtensions(sFilename, Supported_AVI_File_Extensions) else if aFormat = ioMPEG then result := IEFilenameInExtensions(sFilename, Supported_MPEG_File_Extensions) else if aFormat = ioWMV then result := IEFilenameInExtensions(sFilename, Supported_WMV_File_Extensions) else begin Result := False; Ex := IEExtractFileExtS(sFilename, False); c := IEFileFormatGetExtCount(aFormat); for i := 0 to c - 1 do begin if LowerCase(IEFileFormatGetExt(aFormat, i)) = Ex then begin Result := True; exit; end; end; end; end; {!! IEIsInternalFormat Declaration function IEIsInternalFormat(ex: String): Boolean; Description Returns true if the specified extension is recognized as internal file format (i.e. a format that ImageEn natively supports). See Also - !!} function IEIsInternalFormat(ex: String): Boolean; var fpi: TIEFileFormatInfo; begin fpi := IEFileFormatGetInfo2( LowerCase(ex) ); result := assigned(fpi) and fpi.InternalFormat; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// procedure IEInitialize_iexBitmaps; begin IEGlobalSettings().DefGIF_LZWDECOMPFUNC := GIFLZWDecompress; IEGlobalSettings().DefGIF_LZWCOMPFUNC := GIFLZWCompress; IEGlobalSettings().DefTIFF_LZWDECOMPFUNC := TIFFLZWDecompress; IEGlobalSettings().DefTIFF_LZWCOMPFUNC := TIFFLZWCompress; IEInitFileFormats; gAVIFILEinit := false; {$IFDEF IEINCLUDEIEXACQUIRE} iegTwainLogName := ''; {$ENDIF} wininet := 0; IEInitWinINet; {$IFDEF IEREGISTERTPICTUREFORMATS} IERegisterFormats; {$ENDIF} ioplugins := TList.Create(); CMYKProfile := nil; end; procedure IEFinalize_iexBitmaps; begin IECleanupLayers(); FreeAndNil(CMYKProfile); FreeAndNil(SRGBProfile); {$IFDEF IEREGISTERTPICTUREFORMATS} IEUnregisterFormats; {$ENDIF} IEUnLoadIOPlugins; IEFreeFileFormats; if gAVIFILEinit then AviFileExit; IEFreeWinINet; {$IFDEF IEINCLUDEIEXACQUIRE} if iegTwainLogName <> '' then closefile(iegTwainLogFile); {$ENDIF} FreeAndNil(ioplugins); end; end.