(* 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 1200 *) unit hyieutils; {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} {$R-} {$Q-} {$I ie.inc} interface uses Windows, Messages, Forms, Classes, StdCtrls, Graphics, hyiedefs, SysUtils, Controls, ievision, Contnrs; type {!! TIOFileType Declaration TIOFileType = integer; Description Specifies a file format supported by ImageEn (may be read-write, read-only or write-only). Constant Description ioUnknown Unknown file format ioTIFF TIFF Bitmap ioGIF GIF ioJPEG Jpeg bitmap ioPCX PaintBrush PCX ioBMP Windows Bitmap ioICO Windows Icon ioCUR Windows Cursor ioPNG Portable Network Graphics ioWMF Windows Metafile ioEMF Enhanced Windows Metafile ioTGA Targa Bitmap ioPXM Portable Pixmap, GreyMap, BitMap ioJP2 Jpeg2000 ioJ2K Jpeg2000 ioAVI AVI video ioWBMP Wireless bitmap ioPS Postscript ioPDF Adobe PDF ioSVG Scalable Vector Graphics ioDCX Multipage PCX ioRAW Digital Camera RAW (requires ielib or ievision) ioBMPRAW Bitmap RAW ioWMV Windows Media ioMPEG Video MPEG ioPSD Adobe Photoshop PSD ioIEV Vectorial objects () ioIEN ImageEn native image format with layers (formerly ioLYR) ioALL Combined layers and vectorial objects () ioDICOM DICOM medical imaging ioHDP Microsoft HD Photo. Requires Windows XP (SP2) with .Net 3.0, Windows Vista or newer ioOtherDLLPlugIns + offset External plugins (e.g. JBIG) ioMiscDLLPlugIns + offset Misc External plugins (e.g. PCL) ioUSER + offset User registered file formats
!!} TIOFileType = integer; const // types for TIOFileType ioUnknown = 0; ioTIFF = 1; ioGIF = 2; ioJPEG = 3; ioPCX = 4; ioBMP = 5; ioICO = 6; ioCUR = 7; ioPNG = 8; ioWMF = 9; ioEMF = 10; ioTGA = 11; ioPXM = 12; ioJP2 = 13; ioJ2K = 14; ioAVI = 15; ioWBMP = 16; ioPS = 17; ioPDF = 18; ioDCX = 19; ioRAW = 20; ioBMPRAW = 21; ioWMV = 22; ioMPEG = 23; ioPSD = 24; ioIEV = 25; ioIEN = 26; {$ifdef IEIncludeDeprecatedInV6} ioLYR = ioIEN; {$endif} ioALL = 27; ioDICOM = 28; ioHDP = 29; ioRAS = 30; // sun RAS (supported by ievision) ioSVG = 31; ioOtherDLLPlugIns = 4097; ioMiscDLLPlugIns = 8192; ioUSER = 10000; // Support PDF loading by WP PDF Plug-In const iomscWPPDF = ioMiscDLLPlugIns + 30; // Used only by TImageEnView.LayersImport const ioDXF = 9001; type {!! TIEMTruncSide Declaration } TIEMTruncSide = (iemtsLeft, iemtsRight); {!!} {!! TIEDataAccess Declaration } TIEDataAccess = set of (iedRead, iedWrite); {!!} {!! TIEDitherMethod Declaration } TIEDitherMethod = (ieOrdered, ieThreshold, ieDithering); {!!} {!! TIEHAlign Declaration } TIEHAlign = (iehLeft, iehCenter, iehRight); {!!} {!! TIEVAlign Declaration } TIEVAlign = (ievTop, ievCenter, ievBottom); {!!} {!! TIEPixelFormat Declaration TIEPixelFormat = (ienull, ie1g, ie8p, ie8g, ie16g, ie24RGB, ie32f, ieCMYK, ie48RGB, ieCIELab, ie32RGB); Description Value Description ienull Invalid pixel format. ie1g Black/White (1 bit per pixel). ie8p RGB color with colormap (256 colors, 8 bit per pixel). ie8g Gray scale (256 shades of gray, 8 bit per pixel). ie16g Gray scale (65536 shades of gray, 16 bit per pixel). ie24RGB RGB true color (16M colors, 24 bit per pixel, 8 bit per channel). ie32f Gray scale (0..1 floating point shades of gray, 32 bit per pixel). ieCMYK CMYK color (32 bit per pixel, reversed 8 bit per channel). ie48RGB RGB color (48 bit per pixel, 16 bit per channel). ieCIELab CIELab color (24 bit per pixel, 8 bit per channel). ie32RGB RGBA color (32 bit per pixel, 8 bit per channel, for compatibility with Windows DIB pixel format, last 8 bit unused with some exceptions).
!!} TIEPixelFormat = (ienull, ie1g, // gray scale (black/white) ie8p, // color (palette) ie8g, // gray scale (256 levels) ie16g, // gray scale (65536 levels) ie24RGB, // RGB 24 bit (8 bit per channel) ie32f, // floating point values, 32 bit - Single in Pascal - gray scale ieCMYK, // CMYK (reversed 8 bit values) ie48RGB, // RGB 48 bit (16 bit per channel) ieCIELab, // CIELab (8 bit per channel) ie32RGB // RGB 32 bit (8 bit per channel), last 8 bit are unused with some exceptions ); {!! TIEPixelFormatSet Declaration } TIEPixelFormatSet = set of TIEPixelFormat; {!!} {!! TIECompareFunction Declaration } TIECompareFunction = function(Index1, Index2: integer): integer of object; {!!} {!! TIESwapFunction Declaration } TIESwapFunction = procedure(Index1, Index2: integer) of object; {!!} {!! TIEDialogCenter Declaration } TIEDialogCenter = procedure(Wnd: HWnd); {!!} {!! TFitMethod Declaration } TFitMethod = (_fmFitWithinRect, // Normal Usage: All the image is made to fit within the available area (with border area) _fmFillRect_WithOverlap); // Return an image that may be bigger than the available area but that does not have any border area showing {!!} {!! TIERenderOperation Declaration } TIERenderOperation = ( ielNormal, ielAdd, // Additive ielSub, // Difference ielDiv, ielMul, ielOR, ielAND, ielXOR, ielMAX, // Lighten ielMIN, // Darken ielAverage, ielScreen, ielNegation, ielExclusion, ielOverlay, ielHardLight, ielSoftLight, ielXFader, ielColorEdge, ielColorBurn, ielInverseColorDodge, ielInverseColorBurn, ielSoftDodge, ielSoftBurn, ielReflect, ielGlow, ielFreeze, ielEat, ielSubtractive, ielInterpolation, ielStamp, ielRed, ielGreen, ielBlue, ielHue, ielSaturation, ielColor, ielLuminosity, ielStereoBW, ielStereoColor, ielStereoColorDubois, ielStereoEven, ielStereoOdd, ielLuminosity2 ); {!!} {!! TIEOpSys Declaration } TIEOpSys = (ieosWin95, ieosWin98, ieosWinME, ieosWinNT4, ieosWin2000, ieosWinXP, ieosWin2003, ieosWinVista, ieosWin7, ieosWin8, ieosWin10, ieosUnknown); {!!} TIEShadowType = (iestNone, iestSolid, iestSmooth1, iestSmooth2); {!! TPreviewParams Declaration type TPreviewParams = set of (ppALL, ppAUTO, ppJPEG, ppTIFF, ppGIF, ppBMP, ppPCX, ppPNG, ppTGA, ppJ2000); Description Specify which pages are included in the IO Parameters dialog: Value Description ppALL Show all pages ppAUTO Show the relevant page for the current file type (i.e. as specified in Params.FileType) ppJPEG Show JPEG parameters ppTIFF Show TIFF paramaters ppGIF Show GIF (non-animated) parameters ppBMP Show BMP parameters ppPCX Show PCX parameters ppPNG Show PNG parameters ppTGA Show TGA parameters ppJ2000 Show JPEG2000 parameters
!!} TPreviewParams = set of ( ppALL, ppAUTO, ppJPEG, ppTIFF, ppGIF, ppBMP, ppPCX, ppPNG, ppTGA {$IFDEF IEINCLUDEJPEG2000} , ppJ2000 {$ENDIF} ); // previews properties {!! TIOPreviewsParamsItems Declaration TIOPreviewsParamsItems = (ioppDefaultLockPreview, ioppApplyButton); Description Value Description ioppDefaultLockPreview Enable "Lock preview" by default ioppApplyButton Display an "Apply" button
Example // Show preview by default ImageEnView1.IO.PreviewsParams := ImageEnView1.IO.PreviewsParams + [ ioppDefaultLockPreview ]; !!} TIOPreviewsParamsItems = (ioppDefaultLockPreview, ioppApplyButton); {!! TIOPreviewsParams Declaration TIOPreviewsParams = set of
; Description Value Description ioppDefaultLockPreview Enable "Lock preview" by default ioppApplyButton Display an "Apply" button
Example // Show preview by default ImageEnView1.IO.PreviewsParams := ImageEnView1.IO.PreviewsParams + [ ioppDefaultLockPreview ]; !!} TIOPreviewsParams = set of TIOPreviewsParamsItems; {!! TImageEnPaletteDialog Description TImageEnPaletteDialog is a dialog that shows a color palette and allows a color to be selected from it. See also:
Methods !!} TImageEnPaletteDialog = class(TForm) private MouseCol: integer; fPalette: PRGBROW; fNumCol: integer; procedure FormPaint(Sender: TObject); procedure FormMouseMove(Sender: TObject; Shift: TShiftState; x, y: integer); procedure FormClick(Sender: TObject); public ButtonCancel: TButton; SelCol: TColor; property NumCol: integer read MouseCol; constructor Create(AOwner: TComponent); override; procedure SetPalette(var Palette: array of TRGB; NumCol: integer); function Execute: boolean; end; TIEWideStrings = class private fStrings: TList; function CreateCopyBuffer(const S: WideString): PWideChar; function GetCount: integer; function GetString(idx: integer): WideString; procedure SetString(idx: integer; const S: WideString); public constructor Create; destructor Destroy; override; procedure Clear; property Count: integer read GetCount; function Add(const S: WideString): integer; property Strings[idx: integer]: WideString read GetString write SetString; default; end; { Example: var dir: TIEDirContent; sFilename : WideString; begin dir := TIEDirContent.Create('C:\images\*.jpg'); while dir.GetItem(sFilename) do begin Memo.Lines.Add(sFileName); end; dir.free; end; } TIEDirContent = class private fFirstGot : boolean; fHandle : THandle; fFindData : WIN32_FIND_DATAW; fIsDir : boolean; fIsHidden : boolean; fFileSizeBytes : Int64; fCreateDate : TDateTime; fEditDate : TDateTime; public constructor Create(const dir: WideString); destructor Destroy; override; function GetItem(out sFilename : WideString; bGetFiles: boolean = True; bGetDirs: boolean = False; bGetHidden : Boolean = True): boolean; property IsFolder : boolean read fIsDir; property IsHiddenFile : boolean read fIsHidden; property FileSizeBytes : Int64 read fFileSizeBytes; property CreateDate : TDateTime read fCreateDate; property EditDate : TDateTime read fEditDate; class procedure PopulateStrings(const path: WideString; strings: TStrings; bGetFiles: boolean = True; bGetDirs: boolean = False; bGetHidden : Boolean = True); end; ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// // TIEExecutor // // A thread that can be or not be a thread! TIEExecutorFunc = procedure() of object; {$HINTS OFF} TIEExecutorThread = class(TThread) private fExecFunc: TIEExecutorFunc; constructor Create(execFunc: TIEExecutorFunc); procedure Execute(); override; end; {$HINTS ON} TIEExecutor = class private fThread: TIEExecutorThread; public constructor Create(execInThread: Boolean); destructor Destroy(); override; procedure Execute(); virtual; abstract; function GetThread(): TThread; end; ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// // TIEThreadPool TIEThreadPool = class private fThreads: TList; function GetThreads(idx: integer): TIEExecutor; public constructor Create(); destructor Destroy; override; procedure Add(Thread: TIEExecutor); procedure Join(); procedure WaitFor(); property Threads[idx: integer]: TIEExecutor read GetThreads; default; end; // TIEThreadPool ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // TIEDictionary TIEStrHashFunction = function (const str: WideString; bucketCount: cardinal): cardinal; TIEDictionaryValueWideString = class value: WideString; constructor Create(value: WideString); destructor Destroy(); override; end; TIEDictionaryValueInteger = class value: integer; constructor Create(value: integer); destructor Destroy(); override; end; TIEDictionaryValueDouble = class value: double; constructor Create(value: double); destructor Destroy(); override; end; TIEDictionaryValueBoolean = class value: boolean; constructor Create(value: boolean); destructor Destroy(); override; end; TIEDictionaryBucket = class key: WideString; value: TObject; next: TIEDictionaryBucket; constructor Create(const key_: WideString; const value_: TObject; next_: TIEDictionaryBucket = nil); overload; destructor Destroy(); override; end; TIEStrStrEnumerator = class bucket: cardinal; item: TIEDictionaryBucket; constructor Create(); destructor Destroy(); override; end; {!! TIEDictionaryParserLang Declaration } TIEDictionaryParserLang = (ieplJSON, ieplXML); {!!} {!! TIEDictionary Declaration TIEDictionary = class; Description TIEDictionary is a String->Object dictionary (hashmap). It can import/export key-values in a JSON-like (not fully compatible yet) style. Methods and Properties Example var dict: TIEDictionary; begin dict := TIEDictionary.Create(); dict.Insert('doublekey', 10.1); dict.Insert('integerkey', 100); dict.Insert('stringkey', 'hello'); dict.Insert('bool_true', true); dict.Insert('bool_false', false); dict.Insert('dict', TIEDictionary.Create()); dict.GetDictionary('dict').Insert('one', 1); dict.GetDictionary('dict').Insert('two', 'two'); dict.Insert('list', TObjectList.Create()); dict.GetList('list').Add( TIEDictionaryValueWideString.Create('mike') ); dict.GetList('list').Add( TIEDictionaryValueWideString.Create('robert') ); dict.GetList('list').Add( TIEDictionaryValueWideString.Create('john') ); dict.GetList('list').Add( TIEDictionaryValueInteger.Create(2013) ); memo1.lines.add(dict.dump()); dict.free; end; !!} TIEDictionary = class private m_initDone: boolean; m_bucketCount: cardinal; m_buckets: array of TIEDictionaryBucket; m_hashFunction: TIEStrHashFunction; m_caseSensitive: boolean; m_count: integer; procedure CheckInit(); function GetInBucket(bucket: cardinal; key: WideString; out lastItem: TIEDictionaryBucket): TIEDictionaryBucket; function DumpJSON(obj: TObject): WideString; overload; function DumpJSON(obj: TObjectList): WideString; overload; function DumpJSON(): WideString; overload; function DumpXML(obj: TObject): WideString; overload; function DumpXML(obj: TObjectList): WideString; overload; function DumpXML(): WideString; overload; function EncodeString(Text: WideString): WideString; function FindInDictionaries(key: WideString): TObject; function execHash(const str: WideString; bucketCount: cardinal): cardinal; function keysMatch(const key1: WideString; const key2: WideString): boolean; public constructor Create(buckets: cardinal; hashFunction: TIEStrHashFunction; caseSensitive: boolean = false); overload; constructor Create(buckets: cardinal = 103; caseSensitive: boolean = false); overload; destructor Destroy(); override; procedure Clear(); function IsEmpty(): boolean; function HasKey(key: WideString; recursive: boolean = true): boolean; function Get(key: WideString; silent: boolean = false; recursive: boolean = true): TObject; function GetString(key: WideString; recursive: boolean = true): WideString; function GetInteger(key: WideString; recursive: boolean = true): integer; function GetDouble(key: WideString; recursive: boolean = true): double; function GetBoolean(key: WideString; recursive: boolean = true): boolean; function GetDictionary(key: WideString; recursive: boolean = true): TIEDictionary; function GetList(key: WideString; recursive: boolean = true): TObjectList; procedure Insert(key: WideString; value: TObject); overload; procedure Insert(key: WideString; value: WideString); overload; procedure Insert(key: WideString; value: integer); overload; procedure Insert(key: WideString; value: double); overload; procedure Insert(key: WideString; value: boolean); overload; procedure Insert(key: WideString; value: TIEDictionary); overload; procedure Insert(key: WideString; value: TObjectList); overload; function Erase(key: WideString; freeValue: boolean = true): boolean; {!! TIEDictionary.Count Declaration property Count: integer; Description Returns the number of entries in the dictionary. !!} property Count: integer read m_Count; function GetNext(current: TIEStrStrEnumerator): boolean; function Dump(dumpType: TIEDictionaryParserLang): WideString; function Parse(text: WideString): boolean; procedure Assign(Source: TIEDictionary); end; TIEDictionaryParser = class private m_text: WideString; m_textLen: integer; m_textPos: integer; m_abort: boolean; m_lang: TIEDictionaryParserLang; procedure AbortParse(); function IsToken(c: WideChar): boolean; function IsSpace(c: WideChar): boolean; procedure ByPassSpaces(); function HasChar(): boolean; function GetChar(): WideChar; function PeekChar(): WideChar; function GetToken(): WideChar; function PeekToken(): WideChar; function GetString(): WideString; function ParseString(): TIEDictionaryValueWideString; function ParseIdentifier(): TObject; function SavePos(): integer; procedure RestorePos(pos: integer); function DecodeString(Text: WideString): WideString; function JSON_ParseDictionary(mergeWith: TIEDictionary = nil): TIEDictionary; function JSON_ParseValue(): TObject; function JSON_ParseArray(): TObjectList; function XML_ParseContent(mergeWith: TIEDictionary = nil): TIEDictionary; function XML_GetName(): WideString; function XML_ParseAttributes(): TIEDictionary; public constructor Create(Text: WideString); function Parse(mergeWith: TIEDictionary = nil): TIEDictionary; property Aborted: boolean read m_abort; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEHashStream {!! TIEHashAlgorithm Declaration TIEHashAlgorithm = ( iehaMD2, // MD2 hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. iehaMD4, // MD4 hashing algorithm. iehaMD5, // MD5 hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. iehaSHA // SHA hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. ); !!} {$ifdef IEHASCONSTENUM} TIEHashAlgorithm = ( iehaMD2 = $00008001, // MD2 hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. iehaMD4 = $00008002, // MD4 hashing algorithm. iehaMD5 = $00008003, // MD5 hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. iehaSHA = $00008004 // SHA hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. ); {$else} type TIEHashAlgorithm = integer; const iehaMD2 = $00008001; // MD2 hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. const iehaMD4 = $00008002; // MD4 hashing algorithm. const iehaMD5 = $00008003; // MD5 hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. const iehaSHA = $00008004; // SHA hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. {$endif} type {!! TIEHashStream Description Builds a hash string from a stream. Hash algorithm can be MD2, MD4, MD5 and SHA. Examples // saves the file with an unique name (create hash from the jpeg content and use it as file name) var hashStream: TIEHashStream; begin hashStream := TIEHashStream.Create(iehaMD5); try ImageEnView1.IO.SaveToStreamJpeg(hashStream); hashStream.SaveToFile(hashStream.GetHash()+'.jpg'); finally hashStream.Free; end; end; Methods and Properties !!} TIEHashStream = class(TStream) private m_MemStream: TMemoryStream; m_CryptProvider: pointer; m_CryptHash: pointer; public constructor Create(Algorithm: TIEHashAlgorithm=iehaMD5; Buffered: boolean=true); destructor Destroy; override; function GetHash: AnsiString; function Write(const Buffer; Count: longint): longint; override; function Read(var 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} procedure SaveToFile(const filename: WideString); procedure SaveToStream(Stream: TStream); procedure LoadFromFile(const filename: WideString); procedure LoadFromStream(Stream: TStream); end; // TIEHashStream ///////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // a memorystream that doesn't create the memory space (and doesn't free it) TIEMemStream = class(TCustomMemoryStream) public constructor Create(Ptr: pointer; Size: integer); procedure SetSize(NewSize: Longint); override; function Write(const Buffer; Count: Longint): Longint; override; end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEScrollBarParams {!! TIEScrollBarParams Description Allows an application to customize the scrollbar behavior, including tracking (display refresh on mouse dragging), up/down buttons pixel scroll, pagedown/up pixel scroll. Properties - - - !!} TIEScrollBarParams = class private fLineStep: integer; // click on up/down/left/right (-1=default size) fPageStep: integer; // page step (-1=default size) fTracking: boolean; // scroll-bar updates display in real-time (true=default) public constructor Create; destructor Destroy; override; {!! TIEScrollBarParams.LineStep Declaration property LineStep: integer; Description Specifies the number of pixels to scroll when the user clicks the Up or Down button on the scroll bar. Setting the property to -1 will make the control scroll one thumbnail per click. Default: -1 !!} property LineStep: integer read fLineStep write fLineStep; {!! TIEScrollBarParams.PageStep Declaration property PageStep: integer; Description Specifies is the number of pixels to scroll when the user clicks near the cursor (PAGEUP or PAGEDOWN). Setting the property to -1 will make the control scroll by one page (i.e. client height) per click. Default: -1 !!} property PageStep: integer read fPageStep write fPageStep; {!! TIEScrollBarParams.Tracking Declaration property Tracking: boolean Description Set False to disable display refreshing during mouse dragging. Default: True !!} property Tracking: boolean read fTracking write fTracking; end; // TIEScrollBarParams /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEMouseWheelParams {!! TIEMouseWheelParamsAction Declaration TIEMouseWheelParamsAction = (iemwNone, iemwVScroll, iemwZoom, iemwNavigate, iemwZoomView); Description The effect that rolling the mouse wheel has upon a control. Value Description iemwNone Mouse wheel has no effect iemwVScroll Scroll the control up/down iemwZoom Enlarge/Reduce the image (TImageEnView) or thumbnails (TImageEnMView) iemwZoomView In TImageEnMView this cycles through the common display styles and sizes. With TImageEnView it works the same way as iemwZoom iemwNavigate Navigate to the next/previous image. Note: In this is only relevant for images with multiple frames such as TIFFs and GIFs
!!} TIEMouseWheelParamsAction = (iemwNone, iemwVScroll, iemwZoom, iemwNavigate, iemwZoomView); {!! TIEMouseWheelParamsVariation Declaration } TIEMouseWheelParamsVariation = (iemwAbsolute, iemwPercentage); {!!} {!! TIEMouseWheelParamsZoomPosition Declaration } TIEMouseWheelParamsZoomPosition = (iemwCenter, iemwMouse); {!!} {!! TIEMouseWheelParams Description Properties to customize the mouse wheel behavior. Properties - - - - - !!} TIEMouseWheelParams = class( TPersistent ) private fInvertDirection: boolean; fAction: TIEMouseWheelParamsAction; fVariation: TIEMouseWheelParamsVariation; fValue: integer; fZoomPosition: TIEMouseWheelParamsZoomPosition; public procedure Assign(Source: TPersistent); override; constructor Create(DefaultAction : TIEMouseWheelParamsAction); destructor Destroy; override; published {!! TIEMouseWheelParams.InvertDirection Declaration property InvertDirection: boolean; Description Set to True to invert the wheel direction. Default: False !!} property InvertDirection: boolean read fInvertDirection write fInvertDirection default False; {!! TIEMouseWheelParams.Action Declaration property Action: ; Description Action specifies the task to perform on mouse wheel events. Value Description iemwNone Mouse wheel has no effect iemwVScroll Scroll the control up/down iemwZoom Enlarge/Reduce the image (TImageEnView) or thumbnails (TImageEnMView) iemwZoomView In TImageEnMView this cycles through the common display styles and sizes. With TImageEnView it works the same way as iemwZoom iemwNavigate Navigate to the next/previous image. Note: In this is only relevant for images with multiple frames such as TIFFs and GIFs
TImageEnView default: iemwZoom TImageEnMView default: iemwVScroll TImageEnMView default (Alt): iemwZoom !!} property Action: TIEMouseWheelParamsAction read fAction write fAction; // No default {!! TIEMouseWheelParams.Variation Declaration property Variation: ; Description Specifies how much scrolling or zooming occurs in response to mouse wheel rotation Value Description iemwAbsolute contains the absolute value to add or subtract from the current value iemwPercentage contains the percentage of variation from the current value
Default: iemwPercentage Notes: - In the case of , the height is actually based on a theoretical grid of 12.5 thumbnails high. So if iemwPercentage is used 8% equates to scrolling one thumbnail per wheel click, whereas 4% would scroll 1/2 a thumbnail - Has no effect if is iemwNavigate !!} property Variation: TIEMouseWheelParamsVariation read fVariation write fVariation default iemwPercentage; {!! TIEMouseWheelParams.Value Declaration property Value: integer; Description Specifies the Value or percentage of variation. Setting for Description iemwAbsolute value is a specific value to zoom (percentage points) or scroll (pixels) the image iemwPercentage value refers to the percentage to increase or decrease the zoom, or the percentage of the window to scroll (e.g. the default of 8 will scroll the window 8% with each mouse wheel click)
Default: 8 Notes: - In the case of , the height is actually based on a theoretical grid of 12.5 thumbnails high. So if iemwPercentage is used 8% equates to scrolling one thumbnail per wheel click, whereas 4% would scroll 1/2 a thumbnail - Has no effect if is iemwNavigate !!} property Value: integer read fValue write fValue default 8; // value or percentage of variation {!! TIEMouseWheelParams.ZoomPosition Declaration property ZoomPosition: ; Description If Action is iemwZoom, ZoomPosition specifies where the zoom acts. The default is the center of the control, otherwise (iemwMouse) zooms from the mouse’s position. Default: iemwCenter Note: Has no effect with !!} property ZoomPosition: TIEMouseWheelParamsZoomPosition read fZoomPosition write fZoomPosition default iemwCenter; end; // TIEMouseWheelParams /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TIEClientSocket = class private m_socket: pointer; m_littleEndian: boolean; function GetConnected: boolean; public constructor Create; destructor Destroy; override; // options property LittleEndian: boolean read m_littleEndian write m_littleEndian; // receive procedure ReceiveBuffer(buf: pointer; len: integer); function ReceiveBufferSilent(buf: pointer; len: integer): Boolean; procedure ReceivePad(len: integer); function ReceiveByte(): byte; function ReceiveByteSilent(var b: Byte): Boolean; function ReceiveWord(): word; function ReceiveDWord(): dword; // send procedure SendBuffer(buf: pointer; len: integer); procedure SendPad(len: integer); procedure SendByte(value: byte); procedure SendWord(value: word); procedure SendDWord(value: dword); // connect/disconnect procedure Connect(const Address: string; Port: word); procedure Disconnect(); property Connected: boolean read GetConnected; end; TIEByteArray = class private fSize: integer; // size of datas fRSize: integer; // size of allocated buffer fBlockSize: integer; // allocation block size procedure SetSize(v: integer); public Data: pbytearray; constructor Create(InitBlockSize: integer=8192); destructor Destroy; override; procedure AddByte(v: byte); property Size: integer read fSize write SetSize; property BlockSize: integer read fBlockSize write fBlockSize; procedure Clear; function AppendFromStream(Stream: TStream; Count: integer): integer; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// /// TIEIntegerMap (uses integer as keys, integer as values) // handles hash code for numeric values TIEIntegerMapItem = class key: integer; value: integer; nextitem: TIEIntegerMapItem; // nil=end of list end; TIEIntegerMap = class private fItems: array of TIEIntegerMapItem; fIterateIndex: integer; fIterateItem: TIEIntegerMapItem; fKeysCount: integer; function HashFunc(key: integer): integer; public constructor Create(bucketsCount: integer = 262144); destructor Destroy(); override; function Insert(key: integer): boolean; overload; function Insert(key: integer; var item: TIEIntegerMapItem): boolean; overload; function KeyExists(key: integer): boolean; overload; property KeysCount: integer read fKeysCount; procedure Clear(); function IterateBegin(): boolean; function IterateNext(): boolean; function IterateGetKey(): integer; overload; function IterateGetValue(): integer; overload; function DumpStats(): string; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// // TIERGBMap (uses TRGB as keys, integer as values) TIERGBMap = class(TIEIntegerMap) public function Insert(const key: TRGB): boolean; overload; function Insert(const key: TRGB; value: integer): boolean; overload; function KeyExists(const key: TRGB): boolean; overload; function IterateGetKey(): TRGB; overload; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// TNulStream = class(TStream) private fposition: integer; fsize: integer; public constructor Create; destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(Offset: Longint; Origin: Word): Longint; override; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// /// TIELIST and associated classes TIEListChanges = set of (ielItems, ielRange, ielCurrentValue); TIEListCurrentValueEvent = procedure(Sender: TObject; Value: pointer) of object; {!! TIEListSortCompareFunc Declaration } TIEListSortCompareFunc = function(Item1, Item2: Pointer): Integer of object; {!!} {!! TIEList Description This is the abstract class for and . Implemented Methods Implemented Properties !!} // abstract class for IE lists TIEList = class private fCapacity: integer; fCount: integer; fOnGetCurrentValue: TIEListCurrentValueEvent; fOnSetCurrentValue: TIEListCurrentValueEvent; procedure ListQuickSort(L, R: Integer; SCompare: TIEListSortCompareFunc); protected fItemSize: integer; // sizeof(...) fData: pointer; fChanged: TIEListChanges; procedure SetCount(v: integer); virtual; function AddItem(v: pointer): integer; procedure InsertItem(idx: integer; v: pointer); function IndexOfItem(v: pointer): integer; function BaseGetItem(idx: integer): pointer; procedure BaseSetItem(idx: integer; v: pointer); procedure DoGetCurrentValue(value: pointer); procedure DoSetCurrentValue(value: pointer); constructor Create(OnGetCurrentValue: TIEListCurrentValueEvent = nil; OnSetCurrentValue: TIEListCurrentValueEvent = nil); public destructor Destroy; override; procedure Delete(idx: integer); virtual; procedure ExchangeItems(idx1, idx2: integer); property Count: integer read fCount write SetCount; procedure Clear; virtual; procedure Assign(Source: TIEList); virtual; procedure Sort(Compare: TIEListSortCompareFunc); {!! TIEList.Changed Declaration property Changed: TIEListChanges; Description Changed is True whenever the items array, Range or CurrentValue changes. !!} property Changed: TIEListChanges read fChanged write fChanged; end; {!! TIEDoubleList Declaration TIEDoubleList = class(); Description TIEDoubleList is a list of double values. You can handle this object as a standard TList object. An ImageEn list contains an array of values, a current value (not an index of the array), and an allowed range of values. Methods and Properties (inherited from TIEList) !!} TIEDoubleList = class(TIEList) private fRangeMin: double; fRangeMax: double; fRangeStep: double; fCurrentValue: double; function GetItem(idx: integer): double; procedure SetItem(idx: integer; v: double); procedure SetRangeMax(v: double); procedure SetRangeMin(v: double); procedure SetRangeStep(v: double); procedure SetCurrentValue(v: double); function GetCurrentValue(): double; public constructor Create(OnGetCurrentValue: TIEListCurrentValueEvent = nil; OnSetCurrentValue: TIEListCurrentValueEvent = nil); overload; function Add(v: double): integer; procedure Insert(idx: integer; v: double); procedure Clear; override; function IndexOf(v: double): integer; property RangeMin: double read fRangeMin write SetRangeMin; property RangeMax: double read fRangeMax write SetRangeMax; property RangeStep: double read fRangeStep write SetRangeStep; property Items[idx: integer]: double read GetItem write SetItem; default; procedure Assign(Source: TIEList); override; property CurrentValue: double read GetCurrentValue write SetCurrentValue; end; {!! TIEIntegerList Declaration TIEIntegerList = class(); Description TIEIntegerList is a list of integer values. You can handle this object as a standard TList object. An ImageEn list contains an array of values, a current value (not an index of the array), and an allowed range of values. Methods and Properties (inherited from TIEList) !!} TIEIntegerList = class(TIEList) private fRangeMin: integer; fRangeMax: integer; fRangeStep: integer; fCurrentValue: integer; function GetItem(idx: integer): integer; procedure SetItem(idx: integer; v: integer); procedure SetRangeMax(v: integer); procedure SetRangeMin(v: integer); procedure SetRangeStep(v: integer); procedure SetCurrentValue(v: integer); function GetCurrentValue(): integer; public constructor Create(OnGetCurrentValue: TIEListCurrentValueEvent = nil; OnSetCurrentValue: TIEListCurrentValueEvent = nil); overload; function Add(v: integer): integer; procedure Insert(idx: integer; v: integer); procedure Clear; override; function IndexOf(v: integer): integer; property RangeMin: integer read fRangeMin write SetRangeMin; property RangeMax: integer read fRangeMax write SetRangeMax; property RangeStep: integer read fRangeStep write SetRangeStep; property Items[idx: integer]: integer read GetItem write SetItem; default; procedure Assign(Source: TIEList); override; property CurrentValue: integer read GetCurrentValue write SetCurrentValue; end; TIERecordList = class(TIEList) private function GetItem(idx: integer): pointer; procedure SetItem(idx: integer; v: pointer); public constructor Create(RecordSize: integer; OnGetCurrentValue: TIEListCurrentValueEvent = nil; OnSetCurrentValue: TIEListCurrentValueEvent = nil); overload; function Add(v: pointer): integer; procedure Insert(idx: integer; v: pointer); function IndexOf(v: pointer): integer; property Items[idx: integer]: pointer read GetItem write SetItem; default; end; /// TIELIST and associated classes ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// TIETemporaryFileStream = class(THandleStream) private FHandle: THandle; public constructor Create(const FileName: string); destructor Destroy; override; end; TIEWideFileStream = class(THandleStream) private FFileName: WideString; public constructor Create(const FileName: WideString; Mode: Word); destructor Destroy; override; property FileName: WideString read FFileName; end; TIEFileBufferItem = record Pos: int64; // buffer position inside the file Size: int64; // buffer size ptr: pointer; // allocated buffer access: TIEDataAccess; end; PIEFileBufferItem = ^TIEFileBufferItem; // emulates a memory mapped file TIEFileBuffer = class private function IndexOf(ptr: pointer): integer; public fSimFile: TStream; // 3.0.3, can be TIETemporaryFileStream or TMemoryStream fFileName: string; fMapped: TList; // list of TIEFileBufferItem structures constructor Create; destructor Destroy; override; function AllocateFile(InSize: int64; const Descriptor: string; UseDisk: boolean): boolean; procedure ReAllocateFile(NewSize: int64); function Map(InPos, InSize: int64; DataAccess: TIEDataAccess): pointer; procedure UnMap(ptr: pointer); procedure UnMapAll; function IsAllocated: boolean; procedure DeAllocate; procedure CopyTo(Dest: TIEFileBuffer; InPos, InSize: int64); overload; procedure CopyTo(Dest: TStream; InPos, InSize: int64); overload; procedure CopyFrom(DestPos: int64; Source: pointer; Size: int64); end; {$ifdef IEINCLUDERESOURCEEXTRACTOR} {!! TIEResourceBookmark Demo Demos\InputOutput\ResourceLoader\ResourceLoader.dpr Methods and properties - - - !!} TIEResourceBookmark = class private m_TypeIndex: integer; m_NameIndex: integer; m_FrameIndex: integer; public {!! TIEResourceBookmark.TypeIndex Declaration property TypeIndex: integer; Description Resource type index of this bookmark. !!} property TypeIndex: integer read m_TypeIndex; {!! TIEResourceBookmark.NameIndex Declaration property NameIndex: integer; Description Resource name index of this bookmark. !!} property NameIndex: integer read m_NameIndex; {!! TIEResourceBookmark.FrameIndex Declaration property FrameIndex: integer; Description Frame index of a grouped resource of this bookmark. !!} property FrameIndex: integer read m_FrameIndex; constructor Create(TypeIndex_, NameIndex_, FrameIndex_: integer); end; {!! TIEResourceExtractor Description TIEResourceExtractor class helps to extract resources from a PE files like EXE, DLL, OCX, ICL, BPL, etc.. In details, it is intended to extract Icons, Bitmaps, Cursors and other image resources. Demo Demos\InputOutput\ResourceLoader\ResourceLoader.dpr Example // loads resource 143, in "Bitmap"s, from "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; Methods and Properties !!} TIEResourceExtractor = class private m_hlib: THandle; m_typesList: TStringList; m_resourceBookmarks: TList; function GetTypesCount: integer; function GetNamesCount(TypeIndex: integer): integer; function GetTypes(TypeIndex: integer): AnsiString; function GetNames(TypeIndex: integer; NameIndex: integer): AnsiString; function GetFriendlyTypes(TypeIndex: integer): AnsiString; function GetIsValid: boolean; function GetGroupCountFrames(TypeIndex: integer; NameIndex: integer): integer; function GetGroupFrameWidth(TypeIndex: integer; NameIndex: integer; FrameIndex: integer): integer; function GetGroupFrameHeight(TypeIndex: integer; NameIndex: integer; FrameIndex: integer): integer; function GetGroupFrameDepth(TypeIndex: integer; NameIndex: integer; FrameIndex: integer): integer; function GetGroupFrameName(TypeIndex: integer; NameIndex: integer; FrameIndex: integer): AnsiString; function GetIsGroup(TypeIndex: integer): boolean; function GetIsGrouped(TypeIndex: integer): boolean; public constructor Create(const Filename: WideString); destructor Destroy; override; property TypesCount: integer read GetTypesCount; property Types[TypeIndex: integer]: AnsiString read GetTypes; property FriendlyTypes[TypeIndex: integer]: AnsiString read GetFriendlyTypes; property NamesCount[TypeIndex: integer]: integer read GetNamesCount; property Names[TypeIndex: integer; NameIndex: integer]: AnsiString read GetNames; function GetBuffer(TypeIndex: integer; NameIndex: integer; var BufferLength: integer): pointer; overload; function GetBuffer(const TypeStr: AnsiString; const NameStr: AnsiString; var BufferLength: integer): pointer; overload; function GetBuffer(ResourceBookmark: TIEResourceBookmark; var BufferLength: integer): pointer; overload; property IsValid: boolean read GetIsValid; property IsGroup[TypeIndex: integer]: boolean read GetIsGroup; property IsGrouped[TypeIndex: integer]: boolean read GetIsGrouped; property GroupCountFrames[TypeIndex: integer; NameIndex: integer]: integer read GetGroupCountFrames; // number of frames for specified icon/cursor property GroupFrameWidth[TypeIndex: integer; NameIndex: integer; FrameIndex: integer]: integer read GetGroupFrameWidth; property GroupFrameHeight[TypeIndex: integer; NameIndex: integer; FrameIndex: integer]: integer read GetGroupFrameHeight; property GroupFrameDepth[TypeIndex: integer; NameIndex: integer; FrameIndex: integer]: integer read GetGroupFrameDepth; property GroupFrameName[TypeIndex: integer; NameIndex: integer; FrameIndex: integer]: AnsiString read GetGroupFrameName; procedure GetGroupAndFrame(TypeIndex: integer; NameIndex: integer; var GroupTypeIndex: integer; var GroupIndex: integer; var GroupFrameIndex: integer); function IndexOfType(TypeName: AnsiString): integer; function GetFrameBuffer(TypeIndex: integer; NameIndex: integer; FrameIndex: integer; var BufferLength: integer): pointer; function GetResourceBookmark(TypeIndex: integer; NameIndex: integer; FrameIndex: integer = -1): TIEResourceBookmark; end; {$endif} // IEINCLUDERESOURCEEXTRACTOR /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // Xorshift pseudo number generator by George Marsaglia //type TIERandomGenerator = class private x, y, z, w: dword; public constructor Create(Seed: dword); overload; constructor Create(Seed: AnsiString); overload; constructor Create(Seed1, Seed2, Seed3, Seed4: dword); overload; function NextDWORD(): dword; function NextINT64(): int64; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// TIE8087ExceptionsDisabler = class private FPUControlWord: Word; public constructor Create(); destructor Destroy(); override; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// // TIEStringSplitter // Another way to split a string using delimiters // Use inplace of TStringList.DelimitedText, when possible TIEStringSplitter = class private procedure SetText(const Text: string); function GetText(): string; function GetString(Index: integer): string; function GetCount(): integer; function GetDelimiters(): string; procedure SetDelimiters(const Value: string); function GetBypassSpaces(): boolean; procedure SetBypassSpaces(Value: boolean); function IsSpace(c: char): boolean; protected procedure Update(); public constructor Create(const Text: string = ''; const Delimiters: string = ' '); destructor Destroy(); override; property Text: string read GetText write SetText; property Strings[Index: integer]: string read GetString; default; property Count: integer read GetCount; property Delimiters: string read GetDelimiters write SetDelimiters; property BypassSpaces: boolean read GetBypassSpaces write SetBypassSpaces; private m_text: string; m_strings: TStringList; m_delimiters: string; m_bypassSpaces: boolean; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// // Functions function _GetBitCount(b: Integer): Integer; function IEGetFirstSetBit(b: Integer): Integer; function _NColToBitsPixel(NCol: integer): integer; function IEBitmapRowLen(Width: integer; BitCount: integer; align: integer): int64; function IEVCLPixelFormat2RowLen(Width: integer; PixelFormat: TPixelFormat): integer; function IEVCLPixelFormat2BitCount(PixelFormat: TPixelFormat): integer; function IEBitCount2VCLPixelformat(Bitcount: integer): TPixelFormat; function IEVCLPixelFormat2ImageEnPixelFormat(PixelFormat: TPixelFormat): TIEPixelFormat; function IEPixelFormat2BitCount(PixelFormat: TIEPixelFormat): integer; function IEPixelFormat2ChannelCount(PixelFormat: TIEPixelFormat): integer; {$ifdef IEUSEASM} procedure ReverseBits(var inp: dword); assembler; {$else} procedure ReverseBits(var inp: dword); {$endif} procedure ReverseBitsB(var inp: byte); procedure _CastPolySelCC(const x1, y1: integer; var x2, y2: integer); function _RectXRect(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2: integer): boolean; function _RectPRect(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2: integer): integer; function IEPointInRect(xx, yy, x1, y1, x2, y2: integer): boolean; overload; function IEPointInRect(xx, yy : integer; ARect: TRect): boolean; overload; function _InRectO(xx, yy, x1, y1, x2, y2: integer): boolean; function IEGetFileSize(const FileName: string): int64; function PromptForColor(var AColor : TColor): Boolean; procedure IESaveStringToStream(Stream: TStream; const ss: AnsiString); overload; procedure IELoadStringFromStream(Stream: TStream; var ss: AnsiString); overload; {$IfDef UNICODE} procedure IESaveStringToStream(Stream: TStream; const ss: UnicodeString); overload; procedure IELoadStringFromStream(Stream: TStream; var ss: UnicodeString); overload; {$EndIf} procedure IESaveStringToStreamW(Stream: TStream; const ss: widestring); procedure IELoadStringFromStreamW(Stream: TStream; var ss: widestring); overload; procedure IELoadStringFromStreamW(Stream: TStream; var ss: String); overload; procedure IESaveStringListToStream(Stream: TStream; sl: TStringList); procedure IELoadStringListFromStream(Stream: TStream; sl: TStringList); procedure IELoadFontFromStream(Stream: TStream; var Font: TFont); procedure IESaveFontToStream(Stream: TStream; const Font: TFont); function _GetNumCol(BitsPerSample: integer; SamplesPerPixel: integer): integer; function iemsg(const msg: TMsgLanguageWords): WideString; procedure IESetTranslationWord(const lang: TMsgLanguage; const msg: TMsgLanguageWords; const trans: AnsiString); procedure IESetTranslationWordU(const lang: TMsgLanguage; const msg: TMsgLanguageWords; const trans: string); function _DistPoint2Line(xp, yp, x1, y1, x2, y2: integer): double; function _DistPoint2Seg(xp, yp, x1, y1, x2, y2: integer): double; function _DistPoint2Point(x1, y1, x2, y2: integer): double; function IEDDistPoint2Point(x1, y1, x2, y2: double): double; function _DistPoint2Polyline(x, y: integer; PolyPoints: PPointArray; PolyPointsCount: integer; ToSubX, ToSubY, ToAddX, ToAddY: integer; ToMulX, ToMulY: double; penWidth: integer; closed: boolean): double; function IEDistPoint2Ellipse(x, y, x1, y1, x2, y2: integer; filled: boolean; penWidth: integer): double; function IEDist2Box(x, y, x1, y1, x2, y2: integer; filled: boolean; penWidth: integer): double; function IEDistParallelLines(FirstLinePointA: TIE2DPoint; FirstLinePointB: TIE2DPoint; SecondLinePoint: TIE2DPoint): double; function IESignedTriangleArea(Point1: TIE2DPoint; Point2: TIE2DPoint; Point3: TIE2DPoint): double; procedure IEOrthogonalTranslate(OrigSegmentA, OrigSegmentB: TIE2DPoint; Point: TIE2DPoint; out OffsetX: double; out OffsetY: double); function IEMMXSupported: bytebool; //procedure IEMul64(op1, op2: dword; resultlo: pdword; resulthi: pdword); //function IEAdd64(op1_lo, op1_hi, op2_lo, op2_hi: dword; result_lo, result_hi: pdword): integer; //function IEGreater64(op1_lo, op1_hi, op2_lo, op2_hi: dword): boolean; procedure SafeStreamWrite(Stream: TStream; var Aborting: boolean; const Buffer; Count: Longint); // procedure IEBitmapMapXCopy(map: pbyte; maprowlen: dword; mapbitcount: dword; bitmap: TBitmap; mapx, mapy, bitmapx, bitmapy, dx, dy: dword; dir: integer); function IEPower2(const Base, Exponent: Double): Double; function IESwapWord(i: word): word; function IESwapDWord(i: integer): integer; function IESwapInt64(i: int64): int64; procedure IESwap(var a: integer; var b: integer); overload; procedure IESwap(var a: double; var b: double); overload; procedure IESwap(var a: boolean; var b: boolean); overload; procedure IESwap(var a: TIELayerMagnification; var b: TIELayerMagnification); overload; procedure IESwap(var a: TIERenderOperation; var b: TIERenderOperation); overload; procedure IESwap(var a: pointer; var b: pointer); overload; procedure IESwap(var a: TResampleFilter; var b: TResampleFilter); overload; procedure IESwap(var a: AnsiString; var b: AnsiString); overload; {$IfDef UNICODE} procedure IESwap(var a: UnicodeString; var b: UnicodeString); overload; {$EndIf} procedure IESwap(var a: TGuid; var b: TGuid); overload; procedure IESwap(var a: TRGB; var b: TRGB); overload; procedure IESwap(var a: TIEArrayOfTRGB; var b: TIEArrayOfTRGB); overload; procedure IESwap(var a: TRect; var b: TRect); overload; procedure IESwap(var a: TIEShape; var b: TIEShape); overload; procedure IESwap(var a: TColor; var b: TColor); overload; procedure IESwap(var a: TFont; var b: TFont); overload; procedure IESwap(var a: TPoint; var b: TPoint); overload; procedure IEChangeEndiannessWordArray(buffer: pword; items: integer); procedure IEChangeEndiannessDWordArray(buffer: pdword; items: integer); procedure IERightShadow(Canvas: TCanvas; DestBitmap: TBitmap; x1, y1, x2, y2: integer; st: TIEShadowType; dstColor: TColor); procedure IEBottomShadow(Canvas: TCanvas; DestBitmap: TBitmap; x1, y1, x2, y2: integer; st: TIEShadowType; dstColor: TColor); procedure IERectShadow(Bitmap: TBitmap; x1, y1, x2, y2: integer; dstColor: TColor); function IEFloatToStrA(Value: Extended): AnsiString; function IEFloatToStrW(Value: Extended): WideString; function IEFloatToStrS(Value: Extended): string; function IEFindHandle(cmp: TComponent): HWND; procedure DrawDibDrawEmu(hdd: THandle; hDC: THandle; xDst, yDst, dxDst, dyDst: Integer; var lpbi: TBitmapInfoHeader; Bits: Pointer; xSrc, ySrc, dxSrc, dySrc: Integer; wFlags: UInt); procedure DrawDib(hDC: THandle; xDst, yDst, dxDst, dyDst: Integer; var lpbi: TBitmapInfoHeader; Bits: Pointer; xSrc, ySrc, dxSrc, dySrc: Integer); function IEDrawDibClose(hdd: hDrawDib): Boolean; function IEDrawDibDraw(hdd: hDrawDib; hDC: THandle; xDst, yDst, dxDst, dyDst: Integer; var lpbi: TBitmapInfoHeader; Bits: Pointer; xSrc, ySrc, dxSrc, dySrc: Integer; wFlags: UInt): Boolean; function IEDrawDibOpen: hDrawDib; function IEDrawDibRealize(hdd: hDrawDib; hDC: THandle; fBackground: Bool): UInt; procedure IECenterWindow(Wnd: HWnd); procedure IEResetPrinter; function IEStrToFloatDefA(s: AnsiString; Def: extended): extended; function IEStrToFloatDefW(s: WideString; Def: extended): extended; function IEStrToFloatDefS(s: String; Def: extended): extended; function IEStrToFloatDef(s: String; Def: extended): extended; function IERGB2CIELAB(rgb: TRGB): TCIELAB; function IECIELAB2RGB(const lab: TCIELAB): TRGB; procedure IEDraw3DRect(Canvas: TCanvas; x1, y1, x2, y2: integer; cl1, cl2: TColor); procedure IEDraw3DRect2(Canvas: TObject; x1, y1, x2, y2: integer; cl1, cl2: TColor); procedure IEDrawHint(Canvas: TCanvas; var x, y: integer; const ss: string; Font: TFont; Brush: TBrush; var SaveBitmap: TBitmap; MaxWidth, MaxHeight: integer; Border1, Border2: TColor); procedure IEDrawHint2(Canvas: TCanvas; var x, y: integer; const ss: string; const minText: string); function IEDirectoryExists(const Name: string): Boolean; procedure IEForceDirectories(Dir: string); function IEGetMemory(freememory: boolean): int64; procedure IECalcUnitsPerPixel(DpiX, DpiY: Integer; mu: TIEUnits; out cx, cy: double); procedure IESetPlim(var plim: trect; x, y: integer); function IEAngle(x1, y1, x2, y2, x3, y3: double): double; function IEAngle2(x1, y1, x2, y2: integer): double; function IEAngle3(x1, y1, xc, yc, x2, y2: integer): double; function IEGetReferenceAngle(Angle: double): double; function IEArcCos(X: Extended): Extended; function IEDegreesToRadians(Angle: Double): Double; function IERadiansToDegrees(Rad: Double): Double; function IEExtractStylesFromLogFont(logfont: PLogFontA): TFontStyles; function IEExtractStylesFromLogFontW(logfont: PLogFontW): TFontStyles; procedure IECopyLogFont(src: PLogFontA; dst: PLogFontW); function IEConvertGUIDToString(g: PGUID): AnsiString; function CompareGUID(const g1, g2: TGuid): boolean; procedure IEConvertAStringToGUID(invar: AnsiString; gg: PGUID); procedure IEConvertWStringToGUID(invar: WideString; gg: PGUID); procedure IEGetFitResampleSize(owidth, oheight, fwidth, fheight: integer; out rwidth, rheight: integer); procedure IEGetFitResampleSizeWithAutoCrop(iImageWidth, iImageHeight, iAvailableWidth, iAvailableHeight: integer; out RWidth, RHeight: integer; iAutoCropPercent : Integer; out RAutoWidth, RAutoHeight: integer); function IEIsRemoteSession(): boolean; // timeout support function IESetupTimeout(): dword; function IEIsTimeoutExpired(startTime: dword; timeout: dword): boolean; procedure IERotatePoints(var rpt: array of TPoint; PointCount: Integer; angle: double; CenterX, CenterY: integer); procedure IEDRotatePoints(var rpt: array of TIE2DPoint; angle: double); procedure IEDRotatePointsWithCenter(var rpt: array of TIE2DPoint; angle: double; CenterX, CenterY: double); procedure IEDRotateTwoPoints(Angle: double; const P1: TIE2DPoint; const P2: TIE2DPoint; out OutP1: TIE2DPoint; out OutP2: TIE2DPoint); procedure IERotatePoint(var px, py: integer; angle: double; CenterX, CenterY: integer); procedure IEDRotatePoint(var px, py: double; angle: double; CenterX, CenterY: double); function IECalcRotatedRectBoundingBox(Rectangle: TIEDRectangle; RotationCenter: TIE2DPoint; RotationAngle: double): TIEDRectangle; procedure IECalcRotatedBitmapSizes(Width, Height: integer; RotationCenter: TIE2DPoint; RotationAngle: double; out NewWidth: integer; out NewHeight: integer); procedure IERotateBits(Bits: TIEArrayOfByte; Width, Height: integer; RowAlignment: integer; RotationCenter: TIE2DPoint; RotationAngle: double; Background: integer; MaintainOriginalSize: boolean; out outBits: TIEArrayOfByte; out outWidth: integer; out outHeight: integer); procedure IEGetPointsRange(rpt: array of TPoint; PointCount: Integer; out MinX: Integer; out MinY: Integer; out MaxX: Integer; out MaxY: Integer); procedure IEScalePoints(var rpt: array of TPoint; PointCount: Integer; MinX, MinY, MaxX, MaxY: Integer; MaintainAR: Boolean = False); function IECalcOrthogonalLinesIntersectingPoint(FirstLinePoint: TIE2DPoint; FirstLineSlope: double; SecondLinePoint: TIE2DPoint): TIE2DPoint; function IECalcPolygonCentroid(polygon: array of TIE2DPoint): TIE2DPoint; function IECreateRotatedCursor(CursorIntResource: integer; RotationAngle: double): HCURSOR; procedure IECenterRectInRect(OuterRectX1, OuterRectY1, OuterRectX2, OuterRectY2: integer; var InnerRectX1: integer; var InnerRectY1: integer; var InnerRectX2: integer; var InnerRectY2: integer); procedure CalcLineWithinRect(R: TRect; Angle: Integer; out Pt1, Pt2: TPoint); function OffsetPoint(Pt: TPoint; Dist: Double; Angle: Double) : TPoint; function IEISPointInPoly(x, y: integer; poly: array of TPoint): boolean; function IEDISPointInPoly(x, y: double; poly: array of TIE2DPoint): boolean; function IEISPointInPoly2(x, y: integer; PolyPoints: PPointArray; PolyPointsCount: integer; ToSubX, ToSubY, ToAddX, ToAddY: integer; ToMulX, ToMulY: double): boolean; function IEASCII85EncodeBlock(var inbytes: pbyte; buflen: integer; var outstr: PAnsiChar; var asciilen: integer): integer; function IEASCII85DecodeBlock(var instr: PAnsiChar; buflen: integer; var outbytes: pbyte): integer; function IEPSRunLengthEncode(inbytes: pbytearray; inlen: integer; outbytes: pbytearray): integer; procedure IEWriteStrLn(s: TStream; ss: AnsiString); function IECopyFrom(Dest: TStream; Source: TStream; Count: int64): int64; function IEStrLen(const Str: PAnsiChar): Cardinal; function IEStrLenW(Str: PWideChar): Cardinal; function IEStrCopy(Dest: PAnsiChar; const Source: PAnsiChar): PAnsiChar; function IEStrCopyW(Dest: PWideChar; Source: PWideChar): PWideChar; function IEStrPCopy(Dest: PAnsiChar; const Source: AnsiString): PAnsiChar; function IEStrPCopyW(Dest: PWideChar; const Source: WideString): PWideChar; function IEStrPCopyWA(Dest: PWideChar; Source: TIEArrayOfAnsiChar): PWideChar; function IEStrMove(Dest: PAnsiChar; const Source: PAnsiChar; Count: Cardinal): PAnsiChar; function IEAnsiStrScan(Str: PAnsiChar; Chr: AnsiChar): PAnsiChar; function IEStrScan(const Str: PAnsiChar; Chr: AnsiChar): PAnsiChar; function IEStrRScan(const Str: PAnsiChar; Chr: AnsiChar): PAnsiChar; function IETextToFloat(Buffer: PAnsiChar; var Value; ValueType: TFloatValue): Boolean; overload; function IEGetDecimalSeparator: Char; procedure IESetDecimalSeparator(c: Char); function IEOpenClipboard: boolean; procedure IEDrawGrayedOut(Canvas: TCanvas; XDst, YDst, WidthDst, HeightDst: integer; SX1, SY1, SX2, SY2: integer); {!! IEGetCoresCount Declaration function IEGetCoresCount(): integer; Description Returns the total amount of processor's cores present on the system. Some Windows operating system versions cannot communicate this information, so it defaults to . !!} function IEGetCoresCount(): integer; function IEGetRequiredThreads(ImageWidth, ImageHeight: integer): integer; procedure IEEncode64(SrcStream: TStream; DstStream: TStream; linesize: integer); overload; function IEEncode64(SrcBuffer: pbyte; SrcBufferLength: integer; linesize: integer): AnsiString; overload; procedure IEDecode64(SrcStream: TStream; DstStream: TStream); overload; function IEDecode64(SrcString: AnsiString): TIEArrayOfByte; overload; function IEStreamFindString(Stream: TStream; Text: AnsiString; StopAtPos: int64): int64; function IEGetDosOutput(CommandLine: AnsiString; Work: AnsiString = 'C:\'): AnsiString; {$ifndef IEHASUINT64} function UInt64(v : Pointer) : int64; overload; function UInt64(v : Integer) : int64; overload; {$endif} {$ifndef IEHASNATIVEINT} function Nativeint(v: Pointer): DWORD; overload; function Nativeint(v: Char): DWORD; overload; {$endif} {$IfNDef Delphi6orNewer} function Get8087CW: Word; // for D5 {$ENDIF} function IESetScrollRange(hWnd: HWND; nBar, nMinPos, nMaxPos: Integer; bRedraw: BOOL; flat: boolean): BOOL; procedure IESetSBPageSize(HScrollBar: THandle; fnBar: integer; PageSize: Integer; Redraw: boolean; flat: boolean); function IESetScrollPos(hWnd: HWND; nBar, nPos: Integer; bRedraw: BOOL; flat: boolean): Integer; function IEEnableScrollBar(hWnd: HWND; wSBflags, wArrows: UINT; flat: boolean = False): BOOL; function IEShowScrollBar(hWnd: HWND; wBar: Integer; bShow: BOOL; flat: boolean = False): BOOL; function IESetScrollInfo(hWnd: HWND; BarFlag: Integer; const ScrollInfo: TScrollInfo; Redraw: BOOL; flat: boolean): Integer; procedure IESetScrollBar(hWnd: HWND; nBar: integer; nMinPos: integer; nMaxPos: integer; PageSize: integer; nPos: integer; bRedraw: boolean; flat: boolean = False); function IEIsSpace(c: AnsiChar): boolean; function IERemoveCtrlCharsA(const text: AnsiString): AnsiString; function IERemoveCtrlCharsW(const text: WideString): WideString; function IERemoveCtrlCharsS(const text: String): String; function IERGBColorsMatch(rgb1, rgb2 : TRGB; Tolerance : Integer = 0): Boolean; function IERGB2StrS(c: TRGB): string; function IERGB2StrW(c: TRGB): WideString; function IEBool2StrS(v: boolean): string; function IEBool2StrW(v: boolean): WideString; function IEStr2RGBS(const rgbstr: string): TRGB; function IEStr2RGBW(const rgbstr: WideString): TRGB; function IEStr2BoolS(const v: string): boolean; function IEStr2BoolW(const v: WideString): boolean; function IEStr2BoolA(const v: AnsiString): boolean; function IEStr2ColorDefS(const v : string; ADefault : TColor) : TColor; function IECopyArrayOfByte(const Input: TIEArrayOfByte): TIEArrayOfByte; function IECopyArrayOfInteger(const Input: TIEArrayOfInteger): TIEArrayOfInteger; procedure IEQuickSort(ItemsCount: integer; CompareFunction: TIECompareFunction; SwapFunction: TIESwapFunction); function IEGetTempFileName(const Descriptor: string; const Directory: string): string; function IEGetTempFileName2: string; function IEGetNewFilename(const sBaseFilename: string; const sSepChar: Char = ' '): string; procedure IERGB2YCbCr(rgb: TRGB; var Y, Cb, Cr: integer); procedure IEYCbCr2RGB(var rgb: TRGB; Y, Cb, Cr: integer); function IESystemAlloc(ASize: int64): pointer; procedure IESystemFree(var P); function IEAutoAlloc(ASize: int64): pointer; procedure IEAutoFree(var P); procedure IESilentGetMem(var P; Size: Integer); procedure IECreateOSXBackgroundPaper(bmp: TBitmap; width, height: integer); procedure IECreateOSXBackgroundMetal(bmp: TBitmap; width, height: integer); // clipboard helpers function IEEnumClipboardNames: TStringList; function IEGetClipboardDataByName(const name: string): THandle; // alpha/opacity function IEAlphaToOpacity(Alpha: integer ): integer; function IEOpacityToAlpha(Opacity: integer): integer; function IEIsLeftMouseButtonPressed: boolean; function IERGBToStr(rgb: TRGB): AnsiString; function IEExtractFileExtS(const FileName: string; includeDot: boolean=true): string; function IEExtractFileExtW(const FileName: WideString; includeDot: boolean=true): WideString; function IEExtractFileExtA(const FileName: AnsiString; includeDot: boolean=true): AnsiString; function IEAddBackSlash(const Path: String): String; function IETrim(const v: AnsiString): AnsiString; function IEUpperCase(const v: AnsiString): AnsiString; function IELowerCase(const v: AnsiString): AnsiString; function IEIntToStr(v: integer): AnsiString; function IEStrToIntDef(const s: AnsiString; def: integer): integer; function IEBytesToStr(v: integer; iThreshold: Integer = 100 * 1024): AnsiString; function IEBytesToStr2(iBytes: Int64) : AnsiString; function IEIntToFormattedStr(v: integer; iMaxDigitsOfPrecision: Integer = 0): AnsiString; function IECopy(S: AnsiString; Index, Count: Integer): AnsiString; function IEFloatToStrFA(Value: Extended; Format: TFloatFormat; Precision, Digits: Integer): AnsiString; function IEFloatToStrFS(Value: Extended; Format: TFloatFormat; Precision, Digits: Integer): string; function IEIntToHex(Value: Integer; Digits: Integer): AnsiString; function IEPos(Substr: AnsiString; S: AnsiString): Integer; function IEStrDup(s: PAnsiChar): PAnsiChar; function IEStrDupW(s: PWideChar): PWideChar; function IEExtractFilePathA(const FileName: AnsiString): AnsiString; function IEExtractFilePathW(const FileName: WideString): WideString; function IEExtractFileNameW(const FileName: WideString): WideString; function IEExtractFileNameWithoutExt(const FileName: String): String; function IE2DPoint(X, Y: double): TIE2DPoint; function IEFindNearestColor(color: TRGB; palette: TIEArrayOfTRGB; colorCount: integer): integer; function IEGetOpSys(): TIEOpSys; function IEGetDisplayOrientation(): integer; function IEFilenameInExtensions(const sFileName, sExtensions : String) : Boolean; function IEFileExtInExtensions(sFileExt : String; const sExtensions : String) : Boolean; function GetImageRectWithinArea(iImageWidth, iImageHeight : Integer; iAvailableWidth, iAvailableHeight : Integer; iHorzOffset : Integer = 0; iVertOffset : integer = 0; bAllowStretching : boolean = true; bAllowShrinking : boolean = true; bCenterHorz : boolean = true; bCenterVert : boolean = true; iAutoCropPercent : Integer = 0; FitMethod: TFitMethod = _fmFitWithinRect) : TRect; overload; function GetImageRectWithinArea(iImageWidth, iImageHeight: Integer; ADestRect : TRect; bAllowStretching : boolean = true; bAllowShrinking : boolean = true; bCenterHorz : boolean = true; bCenterVert : boolean = true; iAutoCropPercent : Integer = 0; FitMethod: TFitMethod = _fmFitWithinRect) : TRect; overload; function GetImageSizeWithinArea(iImageWidth, iImageHeight : integer; iAvailableWidth, iAvailableHeight : integer; bAllowStretching : boolean = TRUE; FitMethod: TFitMethod = _fmFitWithinRect ) : TPoint; function IEAdjustRectToAspectRatio(InRect : TRect; iImageWidth, iImageHeight: Integer; iDisplayWidth, iDisplayHeight : Integer; FitMethod: TFitMethod = _fmFitWithinRect ) : TRect; function IERectifiedRectangleAspectRatio(x0, y0, x1, y1, x2, y2, x3, y3, cx, cy: double): double; function IEBilinear(needX, needY: Double; centerValue, rightValue, bottomValue, BottomRightValue: integer): integer; function AngleToImageEnRotateAngle(Angle: Double): Double; function ImageEnRotateAngleToAngle(Angle: Double): Double; procedure IEInitializeComboBox(AComboBox : TComboBox); procedure IEDrawComboListBoxItem(ControlCanvas : TCanvas; CanvasRect : trect; ControlEnabled: Boolean; const Text : string; AnImageList : TImageList = nil; iGlyph : Short = -1); function GetNextZoomValue(iCurrentZoom: double; bZoomIn: boolean; iIdealZoom: double = 0) : double; function IEIsWindowsVistaOrNewer : Boolean; function IEIsKeyPressed(aKey: Word): Boolean; function IEFileExists(const FileName: string): Boolean; function IEFileExistsW(const FileName: WideString): Boolean; procedure IEDecimalToFraction(value: double; var numerator: integer; var denominator: integer; accuracy: double = 0.000000005); procedure IECopyTList(source: TList; dest: TList); function IERectangle(x, y, width, height: integer): TIERectangle; overload; function IERectangle(Rect: TRect): TIERectangle; overload; function IETextWidthW(Canvas: TCanvas; const Text: WideString): integer; function IETextHeightW(Canvas: TCanvas; const Text: WideString): integer; function IETruncateStr(sCaption : WideString; TruncSide: TIEMTruncSide; ACanvas : TCanvas; iMaxWidth : Integer) : Widestring; function IEFileTimeToDateTime(ft: TFileTime): TDateTime; function IELargeFileSize(nFileSizeHigh, nFileSizeLow: DWORD) : Int64; function IEGetFileDetails(const sFilename: string; out iFileSizeBytes: Int64; out dtCreateDate: TDateTime; out dtEditDate: TDateTime ): boolean; function IEFileSetDate(const sFilename: string; DateTime: TDateTime): boolean; // convert a real value into a string with decimal places function IEFloatToFormatString(Value: Extended; iDecimalCount: Integer; bStripZeros: boolean): string; // Returns a suitable font to use for Preview dialogs. Segoe UI 9 on Vista, 7. Tahoma 8 on XP, etc function IEGetDefaultDialogFont() : TFont; {$IfNdef Delphi6orNewer} function RoundTo(const AValue: Double; ADigit: Integer): Double; {$endif} type TIEURLType = (ieurlUNKNOWN, ieurlHTTP, ieurlHTTPS, ieurlFTP); function IEGetURLTypeA(const URL: AnsiString): TIEURLType; function IEGetURLTypeW(const URL: WideString): TIEURLType; function IESendMessageTimeout(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM; fuFlags, uTimeout: UINT; lpdwResult: pointer): LRESULT; function IEIsPrime(x: integer): boolean; function IENextPrime(x: integer): integer; // GPS function IEGPSConvertDMSToDegDec(degrees: Double; minutes: Double; seconds: Double; ref: AnsiString): Double; procedure IEGPSConvertDegDecToDMS(dir: AnsiString; value: Double; var degrees: Double; var minutes: Double; var seconds: Double; var ref: AnsiString); {$ifdef IEVISION} function IEVisionBGR8ToTRGB(visionBGR8: TIEVisionBGR8): TRGB; function IETRGBToVisionBGR8(rgb: TRGB): TIEVisionBGR8; procedure IEVisionConvPixelFormat(PixelFormat: TIEPixelFormat; out channelFormat: TIEVisionChannelFormat; out channelCount: integer); overload; function IEVisionConvPixelFormat(channelFormat: TIEVisionChannelFormat; channelCount: integer): TIEPixelFormat; overload; //function IEVision {$endif} procedure IEBlend(var src: TRGB; var dst: TRGB; RenderOperation: TIERenderOperation; row: integer); procedure IEBlendRGBA(var src: TRGBA; var dst: TRGBA; RenderOperation: TIERenderOperation; row: integer); procedure IEBezier2D4Controls(p0: TPoint; c0: TPoint; c1: TPoint; p1: TPoint; pResultArray: PPointArray; nSteps: integer); function IEWStrCopy(Dest: PWideChar; const Source: PWideChar): PWideChar; {$IfNdef Delphi6orNewer} function Sign(const AValue: Double): Integer; {$ENDIF} // Hash Functions function IE_ELFHash(const str: WideString; bucketCount: cardinal): cardinal; function IE_RSHash(const str: WideString; bucketCount: cardinal): cardinal; function IE_JSHash(const str: WideString; bucketCount: cardinal): cardinal; function IE_MMHash(const str: WideString; const Seed: Cardinal = $9747b28c): Cardinal; function IEDrawGradient(R: TRect; DC: HDC; ColorStart, ColorStop: TColor; bVertical: boolean): Boolean; procedure IEPixelFormatToBPSAndSPP(PixelFormat: TIEPixelFormat; out iBitsPerSample: Integer; out iSamplesPerPixel: Integer); procedure BitCountToBPSAndSPP(BitCount: Integer; bAllow32bit: Boolean; out iBitsPerSample: Integer; out iSamplesPerPixel: Integer); procedure IEPrintLogWrite(const ss: String); procedure IESetStringA(var S: AnsiString; Buffer: PAnsiChar; Length: Integer); {$IfNdef Delphi7orNewer} function BoolToStr(B: Boolean): string; {$endif} function IECreateRect(Left, Top, Right, Bottom: Integer): TRect; {!! dmin Declaration function dmin(v1, v2: Double): Double; Description Returns the minimum of v1 and v2. !!} function dmin(v1, v2: Double): Double; {!! dmax Declaration function dmax(v1, v2: Double): Double; Description Returns the maximum of v1 and v2. !!} function dmax(v1, v2: Double): Double; function dwmax(v1, v2: DWord): DWord; {!! imin Declaration function imin(v1, v2: Integer): Integer; Description Returns the minimum of v1 and v2. !!} function imin(v1, v2: Integer): Integer; {$IFDEF IEHASUINT64} function u64min(v1, v2: uint64): uint64; {$ENDIF} function i64min(v1, v2: int64): int64; function i64max(v1, v2: int64): int64; {!! imax Declaration function imax(v1, v2: Integer): Integer; Description Returns the maximum of v1 and v2. !!} function imax(v1, v2: Integer): Integer; {!! ilimit Declaration function ilimit(vv, min, max: Integer): Integer; Description Ensures vv is in the range of min and max. !!} function ilimit(vv, min, max: Integer): Integer; {!! blimit Declaration function blimit(vv: Integer): Integer; Description Ensures vv is in the range of 0 to 255. !!} function blimit(vv: Integer): Integer; {!! wlimit Declaration function wlimit(vv: Integer): word; Description Ensures vv is in the range of 0 to 65535. !!} function wlimit(vv: Integer): word; {!! iswap Declaration procedure iswap(var B1, B2: LongInt); Description Swap B1 with B2. !!} procedure iswap(var B1, B2: LongInt); assembler; procedure dwswap(var B1, B2: dword); assembler; procedure dswap(var v1, v2: Double); {!! bswap Declaration procedure bswap(var B1, B2: Byte); Description Swap B1 with B2. !!} procedure bswap(var B1, B2: Byte); assembler; procedure iedswap(var d1, d2: Double); procedure i64swap(var v1, v2: int64); {!! OrdCor Declaration procedure OrdCor(var x1, y1, x2, y2: Integer); Description Sorts x1, y1, x2, y2 so that x1, y1 is at the top-left and x2, y2 is at the bottom-right vertex of the rectangle. !!} procedure OrdCor(var x1, y1, x2, y2: Integer); {!! TRGB2TColor Declaration function TRGB2TColor(rgb: ): TColor; Description Converts a TRGB color to TColor. Example Panel1.Color := TRGB2TColor(CreateRGB(255, 0, 0)); // Panel1.Color will be clRed See Also - - !!} function TRGB2TColor(rgb: TRGB): TColor; {!! RGB2TColor Declaration function RGB2TColor(r, g, b: Integer): TColor; Description Converts R, G, B values to TColor. Example Panel1.Color := RGB2TColor(255, 0, 0); // Panel1.Color will be clRed See Also - - !!} function RGB2TColor(r, g, b: Integer): TColor; {!! TColor2TRGB Declaration function TColor2TRGB(cl: TColor): ; Description Converts a TColor to TRGB. Example var rgb: TRGB; Begin rgb := TColor2TRGB( clRed ); // Which is the same as rgb := CreateRGB( 255, 0, 0 ); ... End; See Also - - !!} function TColor2TRGB(cl: TColor): TRGB; {!! TColor2TRGBA Declaration function TColor2TRGBA(cl: TColor): ; overload; function TColor2TRGBA(cl: TColor; transparency: Integer): ; Description Converts TColor and transparency to TRGBA. Example var rgb: TRGBA; Begin rgb := TColor2TRGBA( clRed, 255 ); ... End; !!} function TColor2TRGBA(cl: TColor; transparency: Integer): TRGBA; overload; function TColor2TRGBA(cl: TColor): TRGBA; overload; {!! IEApplyAlphaToColor Declaration function IEApplyAlphaToColor(Color: TColor; Alpha: Integer): TColor; overload; function IEApplyAlphaToColor(rgb: ; Alpha: Integer): ; overload; Description Applies Alpha (0=fully transparent, 255=fully visible) to the specified color. Examples Color := IEApplyAlphaToColor( clRed, 255 ); // Returns Pure Red Color := IEApplyAlphaToColor( clRed, 175 ); // Returns Dark Pink Color := IEApplyAlphaToColor( clRed, 50 ); // Returns Pale Pink Color := IEApplyAlphaToColor( clRed, 0 ); // Returns White !!} function IEApplyAlphaToColor(Color: TColor; Alpha: Integer): TColor; overload; function IEApplyAlphaToColor(rgb: TRGB; Alpha: Integer): TRGB; overload; {!! RGB2HSL Declaration procedure RGB2HSL(px: ; var Hue, Sat, Lum: Double); Description Converts a TRGB color to HSL values. Note: Hue, Sat and Lum will be in range 0 to 1. See Also - - - !!} procedure RGB2HSL(px: TRGB; var Hue, Sat, Lum: Double); {!! ColorToHSL Declaration procedure ColorToHSL(cl: TColor; var Hue, Sat, Lum: Double); Description Converts a TColor to HSL values. Note: Hue, Sat and Lum will be in range 0 to 1. !!} procedure ColorToHSL(cl: TColor; var Hue, Sat, Lum: Double); {!! HSL2RGB Declaration procedure HSL2RGB(var px: ; Hue, Sat, Lum: Double); Description Converts an HSL value (Hue, Sat, Lum) with a TRGB (px). Hue, Sat and Lum are in range 0 to 1. See Also - - - !!} procedure HSL2RGB(var px: TRGB; Hue, Sat, Lum: Double); {!! HSLToColor Declaration function HSLToColor(Hue, Sat, Lum: Double) : TColor; Description Converts HSL values (Hue, Sat, Lum) to a TColor. Hue, Sat and Lum are in range 0 to 1. !!} function HSLToColor(Hue, Sat, Lum: Double) : TColor; {!! HSV2RGB Declaration procedure HSV2RGB(var px: ; H, S, V: Integer); Description Converts a HSV values to TRGB. H (Hue) is from 0 to 359 (corresponding to 0..359 degrees around a hexcone). S (Saturation) is from 0 (shade of gray) to 99 (pure color). V (Value) is from 0 (black) to 99 (white). See Also - - - !!} procedure HSV2RGB(var px: TRGB; H, S, V: Integer); {!! HSVToColor Declaration function HSVToColor(h, s, v: Integer): TColor; Description Converts HSV values to a TColor. H (Hue) is from 0 to 359 (corresponding to 0..359 degrees around a hexcone). S (Saturation) is from 0 (shade of gray) to 99 (pure color). V (Value) is from 0 (black) to 99 (white). !!} function HSVToColor(h, s, v: Integer): TColor; {!! RGB2HSV Declaration procedure RGB2HSV(RGB: ; var h, s, v: Integer); Description Converts a TRGB color to HSV values. H (Hue) is from 0 to 359 (corresponding to 0..359 degrees around a hexcone). S (Saturation) is from 0 (shade of gray) to 99 (pure color). V (Value) is from 0 (black) to 99 (white). See Also - - - !!} procedure RGB2HSV(RGB: TRGB; var h, s, v: Integer); {!! ColorToHSV Declaration procedure ColorToHSV(cl: TColor; var h, s, v: Integer); Description Converts a TColor to HSV values. H (Hue) is from 0 to 359 (corresponding to 0..359 degrees around a hexcone). S (Saturation) is from 0 (shade of gray) to 99 (pure color). V (Value) is from 0 (black) to 99 (white). !!} procedure ColorToHSV(cl: TColor; var h, s, v: Integer); {!! ColorToHex Declaration function ColorToHex(Color : TColor): string; Description Returns a hex representation of a TColor (e.g. for use in HTML) Example sHex := ColorToHex(clWhite); // Would return "#FFFFFF' !!} function ColorToHex(Color : TColor): string; {!! CreateRGB Declaration function CreateRGB(r, g, b: byte): ; Description Returns a TRGB record. Example rgb := CreateRGB( 255, 0, 0 ); // Which is the same as rgb := TColor2TRGB( clRed ); See Also - - !!} function CreateRGB(r, g, b: byte): TRGB; {!! CreateRGB48 Declaration function CreateRGB48(r, g, b: word): ; Description Returns a TRGB48 record. !!} function CreateRGB48(r, g, b: word): TRGB48; {!! CreateCMYK Declaration function CreateCMYK(c, m, y, k: byte): ; Description Returns a TCMYK record. !!} function CreateCMYK(c, m, y, k: byte): TCMYK; {!! CreateRGBA Declaration function CreateRGBA(r, g, b, a: byte): ; Description Returns a TRGBA record. !!} function CreateRGBA(r, g, b, a: byte): TRGBA; function CreateRGBFromInt(r, g, b: Integer): TRGB; {!! EqualRGB Declaration function EqualRGB(rgb1, rgb2: ): Boolean; Description Returns True if rgb1 and rgb2 are equal. See Also - - - !!} function EqualRGB(rgb1, rgb2: TRGB): Boolean; {!! IEAverageColor Declaration function IEAverageColor(c1, c2 : TColor): TColor; overload; function IEAverageColor(c1, c2 : TRGB): TRGB; overload; Description Returns the average of two colors. !!} function IEAverageColor(c1, c2 : TColor): TColor; overload; function IEAverageColor(rgb1, rgb2 : TRGB): TRGB; overload; procedure YUV2RGB(y, u, v: Integer; var RGB: TRGB); procedure IERGBtoHSB(const cRed, cGreen, cBlue: byte; var H, S, B: word); procedure IEHSBtoRGB(const H, S, B: word; var cRed, cGreen, cBlue: byte); procedure IEInitializeImageEn; procedure IEFinalizeImageEn; procedure IEInitialize_hyieutils; procedure IEFinalize_hyieutils; // Gestures procedure IEInitialize_gestures(); procedure IEFinalize_gestures(); function IEHasGestures(): boolean; function ProgressRec(Sender: TObject; OnProgress: TIEProgressEvent; var bAborting: Boolean) : TProgressRec; overload; function ProgressRec(Sender: TObject; OnProgress: TIEProgressEvent; pAborting: PBoolean) : TProgressRec; overload; function NullProgressRec(var bAborting: Boolean; bResetAborting : Boolean = true) : TProgressRec; overload; function NullProgressRec(pAborting: PBoolean; bResetAborting : Boolean = true) : TProgressRec; overload; var IEGetGestureInfo: function(hGestureInfo: HGESTUREINFO; pGestureInfo: PIEGESTUREINFO): longbool; stdcall = nil; IECloseGestureInfoHandle: function(hGestureInfo: HGESTUREINFO): longbool; stdcall = nil; IESetGestureConfig: function(hwnd: THandle; dwReserved: DWORD; cIDS: DWORD; pGestureConfig: PIEGESTURECONFIG; cbSize: DWORD): longbool; stdcall = nil; IEUnregisterTouchWindow: function(hwnd: THandle): longbool; stdcall = nil; var // Windows CMS mscms: THandle; implementation uses math, SyncObjs, {$ifdef Delphi7orNewer} Types, {$endif} {$ifdef DelphiXE4orNewer} AnsiStrings, {$endif} {$ifdef IEHASUITYPES}System.UITypes,{$endif} imageenview, imageenproc, imageenio, ieview, neurquant, tiffilt, ievect, printers, ielcms, iej2000, tifccitt, ietextc, iewia, iewic, iepresetim, iesettings, iedicom, iemiscplugins, iemview {$ifdef IEUSEVCLZLIB}, zlib{$else}, iezlib{$endif} {$ifdef IEINCLUDEFLATSB}, flatsb{$endif} , iegdiplus, iewords, Dialogs, iexBitmaps; {$R-} var IECosineTab: array[0..255] of integer; // DRAWDIB LIBRARY const DLL = 'MsVfW32.dll'; function DrawDibClose(hdd: hDrawDib): Boolean; stdcall; external DLL name 'DrawDibClose'; function DrawDibDraw(hdd: hDrawDib; hDC: THandle; xDst, yDst, dxDst, dyDst: Integer; var lpbi: TBitmapInfoHeader; Bits: Pointer; xSrc, ySrc, dxSrc, dySrc: Integer; wFlags: UInt): Boolean; stdcall; external DLL name 'DrawDibDraw'; function DrawDibOpen: hDrawDib; stdcall; external DLL name 'DrawDibOpen'; function DrawDibRealize(hdd: hDrawDib; hDC: THandle; fBackground: Bool): UInt; stdcall; external DLL name 'DrawDibRealize'; // not available on old Delphi versions function IE_EnumDisplaySettingsExW(lpszDeviceName: PWideChar; iModeNum: DWORD; var lpDevMode: TIEDeviceModeW; dwFlags: DWORD): BOOL; stdcall; external user32 name 'EnumDisplaySettingsExW'; //////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEResourceExtractor {$ifdef IEINCLUDERESOURCEEXTRACTOR} function IEIS_INTRESOURCE(const ResID: PAnsiChar): boolean; begin Result := (Windows.HiWord(Windows.DWORD(ResID)) = 0); end; function EnumTypesProc(hModule: THandle; lpszType: PAnsiChar; lParam: pointer): longbool; stdcall; var typesList: TStringList; begin typesList := TStringList(lParam); if IEIS_INTRESOURCE(lpszType) then typesList.Add('INTRESOURCE:'+IntToStr(NativeInt(lpszType))) else typesList.Add(string(AnsiString(lpszType))); result := true; end; function EnumNamesProc(hModule: THandle; lpszType: PAnsiChar; lpszName: PAnsiChar; lParam: pointer): longbool; stdcall; var namesList: TStringList; begin namesList := TStringList(lParam); if IEIS_INTRESOURCE(lpszName) then namesList.Add('INTRESOURCE:'+IntToStr(NativeInt(lpszName))) else namesList.Add(string(AnsiString(lpszName))); result := true; end; {!! TIEResourceExtractor.Create Declaration constructor Create(const Filename: WideString); Description Creates a new instance of TIEResourceExtractor loading the specified PE file (EXE, DLL, OCX, ICL, BPL, etc..). It is possible to check the success of loading reading property. FileName specifies the path and filename of PE module. Example re := TIEResourceExtractor.Create('explorer.exe'); try ... finally re.Free; end; !!} constructor TIEResourceExtractor.Create(const Filename: WideString); const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = $00000040; LOAD_LIBRARY_AS_IMAGE_RESOURCE = $00000020; var resType: PAnsiChar; resTypeStr: AnsiString; i: integer; begin inherited Create; m_hlib := 0; m_typesList := nil; m_resourceBookmarks := nil; if IEGlobalSettings().OpSys < ieosWinVista then m_hlib := LoadLibraryExW(PWideChar(Filename), 0, LOAD_LIBRARY_AS_DATAFILE or DONT_RESOLVE_DLL_REFERENCES) else m_hlib := LoadLibraryExW(PWideChar(Filename), 0, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE or LOAD_LIBRARY_AS_IMAGE_RESOURCE); if m_hlib=0 then exit; // enum types m_typesList := TStringList.Create; EnumResourceTypesA(m_hlib, @EnumTypesProc, NativeInt(m_typesList)); // enum names for i := 0 to m_typesList.Count-1 do begin m_typesList.Objects[i] := TStringList.Create; // associates a list of names to this resource type resTypeStr := AnsiString(m_typesList[i]); if copy(resTypeStr, 1, 12) = 'INTRESOURCE:' then resType := MakeIntResourceA(IEStrToIntDef(IECopy(resTypeStr, 13, length(resTypeStr)-12), 0)) else resType := PAnsiChar(resTypeStr); EnumResourceNamesA(m_hlib, resType, @EnumNamesProc, NativeInt(m_typesList.Objects[i])); end; m_resourceBookmarks := TList.Create; end; destructor TIEResourceExtractor.Destroy; var i: integer; begin if assigned(m_resourceBookmarks) then begin for i := 0 to m_resourceBookmarks.Count-1 do TIEResourceBookmark(m_resourceBookmarks[i]).Free; m_resourceBookmarks.Free; end; if assigned(m_typesList) then begin for i := 0 to m_typesList.Count-1 do if assigned(TStringList(m_typesList.Objects[i])) then TStringList(m_typesList.Objects[i]).Free; m_typesList.Free; end; if m_hlib<>0 then FreeLibrary(m_hlib); inherited; end; type TRES_ICOHEADER = packed record wReserved: word; wResID: word; wNumImages: word; end; PRES_ICOHEADER = ^TRES_ICOHEADER; TRES_ICODIRENTRY = packed record bWidth: byte; bHeight: byte; bColors: byte; bReserved: byte; wPlanes: word; wBitCount: word; dwBytesInImage: dword; wID: word; end; PRES_ICODIRENTRY = ^TRES_ICODIRENTRY; TRES_CURHEADER = packed record wReserved: word; wResID: word; wNumImages: word; end; PRES_CURHEADER = ^TRES_CURHEADER; TRES_CURDIRENTRY = packed record wWidth: word; wHeight: word; wPlanes: word; wBitCount: word; dwBytesInImage: dword; wID: word; end; PRES_CURDIRENTRY = ^TRES_CURDIRENTRY; {!! TIEResourceExtractor.IsGroup Declaration property IsGroup[TypeIndex: integer]: boolean; Description Returns true if the resource type is "GroupIcon" (RT_GROUP_ICON) or "GroupCursor" (RT_GROUP_CURSOR). This means that resources inside this type must be handled as groups. Parameter Description TypeIndex Index of resource type. 0 is first resource type, -1 is last resource type.
!!} function TIEResourceExtractor.GetIsGroup(TypeIndex: integer): boolean; begin result := (FriendlyTypes[TypeIndex] = 'GroupIcon') or (FriendlyTypes[TypeIndex] = 'GroupCursor'); end; {!! TIEResourceExtractor.IsGrouped Declaration property IsGrouped[TypeIndex: integer]: boolean; Description Returns true if the resource type is "Icon" (RT_ICON) or "Cursor" (RT_CURSOR). This means that resources inside this type must be grouped in "GroupIcon" or "GroupCursor" resources. Parameter Description TypeIndex Index of resource type. 0 is first resource type, -1 is last resource type.
!!} function TIEResourceExtractor.GetIsGrouped(TypeIndex: integer): boolean; begin result := (FriendlyTypes[TypeIndex] = 'Icon') or (FriendlyTypes[TypeIndex] = 'Cursor'); end; {!! TIEResourceExtractor.GroupCountFrames Declaration property GroupCountFrames[TypeIndex: integer; NameIndex: integer]: integer; Description Returns the number of frames of specified resource (can be Icon or Cursor resource). Parameter Description TypeIndex Index of resource type. 0 is first resource type, -1 is last resource type. NameIndex Index of actual resource. 0 is first resource name, -1 is last resource name.
!!} function TIEResourceExtractor.GetGroupCountFrames(TypeIndex: integer; NameIndex: integer): integer; var iconGroupIndex: integer; iconHeader: PRES_ICOHEADER; curGroupIndex: integer; curHeader: PRES_CURHEADER; buffer: pointer; bufferLen: integer; begin if FriendlyTypes[TypeIndex] = 'GroupIcon' then begin iconGroupIndex := IndexOfType('GroupIcon'); buffer := GetBuffer(iconGroupIndex, NameIndex, bufferLen); iconHeader := PRES_ICOHEADER(buffer); result := iconHeader^.wNumImages; end else if FriendlyTypes[TypeIndex] = 'GroupCursor' then begin curGroupIndex := IndexOfType('GroupCursor'); buffer := GetBuffer(curGroupIndex, NameIndex, bufferLen); curHeader := PRES_CURHEADER(buffer); result := curHeader^.wNumImages; end else result := 0; end; function GetIconFrameInfo(ResourceExtractor: TIEResourceExtractor; TypeIndex: integer; IconIndex: integer; FrameIndex: integer): PRES_ICODIRENTRY; var buffer: pointer; bufferLen: integer; begin result := nil; buffer := ResourceExtractor.GetBuffer(TypeIndex, IconIndex, bufferLen); // check for buffer overrun if sizeof(TRES_ICOHEADER) + sizeof(TRES_ICODIRENTRY)*(FrameIndex+1) > bufferLen then exit; inc(PRES_ICOHEADER(buffer)); // bypass TRES_ICOHEADER inc(PRES_ICODIRENTRY(buffer), FrameIndex); // bypass unwanted frames (TRES_ICODIRENTRY) result := PRES_ICODIRENTRY(buffer); end; function GetCurFrameInfo(ResourceExtractor: TIEResourceExtractor; TypeIndex: integer; CurIndex: integer; FrameIndex: integer): PRES_CURDIRENTRY; var buffer: pointer; bufferLen: integer; begin buffer := ResourceExtractor.GetBuffer(TypeIndex, CurIndex, bufferLen); inc(pbyte(buffer), sizeof(TRES_CURHEADER)); // bypass TRES_CURHEADER inc(pbyte(buffer), sizeof(TRES_CURDIRENTRY)*FrameIndex); // bypass unwanted frames (TRES_CURDIRENTRY) result := PRES_CURDIRENTRY(buffer); end; {!! TIEResourceExtractor.GroupFrameWidth Declaration property GroupFrameWidth[TypeIndex: integer; NameIndex: integer; FrameIndex: integer]: integer; Description Returns the icon or cursor width. TypeIndex must refer to a "GroupIcon" or "GroupCursor" resource type. Parameter Description TypeIndex Index of resource type. 0 is first resource type, -1 is last resource type. NameIndex Index of actual resource. 0 is first resource name, -1 is last resource name.
!!} function TIEResourceExtractor.GetGroupFrameWidth(TypeIndex: integer; NameIndex: integer; FrameIndex: integer): integer; begin if FriendlyTypes[TypeIndex] = 'GroupIcon' then begin result := GetIconFrameInfo(self, TypeIndex, NameIndex, FrameIndex)^.bWidth; if result = 0 then result := 256; end else if FriendlyTypes[TypeIndex] = 'GroupCursor' then result := GetCurFrameInfo(self, TypeIndex, NameIndex, FrameIndex)^.wWidth else result := 0; end; {!! TIEResourceExtractor.GroupFrameHeight Declaration property GroupFrameHeight[TypeIndex: integer; NameIndex: integer; FrameIndex: integer]: integer; Description Returns the icon or cursor height. TypeIndex must refer to a "GroupIcon" or "GroupCursor" resource type. Parameter Description TypeIndex Index of resource type. 0 is first resource type, -1 is last resource type. NameIndex Index of actual resource. 0 is first resource name, -1 is last resource name.
!!} function TIEResourceExtractor.GetGroupFrameHeight(TypeIndex: integer; NameIndex: integer; FrameIndex: integer): integer; begin if FriendlyTypes[TypeIndex] = 'GroupIcon' then begin result := GetIconFrameInfo(self, TypeIndex, NameIndex, FrameIndex)^.bHeight; if result = 0 then result := 256; end else if FriendlyTypes[TypeIndex] = 'GroupCursor' then result := GetCurFrameInfo(self, TypeIndex, NameIndex, FrameIndex)^.wHeight div 2 else result := 0; end; {!! TIEResourceExtractor.GroupFrameDepth Declaration property GroupFrameDepth[TypeIndex: integer; NameIndex: integer; FrameIndex: integer]: integer; Description Returns the icon or cursor bit depth. TypeIndex must refer to a "GroupIcon" or "GroupCursor" resource type. Parameter Description TypeIndex Index of resource type. 0 is first resource type, -1 is last resource type. NameIndex Index of actual resource. 0 is first resource name, -1 is last resource name.
!!} function TIEResourceExtractor.GetGroupFrameDepth(TypeIndex: integer; NameIndex: integer; FrameIndex: integer): integer; begin if FriendlyTypes[TypeIndex] = 'GroupIcon' then result := GetIconFrameInfo(self, TypeIndex, NameIndex, FrameIndex)^.wBitCount else if FriendlyTypes[TypeIndex] = 'GroupCursor' then result := GetCurFrameInfo(self, TypeIndex, NameIndex, FrameIndex)^.wBitCount else result := 0; end; {!! TIEResourceExtractor.GroupFrameName Declaration property GroupFrameName[TypeIndex: integer; NameIndex: integer; FrameIndex: integer]: AnsiString; Description Returns the icon or cursor resource name. TypeIndex must refer to a "GroupIcon" or "GroupCursor" resource type. Parameter Description TypeIndex Index of resource type. 0 is first resource type, -1 is last resource type. NameIndex Index of actual resource. 0 is first resource name, -1 is last resource name.
!!} function TIEResourceExtractor.GetGroupFrameName(TypeIndex: integer; NameIndex: integer; FrameIndex: integer): AnsiString; begin if FriendlyTypes[TypeIndex] = 'GroupIcon' then result := 'INTRESOURCE:'+IEIntToStr(GetIconFrameInfo(self, TypeIndex, NameIndex, FrameIndex)^.wID) else if FriendlyTypes[TypeIndex] = 'GroupCursor' then result := 'INTRESOURCE:'+IEIntToStr(GetCurFrameInfo(self, TypeIndex, NameIndex, FrameIndex)^.wID) else result := ''; end; {!! TIEResourceExtractor.GetGroupAndFrame Declaration procedure GetGroupAndFrame(TypeIndex: integer; NameIndex: integer; var GroupTypeIndex: integer; var GroupIndex: integer; var GroupFrameIndex: integer); Description This method finds the associated grouping resource for the specified resource. Grouping resources types are "GroupIcon" or "GroupCursor". TypeIndex must be "Icon" or "Cursor", otherwise returns values are undefined. Parameter Description TypeIndex Index of resource type. 0 is first resource type, -1 is last resource type. NameIndex Index of actual resource. 0 is first resource name, -1 is last resource name. GroupTypeIndex GroupIndex GroupFrameIndex
!!} procedure TIEResourceExtractor.GetGroupAndFrame(TypeIndex: integer; NameIndex: integer; var GroupTypeIndex: integer; var GroupIndex: integer; var GroupFrameIndex: integer); var a_GroupCount: integer; a_GroupCountFrames: integer; begin if FriendlyTypes[TypeIndex] = 'Icon' then GroupTypeIndex := IndexOfType('GroupIcon') else if FriendlyTypes[TypeIndex] = 'Cursor' then GroupTypeIndex := IndexOfType('GroupCursor') else exit; a_GroupCount := NamesCount[GroupTypeIndex]; GroupIndex := 0; while GroupIndex < a_GroupCount do begin a_GroupCountFrames := GroupCountFrames[GroupTypeIndex, GroupIndex]; GroupFrameIndex := 0; while GroupFrameIndex < a_GroupCountFrames do begin if GroupFrameName[GroupTypeIndex, GroupIndex, GroupFrameIndex] = Names[TypeIndex, NameIndex] then exit; inc(GroupFrameIndex); end; inc(GroupIndex); end; end; {!! TIEResourceExtractor.GetFrameBuffer Declaration function GetFrameBuffer(TypeIndex: integer; NameIndex: integer; FrameIndex: integer; var BufferLength: integer): pointer; Description Returns the buffer of specified frame, for multi-frame resources. TypeIndex must be 'GroupIcon' or 'GroupCursor'. Parameter Description TypeIndex Index of resource type. 0 is first resource type, -1 is last resource type. NameIndex Index of actual resource. 0 is first resource name, -1 is last resource name. FrameIndex The frame index. 0 is first resource name, -1 is last frame. BufferLength
!!} function TIEResourceExtractor.GetFrameBuffer(TypeIndex: integer; NameIndex: integer; FrameIndex: integer; var BufferLength: integer): pointer; begin if FriendlyTypes[TypeIndex] = 'GroupIcon' then result := GetBuffer('Icon', GroupFrameName[TypeIndex, NameIndex, FrameIndex], BufferLength) else result := GetBuffer('Cursor', GroupFrameName[TypeIndex, NameIndex, FrameIndex], BufferLength); end; {!! TIEResourceExtractor.IndexOfType Declaration function IndexOfType(TypeName: AnsiString): integer; Description Finds the index of specified type name (ex. 'Icon', 'Cursor', 'GroupIcon'...). !!} function TIEResourceExtractor.IndexOfType(TypeName: AnsiString): integer; var i: integer; begin result := m_typesList.IndexOf(string(TypeName)); if result=-1 then // search as friendly type for i := 0 to m_typesList.Count-1 do if FriendlyTypes[i] = TypeName then begin result := i; break; end; end; {!! TIEResourceExtractor.IsValid Declaration property IsValid: boolean; Description Checks if TIEResourceExtractor contains valid data. Example re := TIEResourceExtractor.Create('explorer.exe'); if re.IsValid then begin ... end; re.Free; !!} function TIEResourceExtractor.GetIsValid: boolean; begin result := (m_hlib<>0); end; {!! TIEResourceExtractor.TypesCount Declaration property TypesCount: integer; Description Returns number of resource types found in the PE module. !!} function TIEResourceExtractor.GetTypesCount: integer; begin result := m_typesList.Count; end; {!! TIEResourceExtractor.NamesCount Declaration property NamesCount[TypeIndex: integer]: integer; Description Returns number of resource names found in the PE module, for the specified resource type. Parameter Description TypeIndex Index of resource type. 0 is first resource type, -1 is last resource type.
!!} function TIEResourceExtractor.GetNamesCount(TypeIndex: integer): integer; begin if TypeIndex < 0 then result := 0 else result := TStringList(m_typesList.Objects[TypeIndex]).Count; end; {!! TIEResourceExtractor.Types Declaration property Types[TypeIndex: integer]: AnsiString; Description Returns the specified resource type name. Parameter Description TypeIndex Index of resource type. 0 is first resource type, -1 is last resource type.
See also: for more friendly type strings. !!} function TIEResourceExtractor.GetTypes(TypeIndex: integer): AnsiString; begin result := AnsiString(m_typesList[TypeIndex]); end; {!! TIEResourceExtractor.Names Declaration property Names[TypeIndex: integer; NameIndex: integer]: AnsiString; Description Returns the resource name for specified type and name index. Parameter Description TypeIndex Index of resource type. 0 is first resource type, -1 is last resource type. NameIndex Index of actual resource. 0 is first resource name, -1 is last resource name.
!!} function TIEResourceExtractor.GetNames(TypeIndex: integer; NameIndex: integer): AnsiString; begin result := AnsiString(TStringList(m_typesList.Objects[TypeIndex])[NameIndex]); end; {!! TIEResourceExtractor.FriendlyTypes Declaration property FriendlyTypes[TypeIndex: integer]: AnsiString; Description Returns the specified resource type friendly name (for know types like RT_CURSOR, RT_BITMAP, etc...). Parameter Description TypeIndex Index of resource type. 0 is first resource type, -1 is last resource type.
Here is the list of Windows resource types and related friendly string. Windows resource Friendly type name RT_ACCELERATOR 'Accelerator' RT_ANICURSOR 'AniCursor' RT_ANIICON 'AniIcon' RT_BITMAP 'Bitmap' RT_CURSOR 'Cursor' RT_DIALOG 'Dialog' RT_DLGINCLUDE 'DlgInclude' RT_FONT 'Font' RT_FONTDIR 'FontDir' RT_GROUP_CURSOR 'GroupCursor' RT_GROUP_ICON 'GroupIcon' RT_HTML 'HTML' RT_ICON 'Icon' RT_MANIFEST 'Manifest' RT_MENU 'Menu' RT_MESSAGETABLE 'MessageTable' RT_PLUGPLAY 'PlugPlay' RT_RCDATA 'RCData' RT_STRING 'String' RT_VERSION 'Version' RT_VXD 'VXD'
See also:
for less friendly type strings. !!} function TIEResourceExtractor.GetFriendlyTypes(TypeIndex: integer): AnsiString; const RT_ACCELERATOR = $00000009; RT_ANICURSOR = $00000015; RT_ANIICON = $00000016; RT_BITMAP = $00000002; RT_CURSOR = $00000001; RT_DIALOG = $00000005; RT_DLGINCLUDE = $00000011; RT_FONT = $00000008; RT_FONTDIR = $00000007; RT_GROUP_CURSOR = $0000000C; RT_GROUP_ICON = $0000000E; RT_HTML = $00000017; RT_ICON = $00000003; RT_MANIFEST = $00000018; RT_MENU = $00000004; RT_MESSAGETABLE = $0000000B; RT_PLUGPLAY = $00000013; RT_RCDATA = $0000000A; RT_STRING = $00000006; RT_VERSION = $00000010; RT_VXD = $00000014; var resInt: integer; begin result := Types[TypeIndex]; if copy(result, 1, 12) = 'INTRESOURCE:' then begin resInt := IEStrToIntDef(copy(result, 13, length(result)-12), 0); case resInt of integer(RT_ACCELERATOR): result := 'Accelerator'; integer(RT_ANICURSOR): result := 'AniCursor'; integer(RT_ANIICON): result := 'AniIcon'; integer(RT_BITMAP): result := 'Bitmap'; integer(RT_CURSOR): result := 'Cursor'; integer(RT_DIALOG): result := 'Dialog'; integer(RT_DLGINCLUDE): result := 'DlgInclude'; integer(RT_FONT): result := 'Font'; integer(RT_FONTDIR): result := 'FontDir'; integer(RT_GROUP_CURSOR): result := 'GroupCursor'; integer(RT_GROUP_ICON): result := 'GroupIcon'; integer(RT_HTML): result := 'HTML'; integer(RT_ICON): result := 'Icon'; integer(RT_MANIFEST): result := 'Manifest'; integer(RT_MENU): result := 'Menu'; integer(RT_MESSAGETABLE): result := 'MessageTable'; integer(RT_PLUGPLAY): result := 'PlugPlay'; integer(RT_RCDATA): result := 'RCData'; integer(RT_STRING): result := 'String'; integer(RT_VERSION): result := 'Version'; integer(RT_VXD): result := 'VXD'; end; end; end; {!! TIEResourceExtractor.GetBuffer Declaration function GetBuffer(TypeIndex: integer; NameIndex: integer; var BufferLength: integer): pointer; function GetBuffer(const TypeStr: AnsiString; const NameStr: AnsiString; var BufferLength: integer): pointer; function GetBuffer(ResourceBookmark: ; var BufferLength: integer): pointer; Description Returns memory buffer for the specified resource. Parameter Description TypeIndex Index of resource type. 0 is first resource type, -1 is last resource type. NameIndex Index of actual resource. 0 is first resource name, -1 is last resource name. BufferLength Field filled with the resulting buffer length (in bytes). TypeStr Type as string (ie 'Bitmap', 'Cursor'). NameStr Resource name as string (ie 'INTRESOURCE:100', 'Hand'). ResourceBookmark A resource bookmark returned by .
The buffer must not be freed. Example // loads resource 143, in "Bitmap"s, from "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; // loads the resource specified by parameters "resTypeIndex" and "resNameIndex" var buffer: pointer; bufferLen: integer; begin buffer := m_ResourceExtractor.GetBuffer(resTypeIndex, resNameIndex, bufferLen); ImageEnView1.IO.Params.IsResource := true; if m_ResourceExtractor.FriendlyTypes[resTypeIndex] = 'Bitmap' then ImageEnView1.IO.LoadFromBuffer(buffer, bufferLen, ioBMP) else if m_ResourceExtractor.FriendlyTypes[resTypeIndex] = 'Cursor' then ImageEnView1.IO.LoadFromBuffer(buffer, bufferLen, ioCUR) else if m_ResourceExtractor.FriendlyTypes[resTypeIndex] = 'Icon' then ImageEnView1.IO.LoadFromBuffer(buffer, bufferLen, ioICO) else // We cannot use ioUnknown (autodect) for BMP, CUR and ICO because it is not possible to autodetect BMP, CUR and ICO when they are resources. ImageEnView1.IO.LoadFromBuffer(buffer, bufferLen, ioUnknown) // for jpegs, GIF, etc... end; !!} function TIEResourceExtractor.GetBuffer(TypeIndex: integer; NameIndex: integer; var BufferLength: integer): pointer; var resName: PAnsiChar; resType: PAnsiChar; resNameStr: AnsiString; resTypeStr: AnsiString; resInfo: THandle; resData: THandle; begin result := nil; BufferLength := 0; resTypeStr := Types[TypeIndex]; if copy(resTypeStr, 1, 12) = 'INTRESOURCE:' then resType := MakeIntResourceA(IEStrToIntDef(copy(resTypeStr, 13, length(resTypeStr)-12), 0)) else resType := PAnsiChar(resTypeStr); resNameStr := Names[TypeIndex, NameIndex]; if copy(resNameStr, 1, 12) = 'INTRESOURCE:' then resName := MakeIntResourceA(IEStrToIntDef(IECopy(resNameStr, 13, length(resNameStr)-12), 0)) else resName := PAnsiChar(resNameStr); resInfo := FindResourceA(m_hlib, resName, resType); if resInfo = 0 then exit; resData := LoadResource(m_hlib, resInfo); if resData = 0 then exit; BufferLength := SizeOfResource(m_hlib, resInfo); result := LockResource(resData); end; function TIEResourceExtractor.GetBuffer(const TypeStr: AnsiString; const NameStr: AnsiString; var BufferLength: integer): pointer; var TypeIndex: integer; NameIndex: integer; i: integer; begin result := nil; TypeIndex := m_typesList.IndexOf(string(TypeStr)); if TypeIndex=-1 then for i := 0 to m_typesList.Count-1 do if FriendlyTypes[i] = TypeStr then begin TypeIndex := i; break; end; if TypeIndex>-1 then begin NameIndex := TStringList(m_typesList.Objects[TypeIndex]).IndexOf(string(NameStr)); if NameIndex>-1 then result := GetBuffer(TypeIndex, NameIndex, BufferLength); end; end; {!! TIEResourceExtractor.GetResourceBookmark Declaration function GetResourceBookmark(TypeIndex: integer; NameIndex: integer; FrameIndex: integer = -1): ; Description Creates a bookmark for the specified resource (or resource frame). Bookmarks are automatically freed. Parameter Description TypeIndex Index of resource type. 0 is first resource type, -1 is last resource type. NameIndex Index of actual resource. 0 is first resource name, -1 is last resource name. FrameIndex The frame index. 0 is first resource name, -1 is last frame.
!!} function TIEResourceExtractor.GetResourceBookmark(TypeIndex: integer; NameIndex: integer; FrameIndex: integer = -1): TIEResourceBookmark; begin result := TIEResourceBookmark.Create(TypeIndex, NameIndex, FrameIndex); m_resourceBookmarks.Add(result); end; function TIEResourceExtractor.GetBuffer(ResourceBookmark: TIEResourceBookmark; var BufferLength: integer): pointer; begin if ResourceBookmark.m_FrameIndex < 0 then result := GetBuffer(ResourceBookmark.m_TypeIndex, ResourceBookmark.m_NameIndex, BufferLength) else result := GetFrameBuffer(ResourceBookmark.m_TypeIndex, ResourceBookmark.m_NameIndex, ResourceBookmark.m_FrameIndex, BufferLength); end; constructor TIEResourceBookmark.Create(TypeIndex_, NameIndex_, FrameIndex_: integer); begin inherited Create; m_TypeIndex := TypeIndex_; m_NameIndex := NameIndex_; m_FrameIndex := FrameIndex_; end; {$endif} // IEINCLUDERESOURCEEXTRACTOR // TIEResourceExtractor //////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TIERandomGenerator.Create(Seed: dword); begin x := 123456789 xor (Seed); y := 362436069 xor (Seed shl 8); z := 521288629 xor (Seed shl 16); w := 88675123 xor (Seed shl 24); end; constructor TIERandomGenerator.Create(Seed: AnsiString); var i: integer; begin x := 123456789; y := 362436069; z := 521288629; w := 88675123; for i := 1 to length(Seed) do begin x := x xor (ord(Seed[i])); y := y xor (ord(Seed[i]) shl 8); z := z xor (ord(Seed[i]) shl 16); w := w xor (ord(Seed[i]) shl 24); end; end; constructor TIERandomGenerator.Create(Seed1, Seed2, Seed3, Seed4: dword); begin x := Seed1; y := Seed2; z := Seed3; w := Seed4; end; function TIERandomGenerator.NextDWORD(): dword; var t: dword; begin t := x xor (x shl 11); x := y; y := z; z := w; w := w xor (w shr 19) xor (t xor (t shr 8)); result := w; end; function TIERandomGenerator.NextINT64(): int64; begin result := NextDWORD() or (NextDWORD() shl 32); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TIE8087ExceptionsDisabler.Create(); begin inherited; FPUControlWord := Get8087CW(); Set8087CW($133F); end; destructor TIE8087ExceptionsDisabler.Destroy(); begin Set8087CW(FPUControlWord); inherited; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TIEStringSplitter.Create(const Text: string; const Delimiters: string); begin inherited Create(); m_text := Text; m_strings := TStringList.Create(); m_delimiters := Delimiters; m_bypassSpaces := true; try Update(); except m_strings.Free(); raise; end; end; destructor TIEStringSplitter.Destroy(); begin m_strings.Free(); inherited; end; procedure TIEStringSplitter.SetText(const Text: string); begin m_text := Text; Update(); end; function TIEStringSplitter.GetText(): string; begin result := m_text; end; function TIEStringSplitter.GetString(Index: integer): string; begin result := m_strings[Index]; end; function TIEStringSplitter.GetCount(): integer; begin result := m_strings.Count; end; function TIEStringSplitter.GetDelimiters(): string; begin result := m_delimiters; end; procedure TIEStringSplitter.SetDelimiters(const Value: string); begin if Value <> m_delimiters then begin m_delimiters := Value; Update(); end; end; function TIEStringSplitter.GetByPassSpaces(): boolean; begin result := m_bypassSpaces; end; procedure TIEStringSplitter.SetByPassSpaces(Value: boolean); begin if Value <> m_bypassSpaces then begin m_bypassSpaces := Value; Update(); end; end; function TIEStringSplitter.IsSpace(c: char): boolean; begin result := (c = #$20) or (c = #$09) or (c = #$0a) or (c = #$0b) or (c = #$0c) or (c = #$0d); end; procedure TIEStringSplitter.Update(); var p, i, l, len: integer; procedure bypassSpaces(); begin if m_bypassSpaces then while (i <= len) and IsSpace(m_text[i]) do inc(i); end; function isDelimiter(c: char): boolean; begin result := Pos(c, m_delimiters) > 0; end; procedure add(start: integer; length: integer); begin if m_bypassSpaces then m_strings.Add(trim(Copy(m_text, start, length))) else m_strings.Add(Copy(m_text, start, length)); end; begin m_strings.Clear(); len := length(m_text); if m_bypassSpaces then while (len > 0) and (IsSpace(m_text[len])) do dec(len); i := 1; bypassSpaces(); p := i; while i <= len do begin if isDelimiter(m_text[i]) then begin add(p, i - p); inc(i); bypassSpaces(); p := i; end else inc(i); end; l := len - p + 1; if (l > 0) or ((length(m_text) > 0) and isDelimiter(m_text[i - 1])) then add(p, l); end; ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // TIEFileBuffer ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// constructor TIEFileBuffer.Create; begin inherited; fFileName := ''; fMapped := TList.Create; fSimFile := nil; end; destructor TIEFileBuffer.Destroy; begin DeAllocate; FreeAndNil(fMapped); inherited; end; procedure TIEFileBuffer.DeAllocate; begin if IsAllocated then begin UnMapAll; FreeAndNil(fSimFile); DeleteFile(fFileName); end; end; function TIEFileBuffer.IsAllocated: boolean; begin result := fSimFile <> nil end; // if FileName is '', creates a temp file name in DefTEMPPATH function TIEFileBuffer.AllocateFile(InSize: int64; const Descriptor: string; UseDisk: boolean): boolean; var temppath: array[0..MAX_PATH] of Char; tp: string; begin if IsAllocated then DeAllocate; result := false; if IEGlobalSettings().DefTEMPPATH = '' then begin GetTempPath(250, temppath); tp := string(temppath); end else tp := IEGlobalSettings().DefTEMPPATH; fFileName := IEGetTempFileName(Descriptor, tp); try if UseDisk then begin (* problems of DiskFree: cannot detect disk>2GB, (0)=current directory (imagine changing directory to USB disk or CDROM) if InSize>(DiskFree(0)-128000000) then exit; *) fSimFile := TIETemporaryFileStream.Create(fFileName); end else fSimFile := TMemoryStream.Create; fSimFile.Size := InSize; result := true; except end; end; procedure TIEFileBuffer.ReAllocateFile(NewSize: int64); begin fSimFile.Size := NewSize; end; // can copy maximum 2^31 bytes procedure TIEFileBuffer.CopyTo(Dest: TIEFileBuffer; InPos, InSize: int64); const BUFSIZE = 1024 * 1024; var i: integer; buf: pbyte; begin if (not IsAllocated) or (not Dest.IsAllocated) then exit; UnMapAll; Dest.UnMapAll; (* // disabled because since 2.2.7 we use TIETemporaryFileStream instead of TFileStream if (InPos = 0) and (InSize = fSimFile.Size) then begin // copy the full file using operating system functions FreeAndNil(fSimFile); FreeAndNil(Dest.fSimFile); deletefile(Dest.fFileName); copyfile(PAnsiChar(fFileName), PAnsiChar(Dest.fFileName), false); Dest.fSimFile := TFileStream.Create(Dest.fFileName, fmOpenReadWrite); fSimFile := TFileStream.Create(fFileName, fmOpenReadWrite); end else *) begin fSimFile.Position := InPos; Dest.fSimFile.Position := InPos; getmem(buf, BUFSIZE); repeat if InSize < BUFSIZE then i := InSize else i := BUFSIZE; fSimFile.Read(buf^, i); Dest.fSimFile.Write(buf^, i); dec(InSize, i); until InSize <= 0; freemem(buf); end; end; procedure TIEFileBuffer.CopyTo(Dest: TStream; InPos, InSize: int64); begin if (not IsAllocated) then exit; UnMapAll; fSimFile.Position := InPos; IECopyFrom(Dest, fSimFile, InSize); end; function TIEFileBuffer.IndexOf(ptr: pointer): integer; var i: integer; begin result := -1; for i := 0 to fMapped.Count - 1 do if PIEFileBufferItem(fMapped[i])^.ptr = ptr then begin result := i; break; end; end; function TIEFileBuffer.Map(InPos, InSize: int64; DataAccess: TIEDataAccess): pointer; var item: PIEFileBufferItem; begin result := IEAutoAlloc(InSize); if result <> nil then begin if (fSimFile <> nil) and (iedRead in DataAccess) then begin fSimFile.Position := InPos; fSimFile.Read(pbyte(result)^, InSize); end; new(item); item^.Pos := InPos; item^.Size := InSize; item^.ptr := result; item^.access := DataAccess; fMapped.Add(item); end; end; procedure TIEFileBuffer.UnMap(ptr: pointer); var i: integer; item: PIEFileBufferItem; begin if ptr <> nil then begin i := IndexOf(ptr); item := fMapped[i]; if (fSimFile<>nil) and (iedWrite in item^.access) then begin fSimFile.Position := item^.Pos; fSimFile.Write(pbyte(ptr)^, item^.Size); end; dispose(item); fMapped.Delete(i); IEAutoFree(ptr); end; end; procedure TIEFileBuffer.UnMapAll; begin if IsAllocated then while fMapped.Count > 0 do UnMap(PIEFileBufferItem(fMapped[fMapped.Count - 1]).ptr); end; procedure TIEFileBuffer.CopyFrom(DestPos: int64; Source: pointer; Size: int64); begin if fSimFile <> nil then begin fSimFile.Position := DestPos; fSimFile.Write(pbyte(Source)^, Size); end; end; ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // TIETemporaryFileStream constructor TIETemporaryFileStream.Create(const FileName: string); begin FHandle := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE or FILE_ATTRIBUTE_TEMPORARY, 0); if FHandle = INVALID_HANDLE_VALUE then raise EInOutError.Create('Unable to create '+FileName); inherited Create(FHandle); end; destructor TIETemporaryFileStream.Destroy; begin if FHandle <> INVALID_HANDLE_VALUE then FileClose(FHandle); inherited Destroy; end; ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // Hash functions function IE_ELFHash(const str: WideString; bucketCount: cardinal): cardinal; var i: cardinal; x: cardinal; begin result := 0; for i := 1 to length(str) do begin result := (result shl 4) + ord(str[i]); x := result and $F0000000; if (x <> 0) then result := (result xor (x shr 24)) and (not x); end; result := result mod bucketCount; end; function IE_RSHash(const str: WideString; bucketCount: cardinal): cardinal; const b = 378551; var a : cardinal; i : integer; begin a := 63689; result := 0; for i := 1 to length(str) do begin result := result * a + ord(str[i]); a := a * b; end; result := result mod bucketCount; end; function IE_JSHash(const str: WideString; bucketCount: cardinal): cardinal; var i: integer; begin result := 1315423911; for i := 1 to length(str) do result := result xor ((result shl 5) + ord(str[i]) + (result shr 2)); result := result mod bucketCount; end; // MurmurHash function IE_MMHash(const str: WideString; const Seed: Cardinal = $9747b28c): Cardinal; var h: Cardinal; len: Cardinal; k: Cardinal; data: Integer; const // 'm' and 'r' are mixing constants that work well. m = $5bd1e995; r = 24; begin len := Length( str ); h := seed xor len; // Mix 4 bytes at a time into the hash data := 1; while len >= 4 do begin k := pCardinal( @str[ data ] )^; k := k * m; k := k xor (k shr r); k := k * m; h := h * m; h := h xor k; data := data + 4; len := len - 4; end; // Handle last few bytes of the input array if len = 3 then h := h xor ( Cardinal( str[ data + 2 ]) shl 16 ); if len >= 2 then h := h xor ( Cardinal( str[ data + 1 ]) shl 8 ); if len >= 1 then begin h := h xor ( Cardinal( str[ data ])); h := h * m; end; // Do a few final mixes of the hash to ensure the last few // bytes are well-incorporated. h := h xor ( h shr 13 ); h := h * m; h := h xor ( h shr 15 ); Result := h; end; //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // TIEDictionary constructor TIEDictionaryValueWideString.Create(value: WideString); begin self.value := value; end; destructor TIEDictionaryValueWideString.Destroy(); begin inherited; end; constructor TIEDictionaryValueInteger.Create(value: integer); begin self.value := value; end; destructor TIEDictionaryValueInteger.Destroy(); begin inherited; end; constructor TIEDictionaryValueDouble.Create(value: double); begin self.value := value; end; destructor TIEDictionaryValueDouble.Destroy(); begin inherited; end; constructor TIEDictionaryValueBoolean.Create(value: boolean); begin self.value := value; end; destructor TIEDictionaryValueBoolean.Destroy(); begin inherited; end; constructor TIEDictionaryBucket.Create(const key_: WideString; const value_: TObject; next_: TIEDictionaryBucket); begin inherited Create; key := key_; value := value_; next := next_; end; destructor TIEDictionaryBucket.Destroy(); begin value.Free(); end; constructor TIEStrStrEnumerator.Create(); begin inherited Create; bucket := 0; item := nil; end; destructor TIEStrStrEnumerator.Destroy(); begin inherited; end; procedure TIEDictionary.CheckInit(); var i: cardinal; begin if not m_initDone then begin if not IEIsPrime(m_bucketCount) then m_bucketCount := IENextPrime(m_bucketCount); SetLength(m_buckets, m_bucketCount); for i := 0 to m_bucketCount - 1 do m_buckets[i] := nil; m_initDone := true; end; end; {!! TIEDictionary.Create Declaration constructor Create(buckets: cardinal; hashFunction: TIEStrHashFunction; caseSensitive: boolean = false); overload; constructor Create(buckets: cardinal = 103; caseSensitive: boolean = false); overload; Description Creates a new instance of TIEDictionary. !!} constructor TIEDictionary.Create(buckets: cardinal; hashFunction: TIEStrHashFunction; caseSensitive: boolean); begin inherited Create; m_initDone := false; m_bucketCount := buckets; m_hashFunction := hashFunction; m_caseSensitive := caseSensitive; m_count := 0; end; constructor TIEDictionary.Create(buckets: cardinal; caseSensitive: boolean); begin inherited Create; m_initDone := false; m_bucketCount := buckets; m_hashFunction := @IE_ELFHash; m_caseSensitive := caseSensitive; m_count := 0; end; destructor TIEDictionary.Destroy(); begin Clear(); inherited; end; function TIEDictionary.execHash(const str: WideString; bucketCount: cardinal): cardinal; begin if m_caseSensitive then result := m_hashFunction(str, bucketCount) else result := m_hashFunction(UpperCase(str), bucketCount); end; {!! TIEDictionary.Clear Declaration procedure Clear(); Description Empties the dictionary. !!} procedure TIEDictionary.Clear(); var i: cardinal; nxt, ths: TIEDictionaryBucket; begin if m_initDone then begin for i := 0 to m_bucketCount - 1 do begin ths := m_buckets[i]; while ths <> nil do begin nxt := ths.next; ths.Free(); ths := nxt; end; m_buckets[i] := nil; end; m_count := 0; end; end; function TIEDictionary.keysMatch(const key1: WideString; const key2: WideString): boolean; begin if m_caseSensitive then result := key1 = key2 else result := UpperCase(key1) = UpperCase(key2); end; function TIEDictionary.GetInBucket(bucket: cardinal; key: WideString; out lastItem: TIEDictionaryBucket): TIEDictionaryBucket; var ths: TIEDictionaryBucket; begin CheckInit(); result := nil; ths := m_buckets[bucket]; lastItem := ths; while (ths <> nil) and (result = nil) do begin lastItem := ths; if keysMatch(ths.key, key) then result := ths; ths := ths.next; end; end; {!! TIEDictionary.HasKey Declaration function HasKey(key: WideString; recursive: boolean = true): boolean; Description Returns the true if the key exists. Parameter Description key A key in this dictionary recursive If true then search this key inside subdictionaries
!!} function TIEDictionary.HasKey(key: WideString; recursive: boolean): boolean; begin result := Get(key, true, recursive) <> nil; end; // recursive key search function TIEDictionary.FindInDictionaries(key: WideString): TObject; var current: TIEStrStrEnumerator; olist: TObjectList; i: integer; begin result := nil; current := TIEStrStrEnumerator.Create(); while GetNext(current) do begin if current.item.value is TIEDictionary then begin result := (current.item.value as TIEDictionary).Get(key, true, true); if result <> nil then break; end else if current.item.value is TObjectList then begin olist := current.item.value as TObjectList; for i := 0 to olist.Count - 1 do begin if olist[i] is TIEDictionary then result := (olist[i] as TIEDictionary).Get(key, true, true); if result <> nil then break; end; end; end; current.Free(); end; {!! TIEDictionary.Get Declaration function Get(key: WideString; silent: boolean = false; recursive: boolean = true): TObject; Description Returns the value to which the key is mapped in this dictionary. If the key doesn't exist returns nil or raises an exception. Parameter Description key A key in this dictionary silent If true no exception is raised if the key doesn't exist recursive If true then search this key inside subdictionaries
!!} function TIEDictionary.Get(key: WideString; silent: boolean; recursive: boolean): TObject; var bucket: cardinal; ths, lst: TIEDictionaryBucket; begin CheckInit(); bucket := execHash(key, m_bucketCount); ths := GetInBucket(bucket, key, lst); if ths <> nil then result := ths.value else begin result := nil; if recursive then result := FindInDictionaries(key); if (result = nil) and not silent then raise EIEException.Create(Format('Key "%s" not found', [key])); end; end; {!! TIEDictionary.GetString Declaration function GetString(key: WideString; recursive: boolean = true): WideString; Description Returns the string value to which the key is mapped in this dictionary. If the key doesn't exist an exception is raised. Parameter Description key A key in this dictionary recursive If true then search this key inside subdictionaries
Examples // Return the photo description from the XMP metadata sDescription := ImageEnView1.IO.Params.Dict.GetDictionary( 'XMP' ).GetString( 'dc:description' ); // Return the creation date from the XMP metadata (XMP date strings are formatted the same EXIF date strings) dtCreateDate := EXIFDateToDateTime( ImageEnView1.IO.Params.Dict.GetDictionary( 'XMP' ).GetString( 'xmp:CreateDate' )); // Return the creator or author of the asset from the XMP metadata sCreator := ImageEnView1.IO.Params.Dict.GetDictionary( 'XMP' ).GetString( 'dc:creator' ); // Return location information about the content being shown in the image sLocation := ImageEnView1.IO.Params.Dict.GetDictionary( 'XMP' ).GetString( 'photoshop:City' ) + ', ' + ImageEnView1.IO.Params.Dict.GetDictionary( 'XMP' ).GetString( 'photoshop:State' ) + ', ' + ImageEnView1.IO.Params.Dict.GetDictionary( 'XMP' ).GetString( 'photoshop:Country' ); // Return the document title from the XMP metadata sTitle := ImageEnView1.IO.Params.Dict.GetDictionary( 'XMP' ).GetString( 'dc:title' ); // Return the document keywords from the XMP metadata sKeywords := ImageEnView1.IO.Params.Dict.GetDictionary( 'XMP' ).GetString( 'dc:subject' ); // Return the document copyright information from the XMP metadata sCopyright := ImageEnView1.IO.Params.Dict.GetDictionary( 'XMP' ).GetString( 'dc:rights' ); // Return the Photoshop Headline from the XMP metadata sHeadline := ImageEnView1.IO.Params.Dict.GetDictionary( 'XMP' ).GetString( 'photoshop:Headline' ); // Return the Windows Rating from the XMP metadata (0 to 5) sRating := ImageEnView1.IO.Params.Dict.GetDictionary( 'XMP' ).GetString( 'xmp:Rating' ); !!} function TIEDictionary.GetString(key: WideString; recursive: boolean): WideString; var obj: TObject; begin obj := Get(key, false, recursive); if obj is TIEDictionaryValueInteger then result := IntToStr((obj as TIEDictionaryValueInteger).value) else if obj is TIEDictionaryValueDouble then result := IEFloatToStrW((obj as TIEDictionaryValueDouble).value) else if obj is TIEDictionary then result := (obj as TIEDictionary).GetString('#text', true) else result := (obj as TIEDictionaryValueWideString).value; end; {!! TIEDictionary.GetInteger Declaration function GetInteger(key: WideString; recursive: boolean = true): integer; Description Returns the integer value to which the key is mapped in this dictionary. If the key doesn't exist an exception is raised. Parameter Description key A key in this dictionary recursive If true then search this key inside subdictionaries
Examples // Return the Photoshop Color Mode from the XMP metadata iColorMode := ImageEnView1.IO.Params.Dict.GetDictionary( 'XMP' ).GetInteger( 'photoshop:ColorMode' ); !!} function TIEDictionary.GetInteger(key: WideString; recursive: boolean): integer; var obj: TObject; begin obj := Get(key, false, recursive); if obj is TIEDictionaryValueDouble then result := trunc( (obj as TIEDictionaryValueDouble).value ) else if obj is TIEDictionaryValueWideString then result := StrToInt((obj as TIEDictionaryValueWideString).value) else if obj is TIEDictionary then result := (obj as TIEDictionary).GetInteger('#text', true) else result := (obj as TIEDictionaryValueInteger).value; end; {!! TIEDictionary.GetDouble Declaration function GetDouble(key: WideString; recursive: boolean = true): double; Description Returns the double value to which the key is mapped in this dictionary. If the key doesn't exist an exception is raised. Parameter Description key A key in this dictionary recursive If true then search this key inside subdictionaries
!!} function TIEDictionary.GetDouble(key: WideString; recursive: boolean): double; var obj: TObject; begin obj := Get(key, false, recursive); if obj is TIEDictionaryValueInteger then result := (obj as TIEDictionaryValueInteger).value else if obj is TIEDictionaryValueWideString then result := IEStrToFloatDefW((obj as TIEDictionaryValueWideString).value, 0.0) else if obj is TIEDictionary then result := (obj as TIEDictionary).GetDouble('#text', true) else result := (obj as TIEDictionaryValueDouble).value; end; {!! TIEDictionary.GetBoolean Declaration function GetBoolean(key: WideString; recursive: boolean = true): boolean; Description Returns the boolean value to which the key is mapped in this dictionary. If the key doesn't exist an exception is raised. Parameter Description key A key in this dictionary recursive If true then search this key inside subdictionaries
!!} function TIEDictionary.GetBoolean(key: WideString; recursive: boolean): boolean; var obj: TObject; begin obj := Get(key, false, recursive); if obj is TIEDictionaryValueInteger then result := (obj as TIEDictionaryValueInteger).value <> 0 else if obj is TIEDictionaryValueDouble then result := (obj as TIEDictionaryValueDouble).value <> 0.0 else if obj is TIEDictionaryValueWideString then result := (obj as TIEDictionaryValueWideString).value = 'true' else if obj is TIEDictionary then result := (obj as TIEDictionary).GetBoolean('#text', true) else result := (obj as TIEDictionaryValueBoolean).value; end; {!! TIEDictionary.GetDictionary Declaration function GetDictionary(key: WideString; recursive: boolean = true):
; Description Returns the value to which the key is mapped in this dictionary. If the key doesn't exist an exception is raised. Parameter Description key A key in this dictionary recursive If true then search this key inside subdictionaries
!!} function TIEDictionary.GetDictionary(key: WideString; recursive: boolean): TIEDictionary; begin result := Get(key, false, recursive) as TIEDictionary; end; {!! TIEDictionary.GetList Declaration function GetList(key: WideString; recursive: boolean = true): TObjectList; Description Returns the TObjectList value to which the key is mapped in this dictionary. If the key doesn't exist an exception is raised. Parameter Description key A key in this dictionary recursive If true then search this key inside subdictionaries
!!} function TIEDictionary.GetList(key: WideString; recursive: boolean): TObjectList; begin result := Get(key, false, recursive) as TObjectList; end; {!! TIEDictionary.Insert Declaration procedure Insert(key: WideString; value: TObject); overload; procedure Insert(key: WideString; value: WideString); overload; procedure Insert(key: WideString; value: integer); overload; procedure Insert(key: WideString; value: double); overload; procedure Insert(key: WideString; value: boolean); overload; procedure Insert(key: WideString; value:
); overload; procedure Insert(key: WideString; value: TObjectList); overload; Description Maps the specified key to the specified object or value in this dictionary. Parameter Description key A string key value Object/value to store. The dictionary owns the object: it will be automatically disposed.
!!} procedure TIEDictionary.Insert(key: WideString; value: TObject); var bucket: cardinal; ths, lst: TIEDictionaryBucket; begin CheckInit(); bucket := execHash(key, m_bucketCount); if m_buckets[bucket] = nil then begin // bucket free, just set this item m_buckets[bucket] := TIEDictionaryBucket.Create(key, value); inc(m_count); end else begin // bucket not free, find for equal item ths := GetInBucket(bucket, key, lst); if ths = nil then begin // not equal item, insert this item after the last one lst.next := TIEDictionaryBucket.Create(key, value, nil); inc(m_count); end else begin // equal item found, just replace value ths.value.Free(); ths.value := value; // do not inc m_count! end; end; end; procedure TIEDictionary.Insert(key: WideString; value: WideString); begin Insert(key, TIEDictionaryValueWideString.Create(value)); end; procedure TIEDictionary.Insert(key: WideString; value: integer); begin Insert(key, TIEDictionaryValueInteger.Create(value)); end; procedure TIEDictionary.Insert(key: WideString; value: double); begin Insert(key, TIEDictionaryValueDouble.Create(value)); end; procedure TIEDictionary.Insert(key: WideString; value: boolean); begin Insert(key, TIEDictionaryValueBoolean.Create(value)); end; procedure TIEDictionary.Insert(key: WideString; value: TIEDictionary); begin Insert(key, TObject(value)); end; procedure TIEDictionary.Insert(key: WideString; value: TObjectList); begin Insert(key, TObject(value)); end; {!! TIEDictionary.Erase Declaration function Erase(key: WideString): boolean; Description Remove the specified key. Parameter Description key A key in this dictionary freeValue If True the value is deallocated
!!} function TIEDictionary.Erase(key: WideString; freeValue: boolean): boolean; var bucket: cardinal; ths, prev: TIEDictionaryBucket; begin CheckInit(); result := false; bucket := execHash(key, m_bucketCount); prev := nil; ths := m_buckets[bucket]; while (ths <> nil) do begin if keysMatch(ths.key, key) then begin // found if prev = nil then // this is the first item in bucket m_buckets[bucket] := ths.next else // has a previous item, change it prev.next := ths.next; if not freeValue then ths.value := nil; ths.Free(); dec(m_count); result := true; break; end; prev := ths; ths := ths.next; end; end; {!! TIEDictionary.GetNext Declaration function GetNext(current: TIEStrStrEnumerator): boolean; Description Allows to iterate among all dictionary elements. Returns true if an element is available. Parameter Description current An object used to store current enumerator state.
Example var current: TIEStrStrEnumerator; current := TIEStrStrEnumerator.Create(); while dict.GetNext(current) do begin key := current.item.key; value := current.item.value; ... end; current.Free(); !!} function TIEDictionary.GetNext(current: TIEStrStrEnumerator): boolean; var next: TIEDictionaryBucket; begin CheckInit(); result := false; if current.item <> nil then begin // current doesn't point to "before the first item", so check in current bucket next := current.item.next; if next <> nil then begin // return next item of current bucket current.item := next; result := true; exit; end; inc(current.bucket); // try next bucket end; while current.bucket < m_bucketCount do begin current.item := m_buckets[current.bucket]; if current.item <> nil then begin result := true; break; end; inc(current.bucket); end; if result = false then begin current.bucket := 0; current.item := nil; end; end; {!! TIEDictionary.IsEmpty Declaration function IsEmpty(): boolean; Description Returns True if the dictionary contains no elements. !!} function TIEDictionary.IsEmpty(): boolean; begin result := (m_count = 0); end; function TIEDictionary.EncodeString(Text: WideString): WideString; var i: integer; begin result := ''; for i := 1 to length(Text) do if Text[i] = '"' then result := result + '\"' else result := result + Text[i]; end; function TIEDictionary.DumpJSON(obj: TObject): WideString; begin if obj is TIEDictionaryValueWideString then result := '"' + EncodeString((obj as TIEDictionaryValueWideString).value) + '"' else if obj is TIEDictionaryValueInteger then result := IntToStr((obj as TIEDictionaryValueInteger).value) else if obj is TIEDictionaryValueDouble then result := IEFloatToStrW((obj as TIEDictionaryValueDouble).value) else if obj is TIEDictionaryValueBoolean then case (obj as TIEDictionaryValueBoolean).value of false : result := 'false'; true : result := 'true'; end else if obj is TIEDictionary then result := (obj as TIEDictionary).DumpJSON() else if obj is TObjectList then result := DumpJSON(TObjectList(obj)) else result := obj.ClassName; // unknown end; function TIEDictionary.DumpJSON(obj: TObjectList): WideString; var i: integer; begin result := '['; for i := 0 to obj.Count - 1 do begin result := result + DumpJSON(obj[i]); if i < obj.Count - 1 then result := result + ','; end; result := result + ']'; end; function TIEDictionary.DumpJSON(): WideString; var current: TIEStrStrEnumerator; isfirst: boolean; begin result := '{'; current := TIEStrStrEnumerator.Create(); try isfirst := true; while GetNext(current) do begin if not isfirst then result := result + ','; result := result + '"' + EncodeString(current.item.key) + '"' + ':'; result := result + DumpJSON(current.item.value); isfirst := false; end; finally current.Free(); end; result := result + '}'; end; function TIEDictionary.DumpXML(obj: TObject): WideString; begin if obj is TIEDictionaryValueWideString then result := EncodeString((obj as TIEDictionaryValueWideString).value) else if obj is TIEDictionaryValueInteger then result := IntToStr((obj as TIEDictionaryValueInteger).value) else if obj is TIEDictionaryValueDouble then result := IEFloatToStrW((obj as TIEDictionaryValueDouble).value) else if obj is TIEDictionaryValueBoolean then case (obj as TIEDictionaryValueBoolean).value of false : result := 'false'; true : result := 'true'; end else if obj is TIEDictionary then result := (obj as TIEDictionary).DumpXML() else if obj is TObjectList then result := DumpXML(TObjectList(obj)) else result := obj.ClassName; // unknown end; function TIEDictionary.DumpXML(obj: TObjectList): WideString; var i: integer; begin result := ''; for i := 0 to obj.Count - 1 do result := result + DumpXML(obj[i]); end; function TIEDictionary.DumpXML(): WideString; var current: TIEStrStrEnumerator; begin result := ''; current := TIEStrStrEnumerator.Create(); try while GetNext(current) do begin result := result + '<' + EncodeString(current.item.key) + '>'; result := result + DumpXML(current.item.value); result := result + ''; end; finally current.Free(); end; end; {!! TIEDictionary.Dump Declaration function Dump(dumpType:
): WideString; Description Returns a JSON-like or XML representation of the dictionary. Not all dictionary contents can be dumped to XML and correctly parsed back. See Also - !!} function TIEDictionary.Dump(dumpType: TIEDictionaryParserLang): WideString; begin case dumpType of ieplJSON: result := DumpJSON(); ieplXML: result := DumpXML(); end; end; {!! TIEDictionary.Parse Declaration function Parse(text: WideString): boolean; Description Parses the JSON-like string and populates the dictionary. This method doesn't remove existing items. Parameter Description text A JSON-like text
See Also -
Example } // dict.Parse('{"string" : "string content", "myinteger": 1234, "mydouble": 123.456, "a_bool_true" : true, "a_bool_false" : false, "subdict" : {"name": "john", "surname" : "mad"}, "array": [1,2,3,4,"hello", {}, {"alfa":"beta"}, [9,10]] }'); {!!} function TIEDictionary.Parse(text: WideString): boolean; var parser: TIEDictionaryParser; begin parser := TIEDictionaryParser.Create(text); try parser.Parse(self); result := not parser.Aborted; finally parser.Free(); end; end; procedure TIEDictionary.Assign(Source: TIEDictionary); begin Clear(); Parse(Source.Dump(ieplJSON)); end; constructor TIEDictionaryParser.Create(Text: WideString); begin m_text := Text; m_textLen := length(Text); m_textPos := 1; m_abort := false; // check language to decode m_lang := ieplJSON; if PeekToken() <> '{' then begin m_lang := ieplXML; if PeekToken() <> '<' then m_abort := true; end; end; procedure TIEDictionaryParser.AbortParse(); begin m_abort := true; end; function TIEDictionaryParser.DecodeString(Text: WideString): WideString; var i: integer; begin result := ''; i := 1; while i <= length(Text) do begin if (i < length(Text)) and (Text[i] = '\') and (Text[i + 1] = '"') then begin result := result + '"'; inc(i); end else result := result + Text[i]; inc(i); end; end; function TIEDictionaryParser.IsToken(c: WideChar): boolean; begin case m_lang of ieplJSON: result := (c = '{') or (c = '}') or (c = '[') or (c = ']') or (c = '"') or (c = ':') or (c = ','); ieplXML: result := (c = '<') or (c = '>') or (c = '/') or (c = '''') or (c = '"') or (c = '=') or (c = '?'); else result := false; end; end; function TIEDictionaryParser.IsSpace(c: WideChar): boolean; begin result := (c = ' ') or (c = #8) or (c = #13) or (c = #10); end; procedure TIEDictionaryParser.ByPassSpaces(); begin while HasChar() and IsSpace(PeekChar()) do GetChar(); end; function TIEDictionaryParser.HasChar(): boolean; begin result := m_textPos <= m_textLen; end; function TIEDictionaryParser.GetChar(): WideChar; begin result := m_text[m_textPos]; inc(m_textPos); end; function TIEDictionaryParser.PeekChar(): WideChar; begin result := m_text[m_textPos]; end; function TIEDictionaryParser.SavePos(): integer; begin result := m_textPos; end; procedure TIEDictionaryParser.RestorePos(pos: integer); begin m_textPos := pos; end; function TIEDictionaryParser.GetToken(): WideChar; begin while HasChar() do begin result := GetChar(); if not IsSpace(result) then exit; end; result := ' '; // end of string? end; function TIEDictionaryParser.PeekToken(): WideChar; var lpos: integer; begin lpos := SavePos(); result := GetToken(); RestorePos(lpos); end; function TIEDictionaryParser.GetString(): WideString; var c: WideChar; prevChar: WideChar; marker: WideChar; // character used to open and close string begin result := ''; marker := GetToken(); if (marker <> '"') and (marker <> '''') then // accepts both single quote and double quote begin AbortParse(); exit; end; prevChar := ' '; while HasChar() do begin c := GetChar(); if (prevChar <> '\') and (c = marker) then break; result := result + c; prevChar := c; end; // ending marker already passed result := DecodeString(result); end; function TIEDictionaryParser.Parse(mergeWith: TIEDictionary = nil): TIEDictionary; begin case m_lang of ieplJSON: result := JSON_ParseDictionary(mergeWith); ieplXML: result := XML_ParseContent(mergeWith); else result := nil; end; end; // content can be free text or tags function TIEDictionaryParser.XML_ParseContent(mergeWith: TIEDictionary): TIEDictionary; var key: WideString; value: TIEDictionary; content: TIEDictionary; tk: WideChar; text: WideString; lpos: integer; procedure Ins(key: WideString; value: TObject); var evalue: TObject; arr: TObjectList; begin if result.HasKey(key, false) then begin // key already exist, create an array evalue := result.Get(key); if not (evalue is TObjectList) then begin result.Erase(key, false); // evalue still exists arr := TObjectList.Create(); result.Insert(key, arr); arr.Add(evalue); arr.Add(value); end else (evalue as TObjectList).Add(value); end else result.Insert(key, value); end; begin if mergeWith = nil then result := TIEDictionary.Create() else result := mergeWith; text := ''; while HasChar() and not m_abort do begin lpos := SavePos(); if PeekToken() = '<' then begin GetToken(); // bypass '<' if PeekToken() = '/' then begin // this is an upper enclosing tag, end this procedure RestorePos(lpos); break; end else if PeekToken() = '?' then begin // this is an xml declaration (like ) GetToken(); // bypass '?' key := XML_GetName(); value := XML_ParseAttributes(); Ins(key, value); if (GetToken() = '?') and (GetToken() = '>') then continue; AbortParse(); end else begin // this is a tag key := XML_GetName(); value := XML_ParseAttributes(); Ins(key, value); tk := GetToken(); if (tk = '/') and (PeekToken() = '>') then begin // empty tag (like ) GetToken(); // by pass > end else if (tk = '>') then begin // tag with content, get content (like content ) content := XML_ParseContent(); value.insert('#content', content); if (GetToken() = '<') and (GetToken() = '/') and (XML_GetName() = key) and (GetToken() = '>') then continue; end; end; end else begin // this is text content text := text + GetChar(); end; end; text := trim(text); if text <> '' then result.Insert('#text', text); end; function TIEDictionaryParser.XML_GetName(): WideString; var c: WideChar; begin result := ''; ByPassSpaces(); while HasChar() do begin c := PeekChar(); if IsSpace(c) or IsToken(c) then break; result := result + GetChar(); end; end; function TIEDictionaryParser.XML_ParseAttributes(): TIEDictionary; var key: WideString; value: TIEDictionaryValueWideString; tk: WideChar; begin result := TIEDictionary.Create(); while HasChar() do begin tk := PeekToken(); if (tk = '>') or (tk = '?') or (tk = '/') then break; key := XML_GetName(); if GetToken() <> '=' then begin AbortParse(); exit; end; value := ParseString(); result.Insert(key, value); end; end; function TIEDictionaryParser.JSON_ParseDictionary(mergeWith: TIEDictionary): TIEDictionary; var key: WideString; value: TObject; tk: WideChar; procedure Ins(key: WideString; value: TObject); var evalue: TObject; arr: TObjectList; begin if result.HasKey(key, false) then begin // key already exist, create an array evalue := result.Get(key); if not (evalue is TObjectList) then begin result.Erase(key, false); // evalue still exists arr := TObjectList.Create(); result.Insert(key, arr); arr.Add(evalue); arr.Add(value); end else (evalue as TObjectList).Add(value); end else result.Insert(key, value); end; begin if mergeWith = nil then result := TIEDictionary.Create() else result := mergeWith; if GetToken() <> '{' then begin AbortParse(); exit; end; while HasChar() and not m_abort do begin if PeekToken() = '}' then break; key := GetString(); if GetToken() <> ':' then begin AbortParse(); exit; end; value := JSON_ParseValue(); Ins(key, value); tk := PeekToken(); if tk = '}' then break else if tk <> ',' then AbortParse() else GetToken(); // gets ',' end; if GetToken() <> '}' then AbortParse(); end; function TIEDictionaryParser.JSON_ParseValue(): TObject; var token: WideChar; begin token := PeekToken(); if token = '{' then result := JSON_ParseDictionary() else if token = '[' then result := JSON_ParseArray() else if token = '"' then result := ParseString() else result := ParseIdentifier(); end; function TIEDictionaryParser.JSON_ParseArray(): TObjectList; var value: TObject; tk: WideChar; begin result := TObjectList.Create(); if GetToken() <> '[' then begin AbortParse(); exit; end; while HasChar() and not m_abort do begin if PeekToken() = ']' then break; value := JSON_ParseValue(); if not m_abort then result.Add(value); tk := PeekToken(); if tk = ']' then break else if tk <> ',' then AbortParse() else GetToken(); // gets ',' end; if GetToken() <> ']' then AbortParse(); end; function TIEDictionaryParser.ParseString(): TIEDictionaryValueWideString; begin result := TIEDictionaryValueWideString.Create( GetString() ); end; // true/false/integer/double function TIEDictionaryParser.ParseIdentifier(): TObject; var c: WideChar; s: WideString; begin s := ''; ByPassSpaces(); // get identifier up to space while HasChar() do begin c := PeekChar(); if IsSpace(c) or IsToken(c) then break; s := s + GetChar(); end; if s = 'false' then result := TIEDictionaryValueBoolean.Create(false) else if s = 'true' then result := TIEDictionaryValueBoolean.Create(true) else begin if pos('.', s) > 0 then result := TIEDictionaryValueDouble.Create( IEStrToFloatDefW(s, 0.0) ) else result := TIEDictionaryValueInteger.Create( StrToIntDef(s, 0) ); end; end; ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// // TIEHashStream type HCRYPTPROV = pointer; type HCRYPTKEY = pointer; type HCRYPTHASH = pointer; type ALG_ID = DWORD; function CryptAcquireContext(out phProv: HCRYPTPROV; pszContainer: PAnsiChar; pszProvider: PAnsiChar; dwProvType: DWORD; dwFlags: DWORD): longbool; stdcall; external 'Advapi32.dll' name 'CryptAcquireContextA'; function CryptCreateHash(hProv: HCRYPTPROV; Algid: ALG_ID; hKey: HCRYPTKEY; dwFlags: DWORD; out phHash: HCRYPTHASH): longbool; stdcall; external 'Advapi32.dll' name 'CryptCreateHash'; function CryptHashData(hHash: HCRYPTHASH; pbData: pbyte; dwDataLen: DWORD; dwFlags: DWORD): longbool; stdcall; external 'Advapi32.dll' name 'CryptHashData'; function CryptGetHashParam(hHash: HCRYPTHASH; dwParam: DWORD; pbData: pbyte; pdwDataLen: PDWORD; dwFlags: DWORD): longbool; stdcall; external 'Advapi32.dll' name 'CryptGetHashParam'; function CryptDestroyHash(hHash: HCRYPTHASH): longbool; stdcall; external 'Advapi32.dll' name 'CryptDestroyHash'; function CryptReleaseContext(hProv: HCRYPTPROV; dwFlags: DWORD): longbool; stdcall; external 'Advapi32.dll' name 'CryptReleaseContext'; // ALG_ID values const CALG_3DES = $00006603; // Triple DES encryption algorithm. CALG_3DES_112 = $00006609; // Two-key triple DES encryption with effective key length equal to 112 bits. CALG_AES = $00006611; // Advanced Encryption Standard (AES). This algorithm is supported by the Microsoft AES Cryptographic Provider. Windows 2000/NT: This algorithm is not supported. CALG_AES_128 = $0000660e; // 128 bit AES. This algorithm is supported by the Microsoft AES Cryptographic Provider. Windows 2000/NT: This algorithm is not supported. CALG_AES_192 = $0000660f; // 192 bit AES. This algorithm is supported by the Microsoft AES Cryptographic Provider. Windows 2000/NT: This algorithm is not supported. CALG_AES_256 = $00006610; // 256 bit AES. This algorithm is supported by the Microsoft AES Cryptographic Provider. Windows 2000/NT: This algorithm is not supported. CALG_AGREEDKEY_ANY = $0000aa03; // Temporary algorithm identifier for handles of Diffie-Hellman–agreed keys. CALG_CYLINK_MEK = $0000660c; // An algorithm to create a 40-bit DES key that has parity bits and zeroed key bits to make its key length 64 bits. This algorithm is supported by the Microsoft Base Cryptographic Provider. CALG_DES = $00006601; // DES encryption algorithm. CALG_DESX = $00006604; // DESX encryption algorithm. CALG_DH_EPHEM = $0000aa02; // Diffie-Hellman ephemeral key exchange algorithm. CALG_DH_SF = $0000aa01; // Diffie-Hellman store and forward key exchange algorithm. CALG_DSS_SIGN = $00002200; // DSA public key signature algorithm. CALG_ECDH = $0000aa05; // Elliptic curve Diffie-Hellman key exchange algorithm. Windows Server 2003, Windows XP, and Windows 2000/NT: This algorithm is not supported. CALG_ECDSA = $00002203; // Elliptic curve digital signature algorithm. Windows Server 2003, Windows XP, and Windows 2000/NT: This algorithm is not supported. CALG_ECMQV = $0000a001; // Elliptic curve Menezes, Qu, and Vanstone (MQV) key exchange algorithm. Windows Server 2003, Windows XP, and Windows 2000/NT: This algorithm is not supported. CALG_HASH_REPLACE_OWF = $0000800b; // One way function hashing algorithm. Windows 2000/NT: This algorithm is not supported. CALG_HUGHES_MD5 = $0000a003; // Hughes MD5 hashing algorithm. CALG_HMAC = $00008009; // HMAC keyed hash algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. CALG_KEA_KEYX = $0000aa04; // KEA key exchange algorithm (FORTEZZA). CALG_MAC = $00008005; // MAC keyed hash algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. CALG_MD2 = $00008001; // MD2 hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. CALG_MD4 = $00008002; // MD4 hashing algorithm. CALG_MD5 = $00008003; // MD5 hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. CALG_NO_SIGN = $00002000; // No signature algorithm. Windows 2000/NT: This algorithm is not supported. CALG_OID_INFO_CNG_ONLY = $ffffffff; // The algorithm is only implemented in CNG. The macro, IS_SPECIAL_OID_INFO_ALGID, can be used to determine whether a cryptography algorithm is only supported by using the CNG functions. CALG_OID_INFO_PARAMETERS = $fffffffe; // The algorithm is defined in the encoded parameters. The algorithm is only supported by using CNG. The macro, IS_SPECIAL_OID_INFO_ALGID, can be used to determine whether a cryptography algorithm is only supported by using the CNG functions. CALG_PCT1_MASTER = $00004c04; // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications. CALG_RC2 = $00006602; // RC2 block encryption algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. CALG_RC4 = $00006801; // RC4 stream encryption algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. CALG_RC5 = $0000660d; // RC5 block encryption algorithm. CALG_RSA_KEYX = $0000a400; // RSA public key exchange algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. CALG_RSA_SIGN = $00002400; // RSA public key signature algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. CALG_SCHANNEL_ENC_KEY = $00004c07; // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications. CALG_SCHANNEL_MAC_KEY = $00004c03; // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications. CALG_SCHANNEL_MASTER_HASH = $00004c02; // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications. CALG_SEAL = $00006802; // SEAL encryption algorithm. CALG_SHA = $00008004; // SHA hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. CALG_SHA1 = $00008004; // Same as CALG_SHA. This algorithm is supported by the Microsoft Base Cryptographic Provider. CALG_SHA_256 = $0000800c; // 256 bit SHA hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. Windows XP and Windows 2000/NT: This algorithm is not supported. CALG_SHA_384 = $0000800d; // 384 bit SHA hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. Windows XP and Windows 2000/NT: This algorithm is not supported. CALG_SHA_512 = $0000800e; // 512 bit SHA hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider. Windows XP and Windows 2000/NT: This algorithm is not supported. CALG_SKIPJACK = $0000660a; // Skipjack block encryption algorithm (FORTEZZA). CALG_SSL2_MASTER = $00004c05; // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications. CALG_SSL3_MASTER = $00004c01; // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications. CALG_SSL3_SHAMD5 = $00008008; // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications. CALG_TEK = $0000660b; // TEK (FORTEZZA). CALG_TLS1_MASTER = $00004c06; // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications. CALG_TLS1PRF = $0000800a; // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications. // Providers (predefined only) const PROV_RSA_FULL = 1; PROV_RSA_SIG = 2; PROV_DSS = 3; PROV_FORTEZZA = 4; PROV_MS_EXCHANGE = 5; PROV_SSL = 6; PROV_RSA_SCHANNEL = 12; PROV_DSS_DH = 13; PROV_DH_SCHANNEL = 18; PROV_RSA_AES = 24; // dwFlags definitions for CryptAcquireContext const CRYPT_VERIFYCONTEXT = $F0000000; CRYPT_NEWKEYSET = $00000008; CRYPT_DELETEKEYSET = $00000010; CRYPT_MACHINE_KEYSET = $00000020; CRYPT_SILENT = $00000040; CRYPT_DEFAULT_CONTAINER_OPTIONAL = $00000080; const HP_ALGID = $0001; // Hash algorithm HP_HASHVAL = $0002; // Hash value HP_HASHSIZE = $0004; // Hash value size HP_HMAC_INFO = $0005; // information for creating an HMAC HP_TLS1PRF_LABEL = $0006; // label for TLS1 PRF HP_TLS1PRF_SEED = $0007; // seed for TLS1 PRF {!! TIEHashStream.Create Declaration constructor Create(Algorithm: = iehaMD5; Buffered: boolean = true); Description Creates a TIEHashStream which will use specified hash algorithm. If Buffered is true the stream data is written in a temporary memory stream. This is necessary when Seek and Read methods are necessary. Example // saves the file with an unique name (create hash from the jpeg content and use it as file name) var hashStream: TIEHashStream; begin ImageEnView1.IO.LoadFromFile('input.jpg'); hashStream := TIEHashStream.Create(iehaMD5); try ImageEnView1.IO.SaveToStreamJpeg(hashStream); hashStream.SaveToFile(hashStream.GetHash()+'.jpg'); finally hashStream.Free; end; end; !!} constructor TIEHashStream.Create(Algorithm: TIEHashAlgorithm; Buffered: boolean); begin inherited Create; if Buffered then m_MemStream := TMemoryStream.Create else m_MemStream := nil; if not CryptAcquireContext(m_CryptProvider, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT or CRYPT_MACHINE_KEYSET) then raise EIEException.Create('Unable to use CryptoAPI'); try if not CryptCreateHash(m_CryptProvider, DWORD(Algorithm), nil, 0, m_CryptHash) then raise EIEException.Create('Unable to create Crypto Hash'); except CryptReleaseContext(m_CryptProvider, 0); raise; end; end; destructor TIEHashStream.Destroy; begin m_MemStream.Free; CryptDestroyHash(m_CryptHash); CryptReleaseContext(m_CryptProvider, 0); inherited Destroy; end; {!! TIEHashStream.GetHash Declaration function GetHash: AnsiString; Description Calculates the hash and returns the string representation of the hash. Example // saves the file with an unique name (create hash from the jpeg content and use it as file name) var hashStream: TIEHashStream; begin ImageEnView1.IO.LoadFromFile('input.jpg'); hashStream := TIEHashStream.Create(iehaMD5); try ImageEnView1.IO.SaveToStreamJpeg(hashStream); hashStream.SaveToFile(hashStream.GetHash()+'.jpg'); finally hashStream.Free; end; end; !!} function TIEHashStream.GetHash: AnsiString; var hash: pbytearray; hashSize: DWORD; i: integer; dw: DWORD; begin result := ''; if assigned(m_MemStream) then if not CryptHashData(m_CryptHash, pbyte(m_MemStream.Memory), m_MemStream.Size, 0) then raise EIEException.Create('Unable to add hash data'); // get hash size dw := 4; if not CryptGetHashParam(m_CryptHash, HP_HASHSIZE, @hashSize, @dw, 0) then raise EIEException.Create('Unable to create hash'); getmem(hash, hashSize); // get hash data dw := hashSize; if CryptGetHashParam(m_CryptHash, HP_HASHVAL, @hash[0], @dw, 0) then for i := 0 to hashSize - 1 do result := result + AnsiString(Format('%.2x', [hash[i]])); freemem(hash); result := IELowerCase(result); end; {!! TIEHashStream.Write Declaration function Write(const Buffer; Count: longint): longint; Description Writes data in the hash stream. !!} function TIEHashStream.Write(const Buffer; Count: longint): longint; begin if assigned(m_MemStream) then result := m_MemStream.Write(Buffer, Count) else begin if not CryptHashData(m_CryptHash, pbyte(@Buffer), Count, 0) then raise EIEException.Create('Unable to add hash data'); result := Count; end; end; {!! TIEHashStream.Read Declaration function Read(var Buffer; Count: longint): Longint; Description Reads data in the hash stream. It is necessary to create the stream as "buffered" to use this method. !!} function TIEHashStream.Read(var Buffer; Count: longint): Longint; begin if assigned(m_MemStream) then result := m_MemStream.Read(Buffer, Count) else raise EIEException.Create('Read error. Hash stream not Buffered, please create Buffered stream.'); end; {!! TIEHashStream.Seek Declaration function Seek(const Offset: int64; Origin: TSeekOrigin): int64; Description Seeks data in the hash stream. It is necessary to create the stream as "buffered" to use this method. !!} {$ifdef IEOLDSEEKDEF} function TIEHashStream.Seek(Offset: longint; Origin: word): longint; {$else} function TIEHashStream.Seek(const Offset: int64; Origin: TSeekOrigin): int64; {$endif} begin if assigned(m_MemStream) then result := m_MemStream.Seek(Offset, Origin) else raise EIEException.Create('Seek error. Hash stream not Buffered, please create Buffered stream.'); end; {!! TIEHashStream.SaveToFile Declaration procedure TIEHashStream.SaveToFile(const filename: WideString); Description Saves the stream to file (this is the actual data written, not the hash). This is useful to save the hashed data one time. It is necessary to create the stream as "buffered" to use this method. See also: Example // saves the file with an unique name (create hash from the jpeg content and use it as file name) var hashStream: TIEHashStream; begin ImageEnView1.IO.LoadFromFile('input.jpg'); hashStream := TIEHashStream.Create(iehaMD5); try ImageEnView1.IO.SaveToStreamJpeg(hashStream); hashStream.SaveToFile(hashStream.GetHash()+'.jpg'); finally hashStream.Free; end; end; !!} procedure TIEHashStream.SaveToFile(const filename: WideString); var stream: TIEWideFileStream; begin stream := TIEWideFileStream.Create(filename, fmCreate); try SaveToStream(stream); finally stream.Free(); end; end; {!! TIEHashStream.SaveToStream Declaration procedure SaveToStream(Stream: TStream); Description Saves data to stream (this is the actual data written, not the hash). This is useful to save the hashed data one time. It is necessary to create the stream as "buffered" to use this method. See also: . !!} procedure TIEHashStream.SaveToStream(Stream: TStream); begin if assigned(m_MemStream) then m_MemStream.SaveToStream(Stream) else raise EIEException.Create('SaveToStream error. Hash stream not Buffered, please create Buffered stream.'); end; {!! TIEHashStream.LoadFromFile Declaration procedure LoadFromFile(const filename: WideString); Description Loads data to hash from specified file. It is necessary to create the stream as "buffered" to use this method. !!} procedure TIEHashStream.LoadFromFile(const filename: WideString); var stream: TIEWideFileStream; begin stream := TIEWideFileStream.Create(filename, fmOpenRead or fmShareDenyWrite); try LoadFromStream(stream); finally stream.Free(); end; end; {!! TIEHashStream.LoadFromStream Declaration procedure LoadFromStream(Stream: TStream); Description Loads data to hash from specified stream. It is necessary to create the stream as "buffered" to use this method. !!} procedure TIEHashStream.LoadFromStream(Stream: TStream); begin if assigned(m_MemStream) then m_MemStream.LoadFromStream(Stream) else raise EIEException.Create('LoadFromStream error. Hash stream not Buffered, please create Buffered stream.'); end; ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// // TIEExecutorThread constructor TIEExecutorThread.Create(execFunc: TIEExecutorFunc); begin inherited Create(true); // create suspended fExecFunc := execFunc; end; procedure TIEExecutorThread.Execute(); begin fExecFunc(); end; ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// // TIEExecutor constructor TIEExecutor.Create(execInThread: Boolean); begin if execInThread then fThread := TIEExecutorThread.Create(execute) else fThread := nil; end; destructor TIEExecutor.Destroy(); begin if assigned(fThread) then fThread.Free(); end; function TIEExecutor.GetThread(): TThread; begin result := fThread; end; ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// // TIEThreadPool constructor TIEThreadPool.Create(); begin inherited Create(); fThreads := TList.Create; end; destructor TIEThreadPool.Destroy; begin Join(); fThreads.Free; inherited; end; // like Join() but doesn't destroy threads (you can still access their properties) procedure TIEThreadPool.WaitFor(); var i: integer; t: TThread; begin for i := 0 to fThreads.Count - 1 do begin t := (TObject(fThreads[i]) as TIEExecutor).GetThread(); if assigned(t) then t.WaitFor(); end; end; procedure TIEThreadPool.Join(); var i: integer; t: TThread; begin for i := 0 to fThreads.Count - 1 do begin t := (TObject(fThreads[i]) as TIEExecutor).GetThread(); if assigned(t) then t.WaitFor(); (TObject(fThreads[i]) as TIEExecutor).Free(); end; fThreads.Clear; end; function TIEThreadPool.GetThreads(idx: integer): TIEExecutor; begin result := TObject(fThreads[idx]) as TIEExecutor; end; procedure TIEThreadPool.Add(Thread: TIEExecutor); var t: TThread; begin fThreads.Add(Thread); t := Thread.GetThread(); if assigned(t) then begin {$ifdef IEHASTTHREADSTART} t.Start(); {$else} t.Resume(); {$endif} end else begin // execute inside this thread Thread.Execute(); end; end; // TIEThreadPool ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEWideFileStream function IECreateFileW(lpFileName: PWideChar; dwDesiredAccess, dwShareMode: DWORD; lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: DWORD; hTemplateFile: THandle): THandle; begin if Win32Platform = VER_PLATFORM_WIN32_NT then result := CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile) else result := CreateFileA(PAnsiChar(AnsiString(lpFileName)), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile) end; function WideFileCreate(const FileName: WideString): THandle; begin Result := IECreateFileW(PWideChar(FileName), GENERIC_READ or GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); end; function WideFileOpen(const FileName: WideString; Mode: LongWord): THandle; const AccessMode: array[0..2] of LongWord = ( GENERIC_READ, GENERIC_WRITE, GENERIC_READ or GENERIC_WRITE); ShareMode: array[0..4] of LongWord = ( 0, 0, FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE); begin Result := INVALID_HANDLE_VALUE; if ((Mode and 3) <= fmOpenReadWrite) and ((Mode and $F0) <= fmShareDenyNone) then Result := IECreateFileW(PWideChar(FileName), AccessMode[Mode and 3], ShareMode[(Mode and $F0) shr 4], nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); end; constructor TIEWideFileStream.Create(const FileName: WideString; Mode: Word); const SFCreateError = 'Cannot create file %s'; SFCreateErrorEx = 'Cannot create file "%s". %s'; SFOpenError = 'Cannot open file %s'; SFOpenErrorEx = 'Cannot open file "%s". %s'; var CreateHandle: THandle; ErrorMessage: WideString; begin FFileName := FileName; if Mode = fmCreate then begin CreateHandle := WideFileCreate(FileName); if CreateHandle = INVALID_HANDLE_VALUE then begin ErrorMessage := SysErrorMessage(GetLastError); raise EFCreateError.CreateFmt(SFCreateErrorEx, [ExpandFileName(FileName), ErrorMessage]); end; end else begin CreateHandle := WideFileOpen(FileName, Mode); if CreateHandle = INVALID_HANDLE_VALUE then begin ErrorMessage := SysErrorMessage(GetLastError); raise EFOpenError.CreateFmt(SFOpenErrorEx, [ExpandFileName(FileName), ErrorMessage]); end; end; inherited Create(CreateHandle); end; destructor TIEWideFileStream.Destroy; begin if THandle(Handle) <> INVALID_HANDLE_VALUE then FileClose(Handle); inherited Destroy; end; function IEWStrCopy(Dest: PWideChar; const Source: PWideChar): PWideChar; var Src : PWideChar; begin Result := Dest; Src := Source; while (Src^ <> #$00) do begin Dest^ := Src^; Inc(Src); Inc(Dest); end; Dest^ := #$00; end; // TIEWideFileStream ///////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// // TIEWideStrings constructor TIEWideStrings.Create; begin inherited; fStrings := TList.Create; end; destructor TIEWideStrings.Destroy; begin Clear; fStrings.Free; inherited; end; procedure TIEWideStrings.Clear; var i: integer; begin for i := 0 to fStrings.Count-1 do FreeMem(fStrings[i]); fStrings.Clear; end; function TIEWideStrings.GetCount: integer; begin result := fStrings.Count; end; function TIEWideStrings.CreateCopyBuffer(const S: WideString): PWideChar; var lenInBytes: integer; begin lenInBytes := (length(S)+1)*sizeof(WideChar); getmem(result, lenInBytes); CopyMemory(result, @S[1], lenInBytes); end; function TIEWideStrings.Add(const S: WideString): integer; begin result := fStrings.Add( CreateCopyBuffer(S) ); end; procedure TIEWideStrings.SetString(idx: integer; const S: WideString); begin FreeMem(fStrings[idx]); fStrings[idx] := CreateCopyBuffer(S); end; function TIEWideStrings.GetString(idx: integer): WideString; begin result := WideString(PWideChar(fStrings[idx])); end; ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// // TIEDirContent constructor TIEDirContent.Create(const dir : WideString); begin inherited Create; fHandle := Windows.FindFirstFileW(PWChar(dir), fFindData); fFirstGot := false; end; destructor TIEDirContent.Destroy; begin if fHandle <> INVALID_HANDLE_VALUE then Windows.FindClose(fHandle); inherited; end; function TIEDirContent.GetItem(out sFilename : WideString; bGetFiles: boolean = True; bGetDirs: boolean = False; bGetHidden : Boolean = True): boolean; function allowIt: boolean; var sTempFilename : WideString; begin sTempFilename := fFindData.cFileName; if (sTempFilename = '.') or (sTempFilename = '..') then Result := False else result := (bGetFiles and not boolean(fFindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY)) or (bGetDirs and boolean(fFindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY)); if Result and (bGetHidden = False) then if boolean(fFindData.dwFileAttributes and FILE_ATTRIBUTE_HIDDEN) or boolean(fFindData.dwFileAttributes and FILE_ATTRIBUTE_SYSTEM) then Result := False; end; begin result := fHandle <> INVALID_HANDLE_VALUE; sFilename := ''; fFileSizeBytes := 0; fCreateDate := 0; fEditDate := 0; // Is this a valid folder? if result = False then exit; repeat if fFirstGot then result := Windows.FindNextFileW(fHandle, fFindData); // return false also when fHandle is INVALID_HANDLE_VALUE fFirstGot := true; until not result or allowIt(); fIsDir := boolean(fFindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY); fIsHidden := boolean(fFindData.dwFileAttributes and FILE_ATTRIBUTE_HIDDEN) or boolean(fFindData.dwFileAttributes and FILE_ATTRIBUTE_SYSTEM); sFilename := fFindData.cFileName; try fFileSizeBytes := IELargeFileSize(fFindData.nFileSizeHigh, fFindData.nFileSizeLow); fEditDate := IEFileTimeToDateTime(fFindData.ftLastWriteTime); fCreateDate := IEFileTimeToDateTime(fFindData.ftCreationTime); except // ERROR end; end; // path must include wildcard, ie: ".\*.jpeg" class procedure TIEDirContent.PopulateStrings(const path: WideString; strings: TStrings; bGetFiles: boolean = True; bGetDirs: boolean = False; bGetHidden : Boolean = True); var dir: TIEDirContent; fname: WideString; begin strings.Clear(); dir := TIEDirContent.Create(path); try while dir.getItem(fname, bGetFiles, bGetDirs, bGetHidden) do begin strings.Add(string(fname)); end; finally dir.Free(); end; end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEMemStream constructor TIEMemStream.Create(Ptr: pointer; Size: integer); begin inherited Create; SetPointer(Ptr, Size); end; procedure TIEMemStream.SetSize(NewSize: Longint); begin // not implemented end; function TIEMemStream.Write(const Buffer; Count: Longint): Longint; begin // not implemented result := 0; end; ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// // TIERecordList constructor TIERecordList.Create(RecordSize: integer; OnGetCurrentValue: TIEListCurrentValueEvent; OnSetCurrentValue: TIEListCurrentValueEvent); begin inherited Create(OnGetCurrentValue, OnSetCurrentValue); fItemSize := RecordSize; end; function TIERecordList.GetItem(idx: integer): pointer; begin result := BaseGetItem(idx); end; procedure TIERecordList.SetItem(idx: integer; v: pointer); begin BaseSetItem(idx, v); end; function TIERecordList.Add(v: pointer): integer; begin result := AddItem(v); end; procedure TIERecordList.Insert(idx: integer; v: pointer); begin InsertItem(idx, v); end; function TIERecordList.IndexOf(v: pointer): integer; begin result := IndexOfItem(v); end; ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // TIEIntegerMap ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // sbits: hash table size in bit. constructor TIEIntegerMap.Create(bucketsCount: integer); begin inherited Create; SetLength(fItems, bucketsCount); fKeysCount := 0; end; destructor TIEIntegerMap.Destroy(); begin Clear(); inherited; end; procedure TIEIntegerMap.Clear(); var i: integer; curItem, nextItem: TIEIntegerMapItem; begin for i := 0 to length(fItems) - 1 do begin curItem := fItems[i]; while curItem <> nil do begin nextItem := curItem.nextitem; curItem.Free(); curItem := nextItem; end; fItems[i] := nil; end; fKeysCount := 0; end; // hash function // uses first fHbits-1 as direct index function TIEIntegerMap.HashFunc(key: integer): integer; begin //result := key and (length(fItems) - 1); result := key mod (length(fItems) - 1) end; // insert a new key (if not already exists) // ret TRUE if key didn't exist previously function TIEIntegerMap.Insert(key: integer; var item: TIEIntegerMapItem): boolean; var ix: integer; begin item := nil; ix := HashFunc(key); if fItems[ix] = nil then begin // bucket empty, add the new key item := TIEIntegerMapItem.Create(); item.key := key; item.nextitem := nil; fItems[ix] := item; result := true; end else begin item := fItems[ix]; while item <> nil do begin if item.key = key then begin result := false; exit; // key already exists end; item := item.nextitem; end; // key not found, add the new key item := TIEIntegerMapItem.Create(); item.key := key; item.nextitem := fItems[ix]; fItems[ix] := item; result := true; end; inc(fKeysCount); end; // insert a new key (if not already exists) // ret TRUE if key inserted function TIEIntegerMap.Insert(key: integer): boolean; var item: TIEIntegerMapItem; begin result := Insert(key, item); end; // verify if key key exists function TIEIntegerMap.KeyExists(key: integer): boolean; var curItem: TIEIntegerMapItem; begin result := false; curItem := fItems[ HashFunc(key) ]; while curItem <> nil do begin if curItem.key = key then begin result := true; break; end; curItem := curItem.nextitem; end; end; function TIEIntegerMap.IterateBegin(): boolean; begin fIterateItem := nil; fIterateIndex := -1; result := IterateNext(); end; function TIEIntegerMap.IterateNext(): boolean; begin if fIterateItem <> nil then fIterateItem := fIterateItem.nextitem; while (fIterateItem = nil) do begin inc(fIterateIndex); if fIterateIndex >= length(fItems) then break; fIterateItem := fItems[fIterateIndex]; end; result := (fIterateItem <> nil); end; function TIEIntegerMap.IterateGetValue: integer; begin result := fIterateItem.value; end; function TIEIntegerMap.IterateGetKey(): integer; begin result := fIterateItem.key; end; function TIEIntegerMap.DumpStats(): string; var i, c: integer; item: TIEIntegerMapItem; begin result := ''; for i := 0 to length(fItems) - 1 do begin c := 0; item := fItems[i]; while item <> nil do begin inc(c); item := item.nextitem; end; if c > 0 then result := result + Format('%d => %d'#13#10, [i, c]); end; end; ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // TIERGBMap ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// function TIERGBMap.Insert(const key: TRGB): boolean; begin result := Insert((key.r shl 16) or (key.g shl 8) or key.b); end; function TIERGBMap.Insert(const key: TRGB; value: integer): boolean; var item: TIEIntegerMapItem; begin result := Insert((key.r shl 16) or (key.g shl 8) or key.b, item); item.value := value; end; function TIERGBMap.KeyExists(const key: TRGB): boolean; begin result := KeyExists((key.r shl 16) or (key.g shl 8) or key.b); end; function TIERGBMap.IterateGetKey(): TRGB; var value: integer; begin value := inherited IterateGetKey(); result.r := (value shr 16) and $FF; result.g := (value shr 8) and $FF; result.b := value and $FF; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// constructor TNulStream.Create; begin inherited; fposition := 0; fsize := 0; end; destructor TNulStream.Destroy; begin inherited Destroy; end; function TNulStream.Read(var Buffer; Count: Longint): Longint; begin inc(fposition, Count); if fposition >= fsize then fsize := fposition; result := Count; end; function TNulStream.Write(const Buffer; Count: Longint): Longint; begin inc(fposition, Count); if fposition >= fsize then fsize := fposition; result := Count; end; function TNulStream.Seek(Offset: Longint; Origin: Word): Longint; begin case Origin of soFromBeginning: begin fPosition := offset; if fposition >= fsize then fsize := fposition; end; soFromCurrent: begin inc(fposition, offset); if fposition >= fsize then fsize := fposition; end; soFromEnd: begin fposition := fsize - abs(offset); // offset should be <= 0. Positive values handled as negative end; end; result := fPosition; end; ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// // TIEList constructor TIEList.Create(OnGetCurrentValue: TIEListCurrentValueEvent = nil; OnSetCurrentValue: TIEListCurrentValueEvent = nil); begin inherited Create; fData := nil; fOnGetCurrentValue := OnGetCurrentValue; fOnSetCurrentValue := OnSetCurrentValue; Clear; end; destructor TIEList.Destroy; begin freemem(fData); inherited Destroy; end; {!! TIEList.Clear Declaration procedure Clear; Description Clear empties the Items array. !!} procedure TIEList.Clear; begin fCapacity := 0; fCount := 0; if assigned(fData) then freemem(fData); fData := nil; fChanged := []; end; {!! TIEList.Count Declaration property Count: integer; Description Count contains the number of items in the Items array. !!} procedure TIEList.SetCount(v: integer); var xData: pointer; begin if fCapacity < v then begin fCapacity := imax(fCapacity * 2, v); getmem(xData, fCapacity * fItemSize); if assigned(fData) then begin move(pbyte(fData)^, pbyte(xData)^, imin(fCount, v) * fItemSize); freemem(fData); end; fData := xData; end; fCount := v; fChanged := fChanged + [ielItems]; end; {!! TIEList.Delete Declaration procedure Delete(idx: integer); Description Delete the idx value from the list. !!} procedure TIEList.Delete(idx: integer); var xData: pointer; q: integer; psrc, pdst: pbyte; begin if (idx >= 0) and (idx < fCount) then begin getmem(xData, (fCount - 1) * fItemSize); psrc := fData; pdst := xData; for q := 0 to fCount - 1 do begin if q <> idx then begin // copy move(psrc^, pdst^, fItemSize); inc(pdst, fItemSize); end; inc(psrc, fItemSize); end; freemem(fData); fData := xData; dec(fCount); fCapacity := fCount; fChanged := fChanged + [ielItems]; end; end; procedure TIEList.InsertItem(idx: integer; v: pointer); var xData: pointer; q: integer; psrc, pdst: pbyte; begin if idx < fCount then begin inc(fCount); fCapacity := fCount; getmem(xData, fCount * fItemSize); psrc := fData; pdst := xData; for q := 0 to fCount - 1 do begin if q <> idx then begin // copy move(psrc^, pdst^, fItemSize); inc(psrc, fItemSize); end else // insert move(pbyte(v)^, pdst^, fItemSize); inc(pdst, fItemSize); end; freemem(fData); fData := xData; fChanged := fChanged + [ielItems]; end else AddItem(v); end; function TIEList.IndexOfItem(v: pointer): integer; var pp: pbyte; begin pp := fData; for result := 0 to fCount - 1 do begin if CompareMem(pp, v, fItemSize) then exit; inc(pp, fItemSize); end; result := -1; end; function TIEList.AddItem(v: pointer): integer; var pb: pbyte; begin result := fCount; SetCount(fCount + 1); pb := fData; inc(pb, result * fItemSize); move(pbyte(v)^, pb^, fItemSize); fChanged := fChanged + [ielItems]; end; function TIEList.BaseGetItem(idx: integer): pointer; var pb: pbyte; begin pb := fData; inc(pb, idx * fItemSize); result := pb; end; procedure TIEList.BaseSetItem(idx: integer; v: pointer); var pb: pbyte; begin if idx < fCount then begin pb := fData; inc(pb, idx * fItemSize); move(pbyte(v)^, pb^, fItemSize); fChanged := fChanged + [ielItems]; end; end; procedure TIEList.Assign(Source: TIEList); begin if assigned(Source) then begin fCount := Source.fCount; fItemSize := Source.fItemSize; fChanged := Source.fChanged; if assigned(fData) then begin freemem(fData); fData := nil; end; getmem(fData, fItemSize * fCount); move(pbyte(Source.fData)^, pbyte(fData)^, fItemSize * fCount); end; end; {!! TIEList.ExchangeItems Declaration procedure ExchangeItems(idx1, idx2: integer); Description Swap the position of items at idx1 and idx2. !!} procedure TIEList.ExchangeItems(idx1, idx2: integer); var temp: array of byte; begin if (idx1 < 0) or (idx1 >= FCount) then raise EIEException.create( format( 'List index out of bounds (%d)', [ idx1 ])); if (idx2 < 0) or (idx2 >= FCount) then raise EIEException.create( format( 'List index out of bounds (%d)', [ idx2 ])); SetLength( temp, fItemSize ); Move( pbyte(BaseGetItem(idx1))^, temp[0], fItemSize ); Move( pbyte(BaseGetItem(idx2))^, pbyte(BaseGetItem(idx1))^, fItemSize ); Move( temp[0], pbyte(BaseGetItem(idx2))^, fItemSize ); end; procedure TIEList.ListQuickSort(L, R: Integer; SCompare: TIEListSortCompareFunc); var I, J: Integer; P: Pointer; begin repeat I := L; J := R; P := BaseGetItem(( L + R ) shr 1 ); repeat while SCompare( BaseGetItem( I ), P ) < 0 do Inc( I ); while SCompare( BaseGetItem( J ), P ) > 0 do Dec( J ); if I <= J then begin if I <> J then ExchangeItems(I, J); Inc(I); Dec(J); end; until I > J; if L < J then ListQuickSort( L, J, SCompare ); L := I; until I >= R; end; {!! TIEList.Sort Declaration procedure Sort(const Compare: ); Description Sorts the values of the list !!} procedure TIEList.Sort(Compare: TIEListSortCompareFunc); begin if Count > 1 then ListQuickSort( 0, Count - 1, Compare); end; procedure TIEList.DoGetCurrentValue(value: pointer); begin if assigned(fOnGetCurrentValue) then fOnGetCurrentValue(self, value); end; procedure TIEList.DoSetCurrentValue(value: pointer); begin if assigned(fOnSetCurrentValue) then fOnSetCurrentValue(self, value); end; ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// // TIEDoubleList constructor TIEDoubleList.Create(OnGetCurrentValue: TIEListCurrentValueEvent; OnSetCurrentValue: TIEListCurrentValueEvent); begin inherited Create(OnGetCurrentValue, OnSetCurrentValue); end; procedure TIEDoubleList.Assign(Source: TIEList); begin inherited; if assigned(Source) then begin fRangeMin := (Source as TIEDoubleList).fRangeMin; fRangeMax := (Source as TIEDoubleList).fRangeMax; fRangeStep := (Source as TIEDoubleList).fRangeStep; fCurrentValue := (Source as TIEDoubleList).fCurrentValue; end; end; {!! TIEDoubleList.Add Declaration function Add(v: double): integer; Description Adds a new value to the list. !!} function TIEDoubleList.Add(v: double): integer; begin result := AddItem(@v); end; {!! TIEDoubleList.Clear Declaration procedure Clear; Description Removes all items. !!} procedure TIEDoubleList.Clear; begin inherited; fItemSize := sizeof(double); fRangeMin := 0; fRangeMax := 0; fRangeStep := 0; fCurrentValue := 0; end; {!! TIEDoubleList.Items Declaration property Items[index]: double; Description Items returns the double value of index element. !!} function TIEDoubleList.GetItem(idx: integer): double; begin result := PDouble(BaseGetItem(idx))^; end; procedure TIEDoubleList.SetItem(idx: integer; v: double); begin BaseSetItem(idx, @v); end; {!! TIEDoubleList.Insert Declaration procedure Insert(idx: integer; v: double); Description Insert a new value inside idx position. !!} procedure TIEDoubleList.Insert(idx: integer; v: double); begin InsertItem(idx, @v); end; {!! TIEDoubleList.IndexOf Declaration function IndexOf(v: double): integer; Description IndexOf returns the index of v value. Returns -1 if not found. !!} function TIEDoubleList.IndexOf(v: double): integer; begin result := IndexOfItem(@v); end; {!! TIEDoubleList.RangeMin Declaration property RangeMin: double; Description RangeMin is the minimum value that you can assign to . !!} procedure TIEDoubleList.SetRangeMin(v: double); begin fRangeMin := v; fChanged := fChanged + [ielRange]; end; {!! TIEDoubleList.RangeMax Declaration property RangeMax: double; Description RangeMax is the max value that you can assign to . !!} procedure TIEDoubleList.SetRangeMax(v: double); begin fRangeMax := v; fChanged := fChanged + [ielRange]; end; {!! TIEDoubleList.RangeStep Declaration property RangeStep: double; Description RangeStep defines the step from to . !!} procedure TIEDoubleList.SetRangeStep(v: double); begin fRangeStep := v; fChanged := fChanged + [ielRange]; end; {!! TIEDoubleList.CurrentValue Declaration property CurrentValue: double; Description CurrentValue returns the current value of the list. It isn't an index of , but a "powerup" value. No control is made to values assigned to CurrentValue, but it should be one of the values in or inside of and (regarding also). !!} procedure TIEDoubleList.SetCurrentValue(v: double); begin if fCurrentValue <> v then begin fCurrentValue := v; fChanged := fChanged + [ielCurrentValue]; DoSetCurrentValue(@fCurrentValue); end; end; function TIEDoubleList.GetCurrentValue(): double; begin DoGetCurrentValue(@fCurrentValue); result := fCurrentValue; end; ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// // TIEIntegerList constructor TIEIntegerList.Create(OnGetCurrentValue: TIEListCurrentValueEvent; OnSetCurrentValue: TIEListCurrentValueEvent); begin inherited Create(OnGetCurrentValue, OnSetCurrentValue); end; procedure TIEIntegerList.Assign(Source: TIEList); begin inherited; if assigned(Source) then begin fRangeMin := (Source as TIEIntegerList).fRangeMin; fRangeMax := (Source as TIEIntegerList).fRangeMax; fRangeStep := (Source as TIEIntegerList).RangeStep; fCurrentValue := (Source as TIEIntegerList).fCurrentValue; end; end; {!! TIEIntegerList.Add Declaration function Add(v: integer): integer; Description Adds a new value to the list. !!} function TIEIntegerList.Add(v: Integer): integer; begin result := AddItem(@v); end; {!! TIEIntegerList.Clear Declaration procedure Clear; Description Removes all items. !!} procedure TIEIntegerList.Clear; begin inherited; fRangeMin := 0; fRangeMax := 0; fRangeStep := 0; fCurrentValue := 0; fItemSize := sizeof(Integer); end; {!! TIEIntegerList.Items Declaration property Items[index]: integer; Description Items returns the value of index element. !!} function TIEIntegerList.GetItem(idx: integer): Integer; begin result := PInteger(BaseGetItem(idx))^; end; procedure TIEIntegerList.SetItem(idx: integer; v: Integer); begin BaseSetItem(idx, @v); end; {!! TIEIntegerList.Insert Declaration procedure Insert(idx: integer; v: integer); Description Insert a new value inside idx position. !!} procedure TIEIntegerList.Insert(idx: integer; v: Integer); begin InsertItem(idx, @v); end; {!! TIEIntegerList.IndexOf Declaration function IndexOf(v: integer): integer; Description IndexOf returns the index of v value. Returns -1 if not found. !!} function TIEIntegerList.IndexOf(v: Integer): integer; begin result := IndexOfItem(@v); end; {!! TIEIntegerList.RangeMin Declaration property RangeMin: integer; Description RangeMin is the minimum value that you may assign to . !!} procedure TIEIntegerList.SetRangeMin(v: integer); begin fRangeMin := v; fChanged := fChanged + [ielRange]; end; {!! TIEIntegerList.RangeMax Declaration property RangeMax: integer; Description RangeMax is the maximum value you may assign to . !!} procedure TIEIntegerList.SetRangeMax(v: integer); begin fRangeMax := v; fChanged := fChanged + [ielRange]; end; {!! TIEIntegerList.RangeStep Declaration property RangeStep: integer; Description RangeStep specifies the step from to . !!} procedure TIEIntegerList.SetRangeStep(v: integer); begin fRangeStep := v; fChanged := fChanged + [ielRange]; end; {!! TIEIntegerList.CurrentValue Declaration property CurrentValue: integer; Description CurrentValue returns the current value of the list. It isn't an index of , but a "powerup" value. No control is made to values assigned to CurrentValue, but it should be one of the values in or inside of and (regarding also). !!} procedure TIEIntegerList.SetCurrentValue(v: integer); begin if fCurrentValue <> v then begin fCurrentValue := v; fChanged := fChanged + [ielCurrentValue]; DoSetCurrentValue(@fCurrentValue); end; end; function TIEIntegerList.GetCurrentValue(): integer; begin DoGetCurrentValue(@fCurrentValue); result := fCurrentValue; end; //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // Prime numbers function IEIsPrime(x: integer): boolean; var i, q: integer; begin result := true; i := 3; while true do begin q := x div i; if (q < i) then break; if (x = q * i) then begin result := false; break; end; inc(i, 2); end; end; function IENextPrime(x: integer): integer; begin result := x + 1; if (result <= 2) then begin result := 2; exit; end; if (result and 1) = 0 then inc(result); while not IEIsPrime(result) do inc(result, 2); end; //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// procedure QuickSort1(L, R: Integer; CompareFunction: TIECompareFunction; SwapFunction: TIESwapFunction); var I, J, P: Integer; begin repeat I := L; J := R; P := L + (R - L) shr 1; // 3.0.4 repeat while CompareFunction(I, P) < 0 do Inc(I); while CompareFunction(J, P) > 0 do Dec(J); if I <= J then begin if I=P then P := J else if J=P then P := I; SwapFunction(I, J); Inc(I); Dec(J); end; until I > J; if L < J then QuickSort1(L, J, CompareFunction, SwapFunction); L := I; until I >= R; end; procedure IEQuickSort(ItemsCount: integer; CompareFunction: TIECompareFunction; SwapFunction: TIESwapFunction); begin if ItemsCount > 1 then QuickSort1(0, ItemsCount - 1, CompareFunction, SwapFunction); end; // returns the full file path // Directory must contain the last '\' function IEGetTempFileName(const Descriptor: string; const Directory: string): string; begin repeat result := Directory + Descriptor + '-' + IntToHex(random(MAXINT), 8) + '.tmp'; until not IEFileExists(result); end; // returns the full file path function IEGetTempFileName2: string; var temppath: array[0..MAX_PATH] of Char; tp: string; begin if IEGlobalSettings().DefTEMPPATH = '' then begin GetTempPath(250, temppath); tp := string(temppath); end else tp := IEGlobalSettings().DefTEMPPATH; result := IEGetTempFileName('ietemp', tp); end; // Return a numbered filename that does not exist. I.e. returns sBaseFilename if the file does not already exist. Otherwise returns a numbered version of sBaseFilename function IEGetNewFilename(const sBaseFilename: string; const sSepChar: Char = ' '): string; var I: Integer; iCurrentSuffix: Integer; iFileNumber: Integer; sCurrentSuffix: string; sExt: string; sRootFilename: string; begin sRootFilename := IEAddBackSlash( ExtractFilePath( sBaseFilename )) + IEExtractFileNameWithoutExt( sBaseFilename ); sExt := IEExtractFileExtS( sBaseFilename ); iFileNumber := 1; // Check if it already has a number extension sCurrentSuffix := ''; if ( sSepChar <> '' ) and FileExists( sBaseFilename ) then for I := Length( sRootFilename ) downto 1 do begin if sRootFilename[ I ] = sSepChar then break else sCurrentSuffix := sRootFilename[ I ] + sCurrentSuffix; if Length( sCurrentSuffix ) > 8 then break; // Not a number end; // do we have a valid number suffix? iCurrentSuffix := StrToIntDef( sCurrentSuffix, -1 ); if iCurrentSuffix > 0 then begin iFileNumber := iCurrentSuffix + 1; SetLength( sRootFilename, Length( sRootFilename ) - Length( sSepChar + sCurrentSuffix )); end; // Find the first unique filename for I := iFileNumber to MaxInt do begin if I = 1 then result := sBaseFilename else result := sRootFilename + sSepChar + IntToStr( I ) + sExt; if FileExists( result ) = False then break; end; end; function IEGetMem(ASize: dword): pointer; begin result := VirtualAlloc(nil, ASize, MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE); end; // Frees memory procedure IEFreeMem(var P); begin VirtualFree(pointer(P), 0, MEM_RELEASE); pointer(P) := nil; end; function IEFindNearestColor(color: TRGB; palette: TIEArrayOfTRGB; colorCount: integer): integer; var i: integer; dstSqr: integer; minDstSqr: integer; dr, dg, db: integer; begin result := 0; minDstSqr := 195076; for i := 0 to colorCount - 1 do begin dr := integer(color.r) - integer(palette[i].r); dg := integer(color.g) - integer(palette[i].g); db := integer(color.b) - integer(palette[i].b); dstSqr := dr * dr + dg * dg + db * db; if dstSqr < minDstSqr then begin minDstSqr := dstSqr; result := i; end; end; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// // Search a string from current stream position. Returns the start of string position (or -1 if not found) // The stream position is one character after the end of the string function IEStreamFindString(Stream: TStream; Text: AnsiString; StopAtPos: int64): int64; var spos: int64; c: AnsiChar; i: integer; textLen: integer; begin textLen := length(Text); while (Stream.Position < StopAtpos) do begin spos := Stream.Position; for i := 1 to textLen do begin Stream.Read(c, 1); if c <> Text[i] then break else if i = textLen then begin result := spos; exit; end; end; end; result := -1; end; // Executes a console command and returns its output function IEGetDosOutput(CommandLine: AnsiString; Work: AnsiString = 'C:\'): AnsiString; var SA: TSecurityAttributes; {$IFDEF UNICODE} SI: TStartupInfoA; {$ELSE} SI: TStartupInfo; {$ENDIF} PI: TProcessInformation; StdOutPipeRead, StdOutPipeWrite: THandle; WasOK: Boolean; Buffer: array [0..255] of AnsiChar; BytesRead: Cardinal; WorkDir: AnsiString; Handle: Boolean; begin Result := ''; with SA do begin nLength := SizeOf(SA); bInheritHandle := True; lpSecurityDescriptor := nil; end; CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0); try with SI do begin FillChar(SI, SizeOf(SI), 0); cb := SizeOf(SI); dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; wShowWindow := SW_HIDE; hStdInput := GetStdHandle(STD_INPUT_HANDLE); hStdOutput := StdOutPipeWrite; hStdError := StdOutPipeWrite; end; WorkDir := Work; Handle := CreateProcessA(nil, PAnsiChar('cmd.exe /C ' + CommandLine), nil, nil, True, 0, nil, PAnsiChar(WorkDir), SI, PI); CloseHandle(StdOutPipeWrite); if Handle then try repeat WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil); if BytesRead > 0 then begin Buffer[BytesRead] := #0; Result := Result + Buffer; end; until not WasOK or (BytesRead = 0); WaitForSingleObject(PI.hProcess, INFINITE); finally CloseHandle(PI.hThread); CloseHandle(PI.hProcess); end; finally CloseHandle(StdOutPipeRead); end; end; function IEGPSConvertDMSToDegDec(degrees: Double; minutes: Double; seconds: Double; ref: AnsiString): Double; begin result := degrees + minutes / 60.0 + seconds / 3600.0; if (ref = 'W') or (ref = 'S') then result := - result; end; // dir must be: // 'SN' : latitude conversion // 'WE' : longitude conversion procedure IEGPSConvertDegDecToDMS(dir: AnsiString; value: Double; var degrees: Double; var minutes: Double; var seconds: Double; var ref: AnsiString); begin if value < 0 then ref := dir[1] else ref := dir[2]; value := Abs(value); degrees := Trunc(value); value := Frac(value) * 60.0; minutes := Trunc(value); seconds := Frac(value) * 60.0; end; ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// // IEGetCoresCount const // LOGICAL_PROCESSOR_RELATIONSHIP RelationProcessorCore = 0; RelationNumaNode = 1; RelationCache = 2; RelationProcessorPackage = 3; // PROCESSOR_CACHE_TYPE CacheUnified = 0; CacheInstruction = 1; CacheData = 2; CacheTrace = 3; type CACHE_DESCRIPTOR = packed record Level: BYTE; Associativity: BYTE; LineSize: WORD; Size: DWORD; Type_: DWORD; //PROCESSOR_CACHE_TYPE end; SYSTEM_LOGICAL_PROCESSOR_INFORMATION = packed record ProcessorMask: DWORD; Relationship: DWORD; // LOGICAL_PROCESSOR_RELATIONSHIP case integer of 0: (ProcessorCore : packed record Flags: BYTE; end); 1: (NumaNode : packed record NodeNumber: DWORD; end); 2: (Cache: CACHE_DESCRIPTOR); 3: (Reserved : packed record d1: int64; d2: int64; end); end; PSYSTEM_LOGICAL_PROCESSOR_INFORMATION = ^SYSTEM_LOGICAL_PROCESSOR_INFORMATION; TIEGetLogicalProcessorInformation = function(buffer: PSYSTEM_LOGICAL_PROCESSOR_INFORMATION; ReturnLength: PDWORD): longbool; stdcall; function IEGetCoresCount(): integer; var buffer: pointer; l, c: integer; byteOff: integer; curInfo: PSYSTEM_LOGICAL_PROCESSOR_INFORMATION; hLib: THandle; IEGetLogicalProcessorInformation: TIEGetLogicalProcessorInformation; begin if IEGlobalSettings().DefaultCoresCount = -1 then begin IEGlobalSettings().DefaultCoresCount := 1; l := 0; buffer := nil; hLib := LoadLibrary('Kernel32.dll'); if hlib<>0 then begin @IEGetLogicalProcessorInformation := GetProcAddress(hLib, 'GetLogicalProcessorInformation'); if @IEGetLogicalProcessorInformation<>nil then begin IEGetLogicalProcessorInformation(buffer, @l); // get length of buffer to allocate if GetLastError() = ERROR_INSUFFICIENT_BUFFER then begin getmem(buffer, l); if IEGetLogicalProcessorInformation(buffer, @l) then begin c := 0; curInfo := PSYSTEM_LOGICAL_PROCESSOR_INFORMATION(buffer); byteOff := 0; while byteOff < l do begin if curInfo^.Relationship = RelationProcessorCore then inc(c); inc(curInfo); inc(byteOff, sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)); end; IEGlobalSettings().DefaultCoresCount := c; end; end; end; FreeLibrary(hLib); end; freemem(buffer); end; result := IEGlobalSettings().DefaultCoresCount; end; function IEGetRequiredThreads(ImageWidth, ImageHeight: integer): integer; begin if ImageWidth * ImageHeight >= IEGlobalSettings().ImageProcThreadsMinSize then result := imin(IEGlobalSettings().ImageProcMaxThreads, IEGetCoresCount()) else result := 1; end; // Returns true if the O/S is Vista, 7, 8 or something as yet undiscovered function IEIsWindowsVistaOrNewer : Boolean; begin Result := IEGlobalSettings().OpSys in [ieosUnknown, ieosWinVista, ieosWin7, ieosWin8, ieosWin10]; end; function IEIsKeyPressed(aKey: Word): Boolean; begin Result := ( GetKeyState( aKey ) and $8000 ) <> 0; end; // Returns a suitable font to use for Preview dialogs. Segoe UI 9 on Vista, 7. Tahoma 8 on XP, etc function IEGetDefaultDialogFont() : TFont; const Vista_GUI_Font_Name = 'Segoe UI'; Vista_GUI_Font_Height = -12; XP_GUI_Font_Name = 'Tahoma'; XP_GUI_Font_Height = -11; begin // Note: could use Screen.IconFont but our dialogs may not support unexpected fonts if assigned(IEGlobalSettings().DefaultDialogFont) = False then begin IEGlobalSettings().DefaultDialogFont := TFont.Create; IEGlobalSettings().DefaultDialogFont.Charset := DEFAULT_CHARSET; IEGlobalSettings().DefaultDialogFont.Color := clWindowText; IEGlobalSettings().DefaultDialogFont.Style := []; if IEIsWindowsVistaOrNewer and (Screen.Fonts.IndexOf(Vista_GUI_Font_Name) >= 0) then begin IEGlobalSettings().DefaultDialogFont.Height := Vista_GUI_Font_Height; IEGlobalSettings().DefaultDialogFont.Name := Vista_GUI_Font_Name; end else begin IEGlobalSettings().DefaultDialogFont.Height := XP_GUI_Font_Height; IEGlobalSettings().DefaultDialogFont.Name := XP_GUI_Font_Name; end end; Result := IEGlobalSettings().DefaultDialogFont; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// procedure IECenterWindow(Wnd: HWnd); var Rect: TRect; Monitor: TMonitor; begin if assigned(IEGlobalSettings().DefDialogCenter) then IEGlobalSettings().DefDialogCenter(Wnd) else begin GetWindowRect(Wnd, Rect); if Application.MainForm <> nil then begin if Assigned(Screen.ActiveForm) then Monitor := Screen.ActiveForm.Monitor else Monitor := Application.MainForm.Monitor; end else Monitor := Screen.Monitors[0]; SetWindowPos(Wnd, 0, Monitor.Left + ((Monitor.Width - Rect.Right + Rect.Left) div 2), Monitor.Top + ((Monitor.Height - Rect.Bottom + Rect.Top) div 3), 0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER); end; end; type TMEMORYSTATUSEX=packed record dwLength: DWORD; dwMemoryLoad: DWORD; ullTotalPhys: int64; ullAvailPhys: int64; ullTotalPageFile: int64; ullAvailPageFile: int64; ullTotalVirtual: int64; ullAvailVirtual: int64; ullAvailExtendedVirtual: int64; end; PMEMORYSTATUSEX=^TMEMORYSTATUSEX; TIEGlobalMemoryStatusEx = function(lpBuffer: PMEMORYSTATUSEX): longbool; stdcall; // freememory = false -> total memory // freememory = true -> free memory function IEGetMemory(freememory: boolean): int64; var ms: TMemoryStatus; msx: TMEMORYSTATUSEX; h: THandle; IEGlobalMemoryStatusEx: TIEGlobalMemoryStatusEx; begin h := LoadLibrary('Kernel32.dll'); if h <> 0 then begin @IEGlobalMemoryStatusEx := GetProcAddress(h, 'GlobalMemoryStatusEx'); if @IEGlobalMemoryStatusEx<>nil then begin FillChar(msx, sizeof(TMEMORYSTATUSEX), 0); msx.dwLength := sizeof(TMEMORYSTATUSEX); IEGlobalMemoryStatusEx(@msx); if freememory then result := msx.ullAvailPhys else result := msx.ullTotalPhys; FreeLibrary(h); exit; end; FreeLibrary(h); end; ms.dwLength := sizeof(ms); GlobalMemoryStatus(ms); if freememory then result := ms.dwAvailPhys else result := ms.dwTotalPhys; end; procedure IECalcUnitsPerPixel(DpiX, DpiY: Integer; mu: TIEUnits; out cx, cy: double); const Inches_per_Foot = 12; Inches_per_Yard = 36; Inches_per_Mile = 63360; begin if mu = ieuPIXELS then begin cx := 1; cy := 1; end else if ( DpiX = 0 ) or ( DpiY = 0 ) then begin cx := 1; cy := 1; end else begin cx := 1 / DpiX; cy := 1 / DpiY; case mu of ieuKM: begin cx := (cx * CM_per_Inch) / 100000; cy := (cy * CM_per_Inch) / 100000; end; ieuMETERS: begin cx := (cx * CM_per_Inch) / 100; cy := (cy * CM_per_Inch) / 100; end; ieuCENTIMETERS: begin cx := cx * CM_per_Inch; cy := cy * CM_per_Inch; end; ieuMILLIMETERS: begin cx := (cx * CM_per_Inch) * 10; cy := (cy * CM_per_Inch) * 10; end; ieuMICRONS: begin cx := (cx * CM_per_Inch) * 10000; cy := (cy * CM_per_Inch) * 10000; end; ieuNANOMETERS: begin cx := (cx * CM_per_Inch) * 10000000; cy := (cy * CM_per_Inch) * 10000000; end; ieuFEET: begin cx := cx / Inches_per_Foot; cy := cy / Inches_per_Foot; end; ieuYARDS: begin cx := cx / Inches_per_Yard; cy := cy / Inches_per_Yard; end; ieuMILES: begin cx := cx / Inches_per_Mile; cy := cy / Inches_per_Mile; end; end; end; end; procedure IESetPlim(var plim: trect; x, y: integer); begin if x < plim.Left then plim.left := x; if x > plim.Right then plim.right := x; if y < plim.Top then plim.top := y; if y > plim.Bottom then plim.bottom := y; end; function IEArcCos(X: Extended): Extended; begin if (X = 1) or (X = -1) then result := 0 else Result := ArcTan2(Sqrt(1 - X * X), X); end; function IEDegreesToRadians(Angle: Double): Double; begin Result := Angle * PI / 180.0; end; function IERadiansToDegrees(Rad: Double): Double; begin Result := Rad * 180.0 / PI; end; // calculates the angle (rad) of the specified triangle. x2, y2 is the angle center function IEAngle(x1, y1, x2, y2, x3, y3: double): double; var vx1, vy1, vx2, vy2: double; d1, d2: double; begin vx1 := x2 - x1; vy1 := y2 - y1; vx2 := x3 - x2; vy2 := y3 - y2; try d1 := sqrt(vx1 * vx1 + vy1 * vy1); except d1 := 0; end; try d2 := sqrt(vx2 * vx2 + vy2 * vy2); except d2 := 0; end; if (d1 = 0) or (d2 = 0) then result := 0 else begin d1 := (vx1 * vx2 + vy1 * vy2) / (d1 * d2); if abs(d1) <= 1 then result := IEArcCos(d1) else result := 0; end; end; // Calc angle (rad) of segment x1, y1-x2, y2 relative to the X axis function IEAngle2(x1, y1, x2, y2: integer): double; begin if (x1 < x2) and (y2 < y1) then // 1 result := pi - ieangle(x2, y2, x1, y1, x2, y1) else if (x1 < x2) and (y1 < y2) then // 4 result := pi + ieangle(x2, y1, x1, y1, x2, y2) else if (x2 < x1) and (y1 < y2) then // 3 result := 2 * pi - ieangle(x2, y1, x1, y1, x2, y2) else if (x2 < x1) and (y2 < y1) then // 2 result := ieangle(x2, y1, x1, y1, x2, y2) else if (x2 = x1) and (y1 > y2) then result := pi / 2 else if (x2 = x1) and (y1 < y2) then result := 1.5 * pi else if (y1 = y2) and (x1 > x2) then result := pi else result := 0; end; function ccw(x0, y0, x1, y1, x2, y2: integer): integer; var dx1, dx2, dy1, dy2: integer; begin dx1 := x1 - x0; dy1 := y1 - y0; dx2 := x2 - x0; dy2 := y2 - y0; if dx1 * dy2 > dy1 * dx2 then result := 1 else if dx1 * dy2 < dy1 * dx2 then result := -1 else if (dx1 * dx2 < 0) or (dy1 * dy2 < 0) then result := -1 else if (dx1 * dx1 + dy1 * dy1) < (dx2 * dx2 + dy2 * dy2) then result := 1 else result := 0; end; function IEAngle3(x1, y1, xc, yc, x2, y2: integer): double; var a, b, c: double; begin // a is (xc, yc)-(x2, y2) // b is (x1, y1)-(x2, y2) // c is (xc, yc)-(x1, y1) a := sqrt(sqr(x2 - xc) + sqr(y2 - yc)); if a = 0 then a := 1; b := sqrt(sqr(x2 - x1) + sqr(y2 - y1)); if b = 0 then b := 1; c := sqrt(sqr(xc - x1) + sqr(yc - y1)); if c = 0 then c := 1; result := IEArcCos((sqr(a) + sqr(c) - sqr(b)) / (2 * a * c)); if ccw(x1, y1, xc, yc, x2, y2) = -1 then result := 2 * PI - result; end; // returns reference angle (ex. 45.5 = 45.5, 361 = 1, 1000.5 = // Angles in degrees function IEGetReferenceAngle(Angle: double): double; begin result := Angle - Floor (Angle / 360.0) * 360.0; if Angle < 0 then result := - 360 + result; end; function IEExtractStylesFromLogFont(logfont: PLogFontA): TFontStyles; begin result := []; if LogFont <> nil then with LogFont^ do begin if lfItalic <> 0 then include(result, fsItalic); if lfUnderline <> 0 then include(result, fsUnderline); if lfStrikeOut <> 0 then include(result, fsStrikeOut); if lfWeight >= FW_BOLD then include(result, fsBold); end; end; function IEExtractStylesFromLogFontW(logfont: PLogFontW): TFontStyles; begin result := []; if LogFont <> nil then with LogFont^ do begin if lfItalic <> 0 then include(result, fsItalic); if lfUnderline <> 0 then include(result, fsUnderline); if lfStrikeOut <> 0 then include(result, fsStrikeOut); if lfWeight >= FW_BOLD then include(result, fsBold); end; end; procedure IECopyLogFont(src: PLogFontA; dst: PLogFontW); begin dst^.lfHeight := src^.lfHeight; dst^.lfWidth := src^.lfWidth; dst^.lfEscapement := src^.lfEscapement; dst^.lfOrientation := src^.lfOrientation; dst^.lfWeight := src^.lfWeight; dst^.lfItalic := src^.lfItalic; dst^.lfUnderline := src^.lfUnderline; dst^.lfStrikeOut := src^.lfStrikeOut; dst^.lfCharSet := src^.lfCharSet; dst^.lfOutPrecision := src^.lfOutPrecision; dst^.lfClipPrecision := src^.lfClipPrecision; dst^.lfQuality := src^.lfQuality; dst^.lfPitchAndFamily := src^.lfPitchAndFamily; IEStrPCopyW(@dst^.lfFaceName[0], WideString(AnsiString(src^.lfFaceName))); end; function CompareGUID(const g1, g2: TGuid): boolean; begin result := CompareMem(@g1, @g2, sizeof(TGuid)); end; function IEConvertGUIDToString(g: PGUID): AnsiString; var p: pbyte; i: integer; begin p := pbyte(g); result := '{' + IEIntToHex(pinteger(p)^, 8) + '-'; inc(p, 4); result := result + IEIntToHex(pword(p)^, 4) + '-'; inc(p, 2); result := result + IEIntToHex(pword(p)^, 4) + '-'; inc(p, 2); result := result + IEIntToHex(p^, 2); inc(p); result := result + IEIntToHex(p^, 2) + '-'; inc(p); for i := 0 to 5 do begin result := result + IEIntToHex(p^, 2); inc(p); end; result := IELowerCase(result) + '}'; end; procedure IEConvertWStringToGUID(invar: WideString; gg: PGUID); begin IEConvertAStringToGUID(AnsiString(invar), gg); end; procedure IEConvertAStringToGUID(invar: AnsiString; gg: PGUID); const cv: array[48..70] of integer = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15); mm: array[0..7] of integer = (268435456, 16777216, 1048576, 65536, 4096, 256, 16, 1); var i: integer; v: cardinal; begin invar := IEUpperCase(invar); v := 0; for i := 2 to 9 do v := v + cardinal(cv[ord(invar[i])] * mm[i - 2]); gg^.D1 := v; gg^.D2 := 0; for i := 11 to 14 do gg^.D2 := gg^.D2 + cv[ord(invar[i])] * mm[i - 11 + 4]; gg^.D3 := 0; for i := 16 to 19 do gg^.D3 := gg^.D3 + cv[ord(invar[i])] * mm[i - 16 + 4]; invar := IECopy(invar, 21, 4) + IECopy(invar, 26, 12); for i := 0 to 7 do begin gg^.D4[i] := cv[ord(invar[i * 2 + 1])] * mm[6] + cv[ord(invar[i * 2 + 2])] * mm[7]; end; end; procedure IEResetPrinter; var Device, Driver, Port: pointer; DevMode: THandle; lCopies: integer; lOrient: TPrinterOrientation; lTitle: WideString; begin lCopies := Printer.Copies; lOrient := Printer.Orientation; lTitle := Printer.Title; getmem(Device, 512); getmem(Driver, 512); getmem(Port, 512); try Printer.GetPrinter(Device, Driver, Port, DevMode); Printer.SetPrinter(Device, Driver, Port, 0); finally freemem(Device); freemem(Driver); freemem(Port); end; Printer.Copies := lCopies; Printer.Orientation := lOrient; Printer.Title := lTitle; end; // Adjust the resampling size to match fwidth and fheight // owidth, oheight: source image size // fwidth, fheight: container box size // rwidth, rheight: output - new size // was: IEFitResample procedure IEGetFitResampleSize(OWidth, OHeight, FWidth, FHeight: integer; out RWidth, RHeight: integer); var zz: double; begin if (owidth <> 0) and (oheight <> 0) then begin zz := dmin(fwidth / owidth, fheight / oheight); rwidth := trunc(owidth * zz); if rwidth = 0 then rwidth := 1; rheight := trunc(oheight * zz); if rheight = 0 then rheight := 1; end; end; // Adjust the resampling size to match fwidth and fheight // iImageWidth, iImageHeight: source image size // iAvailableWidth, iAvailableHeight: container box size // rwidth, rheight: output - new size // if iAutoCropPercent > 0 then RAutoWidth, RAutoHeight will return an enlarged size that is bigger than the container box size (overlaps) procedure IEGetFitResampleSizeWithAutoCrop(iImageWidth, iImageHeight, iAvailableWidth, iAvailableHeight: integer; out RWidth, RHeight: integer; iAutoCropPercent : Integer; out RAutoWidth, RAutoHeight: integer); var dResizeRatio, dMaxResizeRatio: Double; dCroppedWidth, dCroppedHeight: Double; begin if iAutoCropPercent > 100 then iAutoCropPercent := 100; if (iImageHeight = 0) or (iImageWidth = 0) or (iAvailableHeight = 0) or (iAvailableWidth = 0) then begin RWidth := 0; RHeight := 0; RAutoWidth := 0; RAutoHeight := 0; end else if (iImageHeight / iAvailableHeight) < (iImageWidth / iAvailableWidth) then // WIDTH IS IMPORTANT begin // if we are allowing a percentage of the image to be auto-cropped then // calculate the maximum possible ratio we can increase by without // without the Height exceeding the available widht if iAutoCropPercent > 0 then begin dCroppedWidth := iImageWidth * (100 - iAutoCropPercent) / 100; if iAutoCropPercent = 100 then dMaxResizeRatio := 1000 else dMaxResizeRatio := iAvailableWidth / dCroppedWidth; if round(iImageHeight * dMaxResizeRatio) > iAvailableHeight then dMaxResizeRatio := iAvailableHeight / iImageHeight; RAutoWidth := round(iImageWidth * dMaxResizeRatio); RAutoHeight := round(iImageHeight * dMaxResizeRatio); RWidth := imin(iAvailableWidth, RAutoWidth); RHeight := imin(iAvailableHeight, RAutoHeight); end else begin dResizeRatio := iAvailableWidth / iImageWidth; RWidth := round(iImageWidth * dResizeRatio); RHeight := round(iImageHeight * dResizeRatio); RAutoWidth := RWidth; RAutoHeight := RHeight; end; end ELSE // HEIGHT IS IMPORTANT begin // if we are allowing a percentage of the image to be auto-cropped then // calculate the maximum possible ratio we can increase by without // without the width exceeding the available widht if iAutoCropPercent > 0 then begin dCroppedHeight := iImageHeight * (100 - iAutoCropPercent) / 100; if iAutoCropPercent = 100 then dMaxResizeRatio := 1000 else dMaxResizeRatio := iAvailableHeight / dCroppedHeight; if round(iImageWidth * dMaxResizeRatio) > iAvailableWidth then dMaxResizeRatio := iAvailableWidth / iImageWidth; RAutoWidth := round(iImageWidth * dMaxResizeRatio); RAutoHeight := round(iImageHeight * dMaxResizeRatio); RWidth := imin(iAvailableWidth, RAutoWidth); RHeight := imin(iAvailableHeight, RAutoHeight); end else begin dResizeRatio := iAvailableHeight / iImageHeight; RWidth := round(iImageWidth * dResizeRatio); RHeight := round(iImageHeight * dResizeRatio); RAutoWidth := RWidth; RAutoHeight := RHeight; end; end; end; // encode maximum 4 bytes (len can be 1 to 4) // pad if len<4 // return chars wrote function _IEASCII85Encode4(var inbytes: pbyte; inlen: integer; var outstr: PAnsiChar): integer; var c: array[1..5] of dword; value: dword; i: integer; begin value := 0; for i := 0 to inlen-1 do begin value := value or (inbytes^ shl (24-i*8)); inc(inbytes); end; (* value := inbytes^ shl 24; inc(inbytes); value := value or (inbytes^ shl 16); inc(inbytes); value := value or (inbytes^ shl 8); inc(inbytes); value := value or inbytes^; inc(inbytes); *) if (value = 0) and (inlen = 4) then begin outstr^ := 'z'; inc(outstr); result := 1; end else begin c[1] := value div 52200625; value := value - c[1] * 52200625; c[2] := value div 614125; value := value - c[2] * 614125; c[3] := value div 7225; value := value - c[3] * 7225; c[4] := value div 85; value := value - c[4] * 85; c[5] := value; for i := 1 to inlen + 1 do begin outstr^ := AnsiChar(c[i] + 33); inc(outstr); end; result := inlen + 1; end; end; function IEASCII85EncodeBlock(var inbytes: pbyte; buflen: integer; var outstr: PAnsiChar; var asciilen: integer): integer; var w: integer; row: integer; begin result := 0; row := 0; repeat w := _IEASCII85Encode4(inbytes, imin(4, buflen), outstr); inc(result, w); inc(asciilen, w); inc(row, w); dec(buflen, 4); if row >= 75 then begin outstr^ := #13; inc(outstr); outstr^ := #10; inc(outstr); inc(result, 2); row := 0; end; until buflen <= 0; outstr^ := '~'; inc(outstr); outstr^ := '>'; inc(outstr); outstr^ := #13; inc(outstr); outstr^ := #10; inc(outstr); inc(result, 4); end; // decode maximum 5 characters (inlen) procedure _IEASCII85Decode5(var instr: PAnsiChar; inlen: integer; var outbytes: pbyte); var value: cardinal; begin if instr^ = 'z' then begin value := 0; inc(instr); end else begin value := (ord(instr^) - 33) * 52200625; inc(instr); if inlen >= 2 then begin value := value + cardinal(ord(instr^) - 33) * 614125; inc(instr); end; if inlen >= 3 then begin value := value + cardinal(ord(instr^) - 33) * 7225; inc(instr); end; if inlen >= 4 then begin value := value + cardinal(ord(instr^) - 33) * 85; inc(instr); end; if inlen >= 5 then begin value := value + cardinal(ord(instr^) - 33); inc(instr); end; end; outbytes^ := value div 16777216; value := value - (outbytes^ * 16777216); inc(outbytes); outbytes^ := value div 65536; value := value - (outbytes^ * 65536); inc(outbytes); outbytes^ := value div 256; value := value - (outbytes^ * 256); inc(outbytes); outbytes^ := value; inc(outbytes); end; // a block is terminates with a '~>' (EOD) // buflen refers to instr length // return output length function IEASCII85DecodeBlock(var instr: PAnsiChar; buflen: integer; var outbytes: pbyte): integer; var i, l, flatlen: integer; flatbuf, ptr, instr2: PAnsiChar; begin result := 0; flatlen := 0; getmem(flatbuf, buflen); ptr := flatbuf; i := 0; while i < buflen do begin while ((ord(instr^) < 33) or (ord(instr^) > 117)) and (instr^ <> '~') and (instr^ <> '>') do begin inc(instr); inc(i); end; if instr^ = '~' then begin instr2 := instr; l := i; inc(instr); while ((ord(instr^) < 33) or (ord(instr^) > 117)) and (instr^ <> '~') and (instr^ <> '>') do inc(instr); if instr^ = '>' then begin inc(instr); break; end else begin instr := instr2; i := l; end; end; ptr^ := instr^; inc(instr); inc(i); inc(ptr); inc(flatlen); end; ptr := flatbuf; repeat i := imin(flatlen, 5); _IEASCII85Decode5(ptr, i, outbytes); inc(result, i - 1); dec(flatlen, i); until flatlen <= 0; freemem(flatbuf); end; // return the number of bytes actually written function IEPSRunLengthEncode(inbytes: pbytearray; inlen: integer; outbytes: pbytearray): integer; var inpos, i, l, j: integer; begin result := 0; // this is output position inpos := 0; while inpos < inlen do begin // search for run lengths i := inpos + 1; while (i < inlen) and (inbytes[inpos] = inbytes[i]) and (i-inpos < 128) do inc(i); l := i - inpos; if (l > 1) then begin // do run length outbytes[result] := 257 - l; inc(result); outbytes[result] := inbytes[inpos]; inc(result); inpos := i; end else begin // search for literals i := inpos + 1; while (i < inlen) and (inbytes[i-1] <> inbytes[i]) and (i-inpos < 128) do inc(i); l := i - inpos; // do literals outbytes[result] := l - 1; inc(result); for j := 0 to l - 1 do begin outbytes[result] := inbytes[inpos]; inc(result); inc(inpos); end; end; end; // do EOD outbytes[result] := 128; inc(result); end; procedure IEWriteStrLn(s: TStream; ss: AnsiString); begin ss := ss + #13#10; s.Write(PAnsiChar(ss)^, length(ss)); end; function IEGetDecimalSeparator: Char; begin {$ifdef IEHASFORMATSETTINGS} result := FormatSettings.DecimalSeparator; {$else} result := DecimalSeparator; {$endif} end; procedure IESetDecimalSeparator(c: Char); begin {$ifdef IEHASFORMATSETTINGS} FormatSettings.DecimalSeparator := c; {$else} DecimalSeparator := c; {$endif} end; function IEFloatToStrA(Value: Extended): AnsiString; var i: integer; begin result := AnsiString(floattostr(Value)); for i := 1 to length(result) do if (result[i]=',') or (result[i]=AnsiChar(IEGetDecimalSeparator)) then result[i] := '.'; end; function IEFloatToStrS(Value: Extended): string; var i: integer; begin result := FloatToStr(Value); for i := 1 to length(result) do if (result[i]=',') or (result[i]=IEGetDecimalSeparator()) then result[i] := '.'; end; function IEFloatToStrW(Value: Extended): WideString; var i: integer; begin result := floattostr(Value); for i := 1 to length(result) do if (result[i]=',') or (result[i]=WideString(IEGetDecimalSeparator())) then result[i] := '.'; end; function IEIsSpace(c: AnsiChar): boolean; begin result := (c = ' ') or (c = #8) or (c = #13) or (c = #10); end; function IERemoveCtrlCharsA(const text: AnsiString): AnsiString; var q: integer; c: integer; begin result := ''; for q := 1 to length(text) do begin c := ord(text[q]); if (c>31) and (c<>127) then result := result+AnsiChar(c); end; end; function IERemoveCtrlCharsS(const text: String): String; begin result := IERemoveCtrlCharsW(text); end; function IERemoveCtrlCharsW(const text: WideString): WideString; var q: integer; c: integer; begin result := ''; for q := 1 to length(text) do begin c := ord(text[q]); if (c>31) and (c<>127) then result := result+WideChar(c); end; end; // Returns true if rgb1, rgb2 are the equal (Tolerance = 0) or closely matched (Tolerance is between 1 and 255) function IERGBColorsMatch(rgb1, rgb2 : TRGB; Tolerance : Integer = 0): Boolean; var dr, dg, db: Integer; begin dr := abs(rgb1.r - rgb2.r); dg := abs(rgb1.g - rgb2.g); db := abs(rgb1.b - rgb2.b); result := (dr <= tolerance) and (dg <= tolerance) and (db <= tolerance); end; function IERGB2StrS(c: TRGB): string; begin with c do result := IntToStr(r)+', '+IntToStr(g)+', '+IntToStr(b); end; function IERGB2StrW(c: TRGB): WideString; begin with c do result := IntToStr(r)+', '+IntToStr(g)+', '+IntToStr(b); end; function IEBool2StrS(v: boolean): string; begin if v then result := '1' else result := '0'; end; function IEBool2StrW(v: boolean): WideString; begin if v then result := '1' else result := '0'; end; function IEStr2RGBW(const rgbstr: WideString): TRGB; begin result := IEStr2RGBS(string(rgbstr)); end; function IEStr2RGBS(const rgbstr: string): TRGB; var p: integer; ps1, q: integer; ss: string; l: integer; begin try l := length(rgbstr); ps1 := 1; p := 0; for q := 1 to l+1 do begin if (rgbstr[q]=',') or (q=l+1) then begin ss := Trim(copy(rgbstr, ps1, (q-ps1))); case p of 0: result.r := StrToIntDef(ss, 0); 1: result.g := StrToIntDef(ss, 0); 2: result.b := StrToIntDef(ss, 0); end; inc(p); ps1 := q+1; end; end; except result := creatergb(0, 0, 0); end; end; function IEStr2BoolS(const v: string): boolean; var ss: string; begin ss := UpperCase(v); result := (ss='1') or (ss='TRUE') or (ss='T'); end; function IEStr2BoolW(const v: WideString): boolean; begin result := IEStr2BoolS(string(v)); end; function IEStr2BoolA(const v: AnsiString): boolean; begin result := IEStr2BoolS(string(v)); end; function IEStr2ColorDefS(const v : string; ADefault : TColor) : TColor; begin Try Result := StringToColor(v); except Result := ADefault; End; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// {!! IESetTranslationWord Declaration procedure IESetTranslationWord(const lang: ; const msg: ; const trans: AnsiString); procedure IESetTranslationWordU(const lang: ; const msg: ; const trans: String); Description IESetTranslationWord allows applications to set a customized word/sentence translation. lang is the target language. msg is the message to translate. trans is the translated message. See also: iewords.pas file. !!} procedure IESetTranslationWord(const lang: TMsgLanguage; const msg: TMsgLanguageWords; const trans: AnsiString); {$ifdef UNICODE} var rbs: RawByteString; begin rbs := trans; SetCodePage(rbs, IELANGUAGECHARINFO[lang].CodePage, false); ieMessages[lang][msg] := string(rbs); end; {$else} begin ieMessages[lang][msg] := string(trans); end; {$endif} procedure IESetTranslationWordU(const lang: TMsgLanguage; const msg: TMsgLanguageWords; const trans: string); begin ieMessages[lang][msg] := trans; end; // returns the message "msg" in current selected language function iemsg(const msg: TMsgLanguageWords): WideString; begin if IEGlobalSettings().MsgLanguage = msSystem then begin case syslocale.PriLangID of {$IFDEF IESUPPORTITALIAN} LANG_ITALIAN: result := ieMessages[msItalian][msg]; {$ENDIF} {$IFDEF IESUPPORTPORTUGUESE} LANG_PORTUGUESE: result := ieMessages[msPortuguese][msg]; {$ENDIF} {$IFDEF IESUPPORTENGLISH} LANG_ENGLISH: result := ieMessages[msEnglish][msg]; {$ENDIF} {$IFDEF IESUPPORTSPANISH} LANG_SPANISH: result := ieMessages[msSpanish][msg]; {$ENDIF} {$IFDEF IESUPPORTFRENCH} LANG_FRENCH: result := ieMessages[msFrench][msg]; {$ENDIF} {$IFDEF IESUPPORTGERMAN} LANG_GERMAN: result := ieMessages[msGerman][msg]; {$ENDIF} {$IFDEF IESUPPORTGREEK} LANG_GREEK: result := ieMessages[msGreek][msg]; {$ENDIF} {$IFDEF IESUPPORTRUSSIAN} LANG_RUSSIAN: result := ieMessages[msRussian][msg]; {$ENDIF} {$IFDEF IESUPPORTDUTCH} LANG_DUTCH: result := ieMessages[msDutch][msg]; {$ENDIF} {$IFDEF IESUPPORTSWEDISH} LANG_SWEDISH: result := ieMessages[msSwedish][msg]; {$ENDIF} {$IFDEF IESUPPORTPOLISH} LANG_POLISH: result := ieMessages[msPolish][msg]; {$ENDIF} {$IFDEF IESUPPORTJAPANESE} LANG_JAPANESE: result := ieMessages[msJapanese][msg]; {$ENDIF} {$IFDEF IESUPPORTCZECH} LANG_CZECH: result := ieMessages[msCzech][msg]; {$ENDIF} {$IFDEF IESUPPORTFINNISH} LANG_FINNISH: result := ieMessages[msFinnish][msg]; {$ENDIF} {$IFDEF IESUPPORTFARSI} LANG_FARSI: result := ieMessages[msFarsi][msg]; {$ENDIF} {$IFDEF IESUPPORTDANISH} LANG_DANISH: result := ieMessages[msDanish][msg]; {$ENDIF} {$IFDEF IESUPPORTTURKISH} LANG_TURKISH: result := ieMessages[msTurkish][msg]; {$ENDIF} {$IFDEF IESUPPORTKOREAN} LANG_KOREAN: result := ieMessages[msKorean][msg]; {$ENDIF} {$IFDEF IESUPPORTHUNGARIAN} LANG_HUNGARIAN: result := ieMessages[msHungarian][msg]; {$ENDIF} {$IFDEF IESUPPORTARABIC} LANG_ARABIC: result := ieMessages[msArabic][msg]; {$ENDIF} {$IFDEF IESUPPORTSERBIAN} LANG_SERBIAN: result := ieMessages[msSerbian][msg]; {$ENDIF} {$IFDEF IESUPPORTNORWEGIAN} LANG_NORWEGIAN: result := ieMessages[msNorwegian][msg]; {$ENDIF} {$IFDEF IESUPPORTCHINESE} LANG_CHINESE: case syslocale.SubLangID of SUBLANG_CHINESE_SIMPLIFIED: result := ieMessages[msChinese][msg]; SUBLANG_CHINESE_TRADITIONAL: result := ieMessages[msChineseTraditionalBig5][msg]; end; {$ENDIF} else {$IFDEF IESUPPORTENGLISH} result := ieMessages[msEnglish][msg]; {$ELSE} result := ieMessages[TMsgLanguage(1)][msg]; {$ENDIF} end; end else begin result := ieMessages[IEGlobalSettings().MsgLanguage][msg]; end; // Fall back to English or whatever language is available if result = '' then {$IFDEF IESUPPORTENGLISH} result := ieMessages[msEnglish][msg]; {$ELSE} result := ieMessages[TMsgLanguage(1)][msg]; {$ENDIF} end; //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// { function CalcLineLenWithinRect(R: TRect; Angle: Integer): Double; var Pt1, Pt2: TPoint; begin CalcLineWithinRect( R, Angle, Pt1, Pt2 ); result := _DistPoint2Point( Pt1.x, Pt1.y, Pt2.x, Pt2.Y ); end; } // point to point distance function _DistPoint2Point(x1, y1, x2, y2: integer): double; begin result := sqrt(sqr(x2 - x1) + sqr(y2 - y1)); end; function IEDDistPoint2Point(x1, y1, x2, y2: double): double; begin result := sqrt(sqr(x2 - x1) + sqr(y2 - y1)); end; // point to line distance function _DistPoint2Line(xp, yp, x1, y1, x2, y2: integer): double; var a, b, c: double; // leave a, b, c as double (not integers! otherwise an overflow could occur) begin a := y1 - y2; b := x2 - x1; c := x1 * y2 - x2 * y1; result := abs(a * xp + b * yp + c) / sqrt(a * a + b * b); end; // Point<->Segment distance function _DistPoint2Seg(xp, yp, x1, y1, x2, y2: integer): double; var r: double; begin result := 1000000; try if (x1 = x2) and (y1 = y2) then result := sqrt(sqr(xp - x1) + sqr(yp - y1)) else begin r := ((y1 - yp) * (y1 - y2) - (x1 - xp) * (x2 - x1)) / (sqr(x2 - x1) + sqr(y2 - y1)); if r > 1 then begin // distance from xp, yp to x2, y2 if abs(xp - x2) > 45000 then exit; if abs(yp - y2) > 45000 then exit; result := sqrt(sqr(xp - x2) + sqr(yp - y2)); end else if r < 0 then begin // distance from xp, yp to x1, y1 if abs(x1 - xp) > 45000 then exit; if abs(y1 - yp) > 45000 then exit; result := sqrt(sqr(x1 - xp) + sqr(y1 - yp)) end else begin // distance from the line result := _DistPoint2Line(xp, yp, x1, y1, x2, y2); end; end; except end; end; function _DistPoint2Polyline(x, y: integer; PolyPoints: PPointArray; PolyPointsCount: integer; ToSubX, ToSubY, ToAddX, ToAddY: integer; ToMulX, ToMulY: double; penWidth: integer; closed: boolean): double; var i: integer; d: double; x1, y1, x2, y2: integer; procedure comp; var j, k: integer; begin d := _DistPoint2Seg(x, y, x1, y1, x2, y2); if penWidth > 1 then for j := -penWidth div 2 to penWidth div 2 do for k := 2 to penWidth div 2 do begin d := dmin(d, _DistPoint2Seg(x, y, x1+j, y1+k, x2+j, y2+k)); end; if d < result then result := d; iswap(x1, x2); iswap(y1, y2); end; begin result := 1000000; if PolyPointsCount > 0 then begin x1 := round((PolyPoints^[0].x - ToSubX) * ToMulX + ToAddX); y1 := round((PolyPoints^[0].y - ToSubY) * ToMulY + ToAddY); for i := 1 to PolyPointsCount - 1 do begin x2 := round((PolyPoints^[i].x - ToSubX) * ToMulX + ToAddX); y2 := round((PolyPoints^[i].y - ToSubY) * ToMulY + ToAddY); comp; end; if closed then begin x2 := round((PolyPoints^[0].x - ToSubX) * ToMulX + ToAddX); y2 := round((PolyPoints^[0].y - ToSubY) * ToMulY + ToAddY); comp; end; end; end; /////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////// function IEGetOpSys(): TIEOpSys; var ver: TOSVersionInfo; begin result := ieosUnknown; ver.dwOSVersionInfoSize := SizeOf(TOSVersionInfo); if not GetVersionEx(ver) then Exit; case ver.dwPlatformId of VER_PLATFORM_WIN32_WINDOWS: begin if (ver.dwMajorVersion=4) then begin if (ver.dwMinorVersion=0) then result := ieosWin95 else if (ver.dwMinorVersion = 10) then result := ieosWin98 else if (ver.dwMinorVersion = 90) then result := ieosWinME; end; end; VER_PLATFORM_WIN32_NT: begin if (ver.dwMajorVersion=4) and (ver.dwMinorVersion=0) then result := ieosWinNT4 else if (ver.dwMajorVersion = 5) and (ver.dwMinorVersion = 0) then result := ieosWin2000 else if (ver.dwMajorVersion = 5) and (ver.dwMinorVersion = 1) then result := ieosWinXP else if (ver.dwMajorVersion = 5) and (ver.dwMinorVersion = 2) then result := ieosWin2003 else if (ver.dwMajorVersion = 6) and (ver.dwMinorVersion = 0) then result := ieosWinVista else if (ver.dwMajorVersion = 6) and (ver.dwMinorVersion = 1) then result := ieosWin7 else if (ver.dwMajorVersion = 6) and (ver.dwMinorVersion = 2) then result := ieosWin8 else if (ver.dwMajorVersion = 10) and (ver.dwMinorVersion = 0) then result := ieosWin10; end; end; end; function IEGetDisplayOrientation(): integer; var devmode: TIEDeviceModeW; begin FillChar(devmode, sizeof(devmode), 0); devmode.dmSize := sizeof(devmode); IE_EnumDisplaySettingsExW(nil, DWORD(-1), devmode, 4); result := devmode.dmDisplayOrientation * 90; end; function IEStrToFloatDefA(s: AnsiString; Def: extended): extended; var q: integer; begin if not IETextToFloat(PAnsiChar(s), result, fvExtended) then begin q := IEPos(',', s); if q > 0 then s[q] := '.' else begin q := IEPos('.', s); if q > 0 then s[q] := ','; end; if not IETextToFloat(PAnsiChar(s), result, fvExtended) then result := Def; end; end; function IEStrToFloatDefW(s: WideString; Def: extended): extended; begin result := IEStrToFloatDefA(AnsiString(s), Def); end; function IEStrToFloatDefS(s: String; Def: extended): extended; begin result := IEStrToFloatDefA(AnsiString(s), Def); end; function IEStrToFloatDef(s: String; Def: extended): extended; begin result := IEStrToFloatDefA(AnsiString(s), Def); end; function IEStrLen(const Str: PAnsiChar): Cardinal; begin {$ifdef DelphiXE4orNewer} result := AnsiStrings.StrLen(Str); {$else} result := StrLen(Str); {$endif} end; function IEStrLenW(Str: PWideChar): Cardinal; begin result := 0; while Str^ <> #0 do begin inc(result); inc(Str); end; end; function IEStrCopy(Dest: PAnsiChar; const Source: PAnsiChar): PAnsiChar; begin {$ifdef DelphiXE4orNewer} result := AnsiStrings.StrCopy(Dest, Source); {$else} result := StrCopy(Dest, Source); {$endif} end; function IEStrCopyW(Dest: PWideChar; Source: PWideChar): PWideChar; begin result := Dest; while Source^ <> #0 do begin Dest^ := Source^; inc(Dest); inc(Source); end; Dest^ := #0; end; function IEStrPCopy(Dest: PAnsiChar; const Source: AnsiString): PAnsiChar; begin {$ifdef DelphiXE4orNewer} result := AnsiStrings.StrPCopy(Dest, Source); {$else} result := StrPCopy(Dest, Source); {$endif} end; function IEStrPCopyW(Dest: PWideChar; const Source: WideString): PWideChar; var i: integer; begin result := Dest; for i := 1 to length(Source) do begin Dest^ := Source[i]; inc(Dest); end; Dest^ := #0; end; // Copies array of ansichar to PWideChar function IEStrPCopyWA(Dest: PWideChar; Source: TIEArrayOfAnsiChar): PWideChar; var i: integer; begin result := Dest; for i := 1 to length(Source) do begin Dest^ := WideChar(Source[i]); inc(Dest); end; Dest^ := #0; end; function IEStrMove(Dest: PAnsiChar; const Source: PAnsiChar; Count: Cardinal): PAnsiChar; begin {$ifdef DelphiXE4orNewer} result := AnsiStrings.StrMove(Dest, Source, Count); {$else} result := StrMove(Dest, Source, Count); {$endif} end; function IEAnsiStrScan(Str: PAnsiChar; Chr: AnsiChar): PAnsiChar; begin {$ifdef DelphiXE4orNewer} result := AnsiStrings.AnsiStrScan(Str, Chr); {$else} result := AnsiStrScan(Str, Chr); {$endif} end; function IEStrScan(const Str: PAnsiChar; Chr: AnsiChar): PAnsiChar; begin {$ifdef DelphiXE4orNewer} result := AnsiStrings.StrScan(Str, Chr); {$else} result := StrScan(Str, Chr); {$endif} end; function IEStrRScan(const Str: PAnsiChar; Chr: AnsiChar): PAnsiChar; begin {$ifdef DelphiXE4orNewer} result := AnsiStrings.StrRScan(Str, Chr); {$else} result := StrRScan(Str, Chr); {$endif} end; function IETextToFloat(Buffer: PAnsiChar; var Value; ValueType: TFloatValue): Boolean; begin {$ifdef DelphiXE4orNewer} result := AnsiStrings.TextToFloat(Buffer, Value, ValueType); {$else} result := TextToFloat(Buffer, Value, ValueType); {$endif} end; function IECopyArrayOfByte(const Input: TIEArrayOfByte): TIEArrayOfByte; begin SetLength(result, length(Input)); move(Input[0], result[0], sizeof(byte) * length(Input)); end; function IECopyArrayOfInteger(const Input: TIEArrayOfInteger): TIEArrayOfInteger; begin SetLength(result, length(Input)); move(Input[0], result[0], sizeof(integer) * length(Input)); end; //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // L: 0..255 // A: -127...127 // B: -127...127 function IERGB2CIELAB(rgb: TRGB): TCIELAB; var X, Y, Z, fX, fY, fZ: double; RR, GG, BB: double; L: double; begin RR := rgb.r / 255.0; GG := rgb.g / 255.0; BB := rgb.b / 255.0; if (RR > 0.04045) then RR := IEPower2(((RR + 0.055) / 1.055), 2.4) else RR := RR / 12.92; if (GG > 0.04045) then GG := IEPower2(((GG + 0.055) / 1.055), 2.4) else GG := GG / 12.92; if (BB > 0.04045) then BB := IEPower2(((BB + 0.055) / 1.055), 2.4) else BB := BB / 12.92; X := (0.412453*RR + 0.357580*GG + 0.180423*BB) / 0.95047; Y := (0.212671*RR + 0.715160*GG + 0.072169*BB); Z := (0.019334*RR + 0.119193*GG + 0.950227*BB) / 1.088883; if (Y > 0.008856) then begin fY := IEPower2(Y, 1.0/3.0); L := 116.0*fY - 16.0; end else begin fY := 7.787*Y + 16.0/116.0; L := 903.3*Y; end; if (X > 0.008856) then fX := IEPower2(X, 1.0/3.0) else fX := 7.787*X + 16.0/116.0; if (Z > 0.008856) then fZ := IEPower2(Z, 1.0/3.0) else fZ := 7.787*Z + 16.0/116.0; result.L := trunc(L*2.55); result.a := trunc(500.0*(fX - fY)); result.b := trunc(200.0*(fY - fZ)); end; function IECIELAB2RGB(const lab: TCIELAB): TRGB; var var_R, var_G, var_B: double; X, Y, Z: double; begin with lab do begin Y := ( L * 0.39215686275 + 16 ) / 116; X := a / 500 + Y; Z := Y - b / 200; end; if ( IEPower2(Y, 3) > 0.008856 ) then Y := IEPower2(Y, 3) else Y := ( Y - 0.13793103448 ) / 7.787; if ( IEPower2(X, 3) > 0.008856 ) then X := IEPower2(X, 3) else X := ( X - 0.13793103448 ) / 7.787; if ( IEPower2(Z, 3) > 0.008856 ) then Z := IEPower2(Z, 3) else Z := ( Z - 0.13793103448 ) / 7.787; X := X * 0.95047; Z := Z * 1.08883; var_R := X * 3.2406 + Y * (-1.5372) + Z * (-0.4986); var_G := X * (-0.9689) + Y * 1.8758 + Z * 0.0415; var_B := X * 0.0557 + Y * (-0.2040) + Z * 1.0570; if ( var_R > 0.0031308 ) then var_R := 1.055 * ( IEPower2(var_R, 0.41666666667) ) - 0.055 else var_R := 12.92 * var_R; if ( var_G > 0.0031308 ) then var_G := 1.055 * ( IEPower2(var_G, 0.41666666667) ) - 0.055 else var_G := 12.92 * var_G; if ( var_B > 0.0031308 ) then var_B := 1.055 * ( IEPower2(var_B, 0.41666666667) ) - 0.055 else var_B := 12.92 * var_B; with result do begin r := blimit(round(var_R * 255)); g := blimit(round(var_G * 255)); b := blimit(round(var_B * 255)); end; end; // draw a 3d rect procedure IEDraw3DRect(Canvas: TCanvas; x1, y1, x2, y2: integer; cl1, cl2: TColor); begin with Canvas do begin Pen.Mode := pmCopy; Pen.Style := psSolid; Pen.Color := cl1; Pen.Width := 1; MoveTo(x1, y2); LineTo(x1, y1); LineTo(x2, y1); Pen.Color := cl2; MoveTo(x1, y2); LineTo(x2, y2); LineTo(x2, y1); end; end; // Same as IEDraw3DRect but using TIECanvas // Canvas must be TIECanvas procedure IEDraw3DRect2(Canvas: TObject; x1, y1, x2, y2: integer; cl1, cl2: TColor); begin with Canvas as TIECanvas do begin Pen.Mode := pmCopy; Pen.Style := psSolid; Pen.Color := cl1; MoveTo(x1, y2); LineTo(x1, y1); LineTo(x2, y1); Pen.Color := cl2; MoveTo(x1, y2); LineTo(x2, y2); LineTo(x2, y1); end; end; procedure IEDrawHint(Canvas: TCanvas; var x, y: integer; const ss: string; Font: TFont; Brush: TBrush; var SaveBitmap: TBitmap; MaxWidth, MaxHeight: integer; Border1, Border2: TColor); const ox = 6; oy = 6; var tw, th: integer; begin Canvas.Font.Assign(Font); Canvas.Brush.Assign(Brush); tw := Canvas.TextWidth(ss) + 6 + ox; th := Canvas.TextHeight(ss) + 6 + oy; if x < 0 then x := 0; if y < 0 then y := 0; x := imin(x, MaxWidth - 1 - tw); y := imin(y, MaxHeight - 1 - th); SaveBitmap.PixelFormat := pf24bit; SaveBitmap.Width := tw; SaveBitmap.Height := th; SaveBitmap.Canvas.CopyMode := cmSrcCopy; SaveBitmap.Canvas.CopyRect(rect(0, 0, tw, th), Canvas, rect(x, y, x + tw, y + th)); canvas.FillRect(rect(x + ox, y + oy, x + tw, y + th)); IEDraw3DRect(Canvas, x + ox, y + oy, x + tw - 1, y + th - 1, Border1, Border2); Canvas.TextOut(x + 3 + ox, y + 3 + oy, string(ss)); end; procedure IEDrawHint2(Canvas: TCanvas; var x, y: integer; const ss: string; const minText: string); const ox = 6; oy = 6; var tw, th: integer; iec: TIECanvas; begin iec := TIECanvas.Create(Canvas, true, true); iec.Font.Name := 'Arial'; iec.Font.Size := 9; iec.Font.Color := clBlack; iec.Brush.Color := $0060FFFF; iec.Brush.Style := bsSolid; iec.Brush.Transparency := 128; tw := imax( iec.TextWidth(ss) + 6 + ox , iec.TextWidth(minText) + 6 + ox ); th := iec.TextHeight(ss) + 6 + oy; if x < 0 then x := 0; if y < 0 then y := 0; iec.FillRect(rect(x + ox, y + oy, x + tw, y + th)); IEDraw3DRect2(iec, x + ox, y + oy, x + tw - 1, y + th - 1, clWhite, clGray); iec.Brush.Style := bsClear; iec.TextOut(x + 3 + ox, y + 3 + oy, ss); iec.Free; end; function IEDrawDibClose(hdd: hDrawDib): Boolean; begin result := DrawDibClose(hdd); end; function IEDrawDibDraw(hdd: hDrawDib; hDC: THandle; xDst, yDst, dxDst, dyDst: Integer; var lpbi: TBitmapInfoHeader; Bits: Pointer; xSrc, ySrc, dxSrc, dySrc: Integer; wFlags: UInt): Boolean; begin result := DrawDibDraw(hdd, hDC, xDst, yDst, dxDst, dyDst, lpbi, Bits, xSrc, ySrc, dxSrc, dySrc, wFlags); end; function IEDrawDibOpen: hDrawDib; begin result := DrawDibOpen; end; function IEDrawDibRealize(hdd: hDrawDib; hDC: THandle; fBackground: Bool): UInt; begin result := DrawDibRealize(hdd, hDC, fBackground); end; procedure SafeStreamWrite(Stream: TStream; var Aborting: boolean; const Buffer; Count: Longint); begin if Stream.Write(Buffer, Count) < Count then Aborting := true; end; ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// // DoPaletteDialog ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// {!! TImageEnPaletteDialog.SetPalette Declaration procedure SetPalette(var Palette: array of ; NumCol: integer); Description Sets palette to show in the dialog. Example Var fPalDial: TImageEnPaletteDialog; Begin fPalDial := TImageEnPaletteDialog.Create(self); fPalDial.SetPalette(ImageEnIO1.Params.ColorMap^, ImageEnIO1.Params.ColorMapCount); if fPalDial.Execute then Panel1.Color := fPalDial.SelCol; fPalDial.free; End; See Also - - - !!} procedure TImageEnPaletteDialog.SetPalette(var Palette: array of TRGB; NumCol: integer); begin fPalette := PRGBROW(@(Palette[0])); fNumCol := NumCol; end; constructor TImageEnPaletteDialog.Create(AOwner: TComponent); const Right_Border = 8; begin inherited CreateNew(AOwner); OnPaint := self.FormPaint; OnMouseMove := self.FormMouseMove; OnClick := self.FormClick; BorderIcons := [biSystemMenu]; BorderStyle := bsDialog; Caption := 'Palette'; Height := 199; Position := poScreenCenter; Width := 520; ButtonCancel := TButton.Create(self); with ButtonCancel do begin Parent := self; ModalResult := mrCancel; Caption := 'Cancel'; Cancel := true; Top := 136; end; ButtonCancel.Left := ClientWidth - ButtonCancel.Width - Right_Border; MouseCol := -1; SelCol := -1; end; procedure TImageEnPaletteDialog.FormPaint(Sender: TObject); var c, x, y: integer; begin for c := 0 to fNumCol - 1 do begin y := 1 + (c div 32) * 16; x := 1 + (c - (c div 32) * 32) * 16; Canvas.Brush.Color := TRGB2TColor(fPalette^[c]); if MouseCol = c then Canvas.Pen.Color := clBlack else if Canvas.Brush.Color = SelCol then Canvas.Pen.Color := $00555555 else Canvas.Pen.Color := clWhite; Canvas.Rectangle(x, y, x + 15, y + 15); end; end; procedure TImageEnPaletteDialog.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var c: integer; begin c := ((x - 1) div 16) + ((y - 1) div 16) * 32; if (c >= 0) and (c < fNumCol) and (c <> MouseCol) then begin MouseCol := c; FormPaint(self); end; end; procedure TImageEnPaletteDialog.FormClick(Sender: TObject); begin SelCol := TRGB2TCOLOR(fPalette^[MouseCol]); modalresult := mrOK; end; {!! TImageEnPaletteDialog.Execute Declaration function Execute: boolean; Description Executes the dialog. Returns True if the user select a color, otherwise False if the user Cancel the dialog. Use SelCol property to get the color selected as TColor or NumCol to get as integer index. Example Var fPalDial: TImageEnPaletteDialog; Begin fPalDial := TImageEnPaletteDialog.Create(self); fPalDial.SetPalette(ImageEnIO1.Params.ColorMap^, ImageEnIO1.Params.ColorMapCount); if fPalDial.Execute then Panel1.Color := fPalDial.SelCol; fPalDial.free; End; !!} function TImageEnPaletteDialog.Execute: boolean; begin if fPalette = nil then raise EIEException.create('Invalid Palette!'); result := ShowModal = mrOK; end; ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// function IEDirectoryExists(const Name: string): Boolean; var Code: Integer; begin Code := GetFileAttributes(PChar(Name)); Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0); end; procedure IEForceDirectories(Dir: string); begin if Length(Dir) = 0 then exit; if (AnsiLastChar(Dir) <> nil) and (AnsiLastChar(Dir)^ = '\') then Delete(Dir, Length(Dir), 1); if (Length(Dir) < 3) or IEDirectoryExists(Dir) or (ExtractFilePath(Dir) = Dir) then exit; IEForceDirectories(ExtractFilePath(Dir)); CreateDir(Dir); end; // count consecutive bits // ex 000111110000 return 5 function _GetBitCount(b: Integer): Integer; var i: Integer; begin i := 0; while (i < 31) and (((1 shl i) and b) = 0) do Inc(i); Result := 0; while (((1 shl i) and b) <> 0) and (i < 32) do begin Inc(i); Inc(Result); end; end; // return first set bit // ex 000011100000 return 6 (first bit is "1") // return 0 if no set bit found function IEGetFirstSetBit(b: Integer): Integer; var i: Integer; begin i := 0; while (i < 32) and (((1 shl i) and b) = 0) do Inc(i); if i = 32 then result := 0 else result := i + 1; end; // Converts colors count to needed bits per pixels (rounded) function _NColToBitsPixel(NCol: integer): integer; var q: integer; begin result := -1; for q := 0 to 31 do if (NCol and (1 shl q)) <> 0 then begin if result <> -1 then result := q + 1 else result := q; end; end; // return line length in bytes // align is the number of bits of alignment. Allowed multiple of 8 bits (8, 16, 24, 32, 48...) function IEBitmapRowLen(Width: integer; BitCount: integer; align: integer): int64; begin case align of 32: // formula optimized for 32 result := (((Width * BitCount) + 31) shr 5) shl 2; // (((Width*BitCount)+31) div 32) * 4 else // generic formula result := (((Width * BitCount) + (align - 1)) div align) * (align div 8); end; end; // Converts Pixelformat of TBitmap to BitCount function IEVCLPixelFormat2BitCount(PixelFormat: TPixelFormat): integer; const conv: array[pfDevice..pfCustom] of integer = (0, 1, 4, 8, 15, 16, 24, 32, 0); begin case PixelFormat of pf1bit: result := 1; pf4bit: result := 4; pf8bit: result := 8; pf15bit: result := 15; pf16bit: result := 16; pf24bit: result := 24; pf32bit: result := 32; else result := 0; end; end; function IEVCLPixelFormat2ImageEnPixelFormat(PixelFormat: TPixelFormat): TIEPixelFormat; begin case PixelFormat of pf1bit: result := ie1g; pf4bit: result := ie8p; pf8bit: result := ie8p; pf15bit: result := ie24RGB; pf16bit: result := ie24RGB; pf24bit: result := ie24RGB; pf32bit: result := ie24RGB; else result := ie24RGB; end; end; // Get rowlen from PixelFormat function IEVCLPixelFormat2RowLen(Width: integer; PixelFormat: TPixelFormat): integer; begin result := IEBitmapRowLen(Width, IEVCLPixelFormat2BitCount(PixelFormat), 32); end; // converts BitCount to PixelFormat (of TBitmap) function IEBitCount2VCLPixelformat(Bitcount: integer): TPixelFormat; begin case BitCount of 1: result := pf1bit; 4: result := pf4bit; 8: result := pf8bit; 15: result := pf15bit; 16: result := pf16bit; 24: result := pf24bit; 32: result := pf32bit; else result := pfCustom; end; end; function IEPixelFormat2BitCount(PixelFormat: TIEPixelFormat): integer; const PIXELFORMAT2BITCOUNT: array [TIEPixelFormat] of integer = ( 0, // ienull 1, // ie1g 8, // ie8p 8, // ie8g 16, // ie16g 24, // ie24RGB 32, // ie32f 32, // ieCMYK 48, // ie48RGB 24, // ieCIELab 32); // ie32RGB begin result := PIXELFORMAT2BITCOUNT[PixelFormat]; end; function IEPixelFormat2ChannelCount(PixelFormat: TIEPixelFormat): integer; const PIXELFORMAT2CHANNELCOUNT: array [TIEPixelFormat] of integer = ( 0, // ienull 1, // ie1g 1, // ie8p 1, // ie8g 1, // ie16g 3, // ie24RGB 1, // ie32f 4, // ieCMYK 3, // ie48RGB 3, // ieCIELab 4); // ie32RGB begin result := PIXELFORMAT2CHANNELCOUNT[PixelFormat]; end; const invtab: array[0..255] of byte = ($00, $80, $40, $C0, $20, $A0, $60, $E0, $10, $90, $50, $D0, $30, $B0, $70, $F0, $08, $88, $48, $C8, $28, $A8, $68, $E8, $18, $98, $58, $D8, $38, $B8, $78, $F8, $04, $84, $44, $C4, $24, $A4, $64, $E4, $14, $94, $54, $D4, $34, $B4, $74, $F4, $0C, $8C, $4C, $CC, $2C, $AC, $6C, $EC, $1C, $9C, $5C, $DC, $3C, $BC, $7C, $FC, $02, $82, $42, $C2, $22, $A2, $62, $E2, $12, $92, $52, $D2, $32, $B2, $72, $F2, $0A, $8A, $4A, $CA, $2A, $AA, $6A, $EA, $1A, $9A, $5A, $DA, $3A, $BA, $7A, $FA, $06, $86, $46, $C6, $26, $A6, $66, $E6, $16, $96, $56, $D6, $36, $B6, $76, $F6, $0E, $8E, $4E, $CE, $2E, $AE, $6E, $EE, $1E, $9E, $5E, $DE, $3E, $BE, $7E, $FE, $01, $81, $41, $C1, $21, $A1, $61, $E1, $11, $91, $51, $D1, $31, $B1, $71, $F1, $09, $89, $49, $C9, $29, $A9, $69, $E9, $19, $99, $59, $D9, $39, $B9, $79, $F9, $05, $85, $45, $C5, $25, $A5, $65, $E5, $15, $95, $55, $D5, $35, $B5, $75, $F5, $0D, $8D, $4D, $CD, $2D, $AD, $6D, $ED, $1D, $9D, $5D, $DD, $3D, $BD, $7D, $FD, $03, $83, $43, $C3, $23, $A3, $63, $E3, $13, $93, $53, $D3, $33, $B3, $73, $F3, $0B, $8B, $4B, $CB, $2B, $AB, $6B, $EB, $1B, $9B, $5B, $DB, $3B, $BB, $7B, $FB, $07, $87, $47, $C7, $27, $A7, $67, $E7, $17, $97, $57, $D7, $37, $B7, $77, $F7, $0F, $8F, $4F, $CF, $2F, $AF, $6F, $EF, $1F, $9F, $5F, $DF, $3F, $BF, $7F, $FF); // reverse byte bits procedure ReverseBitsB(var inp: byte); begin inp := invtab[inp]; end; {$ifdef IEUSEASM} procedure ReverseBits(var inp: dword); assembler; asm push esi push ebx mov esi, eax mov eax, DWord Ptr [esi] BSWAP EAX MOV EDX, EAX AND EAX, 0AAAAAAAAh SHR EAX, 1 AND EDX, 055555555h SHL EDX, 1 OR EAX, EDX MOV EDX, EAX AND EAX, 0CCCCCCCCh SHR EAX, 2 AND EDX, 033333333h SHL EDX, 2 OR EAX, EDX MOV EDX, EAX AND EAX, 0F0F0F0F0h SHR EAX, 4 AND EDX, 00F0F0F0Fh SHL EDX, 4 OR EAX, EDX mov DWord Ptr [esi], eax pop ebx pop esi end; {$else} procedure ReverseBits(var inp: dword); begin inp := (invtab[(inp shr 24) and $FF]) or (invtab[(inp shr 16) and $FF] shl 8) or (invtab[(inp shr 8) and $FF] shl 16) or (invtab[(inp) and $FF] shl 24); end; {$endif} {$ifdef IEUSEASM} function IEPower2(const Base, Exponent: Double): Double; const MAXINTFP : Extended = $7fffffff; asm sub esp,$14 //if (Abs(Exponent) <= MaxInt) then fld MAXINTFP fld Exponent fld st(0) fabs fcomp st(2) fstsw ax sahf ffree st(1) jae @IfEnd1 //Y := Round(Exponent); fld st(0) frndint fist dword ptr [esp] fcomp st(1) fstsw ax sahf ffree st(0) jnz @IfEnd2 //Result := IntPowerDKCIA32_4e(Base, Y) //if Base = 0 then fldz fld Base fcom st(1) fstsw ax sahf jnz @IntPowIfEnd2 //if Exponent = 0 then mov ecx,[esp] test ecx,ecx jnz @IntPowElse2 //ResultX := 1 ffree st(1) ffree st(0) fld1 wait mov esp,ebp pop ebp ret $10 @IntPowElse2 : //ResultX := 0; fxch st(1) ffree st(1) wait mov esp,ebp pop ebp ret $10 @IntPowIfEnd2 : //else if Exponent = 0 then mov ecx,[esp] test ecx,ecx jnz @IntPowElseIf2 //ResultX := 1 ffree st(1) ffree st(0) fld1 wait mov esp,ebp pop ebp ret $10 @IntPowElseIf2 : //else if Exponent = 1 then cmp ecx,1 jnz @IntPowElseIf3 //ResultX := Base ffree st(1) wait mov esp,ebp pop ebp ret $10 @IntPowElseIf3 : //else if Exponent = 2 then cmp ecx,2 jnz @IntPowElseIf4 //ResultX := Base * Base ffree st(1) fmul st(0),st(0) wait mov esp,ebp pop ebp ret $10 @IntPowElseIf4 : //else if Exponent > 2 then cmp ecx,2 jle @IntPowElseIf5 ffree st(1) //ResultX2 := 1; fld1 //ResultX := Base; fxch st(1) mov eax,ecx //I := 2; mov edx,2 //I2 := Exponent; @IntPowRepeat1Start : //I2 := I2 shr 1; shr ecx,1 jnc @IntPowIfEnd8 //ResultX2 := ResultX2 * ResultX; fmul st(1),st(0) @IntPowIfEnd8 : //ResultX := ResultX * ResultX; fmul st(0),st(0) //I := I * 2; add edx,edx //until(I > Exponent); cmp eax,edx jnl @IntPowRepeat1Start //ResultX := ResultX * ResultX2; fmulp st(1),st(0) wait mov esp,ebp pop ebp ret $10 @IntPowElseIf5 : //else if Exponent = -1 then cmp ecx,-1 jnz @IntPowElseIf6 ffree st(1) //ResultX := 1/Base fld1 fdivrp st(1),st(0) wait mov esp,ebp pop ebp ret $10 @IntPowElseIf6 : //else if Exponent = -2 then cmp ecx,-2 jnz @IntPowElse7 //ResultX := 1/(Base*Base) ffree st(1) fmul st(0),st(0) fld1 fdivrp wait mov esp,ebp pop ebp ret $10 @IntPowElse7 : ffree st(1) //else //if Exponent < -2 then //I2 := -Exponent; mov eax,ecx neg eax mov edx,eax //I := 2; mov ecx,2 //ResultX2 := 1; fld1 //ResultX := Base; fxch st(1) @IntPowRepeat2Start : //I2 := I2 shr 1; shr eax,1 jnc @IntPowIfEnd7 //ResultX2 := ResultX2 * ResultX; fmul st(1),st(0) @IntPowIfEnd7 : //ResultX := ResultX * ResultX; fmul st(0),st(0) //I := I * 2; add ecx,ecx //until(I > -Exponent); cmp ecx,edx jle @IntPowRepeat2Start //ResultX := ResultX * ResultX2; fmulp st(1),st(0) //ResultX := 1 / ResultX; fld1 fdivr wait mov esp,ebp pop ebp ret $10 @IfEnd2 : //Result := Exp(Exponent * Ln(Base)) fld Base fldln2 fxch st(1) fyl2x fld Exponent fmulp fldl2e fmulp fld st(0) frndint fsub st(1),st(0) fxch st(1) f2xm1 fld1 faddp fscale ffree st(1) wait mov esp,ebp pop ebp ret $10 @IfEnd1 : //if (Exponent > 0) and (Base <> 0) then fldz fcom st(1) fstsw ax sahf jbe @IfEnd3 fld Base fcom st(1) fstsw ax sahf jz @IfEnd3 ffree st(1) //Result := Exp(Exponent * Ln(Base)) fldln2 fxch st(1) fyl2x fmul st(0), st(2) ffree st(2) fldl2e fmulp fld st(0) frndint fsub st(1),st(0) fxch st(1) f2xm1 fld1 faddp fscale ffree st(1) wait mov esp,ebp pop ebp ret $10 @IfEnd3 : //else if Base = 0 then fld Base fcom st(1) fstsw ax sahf ffree st(1) jnz @ElseIfEnd4 //Result := 0 ffree st(2) wait mov esp,ebp pop ebp ret $10 @ElseIfEnd4 : //Result := Exp(Exponent * Ln(Base)) fldln2 fxch st(1) fyl2x fmul st(0),st(2) ffree st(2) fldl2e fmulp fld st(0) frndint fsub st(1),st(0) fxch st(1) f2xm1 fld1 faddp fscale ffree st(1) wait mov esp,ebp end; {$else} function IEPower2(const Base, Exponent: Double): Double; begin result := Power(Base, Exponent); end; {$endif} // if hdd<>0 uses DibDrawDib otherwise StetchDIBits // USE THIS ONLY ON PRINTING FUNCTION OF TIMAGEENIO procedure DrawDibDrawEmu(hdd: THandle; hDC: THandle; xDst, yDst, dxDst, dyDst: Integer; var lpbi: TBitmapInfoHeader; Bits: Pointer; xSrc, ySrc, dxSrc, dySrc: Integer; wFlags: UInt); var fr: boolean; begin fr := (lpbi.biBitCount = 24) and (hdd = 0); if fr then hdd := drawdibopen; if hdd = 0 then begin StretchDIBits(hDC, xDst, yDst, dxDst, dyDst, xSrc, ySrc, dxSrc, dySrc, Bits, PBITMAPINFO(@lpbi)^, DIB_RGB_COLORS, SRCCOPY); end else DrawDibDraw(hdd, hDC, xDst, yDst, dxDst, dyDst, lpbi, Bits, xSrc, ySrc, dxSrc, dySrc, wFlags); if fr then drawdibclose(hdd); end; procedure DrawDib(hDC: THandle; xDst, yDst, dxDst, dyDst: Integer; var lpbi: TBitmapInfoHeader; Bits: Pointer; xSrc, ySrc, dxSrc, dySrc: Integer); begin SetStretchBltMode(hDC, HALFTONE); StretchDIBits(hDC, xDst, yDst, dxDst, dyDst, xSrc, ySrc, dxSrc, dySrc, Bits, PBITMAPINFO(@lpbi)^, DIB_RGB_COLORS, SRCCOPY); end; //////////////////////////////////////////////////////////////////////////////////// // exchanges WORD [ ex result := hibyte(i) or (lobyte(i) shl 8); ] {$ifdef IEUSEASM} function IESwapWord(i: word): word; assembler; asm ror ax,8 end; {$else} function IESwapWord(i: word): word; begin result := (i and $FF shl 8) or (i and $FF00 shr 8); end; {$endif} procedure IEChangeEndiannessWordArray(buffer: pword; items: integer); begin for items := items - 1 downto 0 do begin buffer^ := (buffer^ and $FF shl 8) or (buffer^ and $FF00 shr 8); inc(buffer); end; end; procedure IEChangeEndiannessDWordArray(buffer: pdword; items: integer); begin for items := items - 1 downto 0 do begin buffer^ := (buffer^ and $FF shl 24) or (buffer^ and $FF00 shl 8) or (buffer^ and $FF0000 shr 8) or (buffer^ and $FF000000 shr 24); inc(buffer); end; end; //////////////////////////////////////////////////////////////////////////////////// // swap DWORD and int64 function IESwapDWord(i: integer): integer; 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; // cannot compile with Delphi 5 (internal error) if "result" and "i" are directly indexed function IESwapInt64(i: int64): int64; var dst, src: PByteArray; begin dst := PByteArray(@result); src := PByteArray(@i); dst[0] := src[7]; dst[1] := src[6]; dst[2] := src[5]; dst[3] := src[4]; dst[4] := src[3]; dst[5] := src[2]; dst[6] := src[1]; dst[7] := src[0]; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// // changes x2, y2 to make an angle of 45° or 90° with the line to x1, y1 // useful when CTRL is pressed procedure _CastPolySelCC(const x1, y1: integer; var x2, y2: integer); var dx, dy: integer; adx, ady: integer; begin dx := x1 - x2; adx := abs(dx); dy := y1 - y2; ady := abs(dy); if adx + 30 < ady then x2 := x1 else if adx - 30 > ady then y2 := y1 else begin if (dx < 0) and (dy < 0) then begin if (adx < ady) then inc(x2, abs(adx - ady)) else inc(y2, abs(adx - ady)); end else if (dx > 0) and (dy > 0) then begin if (adx < ady) then inc(y2, abs(adx - ady)) else inc(x2, abs(adx - ady)); end else if (dx > 0) then begin if (adx < ady) then dec(x2, abs(adx - ady)) else inc(y2, abs(adx - ady)); end else if (dy > 0) then begin if (adx < ady) then inc(x2, abs(adx - ady)) else dec(y2, abs(adx - ady)); end; end; end; // Return true if the two rectangles have a common region // The rectangles must have ordered coordinates function _RectXRect(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2: integer): boolean; begin result := not ((IMAX(ax1, ax2) < bx1) or (IMIN(ax1, ax2) > bx2) or (IMAX(ay1, ay2) < by1) or (IMIN(ay1, ay2) > by2)); end; // Return "How much" the rectangle "b" is included in "a" // 0 = no common region // 1 = common region (not all) // 2 = common region // The rectangles must have ordered coordinates function _RectPRect(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2: integer): integer; var vx1, vx2: boolean; vy1, vy2: boolean; begin vx1 := (bx1 >= ax1) and (bx1 <= ax2); vx2 := (bx2 >= ax1) and (bx2 <= ax2); vy1 := (by1 >= ay1) and (by1 <= ay2); vy2 := (by2 >= ay1) and (by2 <= ay2); if (vx1 xor vx2) and (vy1 or vy2) then result := 1 // partial x else if (vx1 or vx2) and (vy1 xor vy2) then result := 1 // partial y else if (vx1 xor vx2) and (vy1 xor vy2) then result := 1 // partial xy else if vx1 and vx2 and vy1 and vy2 then result := 2 // full else result := 0; // null end; // return true if the point xx, yy is inside the rectangle x1, y1, x2, y2 // x1, y1, x2, y2 must be ordered function IEPointInRect(xx, yy, x1, y1, x2, y2: integer): boolean; begin result := (xx >= x1) and (xx <= x2) and (yy >= y1) and (yy <= y2); end; function IEPointInRect(xx, yy : integer; ARect: TRect): boolean; begin Result := IEPointInRect(xx, yy, ARect.Left, ARect.Top, ARect.Right, ARect.Bottom); end; // return true if the point xx, yy is inside the rectangle x1, y1, x2, y2 // x1, y1, x2, y2 ordered or not ordered function _InRectO(xx, yy, x1, y1, x2, y2: integer): boolean; begin OrdCor(x1, y1, x2, y2); result := (xx >= x1) and (xx <= x2) and (yy >= y1) and (yy <= y2); end; {!! IEGetFileSize Declaration function IEGetFileSize(const Filename: string): int64; Description Returns the size of a file (even if larger than 2GB). Result is 0 if an error occured. See Also - !!} function IEGetFileSize(const Filename: string): int64; var sr: TSearchRec; begin if FindFirst(filename, faAnyFile, sr) = 0 then result := int64(sr.FindData.nFileSizeHigh) shl int64(32) + int64(sr.FindData.nFileSizeLow) else result := 0; FindClose(sr); end; // Displays the TColorDialog so the user can select a color. Result is false if user cancels out function PromptForColor(var AColor : TColor): Boolean; var cl: TColorDialog; begin Result := False; cl := TColorDialog.Create(nil); try cl.CustomColors.Clear; if IEGlobalSettings().ColorDialogCustomColors <> '' then cl.CustomColors.Text := IEGlobalSettings().ColorDialogCustomColors else begin cl.CustomColors.Add('ColorA=D670DA'); cl.CustomColors.Add('ColorB=8B3D48'); cl.CustomColors.Add('ColorC=FF901E'); cl.CustomColors.Add('ColorD=ED9564'); cl.CustomColors.Add('ColorE=EBCE87'); cl.CustomColors.Add('ColorF=908070'); cl.CustomColors.Add('ColorG=4F4F2F'); cl.CustomColors.Add('ColorH=2F6B55'); cl.CustomColors.Add('ColorI=008080'); cl.CustomColors.Add('ColorJ=7FFF00'); cl.CustomColors.Add('ColorK=00FC7C'); cl.CustomColors.Add('ColorL=32CD9A'); cl.CustomColors.Add('ColorM=B9DAFF'); cl.CustomColors.Add('ColorN=00D7FF'); cl.CustomColors.Add('ColorO=20A5DA'); cl.CustomColors.Add('ColorP=1E69D2'); end; cl.Color := AColor; If cl.Execute then begin AColor := cl.Color; Result := True; end; IEGlobalSettings().ColorDialogCustomColors := cl.CustomColors.Text finally FreeAndNil(cl); end; end; ///////////////////////////////////////////////////////////////////////////////////// // search for the window handle that contains cmp, going back (start from cmp) function IEFindHandle(cmp: TComponent): HWND; var xowner: TComponent; begin xowner := cmp; while assigned(xowner) and not (xowner is TWinControl) do xowner := xowner.owner; if assigned(xowner) and (xowner as TWinControl).handleallocated then result := (xowner as TWinControl).Handle else result := 0; end; procedure IERightShadow(Canvas: TCanvas; DestBitmap: TBitmap; x1, y1, x2, y2: integer; st: TIEShadowType; dstColor: TColor); var y, x, ww, hh: integer; cl1, cl2, cl: integer; o: integer; cl_c, radius, Temp: double; dstRGB: TRGB; cl_r, cl_g, cl_b: integer; //bmp: TIEBitmap; px: PRGB; bmpw, bmph: integer; begin ww := x2 - x1 + 1; hh := y2 - y1 + 1; case st of iestSolid: Canvas.FillRect(Rect(x1, y1 + ww, x2, y2 + 1)); iestSmooth1: begin bmpw := 0; bmph := 0; if assigned(DestBitmap) then begin bmpw := DestBitmap.Width; bmph := DestBitmap.Height; end; radius := ww/3; for x := 0 to ww - 1 do begin Temp := (ww-x) / radius; cl_c := Exp(-0.1 - Temp * Temp / 6); for y := y1+ww to y2-ww+x+3 do begin if assigned(DestBitmap) and (x+x1>=0) and (y>=0) and (x+x1 hh - ww + 1 then inc(o); for x := o to ww do begin cl1 := trunc(exp(x / ww) / exp(1) * 255); cl := imax(cl1, cl2); Canvas.Pixels[x1 + x, y1 + y] := TColor((cl) + (cl shl 8) + (cl shl 16)); end; end; end; (* iestSmooth3: // EXPERIMENTAL! begin o := hh+20; bmp := TIEBitmap.Create(o, o, ie8g); bmp.Fill(0); bmp.FillRect(10, 10, o-10, o-10, 255); _IEGBlurRect8(bmp, 0, 0, o-1, o-1, 4); for y := y1 to y2 do begin for x := x1 to x2 do begin dstRGB := TColor2TRGB(Canvas.Pixels[x, y]); cl_c := 1-bmp.Pixels_ie8[x-x1+o-10, y-y1+10]/255; cl_r := trunc(cl_c*dstRGB.r); cl_g := trunc(cl_c*dstRGB.g); cl_b := trunc(cl_c*dstRGB.b); Canvas.pixels[x, y] := TColor((cl_r) + (cl_g shl 8) + (cl_b shl 16)); end; end; bmp.free; end; *) end; end; ///////////////////////////////////////////////////////////////////////////////////// procedure IEBottomShadow(Canvas: TCanvas; DestBitmap: TBitmap; x1, y1, x2, y2: integer; st: TIEShadowType; dstColor: TColor); var y, x, ww, hh: integer; cl1, cl2, cl: integer; o: integer; cl_c, radius, Temp: double; dstRGB: TRGB; cl_r, cl_g, cl_b: integer; bmpw, bmph: integer; px: PRGB; begin ww := x2 - x1 + 1; hh := y2 - y1 + 1; case st of iestSolid: Canvas.FillRect(Rect(x1 + hh, y1, x2 + 1, y2)); iestSmooth1: begin bmpw := 0; bmph := 0; if assigned(DestBitmap) then begin bmpw := DestBitmap.Width; bmph := DestBitmap.Height; end; px := nil; radius := hh/3; for y := 0 to hh - 1 do begin Temp := (y-hh) / radius; cl_c := Exp(-0.1 - Temp * Temp / 6); if assigned(DestBitmap) and (y+y1>0) and (y+y1=0) and (y+y1>=0) and (x ww - hh + 1 then inc(o); for y := o to hh do begin cl1 := trunc(exp(y / hh) / exp(1) * 255); cl := imax(cl1, cl2); Canvas.Pixels[x1 + x, y1 + y] := TColor((cl) + (cl shl 8) + (cl shl 16)); end; end; end; end; end; procedure IERectShadow(Bitmap: TBitmap; x1, y1, x2, y2: integer; dstColor: TColor); var ww, hh: integer; bmp: TIEBitmap; cl_c: double; radius: integer; bmpw, bmph: integer; pb: pbyte; px: PRGB; x, y: integer; offx, offy: integer; begin radius := 5; offx := 2; offy := 2; bmpw := Bitmap.Width; bmph := Bitmap.Height; ww := x2 - x1 + 1; hh := y2 - y1 + 1; bmp := TIEBitmap.Create(ww+radius*2, hh+radius*2, ie8g); bmp.Fill(0); bmp.FillRect(radius, radius, ww+radius-1+offx, hh+radius-1+offy, 255); _IEGBlurRect8(bmp, 0, 0, ww+radius*2-1, hh+radius*2-1, radius/2); for y := y1-radius to y2+radius do begin if (y>=0) and (y=0) and (x=x2) or (y=y2)) then begin cl_c := 1-pb^/255; with px^ do begin r := trunc(cl_c*r); g := trunc(cl_c*g); b := trunc(cl_c*b); end; end; inc(px); inc(pb); end; end; end; bmp.free; end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// // Saves the string ss to Stream. Saves the size (integer) then the string. // Compatible with LoadStringFromStream procedure IESaveStringToStream(Stream: TStream; const ss: AnsiString); var i: integer; begin i := length(ss); Stream.Write(i, sizeof(integer)); Stream.Write(PAnsiChar(ss)^, i); end; // Loads a string from Stream. Compatible with SaveStringToStream procedure IELoadStringFromStream(Stream: TStream; var ss: AnsiString); var i: integer; begin Stream.Read(i, sizeof(integer)); SetLength(ss, i); Stream.Read(PAnsiChar(ss)^, i); end; {$IfDef UNICODE} // Saves the string ss to Stream. Saves the size (integer) then the string. // Compatible with LoadStringFromStream procedure IESaveStringToStream(Stream: TStream; const ss: UnicodeString); var strLen: integer; begin strLen := Length( ss ); Stream.Write( strLen, sizeof( integer )); if strLen > 0 then Stream.Write( ss[1], strLen * SizeOf( ss[1] )); end; // Loads a string from Stream. Compatible with SaveStringToStream procedure IELoadStringFromStream(Stream: TStream; var ss: UnicodeString); var strLen: integer; begin Stream.Read( strLen, sizeof(integer)); SetLength( ss, strLen ); if strLen > 0 then Stream.Read( ss[1], strLen * SizeOf( ss[1] )); end; {$EndIf} // Saves the string ss to Stream. Saves the size (integer) then the string. // Compatible with LoadStringFromStreamW procedure IESaveStringToStreamW(Stream: TStream; const ss: widestring); var i: integer; begin i := length(ss); Stream.Write(i, sizeof(integer)); Stream.Write(ss[1], i*2); end; // Loads a string from Stream. Compatible with SaveStringToStreamW procedure IELoadStringFromStreamW(Stream: TStream; var ss: widestring); var i: integer; begin Stream.Read(i, sizeof(integer)); SetLength(ss, i); Stream.Read(ss[1], i*2); end; procedure IELoadStringFromStreamW(Stream: TStream; var ss: String); var ws: Widestring; begin IELoadStringFromStreamW( Stream, ws ); ss := ws; end; procedure IESaveStringListToStream(Stream: TStream; sl: TStringList); var i: integer; begin i := sl.Count; Stream.Write(i, sizeof(integer)); for i := 0 to sl.Count - 1 do IESaveStringToStream(Stream, AnsiString(sl[i])); end; procedure IELoadStringListFromStream(Stream: TStream; sl: TStringList); var i, w: integer; ss: AnsiString; begin Stream.Read(w, sizeof(integer)); sl.Clear; for i := 0 to w - 1 do begin IELoadStringFromStream(Stream, ss); sl.Add(string(ss)); end; end; procedure IELoadFontFromStream(Stream: TStream; var Font: TFont); var fontName : string; fontCharset : TFontCharset; fontColor : TColor; fontHeight : Integer; fontStyle : TFontStyles; begin IELoadStringFromStreamW(Stream, fontName); Font.Name := fontName; Stream.Read( fontCharset , SizeOf( TFontCharset )); Font.Charset := fontCharset; Stream.Read( fontColor , SizeOf( TColor )); Font.Color := fontColor ; Stream.Read( fontHeight , SizeOf( Integer )); Font.Height := fontHeight; Stream.Read( fontStyle , SizeOf( TFontStyles )); Font.Style := fontStyle; end; procedure IESaveFontToStream(Stream: TStream; const Font: TFont); var fontName : string; fontCharset : TFontCharset; fontColor : TColor; fontHeight : Integer; fontStyle : TFontStyles; begin fontName := Font.Name; IESaveStringToStreamW(Stream, fontName); fontCharset := Font.Charset; Stream.Write( fontCharset , SizeOf( TFontCharset )); fontColor := Font.Color; Stream.Write( fontColor , SizeOf( TColor )); fontHeight := Font.Height; Stream.Write( fontHeight , SizeOf( Integer )); fontStyle := Font.Style; Stream.Write( fontStyle , SizeOf( TFontStyles )); end; // Returns number of colors calculated from BitsPerSample and SamplesperPixel function _GetNumCol(BitsPerSample: integer; SamplesPerPixel: integer): integer; begin result := 1; while SamplesPerPixel > 0 do begin result := result * (1 shl BitsPerSample); dec(SamplesPerPixel); end; end; procedure IEBlendRGBA(var src: TRGBA; var dst: TRGBA; RenderOperation: TIERenderOperation; row: integer); var osrc, odst: TRGB; begin osrc.r := src.r; osrc.g := src.g; osrc.b := src.b; odst.r := dst.r; odst.g := dst.g; odst.b := dst.b; IEBlend(osrc, odst, RenderOperation, row); src.r := osrc.r; src.g := osrc.g; src.b := osrc.b; dst.r := odst.r; dst.g := odst.g; dst.b := odst.b; end; procedure IEBlend(var src: TRGB; var dst: TRGB; RenderOperation: TIERenderOperation; row: integer); // filters function softlight(ib, ia: integer): integer; {$ifdef IESUPPORTINLINE} inline; {$endif} var a, b, r: double; begin a := ia / 255; b := ib / 255; if b < 0.5 then r := 2 * a * b + sqr(a) * (1 - 2 * b) else r := sqrt(a) * (2 * b - 1) + (2 * a) * (1 - b); result := trunc(r * 255); end; function xfader(b, a: integer): integer; {$ifdef IESUPPORTINLINE} inline; {$endif} var c: integer; begin c := a * b shr 8; result := c + a * (255 - ((255 - a) * (255 - b) shr 8) - c) shr 8; end; function coloredge(b, a: integer): integer; {$ifdef IESUPPORTINLINE} inline; {$endif} var c: integer; begin if b = 255 then result := 255 else begin c := (a shl 8) div (255 - b); if c > 255 then result := 255 else result := c; end; end; function colorburn(b, a: integer): integer; {$ifdef IESUPPORTINLINE} inline; {$endif} var c: integer; begin if b = 0 then result := 0 else begin c := 255 - (((255 - a) shl 8) div b); if c < 0 then result := 0 else result := c; end; end; function inversecolordodge(b, a: integer): integer; {$ifdef IESUPPORTINLINE} inline; {$endif} var c: integer; begin if a = 255 then result := 255 else begin c := (b shl 8) div (255 - a); if c > 255 then result := 255 else result := c; end; end; function inversecolorburn(b, a: integer): integer; {$ifdef IESUPPORTINLINE} inline; {$endif} var c: integer; begin if a = 0 then result := 0 else begin c := 255 - (((255 - b) shl 8) div a); if c < 0 then result := 0 else result := c; end; end; function softdodge(b, a: integer): integer; {$ifdef IESUPPORTINLINE} inline; {$endif} var c: integer; begin if a + b < 256 then begin if b = 255 then result := 255 else begin c := (a shl 7) div (255 - b); if c > 255 then result := 255 else result := c; end; end else begin c := 255 - (((255 - b) shl 7) div a); if c < 0 then result := 0 else result := c; end; end; function softburn(b, a: integer): integer; {$ifdef IESUPPORTINLINE} inline; {$endif} var c: integer; begin if a + b < 256 then begin if a = 255 then Result := 255 else begin c := (b shl 7) div (255 - a); if c > 255 then Result := 255 else Result := c; end; end else begin c := 255 - (((255 - a) shl 7) div b); if c < 0 then Result := 0 else Result := c; end; end; function reflect(b, a: integer): integer; {$ifdef IESUPPORTINLINE} inline; {$endif} var c: integer; begin if b = 255 then result := 255 else begin c := a * a div (255 - b); if c > 255 then result := 255 else result := c; end; end; function glow(b, a: integer): integer; {$ifdef IESUPPORTINLINE} inline; {$endif} var c: integer; begin if a = 255 then result := 255 else begin c := b * b div (255 - a); if c > 255 then result := 255 else result := c; end; end; function freeze(b, a: integer): integer; {$ifdef IESUPPORTINLINE} inline; {$endif} var c: integer; begin if b = 0 then result := 0 else begin c := 255 - sqr(255 - a) div b; if c < 0 then result := 0 else result := c; end; end; function eat(b, a: integer): integer; {$ifdef IESUPPORTINLINE} inline; {$endif} var c: integer; begin if a = 0 then result := 0 else begin c := 255 - sqr(255 - b) div a; if c < 0 then result := 0 else result := c; end; end; function interpolation(b, a: integer): integer; {$ifdef IESUPPORTINLINE} inline; {$endif} var c: integer; begin c := IECosineTab[b] + IECosineTab[a]; if c > 255 then result := 255 else result := c; end; function stamp(b, a: integer): integer; {$ifdef IESUPPORTINLINE} inline; {$endif} var c: integer; begin c := a + 2 * b - 256; if c < 0 then result := 0 else if c > 255 then result := 255 else result := c; end; // var Ha, Sa, La: double; Hb, Sb, Lb: double; tmp: TRGB; v1, v2: byte; Y_1, Cb_1, Cr_1: integer; Y_2, Cb_2, Cr_2: integer; RedToGrayCoef, GreenToGrayCoef, BlueToGrayCoef: integer; begin case RenderOperation of ielNormal: begin dst := src; end; ielAdd: begin dst.r := blimit(dst.r + src.r); dst.g := blimit(dst.g + src.g); dst.b := blimit(dst.b + src.b); end; ielSub: begin dst.r := abs(dst.r - src.r); dst.g := abs(dst.g - src.g); dst.b := abs(dst.b - src.b); end; ielDiv: begin dst.r := blimit(dst.r div ilimit(src.r, 1, 255)); dst.g := blimit(dst.g div ilimit(src.g, 1, 255)); dst.b := blimit(dst.b div ilimit(src.b, 1, 255)); end; ielMul: begin dst.r := (dst.r * src.r) shr 8; dst.g := (dst.g * src.g) shr 8; dst.b := (dst.b * src.b) shr 8; end; ielOR: begin dst.r := blimit(dst.r or src.r); dst.g := blimit(dst.g or src.g); dst.b := blimit(dst.b or src.b); end; ielAND: begin dst.r := blimit(dst.r and src.r); dst.g := blimit(dst.g and src.g); dst.b := blimit(dst.b and src.b); end; ielXOR: begin dst.r := blimit(dst.r xor src.r); dst.g := blimit(dst.g xor src.g); dst.b := blimit(dst.b xor src.b); end; ielMAX: begin dst.r := imax(dst.r, src.r); dst.g := imax(dst.g, src.g); dst.b := imax(dst.b, src.b); end; ielMIN: begin dst.r := imin(dst.r, src.r); dst.g := imin(dst.g, src.g); dst.b := imin(dst.b, src.b); end; ielAverage: begin dst.r := (dst.r + src.r) shr 1; dst.g := (dst.g + src.g) shr 1; dst.b := (dst.b + src.b) shr 1; end; ielScreen: begin dst.r := trunc( 255 - ((255 - dst.r) * (255 - src.r) / 255) ); dst.g := trunc( 255 - ((255 - dst.g) * (255 - src.g) / 255) ); dst.b := trunc( 255 - ((255 - dst.b) * (255 - src.b) / 255) ); end; ielNegation: begin dst.r := 255 - abs(255 - src.r - dst.r); dst.g := 255 - abs(255 - src.g - dst.g); dst.b := 255 - abs(255 - src.b - dst.b); end; ielExclusion: begin dst.r := src.r + dst.r - (src.r * dst.r shr 7); dst.g := src.g + dst.g - (src.g * dst.g shr 7); dst.b := src.b + dst.b - (src.b * dst.b shr 7); end; ielOverlay: begin if dst.r < 128 then dst.r := (src.r * dst.r) shr 7 else dst.r := 255 - ((255 - src.r) * (255 - dst.r) shr 7); if dst.g < 128 then dst.g := (src.g * dst.g) shr 7 else dst.g := 255 - ((255 - src.g) * (255 - dst.g) shr 7); if dst.b < 128 then dst.b := (src.b * dst.b) shr 7 else dst.b := 255 - ((255 - src.b) * (255 - dst.b) shr 7); end; ielHardLight: begin if src.r < 128 then dst.r := (src.r * dst.r) shr 7 else dst.r := 255 - ((255 - src.r) * (255 - dst.r) shr 7); if src.g < 128 then dst.g := (src.g * dst.g) shr 7 else dst.g := 255 - ((255 - src.g) * (255 - dst.g) shr 7); if src.b < 128 then dst.b := (src.b * dst.b) shr 7 else dst.b := 255 - ((255 - src.b) * (255 - dst.b) shr 7); end; ielSoftLight: begin dst.r := softlight(src.r, dst.r); dst.g := softlight(src.r, dst.g); dst.b := softlight(src.r, dst.b); end; ielXFader: begin dst.r := XFader(src.r, dst.r); dst.g := XFader(src.g, dst.g); dst.b := XFader(src.b, dst.b); end; ielColorEdge: begin dst.r := ColorEdge(src.r, dst.r); dst.g := ColorEdge(src.g, dst.g); dst.b := ColorEdge(src.b, dst.b); end; ielColorBurn: begin dst.r := ColorBurn(src.r, dst.r); dst.g := ColorBurn(src.g, dst.g); dst.b := ColorBurn(src.b, dst.b); end; ielInverseColorDodge: begin dst.r := InverseColorDodge(src.r, dst.r); dst.g := InverseColorDodge(src.g, dst.g); dst.b := InverseColorDodge(src.b, dst.b); end; ielInverseColorBurn: begin dst.r := InverseColorBurn(src.r, dst.r); dst.g := InverseColorBurn(src.g, dst.g); dst.b := InverseColorBurn(src.b, dst.b); end; ielSoftDodge: begin dst.r := SoftDodge(src.r, dst.r); dst.g := SoftDodge(src.g, dst.g); dst.b := SoftDodge(src.b, dst.b); end; ielSoftBurn: begin dst.r := SoftBurn(src.r, dst.r); dst.g := SoftBurn(src.g, dst.g); dst.b := SoftBurn(src.b, dst.b); end; ielReflect: begin dst.r := Reflect(src.r, dst.r); dst.g := Reflect(src.g, dst.g); dst.b := Reflect(src.b, dst.b); end; ielGlow: begin dst.r := Glow(src.r, dst.r); dst.g := Glow(src.g, dst.g); dst.b := Glow(src.b, dst.b); end; ielFreeze: begin dst.r := Freeze(src.r, dst.r); dst.g := Freeze(src.g, dst.g); dst.b := Freeze(src.b, dst.b); end; ielEat: begin dst.r := Eat(src.r, dst.r); dst.g := Eat(src.g, dst.g); dst.b := Eat(src.b, dst.b); end; ielSubtractive: begin dst.r := blimit(dst.r + src.r - 256); dst.g := blimit(dst.g + src.g - 256); dst.b := blimit(dst.b + src.b - 256); end; ielInterpolation: begin dst.r := Interpolation(src.r, dst.r); dst.g := Interpolation(src.g, dst.g); dst.b := Interpolation(src.b, dst.b); end; ielStamp: begin dst.r := Stamp(src.r, dst.r); dst.g := Stamp(src.g, dst.g); dst.b := Stamp(src.b, dst.b); end; ielRed: begin dst.r := src.r; end; ielGreen: begin dst.g := src.g; end; ielBlue: begin dst.b := src.b; end; ielHue: begin RGB2HSL(src, Ha, Sa, La); RGB2HSL(dst, Hb, Sb, Lb); HSL2RGB(dst, Ha, Sb, Lb); end; ielSaturation: begin RGB2HSL(src, Ha, Sa, La); RGB2HSL(dst, Hb, Sb, Lb); HSL2RGB(dst, Hb, Sa, Lb); end; ielColor: begin RGB2HSL(src, Ha, Sa, La); RGB2HSL(dst, Hb, Sb, Lb); HSL2RGB(dst, Ha, Sa, Lb); end; ielLuminosity: begin RGB2HSL(src, Ha, Sa, La); RGB2HSL(dst, Hb, Sb, Lb); HSL2RGB(dst, Hb, Sb, La); end; ielLuminosity2: begin IERGB2YCbCr(src, Y_1, Cb_1, Cr_1); IERGB2YCbCr(dst, Y_2, Cb_2, Cr_2); IEYCbCr2RGB(dst, Y_1, Cb_2, Cr_2); end; ielStereoBW: // black&white begin RedToGrayCoef := IEGlobalSettings().RedToGrayCoef; GreenToGrayCoef := IEGlobalSettings().GreenToGrayCoef; BlueToGrayCoef := IEGlobalSettings().BlueToGrayCoef; v1 := (src.r * RedToGrayCoef + src.g * GreenToGrayCoef + src.b * BlueToGrayCoef) div 100; v2 := (dst.r * RedToGrayCoef + dst.g * GreenToGrayCoef + dst.b * BlueToGrayCoef) div 100; dst.r := v2; dst.g := v1; dst.b := v1; end; ielStereoColor: begin dst.r := dst.r; dst.g := src.g; dst.b := src.b; end; ielStereoColorDubois: begin tmp.r := blimit(round( 0.456100*dst.r +0.500484*dst.g +0.176381*dst.b -0.0434706*src.r -0.0879388*src.g -0.00155529*src.b)); tmp.g := blimit(round( -0.0400822*dst.r -0.0378246*dst.g -0.0157589*dst.b +0.378476*src.r +0.73364*src.g -0.0184503*src.b)); tmp.b := blimit(round( -0.0152161*dst.r -0.0205971*dst.g -0.00546856*dst.b -0.0721527*src.r -0.112961*src.g +1.2264*src.b)); dst := tmp; end; ielStereoEven: if not Odd(row) then dst := src; ielStereoOdd: if Odd(row) then dst := src; end; end; //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // TIEScrollBarParams constructor TIEScrollBarParams.Create; begin inherited Create; fLineStep := -1; fPageStep := -1; fTracking := true; end; destructor TIEScrollBarParams.Destroy; begin inherited; end; //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// constructor TIEMouseWheelParams.Create(DefaultAction : TIEMouseWheelParamsAction); begin inherited Create; InvertDirection := false; Action := DefaultAction; Variation := iemwPercentage; Value := 8; ZoomPosition := iemwCenter; end; destructor TIEMouseWheelParams.Destroy; begin inherited; end; procedure TIEMouseWheelParams.Assign(Source: TPersistent); begin if Source is TIEMouseWheelParams then begin InvertDirection := TIEMouseWheelParams( Source ).InvertDirection; Action := TIEMouseWheelParams( Source ).Action ; Variation := TIEMouseWheelParams( Source ).Variation ; Value := TIEMouseWheelParams( Source ).Value ; ZoomPosition := TIEMouseWheelParams( Source ).ZoomPosition ; end else inherited; end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function IEIsRemoteSession(): boolean; const SM_REMOTESESSION = $1000; begin result := Windows.GetSystemMetrics( SM_REMOTESESSION ) <> 0; end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Base64 support const encoding_table: array [0..63] of AnsiChar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; procedure IEEncodeBlock64(xin: pbytearray; xout: PAnsiChar; len: integer); begin xout[0] := encoding_table[ xin[0] shr 2 ]; xout[1] := encoding_table[ ((xin[0] and $03) shl 4) or ((xin[1] and $f0) shr 4) ]; if len > 1 then xout[2] := encoding_table[ ((xin[1] and $0f) shl 2) or ((xin[2] and $c0) shr 6) ] else xout[2] := '='; if len > 2 then xout[3] := encoding_table[ xin[2] and $3f ] else xout[3] := '='; end; procedure IEEncode64(SrcStream: TStream; DstStream: TStream; linesize: integer); var xin: array [0..2] of byte; xout: array [0..3] of AnsiChar; i, len, blocksout: integer; SrcStreamSize: int64; begin SrcStreamSize := SrcStream.Size; blocksout := 0; while SrcStream.Position < SrcStreamSize do begin len := 0; for i := 0 to 2 do begin if SrcStream.Position < SrcStreamSize then begin SrcStream.Read(xin[i], 1); inc(len); end else xin[i] := 0; end; if len > 0 then begin IEEncodeBlock64(@xin, xout, len); DstStream.Write(xout[0], 4); inc(blocksout); end; if (blocksout >= (linesize / 4)) or (SrcStream.Position >= SrcStreamSize) then begin if blocksout > 0 then IEStreamWriteLn(DstStream, ''); blocksout := 0; end; end; end; function IEEncode64(SrcBuffer: pbyte; SrcBufferLength: integer; linesize: integer): AnsiString; var srcStream: TIEMemStream; dstStream: TMemoryStream; begin srcStream := TIEMemStream.Create(SrcBuffer, SrcBufferLength); dstStream := TMemoryStream.Create(); try IEEncode64(srcStream, dstStream, linesize); SetLength(result, dstStream.size); CopyMemory(@result[1], dstStream.Memory, dstStream.Size); finally dstStream.Free(); srcStream.Free(); end; end; procedure IEDecode64(SrcStream: TStream; DstStream: TStream); const mod_table: array [0..2] of integer = (0, 2, 1); EQCHR: byte = ord('='); var decoding_table: array of byte; i: integer; input_length: int64; data: TIEBufferedReadStream; sextet_a: dword; sextet_b: dword; sextet_c: dword; sextet_d: dword; triple: dword; b: byte; procedure NextByte(); begin while i < input_length do begin data.Read(b, 1); inc(i); if not IEIsSpace(AnsiChar(b)) then break; b := 0; // in case "i = input_length" we returns always 0 end; end; begin data := TIEBufferedReadStream.Create(SrcStream, 8192); try input_length := data.Size; SetLength(decoding_table, 256); for i := 0 to 63 do decoding_table[ord(encoding_table[i])] := i; decoding_table[EQCHR] := 0; // '=' -> 0 i := 0; while i < input_length do begin NextByte(); sextet_a := decoding_table[b]; NextByte(); sextet_b := decoding_table[b]; NextByte(); sextet_c := decoding_table[b]; NextByte(); sextet_d := decoding_table[b]; triple := (sextet_a shl 18) + (sextet_b shl 12) + (sextet_c shl 6) + sextet_d; IEStreamWriteByte(DstStream, (triple shr 16) and $FF); IEStreamWriteByte(DstStream, (triple shr 8) and $FF); IEStreamWriteByte(DstStream, triple and $FF); end; finally data.Free(); end; end; function IEDecode64(SrcString: AnsiString): TIEArrayOfByte; var srcStream: TIEMemStream; dstStream: TMemoryStream; begin srcStream := TIEMemStream.Create(@SrcString[1], length(SrcString)); dstStream := TMemoryStream.Create(); try IEDecode64(srcStream, dstStream); SetLength(result, dstStream.Size); CopyMemory(@result[0], dstStream.Memory, dstStream.Size); finally dstStream.Free(); srcStream.Free(); end; end; // Base64 support /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const WSB_PROP_CYVSCROLL =$00000001; WSB_PROP_CXHSCROLL =$00000002; WSB_PROP_CYHSCROLL =$00000004; WSB_PROP_CXVSCROLL =$00000008; WSB_PROP_CXHTHUMB =$00000010; WSB_PROP_CYVTHUMB =$00000020; WSB_PROP_VBKGCOLOR =$00000040; WSB_PROP_HBKGCOLOR =$00000080; WSB_PROP_VSTYLE =$00000100; WSB_PROP_HSTYLE =$00000200; WSB_PROP_WINSTYLE =$00000400; WSB_PROP_PALETTE =$00000800; WSB_PROP_MASK =$00000FFF; FSB_FLAT_MODE = 2; FSB_ENCARTA_MODE = 1; FSB_REGULAR_MODE = 0; procedure IESetScrollBar(hWnd: HWND; nBar: integer; nMinPos: integer; nMaxPos: integer; PageSize: integer; nPos: integer; bRedraw: boolean; flat: boolean = False); var ScrollInfo: TScrollInfo; begin FillChar(ScrollInfo, sizeof(ScrollInfo), 0); ScrollInfo.cbSize := SizeOf(ScrollInfo); ScrollInfo.fMask := SIF_RANGE or SIF_POS or SIF_PAGE; ScrollInfo.nMin := nMinPos; ScrollInfo.nMax := nMaxPos; ScrollInfo.nPos := nPos; ScrollInfo.nPage := PageSize; IESetScrollInfo(hWnd, nBar, ScrollInfo, bRedraw, flat); end; // 3.0.3 function IESetScrollRange(hWnd: HWND; nBar, nMinPos, nMaxPos: Integer; bRedraw: BOOL; flat: boolean): BOOL; var ScrollInfo: TScrollInfo; begin FillChar(ScrollInfo, sizeof(ScrollInfo), 0); ScrollInfo.cbSize := SizeOf(ScrollInfo); ScrollInfo.fMask := SIF_RANGE; ScrollInfo.nMin := nMinPos; ScrollInfo.nMax := nMaxPos; IESetScrollInfo(hWnd, nBar, ScrollInfo, bRedraw, flat); result := true; end; // 3.0.3 function IESetScrollPos(hWnd: HWND; nBar, nPos: Integer; bRedraw: BOOL; flat: boolean): Integer; var ScrollInfo: TScrollInfo; begin FillChar(ScrollInfo, sizeof(ScrollInfo), 0); ScrollInfo.cbSize := SizeOf(ScrollInfo); ScrollInfo.fMask := SIF_POS; ScrollInfo.nPos := nPos; result := IESetScrollInfo(hWnd, nBar, ScrollInfo, bRedraw, flat); end; // Set cursor size (pagesize) of a scroll bar // fnBar can be SB_HORZ or SB_VERT procedure IESetSBPageSize(HScrollBar: THandle; fnBar: integer; PageSize: Integer; Redraw: boolean; flat: boolean); var ScrollInfo: TScrollInfo; begin FillChar(ScrollInfo, sizeof(ScrollInfo), 0); ScrollInfo.cbSize := Sizeof(ScrollInfo); ScrollInfo.fMask := SIF_PAGE; ScrollInfo.nPage := PageSize; IESetScrollInfo(HScrollBar, fnBar, ScrollInfo, Redraw, flat); end; function IESetScrollInfo(hWnd: HWND; BarFlag: Integer; const ScrollInfo: TScrollInfo; Redraw: BOOL; flat: boolean): Integer; begin {$ifdef IEINCLUDEFLATSB} if flat then result := FlatSB_SetScrollInfo(hWnd, BarFlag, ScrollInfo, Redraw) else result := SetScrollInfo(hWnd, BarFlag, ScrollInfo, Redraw); {$else} result := SetScrollInfo(hWnd, BarFlag, ScrollInfo, Redraw); {$endif} end; function IEEnableScrollBar(hWnd: HWND; wSBflags, wArrows: UINT; flat: boolean = False): BOOL; begin {$ifdef IEINCLUDEFLATSB} if flat then begin result := FlatSB_EnableScrollBar(hWnd, wSBflags, wArrows); end else result := EnableScrollBar(hWnd, wSBflags, wArrows); {$else} result := EnableScrollBar(hWnd, wSBflags, wArrows); {$endif} end; function IEShowScrollBar(hWnd: HWND; wBar: Integer; bShow: BOOL; flat: boolean = False): BOOL; begin {$ifdef IEINCLUDEFLATSB} if flat then begin result := FlatSB_ShowScrollBar(hWnd, wBar, bShow); end else result := ShowScrollBar(hWnd, wBar, bShow); {$else} result := ShowScrollBar(hWnd, wBar, bShow); {$endif} end; {!! GetImageSizeWithinArea Declaration function GetImageSizeWithinArea(iImageWidth, iImageHeight : integer; iAvailableWidth, iAvailableHeight : integer; bAllowStretching : boolean = TRUE; FitMethod: = _fmFitWithinRect ): TPoint; Description Return the new size of an image we wish to fit within an area of size iAvailableWidth x iAvailableHeight while maintaining the original aspect ratio Parameter Description iImageWidth, iImageHeight The dimensions of the image iAvailableWidth, iAvailableHeight The space available for the image (e.g. the client area of a display control, such as a TImageEnView) bAllowStretching If the image is smaller than the available area it will be stretched to the full available size (otherwise result is the original width/height) FitMethod Generally _fmFitWithinRect, but _fmFillRect_WithOverlap will return an image that makes the image as large as possible without any border area (so one dimension will match the available size, and the other will generally be larger)
See Also -
- !!} function GetImageSizeWithinArea(iImageWidth, iImageHeight : integer; // height and width of object iAvailableWidth, iAvailableHeight : integer; // the space available bAllowStretching : boolean = TRUE; // if the image is smaller than the available area it will be stretched to the full available size; FitMethod: TFitMethod = _fmFitWithinRect ): TPoint; // NPC: 24/10/11 var TempRect : TRect; begin TempRect := GetImageRectWithinArea(iImageWidth, iImageHeight, iAvailableWidth, iAvailableHeight, 0, 0, bAllowStretching, True, false, False, 0, FitMethod); result.x := TempRect.Right; result.y := TempRect.Bottom; end; // Estimate aspect ratio of rectified rectangle having four perspective quadrilater points // tech report: "Whiteboard Scanning and Image Enhancement", Zhengyou Zhang // x0, y0 = top-left // x1, y1 = top-right // x2, y2 = bottom-right // x3, y3 = bottom-left // cx, cy = center of image (Bitmap.Width / 2, Bitmap.Height / 2) function IERectifiedRectangleAspectRatio(x0, y0, x1, y1, x2, y2, x3, y3, cx, cy: double): double; var k2, k3: double; f2: double; r2: double; begin x0 := x0 - cx; y0 := y0 - cy; x1 := x1 - cx; y1 := y1 - cy; x2 := x2 - cx; y2 := y2 - cy; x3 := x3 - cx; y3 := y3 - cy; k2 := ((y3 - y1) * x0 - (x3 - x1) * y0 + x3 * y1 - y3 * x1) / ((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1) ; k3 := ((y3 - y1) * x2 - (x3 - x1) * y2 + x3 * y1 - y3 * x1) / ((y0 - y1) * x2 - (x0 - x1) * y2 + x0 * y1 - y0 * x1) ; result := 0; if (k2 <> 1) and (k3 <> 1) then begin f2 := -((k3 * y0 - y3) * (k2 * y2 - y3) + (k3 * x0 - x3) * (k2 * x2 - x3)) / ((k3 - 1) * (k2 - 1)); r2 := (sqr(k2 - 1) + sqr(k2 * y2 - y3) / f2 + sqr(k2 * x2 - x3) / f2) / (sqr(k3 - 1) + sqr(k3 * y0 - y3) / f2 + sqr(k3 * x0 - x3) / f2); if r2 > 0 then result := sqrt(r2); end; if result = 0 then result := sqrt((sqr(y2 - y3) + sqr(x2 - x3)) / (sqr(y0 - y3) + sqr(x0 - x3))); end; {!! GetImageRectWithinArea Declaration function GetImageRectWithinArea(iImageWidth, iImageHeight : Integer; iAvailableWidth, iAvailableHeight : Integer; iHorzOffset : Integer = 0; iVertOffset : integer = 0; bAllowStretching : boolean = true; bAllowShrinking : boolean = true; bCenterHorz : boolean = true; bCenterVert : boolean = true; iAutoCropPercent : Integer = 0; FitMethod: = _fmFitWithinRect) : TRect; overload; function GetImageRectWithinArea(iImageWidth, iImageHeight: Integer; ADestRect : TRect; bAllowStretching : boolean = true; bAllowShrinking : boolean = true; bCenterHorz : boolean = true; bCenterVert : boolean = true; iAutoCropPercent : Integer = 0; FitMethod: = _fmFitWithinRect) : TRect; overload; Description Return the new size and position of an image within an area assuming that we maintain the aspect ratio of the image. Parameter Description iImageWidth/iImageHeight The dimensions of the image iAvailableWidth/iAvailableHeight or ADestRect The space available for the image (e.g. the client area of a display control, such as a TImageEnView) iHorzOffset/iVertOffset Added to the left/top of the image position, e.g. to add a margin bAllowStretching If image is smaller than iAvailableWidth/iAvailableHeight its dimensions will be enlarged bAllowShrinking If image is larger than iAvailableWidth/iAvailableHeight its dimensions will be reduced bCenterHorz Image is positioned in the horizontal center (Otherwise result.Left will be zero) bCenterVert Image is positioned in the vertical center (Otherwise result.Top will be zero) iAutoCropPercent An advanced parameter that allows the image to be positioned outside of the display area to that it appears larger (i.e. part of the image is cropped). For example, if a portrait image is shown on screen generally there are wide side borders. An autocrop value of 10% would see (up to) 5% of the image not shown at the top and bottom so the border areas are reduced FitMethod Generally _fmFitWithinRect, but _fmFillRect_WithOverlap will return an image that makes the image as large as possible without any border area (but with part of the image offscreen). This is the same as using an iAutoCropPercent of 100
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 ) ); // 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 -
- !!} // pass the dimensions of an image and the space available to display it // Result will be a rectangle to with the position and size to show the image within that area (with aspect ratio maintained) function GetImageRectWithinArea(iImageWidth, iImageHeight : Integer; // height and widht of object being put within the space iAvailableWidth, iAvailableHeight : Integer; // the space available iHorzOffset : Integer = 0; // Added to the left of the object iVertOffset : integer = 0; // Added to the top of the object bAllowStretching : boolean = true; // if the image is smaller than the available area it will be stretched to the full available size bAllowShrinking : boolean = true; // if the image is larger than the available area it will be shrunk to the full available size bCenterHorz : boolean = true; // center the image horizontally if it is narrower than the available area (otherwise placed on the left) bCenterVert : boolean = true; // center the image vertically if it is shorter than the available area (otherwise placed on the Top) iAutoCropPercent : Integer = 0; // if > 0 then that percentage of the image will be be placed OUTSIDE the available area (for cropping) to better match the aspect ratio of the available area FitMethod: TFitMethod = _fmFitWithinRect // See TFitMethod declaration ) : TRect; overload; var iNewObjHeight, iNewObjWidth: integer; bWidthIsCloserRatioMatch: Boolean; bSizeToWidth: Boolean; procedure SetImageNoChange; // no change to size of object begin iNewObjWidth := iImageWidth; iNewObjHeight := iImageHeight; end; procedure SetImageToWidth; // object Width is set to max, Height is calculated var dResizeRatio, dMaxResizeRatio: Double; dCroppedWidth: Double; begin dResizeRatio := iAvailableWidth / iImageWidth; // if we are allowing a percentage of the image to be auto-cropped then // calculate the maximum possible ratio we can increase by without // without the Height exceeding the available widht if iAutoCropPercent > 0 then begin dCroppedWidth := iImageWidth * (100 - iAutoCropPercent) / 100; if iAutoCropPercent = 100 then dMaxResizeRatio := 1000 else dMaxResizeRatio := iAvailableWidth / dCroppedWidth; if round(iImageHeight * dMaxResizeRatio) > iAvailableHeight then dMaxResizeRatio := iAvailableHeight / iImageHeight; dResizeRatio := dMaxResizeRatio; end; iNewObjHeight := round(iImageHeight * dResizeRatio); iNewObjWidth := round(iImageWidth * dResizeRatio); end; procedure SetImageToHeight; // object height is set to max, width is calculated var dResizeRatio, dMaxResizeRatio: Double; dCroppedHeight: Double; begin dResizeRatio := iAvailableHeight / iImageHeight; // if we are allowing a percentage of the image to be auto-cropped then // calculate the maximum possible ratio we can increase by without // without the width exceeding the available widht if iAutoCropPercent > 0 then begin dCroppedHeight := iImageHeight * (100 - iAutoCropPercent) / 100; if iAutoCropPercent = 100 then dMaxResizeRatio := 1000 else dMaxResizeRatio := iAvailableHeight / dCroppedHeight; if round(iImageWidth * dMaxResizeRatio) > iAvailableWidth then dMaxResizeRatio := iAvailableWidth / iImageWidth; dResizeRatio := dMaxResizeRatio; end; iNewObjWidth := round(iImageWidth * dResizeRatio); iNewObjHeight := round(iImageHeight * dResizeRatio); end; begin if ( iImageWidth = 0 ) or ( iImageHeight = 0 ) or ( iAvailableHeight = 0 ) or ( iAvailableWidth = 0 ) then begin result := rect(iHorzOffset, iVertOffset, 0, 0); exit; end; bWidthIsCloserRatioMatch := (iImageHeight / iAvailableHeight)<(iImageWidth / iAvailableWidth); if FitMethod = _fmFitWithinRect then bSizeToWidth := bWidthIsCloserRatioMatch else bSizeToWidth := not bWidthIsCloserRatioMatch; if bSizeToWidth then // WIDTH IS IMPORTANT begin if iImageWidth > iAvailableWidth then begin if bAllowShrinking = False then SetImageNoChange else SetImageToWidth; end else begin if bAllowStretching = False then SetImageNoChange else SetImageToWidth; end; end ELSE // HEIGHT IS IMPORTANT begin if iImageHeight > iAvailableHeight then begin if bAllowShrinking=False then SetImageNoChange else SetImageToHeight; end else begin if bAllowStretching = False then SetImageNoChange else SetImageToHeight; end; end; result.Left := iHorzOffset; result.Top := iVertOffset; // center image in the available area if bCenterHorz then result.left := (trunc((iAvailableWidth /2)-(iNewObjWidth /2)))+iHorzOffset; if bCenterVert then result.top := (trunc((iAvailableHeight / 2)-(iNewObjHeight / 2)))+iVertOffset; result.right := result.left + iNewObjWidth; result.bottom := result.top + iNewObjHeight; end; // pass the dimensions of an image and the Rect where it will be displayed // Result will be a rectangle to with the position and size to show the image within that area (with aspect ratio maintained) function GetImageRectWithinArea(iImageWidth, iImageHeight: Integer; // height and width of object being put within the space ADestRect : TRect; // The rect that iImageWidth/iImageHeight must fit within bAllowStretching : boolean = true; // if the image is smaller than the available area it will be stretched to the full available size bAllowShrinking : boolean = true; // if the image is larger than the available area it will be shrunk to the full available size bCenterHorz : boolean = true; // center the image horizontally if it is narrower than the available area (otherwise placed on the left) bCenterVert : boolean = true; // center the image vertically if it is shorter than the available area (otherwise placed on the Top) iAutoCropPercent : Integer = 0; // if > 0 then that percentage of the image will be be placed OUTSIDE the available area (for cropping) to better match the aspect ratio of the available area FitMethod: TFitMethod = _fmFitWithinRect // See TFitMethod declaration ) : TRect; overload; var iRectWidth, iRectHeight : Integer; begin iRectWidth := ADestRect.Right - ADestRect.Left; iRectHeight := ADestRect.Bottom - ADestRect.Top; Result := GetImageRectWithinArea(iImageWidth, iImageHeight, iRectWidth, iRectHeight, ADestRect.Left, ADestRect.Top, bAllowStretching, bAllowShrinking, bCenterHorz, bCenterVert, iAutoCropPercent, FitMethod); end; {!! IEAdjustRectToAspectRatio Declaration function IEAdjustRectToAspectRatio(InRect : TRect; iImageWidth, iImageHeight: Integer; iDisplayWidth, iDisplayHeight : Integer; FitMethod: = _fmFitWithinRect ) : TRect; Description Adjusts the past rect so that it matches the aspect ratio of an image. For example, if InRect specifies a selected area where you want to draw an image, you can adjust the selection so that the image is not stretched (maintains its aspect ratio). Parameter Description InRect The source rect (to be adjusted) iImageWidth, iImageHeight The dimensions of the image (to which inRect will be adjusted) iDisplayWidth, iDisplayHeight The maximum width/height for the rect (typically the client area of a display control, such as a TImageEnView) FitMethod Rather than reducing the area of InRect, it is increased. The returned rect will cover the entire passed rect
Assuming InRect does not already match the ratio of iImageWidth/iImageHeight then IEAdjustRectToAspectRatio will return a rect with either: - Left and Right unchanged but Top increased and Bottom decreased - Top and Bottom unchanged but Left increased and Right decreased But if FitMethod is _fmFillRect_WithOverlap then result wil be either: - Left and Right unchanged but Top decreased and Bottom increased - Top and Bottom unchanged but Left decreased and Right increased Compatibility Notes This is the same as the AdjustRectToAspectRatio() method in versions prior to v6.0.0 but note the change of parameter order See Also -
- !!} function IEAdjustRectToAspectRatio(InRect : TRect; iImageWidth, iImageHeight: Integer; iDisplayWidth, iDisplayHeight : Integer; FitMethod: TFitMethod = _fmFitWithinRect ) : TRect; var bAdjustWidth: Boolean; iNewLeft, iNewTop, iNewWidth, iNewHeight: Integer; iObjLeft, iObjTop, iObjHeight, iObjWidth: Integer; begin iObjLeft := imax(0, InRect.left); iObjTop := imax(0, InRect.Top); iObjWidth := imin(iImageWidth, InRect.Right-InRect.Left); iObjHeight := imin(iImageHeight, InRect.Bottom-InRect.Top); if FitMethod = _fmFillRect_WithOverlap then bAdjustWidth := iObjHeight / iDisplayHeight < iObjWidth / iDisplayWidth else bAdjustWidth := iObjHeight / iDisplayHeight > iObjWidth / iDisplayWidth; if bAdjustWidth then // ADJUST WIDTH begin iNewHeight := iObjHeight; iNewTop := iObjTop; iNewWidth := round(iObjHeight * iDisplayWidth / iDisplayHeight); iNewLeft := iObjLeft-((iNewWidth-iObjWidth) div 2); if FitMethod = _fmFillRect_WithOverlap then begin if iNewLeft < 0 then iNewLeft := 0; if iNewWidth > iImageWidth then begin iNewWidth := iImageWidth; iNewHeight := round(iNewWidth * iDisplayHeight / iDisplayWidth); iNewTop := iObjTop - ((iNewHeight - iObjHeight) div 2); end; end; end ELSE // ADJUST HEIGHT begin iNewWidth := iObjWidth; iNewLeft := iObjLeft; iNewHeight := round(iObjWidth * iDisplayHeight / iDisplayWidth); iNewTop := iObjTop - ((iNewHeight - iObjHeight) div 2); if FitMethod = _fmFillRect_WithOverlap then begin if iNewTop < 0 then iNewTop := 0; if iNewHeight>iImageHeight then begin iNewHeight := iImageHeight; iNewWidth := round(iNewHeight * iDisplayWidth / iDisplayHeight); iNewLeft := iObjLeft-((iNewWidth-iObjWidth) div 2); end; end; end; if FitMethod = _fmFillRect_WithOverlap then begin if iNewLeft + iNewWidth > iImageWidth then iNewLeft := iImageWidth - iNewWidth; if iNewTop + iNewHeight > iImageHeight then iNewTop := iNewHeight - iImageHeight; end; result := rect(iNewLeft, iNewTop, iNewLeft + iNewWidth, iNewTop + iNewHeight); end; {!! AngleToImageEnRotateAngle Declaration function AngleToImageEnRotateAngle(Angle: Double): Double; Description ImageEn's rotation parameter requires a value specified negative or positive degrees counter-clockwise. This method converts a standard positive clockwise value to an ImageEn value. See also: Example // Rotate image 90 deg. clockwise ImageEnView1.Proc.Rotate( AngleToImageEnRotateAngle( 90 ) ); !!} function AngleToImageEnRotateAngle(Angle: Double): Double; begin result := abs( 360 - Angle ); end; {!! ImageEnRotateAngleToAngle Declaration function AngleToImageEnRotateAngle(Angle: Double): Double; Description ImageEn's rotation parameter requires a value specified negative or positive degrees counter-clockwise. This method converts an ImageEn rotation value to a value between -180 and +180. See also: Example ImageEnView1.Proc.Rotate( 90 ); ShowMessage( Format( 'Rotated by %d degrees', [ ImageEnRotateAngleToAngle( 90 )]); !!} function ImageEnRotateAngleToAngle(Angle: Double): Double; begin result := -1 * Angle; if Result > 180 then Result := Result - 360 else if Result <= 180 then Result := Result + 360; end; function IEBilinear(needX, needY: Double; centerValue, rightValue, bottomValue, BottomRightValue: integer): integer; var m0, m1: Double; begin needX := needX - trunc(needX); needY := needY - trunc(needY); if (needX < 0) then needX := needX + 1.0; if (needY < 0) then needY := needY + 1.0; m0 := (1.0 - needX) * centerValue + needX * rightValue; m1 := (1.0 - needX) * bottomValue + needX * BottomRightValue; result := trunc((1.0 - needY) * m0 + needY * m1); end; // Adjust the size of ItemHeight for ComboBox Items to cope with windows font scaling // Can call for any combo box, but only needed for csOwnerDrawFixed procedure IEInitializeComboBox(AComboBox : TComboBox); var TM : Windows.TTextMetric; iSize: Integer; begin if AComboBox.Style = csOwnerDrawFixed then try GetTextMetrics(AComboBox.Canvas.Handle, TM); iSize := GetSystemMetrics(SM_CYBORDER) * 2 + TM.tmHeight; if iSize > AComboBox.ItemHeight then AComboBox.ItemHeight := iSize; except // UNEXPECTED FAILURE end; end; { Typical Usage: procedure TfrmMain.cmbSourcesDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); begin IEDrawComboListBoxItem( TCombobox(Control).Canvas, Rect, Control.Enabled, TCombobox(Control).Items[ Index ], ImageList1, Drive_Glyph_Index ); end; Code that was IEDrawComboListBoxItem( TCombobox(Control), Rect, TCombobox(Control).Items[ Index ], ImageList1, Drive_Glyph_Index ); Should change to: IEDrawComboListBoxItem( TCombobox(Control).Canvas, Rect, Control.Enabled, TCombobox(Control).Items[ Index ], ImageList1, Drive_Glyph_Index ); } procedure IEDrawComboListBoxItem(ControlCanvas : TCanvas; CanvasRect : trect; ControlEnabled: Boolean; const Text : string; AnImageList : TImageList = nil; iGlyph : Short = -1); const DRAW_GLYPH_LEFT = 2; DRAW_GLYPH_TEXT_MARGIN = 3; DRAW_TEXT_LEFT_NO_GLYPH = 4; var AColor: TColor; textX : Integer; textY : Integer; glyphX : Integer; glyphY : Integer; begin ControlCanvas.FillRect(CanvasRect); if ControlEnabled = False then ControlCanvas.font.color := clGrayText; if assigned(AnImageList) and (iGlyph >= 0) then begin glyphX := DRAW_GLYPH_LEFT; glyphY := ((CanvasRect.Bottom - CanvasRect.Top) - AnImageList.Height) div 2; textX := DRAW_GLYPH_LEFT + AnImageList.Width + DRAW_GLYPH_TEXT_MARGIN; textY := ((CanvasRect.Bottom - CanvasRect.Top) - ControlCanvas.TextHeight(Text)) div 2; ControlCanvas.TextOut(CanvasRect.left + textX, CanvasRect.top + textY, Text); AColor := ControlCanvas.Brush.Color; AnImageList.Draw(ControlCanvas, CanvasRect.Left + glyphX, CanvasRect.Top + glyphY, iGlyph, ControlEnabled ); ControlCanvas.Brush.Color := AColor; end else begin textX := DRAW_TEXT_LEFT_NO_GLYPH; textY := ((CanvasRect.Bottom - CanvasRect.Top) - ControlCanvas.TextHeight(Text)) div 2; ControlCanvas.TextOut(CanvasRect.left + textX, CanvasRect.top + textY, Text); end; end; // Useful to get a suitable next zoom step when clicking a "Zoom In" or "Zoom Out" button // bZoomIn: true if a "Zoom In" button was pressed or false for "Zoom Out" // iIdealZoom: Optionally specify the zoom level required to fit to window (i.e. ieImage.GetIdealZoom) and it will be offered as a zoom step // E.g. ieImage.Zoom := GetNextZoomValue(ieImage.Zoom, Sender = btnZoomIn, ieImage.GetIdealZoom); function GetNextZoomValue(iCurrentZoom: double; bZoomIn: boolean; iIdealZoom: double = 0) : double; var iZoomInc: integer; begin result := iCurrentZoom; if bZoomIn then begin iZoomInc := 25; result := result + 1; end else begin if result < 6 then begin Result := 1; exit end else begin iZoomInc := 0; result := result - 1; end; end; if result < 26 then result := ((trunc(result) div 5) * 5) + (iZoomInc div 5) else if result < 300 then result := ((trunc(result) div 25) * 25) + iZoomInc else result := ((trunc(result) div 100) * 100) + (iZoomInc * 4); if (iIdealZoom > 0) and (iIdealZoom <> iCurrentZoom) and (trunc(iIdealZoom) <> trunc(iCurrentZoom)) and (iIdealZoom > Min(trunc(result), trunc(iCurrentZoom))) and (iIdealZoom < Max(trunc(result), trunc(iCurrentZoom))) then result := iIdealZoom; // snap to fit end; (* CCIR Recommendation 601-1 (lumaRed=0.299, lumaGreen=0.587, lumaBlue=0.114) R = Y + 1.40200 * Cr G = Y - 0.34414 * Cb - 0.71414 * Cr B = Y + 1.77200 * Cb Y = 0.29900 * R + 0.58700 * G + 0.11400 * B Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + 128 Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + 128 *) procedure IERGB2YCbCr(rgb: TRGB; var Y, Cb, Cr: integer); begin with rgb do begin Y := blimit(trunc(0.29900 * R + 0.58700 * G + 0.11400 * B)); Cb := blimit(trunc(-0.16874 * R - 0.33126 * G + 0.50000 * B + 128)); Cr := blimit(trunc(0.50000 * R - 0.41869 * G - 0.08131 * B + 128)); end; end; procedure IEYCbCr2RGB(var rgb: TRGB; Y, Cb, Cr: integer); begin Cb := Cb-128; Cr := Cr-128; rgb.r := blimit(trunc(Y + 1.40200 * Cr)); rgb.g := blimit(trunc(Y - 0.34414 * Cb - 0.71414 * Cr)); rgb.b := blimit(trunc(Y + 1.77200 * Cb)); end; function IESystemAlloc(ASize: int64): pointer; begin result := pointer(GlobalAlloc(GPTR, ASize)); end; // Frees memory procedure IESystemFree(var P); begin GlobalFree(THandle(pointer(P))); pointer(P) := nil; end; const IEMINSYSALLOC = 1048576; function IEAutoAlloc(ASize: int64): pointer; begin if ASize >= IEMINSYSALLOC then begin result := IESystemAlloc(ASize + 4); if result = nil then exit; // FAIL pboolean(result)^ := true; end else begin try GetMem(result, ASize + 4); pboolean(result)^ := false; except result := IESystemAlloc(ASize + 4); if result = nil then exit; // FAIL pboolean(result)^ := true; end; end; inc(pboolean(result)); end; procedure IEAutoFree(var P); begin dec(pboolean(P)); if pboolean(P)^ then IESystemFree(P) else FreeMem(pointer(P)); end; procedure IESilentGetMem(var P; Size: Integer); begin try GetMem(pointer(P), Size); except pointer(P) := nil; end; end; //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // check if mmx available function IEMMXSupported: bytebool; begin result := false; {$ifdef IEUSEASM} asm push ebx // check if the cpuid instruction is available pushfd pushfd pop eax mov ecx, eax xor eax, 200000h push eax popfd pushfd pop eax popfd xor eax, ecx jz @nocpuid // cpuid supported, check MMX mov eax, 1 Dw $A20F // CPUID test edx, 800000h setnz result @nocpuid: pop ebx end; {$endif} end; ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Extra backgrounds (* f(x)=(1/(sqrt(2*pi)*var))*e^((-1/2*(var^2))*(x-mean)^2) mean: center of highest value. 0=centered on zero var: width of the curve. 0.1=maximum width, 1=minimum, ref=0.2 *) procedure IECreateGaussCurve(variance: double; curveCount: integer; curveMin, curveMax: integer; var curve: array of double); const mean=0; var i: integer; x: double; mx: double; begin mx := -100000; for i := 0 to curveCount-1 do begin x := (i/curveCount)*2-1; curve[i] := (1/(sqrt(2*pi)*variance))*exp((-1/2*(Power(variance, 2)))*Power(x-mean, 2)); if curve[i]>mx then mx := curve[i]; end; for i := 0 to curveCount-1 do curve[i] := curveMin+ curve[i]/mx*(curveMax-curveMin); end; procedure IECreateOSXBackgroundPaper(bmp: TBitmap; width, height: integer); var px: PRGB; col: TRGB; x, y: integer; c: integer; gauss: array [0..3] of double; begin bmp.Width := width; bmp.Height := height; bmp.PixelFormat := pf24bit; IECreateGaussCurve(0.5, 4, 130, 255, gauss); c := 0; for y := 0 to bmp.Height-1 do begin px := bmp.Scanline[y]; col.r := trunc(gauss[c]); col.g := col.r; col.b := col.r; for x := 0 to bmp.Width-1 do begin px^ := col; inc(px); end; inc(c); if c=4 then c := 0; end; end; procedure IECreateOSXBackgroundMetal(bmp: TBitmap; width, height: integer); var px: PRGB; x, y: integer; c, a: integer; gauss: pdoublearray; bmpWidth, bmpHeight: integer; begin bmp.Width := width; bmp.Height := height; bmp.PixelFormat := pf24bit; bmpWidth := bmp.Width; bmpHeight := bmp.Height; getmem(gauss, bmpWidth*sizeof(double)); IECreateGaussCurve(3, bmpWidth, 160, 208, gauss^); a := 0; for y := 0 to bmpHeight-1 do begin c := 0; px := bmp.Scanline[y]; for x := 0 to bmpWidth-1 do begin px^.r := trunc(gauss[x])+a; px^.g := px^.r; px^.b := px^.r; inc(px); inc(c); if c>(100+random(bmpWidth)) then begin c := 0; a := random(11); end; end; end; freemem(gauss); end; // Extra backgrounds ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Clipboard helper functions // you must call OpenClipboard before call this function function IEEnumClipboardNames: TStringList; const MX=512; var cf: cardinal; pc: PChar; len: integer; begin getmem(pc, (MX+1)*sizeof(Char)); result := TStringList.Create; cf := 0; while true do begin cf := EnumClipboardFormats(cf); if cf=0 then break; len := GetClipboardFormatName(cf, pc, MX); if len > 0 then result.AddObject( copy(pc, 1, len), pointer(cf) ); end; freemem(pc); end; // you must call OpenClipboard before call this function function IEGetClipboardDataByName(const name: string): THandle; var l: TStringList; i: integer; begin result := 0; l := IEEnumClipboardNames; i := l.IndexOf(name); if i>-1 then result := cardinal(l.Objects[i]); l.free; end; // Clipboard helper functions ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Sometimes OpenClipboard fails. In particular when big images are just copied in and a paste is done immediately. function IEOpenClipboard: boolean; var i: integer; begin for i := 1 to 10 do begin if OpenClipboard(0) then begin result := true; exit; end; sleep(20); // up to 200 ms (20*10) end; result := false; end; {!! IEAlphaToOpacity Declaration function IEAlphaToOpacity(Alpha: integer ): integer; Description COnverts an alpha value (in range of 0 - 255) to an opacity percentage (0 - 100). Opacity is generally referred to as percent. (e.g. Alpha of 255 would return Opacity of 100% ) See also: !!} function IEAlphaToOpacity(Alpha: integer ): integer; begin result := Round( Alpha / 255 * 100 ); end; {!! IEOpacityToAlpha Declaration function IEOpacityToAlpha(Opacity: integer): integer; Description COnverts a opacity percentage (0 - 100) to an alpha value (in range of 0 - 255). For example Opacity of 100% would return Alpha of 255. See also: !!} function IEOpacityToAlpha(Opacity: integer): integer; begin result := ( Opacity * 255 ) div 100; end; // calculates coordinates of intersection of two perpendicular lines // First line is specified by slope and one point // Second line is specified by a single point function IECalcOrthogonalLinesIntersectingPoint(FirstLinePoint: TIE2DPoint; FirstLineSlope: double; SecondLinePoint: TIE2DPoint): TIE2DPoint; var A, B, C: double; z: double; begin // equation of first line A := -FirstLineSlope; B := 1; C := -FirstLinePoint.Y + FirstLineSlope * FirstLinePoint.X; // dropping a perpendicular and find intersection point z := (A * SecondLinePoint.X + B * SecondLInePoint.Y + C) / (sqr(A) + sqr(B)); result := IE2DPoint(SecondLinePoint.X - A * z, SecondLinePoint.Y - B * z); end; function IECalcPolygonCentroid(polygon: array of TIE2DPoint): TIE2DPoint; var i, j: integer; ai, atmp, xtmp, ytmp: double; xi, yi, xj, yj: double; begin result.X := 0; result.Y := 0; atmp := 0; xtmp := 0; ytmp := 0; i := length(polygon) - 1; j := 0; while j < length(polygon) do begin xi := polygon[i].x; yi := polygon[i].y; xj := polygon[j].x; yj := polygon[j].y; ai := xi * yj - xj * yi; atmp := atmp + ai; xtmp := xtmp + (xj + xi) * ai; ytmp := ytmp + (yj + yi) * ai; i := j; inc(j); end; if (atmp <> 0) then begin result.x := xtmp / (3 * atmp); result.y := ytmp / (3 * atmp); end; end; procedure IERotatePoints(var rpt: array of TPoint; PointCount: Integer; angle: double; CenterX, CenterY: integer); var aa: double; i, x, y: integer; begin aa := -angle * pi / 180; for i := 0 to PointCount - 1 do begin x := rpt[i].X; y := rpt[i].Y; rpt[i].X := CenterX + trunc( (x-CenterX)*cos(aa) - (y-CenterY)*sin(aa) ); rpt[i].Y := CenterY + trunc( (x-CenterX)*sin(aa) + (y-CenterY)*cos(aa) ); end; end; procedure IEDRotatePointsWithCenter(var rpt: array of TIE2DPoint; angle: double; CenterX, CenterY: double); var i: integer; aa: double; x, y: double; begin aa := -angle * pi / 180; for i := 0 to High(rpt) do begin x := rpt[i].X; y := rpt[i].Y; rpt[i].X := CenterX + (x - CenterX) * cos(aa) - (y - CenterY) * sin(aa); rpt[i].Y := CenterY + (x - CenterX) * sin(aa) + (y - CenterY) * cos(aa); end; end; procedure IEDRotatePoints(var rpt: array of TIE2DPoint; angle: double); var center: TIE2DPoint; begin center := IECalcPolygonCentroid(rpt); IEDRotatePointsWithCenter(rpt, angle, Center.X, Center.Y); end; procedure IEDRotateTwoPoints(Angle: double; const P1: TIE2DPoint; const P2: TIE2DPoint; out OutP1: TIE2DPoint; out OutP2: TIE2DPoint); var radAngle: double; centerX, centerY: double; begin radAngle := -Angle * PI / 180; centerX := (P1.X + P2.X) / 2.0; centerY := (P1.Y + P2.Y) / 2.0; OutP1.X := centerX + (P1.X - centerX) * cos(radAngle) - (P1.Y - centerY) * sin(radAngle); OutP1.Y := centerY + (P1.X - centerX) * sin(radAngle) + (P1.Y - centerY) * cos(radAngle); OutP2.X := centerX + (P2.X - centerX) * cos(radAngle) - (P2.Y - centerY) * sin(radAngle); OutP2.Y := centerY + (P2.X - centerX) * sin(radAngle) + (P2.Y - centerY) * cos(radAngle); end; procedure IERotatePoint(var px, py: integer; angle: double; CenterX, CenterY: integer); var aa: double; x, y: integer; begin aa := -angle * pi / 180; x := px; y := py; px := CenterX + trunc( (x-CenterX)*cos(aa) - (y-CenterY)*sin(aa) ); py := CenterY + trunc( (x-CenterX)*sin(aa) + (y-CenterY)*cos(aa) ); end; procedure IEDRotatePoint(var px, py: double; angle: double; CenterX, CenterY: double); var aa: double; x, y: double; begin aa := -angle * pi / 180; x := px; y := py; px := CenterX + (x - CenterX) * cos(aa) - (y - CenterY) * sin(aa); py := CenterY + (x - CenterX) * sin(aa) + (y - CenterY) * cos(aa); end; function IECalcRotatedRectBoundingBox(Rectangle: TIEDRectangle; RotationCenter: TIE2DPoint; RotationAngle: double): TIEDRectangle; var rotRect: array [0..4] of TIE2DPoint; i: integer; begin rotRect[0] := IE2DPoint(Rectangle[0].X, Rectangle[0].Y); rotRect[1] := IE2DPoint(Rectangle[1].X, Rectangle[0].Y); rotRect[2] := IE2DPoint(Rectangle[1].X, Rectangle[1].Y); rotRect[3] := IE2DPoint(Rectangle[0].X, Rectangle[1].Y); for i := 0 to 3 do IEDRotatePoint(rotRect[i].X, rotRect[i].Y, RotationAngle, RotationCenter.X, RotationCenter.Y); result[0] := rotRect[0]; result[1] := rotRect[0]; for i := 1 to 3 do begin result[0].X := dmin(result[0].X, rotRect[i].X); result[0].Y := dmin(result[0].Y, rotRect[i].Y); result[1].X := dmax(result[1].X, rotRect[i].X); result[1].Y := dmax(result[1].Y, rotRect[i].Y); end; end; procedure IECalcRotatedBitmapSizes(Width, Height: integer; RotationCenter: TIE2DPoint; RotationAngle: double; out NewWidth: integer; out NewHeight: integer); var rc: TIEDRectangle; bbox: TIEDRectangle; begin rc[0].X := 0; rc[0].Y := 0; rc[1].X := Width - 1; rc[1].Y := Height - 1; bbox := IECalcRotatedRectBoundingBox(rc, RotationCenter, RotationAngle); NewWidth := round(bbox[1].X - bbox[0].X + 1); NewHeight := round(bbox[1].Y - bbox[0].Y + 1); end; // RotationAngle in degrees // Background can be 0 or 1 procedure IERotateBits(Bits: TIEArrayOfByte; Width, Height: integer; RowAlignment: integer; RotationCenter: TIE2DPoint; RotationAngle: double; Background: integer; MaintainOriginalSize: boolean; out outBits: TIEArrayOfByte; out outWidth: integer; out outHeight: integer); var i, j: integer; radAngle: double; rowlen, outRowlen: integer; deltaX, deltaY: double; rotX, rotY: integer; dstRow, srcRow: pbyte; newWidth, newHeight: integer; offX, offY: integer; row, col: integer; begin if RotationAngle = 0.0 then begin // no rotation outWidth := Width; outHeight := Height; SetLength(outBits, length(Bits)); for i := 0 to high(Bits) do outBits[i] := Bits[i]; exit; end; radAngle := RotationAngle * PI / 180.0; IECalcRotatedBitmapSizes(Width, Height, RotationCenter, RotationAngle, newWidth, newHeight); if MaintainOriginalSize then begin outWidth := Width; outHeight := Height; offX := (outWidth - Width) div 2; offY := (outHeight - Height) div 2; end else begin outWidth := newWidth; outHeight := newHeight; offX := 0; offY := 0; end; rowlen := IEBitmapRowLen(Width, 1, RowAlignment); outRowlen := IEBitmapRowLen(outWidth, 1, RowAlignment); SetLength(outBits, outRowlen * outHeight); dstRow := @outBits[0]; for i := 0 to outHeight - 1 do begin for j := 0 to outWidth - 1 do begin col := offX + j; row := offY + i; deltaY := col - RotationCenter.X; deltaX := row - RotationCenter.Y; rotX := round(RotationCenter.X + deltaX * sin(radAngle) + deltaY * cos(radAngle)); rotY := round(RotationCenter.Y + deltaX * cos(radAngle) - deltaY * sin(radAngle)); if (rotX >= 0) and (rotX < Width) and (rotY >= 0) and (rotY < Height) then begin srcRow := @Bits[0]; inc(srcRow, rowlen * rotY); _SetPixelbw(dstRow, col, _GetPixelbw(srcRow, rotX)); end else begin _SetPixelbw(dstRow, col, Background); end; end; inc(dstRow, outRowlen); end; end; // RotationAngle in degrees around cursor hotspot // No need to call DestroyCursor when assigned to Screen.Cursors[] function IECreateRotatedCursor(CursorIntResource: integer; RotationAngle: double): HCURSOR; var hresInfo: HRSRC; hres: THandle; buf: pbyte; bufLen: integer; ms: TIEMemStream; hotSpotX, hotSpotY: word; rotationCenter: TIE2DPoint; infoHead: TBITMAPINFOHEADER; width, height: integer; colorMap: array of TRGBQUAD; plane: TIEArrayOfByte; XORplane: TIEArrayOfByte; ANDplane: TIEArrayOfByte; rowlen: integer; newWidth, newHeight: integer; begin result := 0; hresInfo := FindResource(HInstance, MakeIntResource(CursorIntResource), RT_CURSOR); hres := LoadResource(HInstance, hresInfo); bufLen := SizeOfResource(HInstance, hresInfo); buf := LockResource(hres); if (buf <> nil) and (buflen > 0) then begin ms := TIEMemStream.Create(buf, bufLen); // hot spot ms.Read(hotSpotX, sizeof(word)); ms.Read(hotSpotY, sizeof(word)); // rotate around hotsport rotationCenter.X := hotSpotX; rotationCenter.Y := hotSpotY; // Bitmap info header FillChar(InfoHead, sizeof(InfoHead), 0); ms.Read(infoHead, sizeof(TBITMAPINFOHEADER)); // here only black/white cursor are supported if infoHead.biBitCount = 1 then begin // color map SetLength(colorMap, 2); ms.Read(colorMap[0], sizeof(TRGBQUAD) * length(colorMap)); width := infoHead.biWidth; height := infoHead.biHeight div 2; // allocate buffer to contain source XOR and AND planes rowlen := IEBitmapRowLen(width, 1, 32); SetLength(plane, rowlen * height); // load and rotate XOR plane ms.Read(plane[0], length(plane)); IERotateBits(plane, width, height, 32, rotationCenter, RotationAngle, 0, true, XORplane, newWidth, newHeight); // load and rotate AND plane ms.Read(plane[0], length(plane)); IERotateBits(plane, width, height, 32, rotationCenter, RotationAngle, 1, true, ANDplane, newWidth, newHeight); // creates the new cursor result := CreateCursor(HInstance, hotSpotX, hotSpotY, newWidth, newHeight, @ANDplane[0], @XORplane[0]); end; ms.Free(); end; UnlockResource(hres); FreeResource(hres); end; // Return the max and min x and y in a point array procedure IEGetPointsRange(rpt: array of TPoint; PointCount: Integer; out MinX: Integer; out MinY: Integer; out MaxX: Integer; out MaxY: Integer); var i: Integer; begin MinX := 0; MaxX := 0; MinY := 0; MaxY := 0; if PointCount < 1 then exit; MinX := MaxInt; MaxX := - MaxInt; MinY := MaxInt; MaxY := - MaxInt; for i := 0 to PointCount - 1 do begin if rpt[i].X > MaxX then MaxX := rpt[i].X; if rpt[i].X < MinX then MinX := rpt[i].X; if rpt[i].Y > MaxY then MaxY := rpt[i].Y; if rpt[i].Y < MinY then MinY := rpt[i].Y; end; end; // Scale all points so they are in the range minx to maxx and miny to maxy procedure IEScalePoints(var rpt: array of TPoint; PointCount: Integer; MinX, MinY, MaxX, MaxY: Integer; MaintainAR: Boolean = False); var i, currMinX, currMinY, currMaxX, currMaxY : Integer; addX, addY: Integer; scaleX, ScaleY: Double; rightMostX, bottomMostY: Integer; begin if PointCount < 1 then exit; IEGetPointsRange(rpt, PointCount, currMinX, currMinY, currMaxX, currMaxY ); addX := MinX - currMinX; scaleX := ( MaxX - MinX ) / (( currMaxX - CurrMinX )); addY := MinY - currMinY; scaleY := ( MaxY - MinY ) / (( currMaxY - CurrMinY )); if MaintainAR then begin if scaleX < ScaleY then begin bottomMostY := Round(( currMaxY - currMinY ) * ScaleX ) + addY + currMinY; inc( addY, ( MaxY - bottomMostY ) div 2 ); ScaleY := scaleX; end else begin rightMostX := Round(( currMaxX - currMinX ) * ScaleY ) + addX + currMinX; inc( addX, ( MaxX - rightMostX ) div 2 ); scaleX := ScaleY; end; end; for i := 0 to PointCount - 1 do begin rpt[i].X := Round(( rpt[i].X - currMinX ) * ScaleX ) + addX + currMinX; rpt[i].Y := Round(( rpt[i].Y - currMinY ) * ScaleY ) + addY + currMinY; end; end; function IEDISPointInPoly(x, y: double; poly: array of TIE2DPoint): boolean; var i, j: integer; begin result := false; j := High(poly); for i := Low(poly) to High(poly) do begin if ((((poly[i].y <= y) and (y < poly[j].y)) or ((poly[j].y <= y) and (y < poly[i].y)) ) and (x < ((poly[j].x - poly[i].x) * (y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x))) then result := not result; j := i end; end; function IEISPointInPoly(x, y: integer; poly: array of TPoint): boolean; var i, j: integer; begin result := false; j := High(poly); for i := Low(poly) to High(poly) do begin if ((((poly[i].y <= y) and (y < poly[j].y)) or ((poly[j].y <= y) and (y < poly[i].y)) ) and (x < ((poly[j].x - poly[i].x) * (y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x))) then result := not result; j := i end; end; function IEISPointInPoly2(x, y: integer; PolyPoints: PPointArray; PolyPointsCount: integer; ToSubX, ToSubY, ToAddX, ToAddY: integer; ToMulX, ToMulY: double): boolean; var i, j: integer; xi, yi, xj, yj: double; begin result := false; j := PolyPointsCount-1; for i := 0 to PolyPointsCount-1 do begin xi := (PolyPoints[i].x-ToSubX)*ToMulX+ToAddX; yi := (PolyPoints[i].y-ToSubY)*ToMulY+ToAddY; xj := (PolyPoints[j].x-ToSubX)*ToMulX+ToAddX; yj := (PolyPoints[j].y-ToSubY)*ToMulY+ToAddY; if ((((yi <= y) and (y < yj)) or ((yj <= y) and (y < yi)) ) and (x < ((xj - xi) * (y - yi) / (yj - yi) + xi))) then result := not result; j := i end; end; procedure IECenterRectInRect(OuterRectX1, OuterRectY1, OuterRectX2, OuterRectY2: integer; var InnerRectX1: integer; var InnerRectY1: integer; var InnerRectX2: integer; var InnerRectY2: integer); var outerWidth, outerHeight: integer; innerWidth, innerHeight: integer; offX, offY: integer; begin outerWidth := OuterRectX2 - OuterRectX1 + 1; outerHeight := OuterRectY2 - OuterRectY1 + 1; innerWidth := InnerRectX2 - InnerRectX1 + 1; innerHeight := InnerRectY2 - InnerRectY1 + 1; offX := (outerWidth - innerWidth) div 2; offY := (outerHeight - innerHeight) div 2; InnerRectX1 := OuterRectX1 + offX; InnerRectY1 := OuterRectY1 + offY; InnerRectX2 := InnerRectX1 + innerWidth - 1; InnerRectY2 := InnerRectY1 + innerHeight - 1; end; // Given a rect and an angle, for a line passing through the center, where would it intersect with the rect edges? procedure CalcLineWithinRect(R: TRect; Angle: Integer; out Pt1, Pt2: TPoint); var baseAngle: Integer; x1gr, y1gr: Boolean; w2, h2 : Double; procedure _FitTopAndBottom(); var a: Double; xOffset: Double; begin // Intersects on top and bottom edges Pt1.Y := R.Top; Pt2.Y := R.Bottom; a := IEDegreesToRadians( 90 - angle ); xOffset := Abs( Tan( a ) * h2 ); if Angle > 45 then xOffset := -1 * xOffset; Pt1.X := Round( R.Left + w2 - xOffset ); Pt2.X := Round( R.Left + w2 + xOffset ); end; procedure _FitLeftAndRight(); var a: Double; yOffset: Double; begin // Intersects on left and right side Pt1.X := R.Left; Pt2.X := R.Right; a := IEDegreesToRadians( angle ); yOffset := Abs( Tan( a ) * w2 ); if Angle < 0 then yOffset := -1 * yOffset; Pt1.Y := Round( R.Top + h2 + yOffset ); Pt2.Y := Round( R.Top + h2 - yOffset ); end; procedure _SwapX(); var tempX: Integer; begin tempX := pt1.X; pt1.X := pt2.X; pt2.X := tempX; end; procedure _SwapY(); var tempY: Integer; begin tempY := pt1.Y; pt1.Y := pt2.Y; pt2.Y := tempY; end; begin if ( R.Left > R.Right ) or ( R.Top > R.Bottom ) then begin Pt1 := Point( -1, -1 ); Pt2 := Point( -1, -1 ); exit; end; baseAngle := Angle; while baseAngle < 0 do baseAngle := baseAngle + 360; // Want angle to be in range -90 - 90 While Angle <= -90 do Angle := Angle + 180; While Angle > 90 do Angle := Angle - 180; w2 := ( R.Right - R.Left ) / 2; h2 := ( R.Bottom - R.Top ) / 2; if ( Angle < -45 ) or ( Angle > 45 ) then begin _FitTopAndBottom(); x1gr := ( Pt1.X > Pt2.X ); y1gr := ( Pt1.Y > Pt2.Y ); if ( Pt1.X < R.Left ) or ( Pt2.X < R.Left ) then _FitLeftAndRight(); end else // > -45 and < 45 begin _FitLeftAndRight(); x1gr := ( Pt1.X > Pt2.X ); y1gr := ( Pt1.Y > Pt2.Y ); if ( Pt1.Y < R.Top ) or ( Pt2.Y < R.Top ) then _FitTopAndBottom(); end; // Correct for refits if x1gr and ( Pt2.X > Pt1.X ) then _SwapX() else if ( x1gr = False ) and ( Pt1.X > Pt2.X ) then _SwapX(); if y1gr and ( Pt2.Y > Pt1.Y ) then _SwapY() else if ( y1gr = False ) and ( Pt1.Y > Pt2.Y ) then _SwapY(); if ( baseAngle > 45 ) and (baseAngle <= 225 )then IESwap( Pt1, Pt2 ); end; // Given a distance and an angle from a point, what would be the new position? function OffsetPoint(Pt: TPoint; Dist: Double; Angle: Double) : TPoint; var aa: Double; begin aa := -angle * pi / 180; Result.X := Pt.X + trunc(( Dist * cos( aa ))); Result.Y := Pt.Y + trunc(( Dist * sin( aa ))); end; function IEIsLeftMouseButtonPressed: boolean; begin result := (((GetAsyncKeyState(VK_LBUTTON) and $8000)<>0) and (GetSystemMetrics(SM_SWAPBUTTON)=0)) or (((GetAsyncKeyState(VK_RBUTTON) and $8000)<>0) and (GetSystemMetrics(SM_SWAPBUTTON)<>0)); end; function IERGBToStr(rgb: TRGB): AnsiString; begin with rgb do result := IEIntToStr(r)+', '+IEIntToStr(g)+', '+IEIntToStr(b); end; function IEGetURLTypeW(const URL: WideString): TIEURLType; begin result := IEGetURLTypeA(AnsiString(URL)); end; function IEGetURLTypeA(const URL: AnsiString): TIEURLType; var tmp: AnsiString; begin tmp := IELowerCase(URL); if IECopy(tmp, 1, 7) = 'http://' then result := ieurlHTTP else if IECopy(tmp, 1, 8) = 'https://' then result := ieurlHTTPS else if IECopy(tmp, 1, 6) = 'ftp://' then result := ieurlFTP else result := ieurlUNKNOWN; end; // Return distance between (x, y) and the ellipse inside x1, y1, x2, y2 // Coordinates x1, y1, x2, y2 must be ordered // 3.0.2 (penWidth) function IEDistPoint2Ellipse(x, y, x1, y1, x2, y2: integer; filled: boolean; penWidth: integer): double; var g, xr1, yr1, xr2, yr2, rx, ry, p, pw, ox, oy: integer; d: double; begin result := 2147483647; for pw := -penWidth div 2 to penWidth div 2 do begin rx := (x2 - x1) div 2 + pw; // ray x ry := (y2 - y1) div 2 + pw; // ray y ox := x - (x1 + rx)+pw; oy := y - (y1 + ry)+pw; if filled then p := trunc(2 * pi * imin(rx, ry)) else p := trunc(2 * pi * imin(rx, ry)) shr 3; if p<2 then p := 2; xr1 := rx; yr1 := 0; for g := 1 to p - 1 do begin xr2 := trunc(cos((2 * pi / p) * g) * rx); yr2 := trunc(sin((2 * pi / p) * g) * ry); if filled then d := trunc(_DistPoint2Seg(ox, oy, 0, 0, xr2, yr2)) else d := _DistPoint2Seg(ox, oy, xr1, yr1, xr2, yr2); if d < result then result := d; xr1 := xr2; yr1 := yr2; end; end; end; // 3.0.2 (penWidth) function IEDist2Box(x, y, x1, y1, x2, y2: integer; filled: boolean; penWidth: integer): double; var pw: integer; begin result := 2147483647; for pw := -penWidth div 2 to penWidth div 2 do begin result := dmin(result, dmin(_DistPoint2Seg(x, y, x1+pw, y1+pw, x2+pw, y1+pw), dmin(_DistPoint2Seg(x, y, x2+pw, y1+pw, x2+pw, y2+pw), dmin(_DistPoint2Seg(x, y, x2+pw, y2+pw, x1+pw, y2+pw), _DistPoint2Seg(x, y, x1+pw, y2+pw, x1+pw, y1+pw))))); if filled and IEPointInRect(x, y, x1+pw, y1+pw, x2+pw, y2+pw) then begin result := 0; break; end; end; end; // calculate the distance of two parallel lines // line A: defined by two points (FirstLinePointA, FirstLinePointB) // line B: defined by one point (SecondLinePoint) function IEDistParallelLines(FirstLinePointA: TIE2DPoint; FirstLinePointB: TIE2DPoint; SecondLinePoint: TIE2DPoint): double; var AB, BC, AC: double; p: double; S: double; begin AB := IEDDistPoint2Point(FirstLinePointA.X, FirstLinePointA.Y, FirstLinePointB.X, FirstLinePointB.Y); BC := IEDDistPoint2Point(FirstLinePointB.X, FirstLinePointB.Y, SecondLinePoint.X, SecondLinePoint.Y); AC := IEDDistPoint2Point(FirstLinePointA.X, FirstLinePointA.Y, SecondLinePoint.X, SecondLinePoint.Y); p := (AB + BC + AC) / 2.0; // perimeter / 2 S := sqrt(p * (p - AB) * (p - BC) * (p - AC)); // area (Heron's formula) result := 2.0 * S / AB; // triangle height end; // calculate the signed area of triangle function IESignedTriangleArea(Point1: TIE2DPoint; Point2: TIE2DPoint; Point3: TIE2DPoint): double; begin result := (-Point2.X * Point1.Y + Point3.X * Point1.Y + Point1.X * Point2.Y - Point3.X * Point2.Y - Point1.X * Point3.Y + Point2.X * Point3.Y) / 2.0; end; // calculate the offsets to translate a segment such that it passes by a given point, respecting the original orientation and direction (that is "to offset the coordinates in the orthogonal direction") // "P" (Point) can be any point in the translated line (even out of segment) // P // / // / / // / / // / procedure IEOrthogonalTranslate(OrigSegmentA, OrigSegmentB: TIE2DPoint; Point: TIE2DPoint; out OffsetX: double; out OffsetY: double); var L, offsetPixels: double; begin offsetPixels := IEDistParallelLines(OrigSegmentA, OrigSegmentB, Point); if IESignedTriangleArea(OrigSegmentA, OrigSegmentB, Point) > 0 then offsetPixels := -offsetPixels; L := sqrt((OrigSegmentA.X - OrigSegmentB.X) * (OrigSegmentA.X - OrigSegmentB.X) + (OrigSegmentA.Y - OrigSegmentB.Y) * (OrigSegmentA.Y - OrigSegmentB.Y)); OffsetX := offsetPixels * (OrigSegmentB.Y - OrigSegmentA.Y) / L; OffsetY := offsetPixels * (OrigSegmentA.X - OrigSegmentB.X) / L; end; function IETrim(const v: AnsiString): AnsiString; begin {$IFDEF UNICODE} result := AnsiString(trim(string(v))); {$ELSE} result := trim(v); {$ENDIF} end; function IEExtractFileExtS(const FileName: string; includeDot: boolean=true): string; begin result := ExtractFileExt(LowerCase(FileName)); if not includeDot then result := Copy(result, 2, length(result)-1); end; function IEExtractFileExtA(const FileName: AnsiString; includeDot: boolean): AnsiString; begin {$ifdef IEHASANSISTRINGBUG} result := IEExtractFileExtS(string(FileName), includeDot); {$else} result := AnsiString(IEExtractFileExtS(string(FileName), includeDot)); {$endif} end; function IEExtractFileExtW(const FileName: WideString; includeDot: boolean): WideString; begin result := WideString(IEExtractFileExtS(string(FileName), includeDot)); end; // = IncludeTrailingBackSlash, but if path is '' it returns '' function IEAddBackSlash(const Path: String): String; begin Result := ''; if Path <> '' then Result := IncludeTrailingBackSlash( Path ); end; {!! IEFilenameInExtensions Declaration function IEFilenameInExtensions(const sFileName, sExtensions : String) : Boolean; Description Returns true if the filename has an extension listed in those passed (in format '*.jpeg;*.jpg;*.gif;'); For example: IEFilenameInExtensions('C:\File.avi', '*.AVI;*.mpg;*.mpeg') would return true See Also - !!} function IEFilenameInExtensions(const sFileName, sExtensions : String) : Boolean; begin Result := IEFileExtInExtensions(ExtractFileExt(sFilename), sExtensions); end; {!! IEFileExtInExtensions Declaration function IEFileExtInExtensions(sFileExt : String; const sExtensions : String) : Boolean; Description Returns true if the extension (with or without the dot) is listed in those passed (in format '*.jpeg;*.jpg;*.gif;'); For example: IEFilenameInExtensions('.avi', '*.AVI;*.mpg;*.mpeg') would return true Note: sExtensions can be '*.*'; See Also - !!} function IEFileExtInExtensions(sFileExt : String; const sExtensions : String) : Boolean; begin Result := False; sFileExt := Lowercase(sFileExt); if (sFileExt <> '') and (sFileExt[1] <> '.') then sFileExt := '.' + sFileExt; if ( sExtensions = '*.*' ) or ( sExtensions = '*.*;' ) then result := True else if ( Length( sFileExt ) > 1 ) and ( pos( sFileExt + ';', Lowercase( sExtensions + ';' )) > 0 ) then result := True; end; function IEUpperCase(const v: AnsiString): AnsiString; begin {$IFDEF UNICODE} result := AnsiString(UpperCase(string(v))); {$ELSE} result := UpperCase(v); {$ENDIF} end; function IELowerCase(const v: AnsiString): AnsiString; begin {$IFDEF UNICODE} result := AnsiString(LowerCase(string(v))); {$ELSE} result := LowerCase(v); {$ENDIF} end; function IEIntToStr(v: integer): AnsiString; begin {$IFDEF UNICODE} result := AnsiString(IntToStr(v)); {$ELSE} result := IntToStr(v); {$ENDIF} end; // iMaxDigitsOfPrecision: Specifies number of leading digits that are non zero, e.g. 3 woudl make 123,456 return 123,000 function IEIntToFormattedStr(v: integer; iMaxDigitsOfPrecision: Integer = 0): AnsiString; var iRoundTo: Integer; begin if iMaxDigitsOfPrecision > 0 then begin iRoundTo := Length( IntToStr( v )) - iMaxDigitsOfPrecision; if iRoundTo > 0 then v := Trunc( RoundTo( v, iRoundTo )); end; {$IFDEF UNICODE} result := AnsiString(format('%.0n', [v * 1.0])); {$ELSE} result := format('%.0n', [v * 1.0]); {$ENDIF} end; // MAX VALUE: 2GB!!! function IEBytesToStr(v: integer; iThreshold: Integer = 100 * 1024) : AnsiString; begin {$IFDEF UNICODE} if v < iThreshold then Result := IEIntToFormattedStr(v) + AnsiString(' bytes') else Result := IEIntToFormattedStr(v div 1024) + AnsiString(' KB'); {$ELSE} if v < iThreshold then Result := IEIntToFormattedStr(v) + ' bytes' else Result := IEIntToFormattedStr(v div 1024) + ' KB'; {$ENDIF} end; // Handles very big sizes which may include files in KB, MB or FB function IEBytesToStr2(iBytes: Int64) : AnsiString; const ONE_KB = 1024; ONE_MB = ONE_KB * ONE_KB; ONE_GB = ONE_MB * ONE_KB; function _FloatToFormatString(Value: Real; iDecimalCount: Integer; bStripZeros: boolean = True): AnsiString; begin result := AnsiString(Format('%.' + inttostr(iDecimalCount) + 'f', [Value])); if bStripZeros and (IEPos('.', result) > 0) then begin while result[length(result)] = '0' do setlength(result, length(result) - 1); if result[length(result)] = '.' then setlength(result, length(result) - 1); end; end; begin {$IFDEF UNICODE} if iBytes < 10 * ONE_MB then Result := IEBytesToStr(iBytes, ONE_KB) else if iBytes < 1 * ONE_GB then result := _FloatToFormatString(iBytes / ONE_MB, 2) + AnsiString(' MB') else result := _FloatToFormatString(iBytes / ONE_GB, 2) + AnsiString(' GB'); {$ELSE} if iBytes < 10 * ONE_MB then Result := IEBytesToStr(iBytes, ONE_KB) else if iBytes < 1 * ONE_GB then result := _FloatToFormatString(iBytes / ONE_MB, 2) + ' MB' else result := _FloatToFormatString(iBytes / ONE_GB, 2) + ' GB'; {$ENDIF} end; function IEStrToIntDef(const s: AnsiString; def: integer): integer; begin {$IFDEF UNICODE} result := StrToIntDef(string(s), def); {$ELSE} result := StrToIntDef(s, def); {$ENDIF} end; function IECopy(S: AnsiString; Index, Count: Integer): AnsiString; begin {$IFDEF UNICODE} result := AnsiString(Copy(string(S), Index, Count)); {$ELSE} result := Copy(S, Index, Count); {$ENDIF} end; function IEFloatToStrFA(Value: Extended; Format: TFloatFormat; Precision, Digits: Integer): AnsiString; begin result := AnsiString(FloatToStrF(Value, Format, Precision, Digits)); end; function IEFloatToStrFS(Value: Extended; Format: TFloatFormat; Precision, Digits: Integer): string; begin result := FloatToStrF(Value, Format, Precision, Digits); end; function IEIntToHex(Value: Integer; Digits: Integer): AnsiString; begin {$IFDEF UNICODE} result := AnsiString(IntToHex(Value, Digits)); {$ELSE} result := IntToHex(Value, Digits); {$ENDIF} end; function IEPos(Substr: AnsiString; S: AnsiString): Integer; begin {$IFDEF UNICODE} result := Pos(string(Substr), string(S)); {$ELSE} result := Pos(Substr, S); {$ENDIF} end; function IEExtractFilePathA(const FileName: AnsiString): AnsiString; begin {$IFDEF UNICODE} result := AnsiString(ExtractFilePath(string(FileName))); {$ELSE} result := ExtractFilePath(FileName); {$ENDIF} end; function IEExtractFilePathW(const FileName: WideString): WideString; var I: Integer; begin I := LastDelimiter('\:', FileName); Result := Copy(FileName, 1, I); end; function IEExtractFileNameW(const FileName: WideString): WideString; var I: Integer; begin I := LastDelimiter('\:', FileName); Result := Copy(FileName, I + 1, MaxInt); end; function IEExtractFileNameWithoutExt(const FileName: String): String; var iExtLen: integer; begin Result := ExtractFilename( FileName ); iExtLen := length( IEExtractFileExtW( Result )); if ( iExtLen > 0 ) and ( iExtLen < Length( Result )) then // avoid issues with folder names with a leading period Delete( Result, Length( Result ) - iExtLen + 1, iExtLen ); end; function IEStrDup(s: PAnsiChar): PAnsiChar; begin if s <> nil then begin getmem(result, IEStrLen(s) + 1); IEStrCopy(result, s); end else result := nil; end; function IEStrDupW(s: PWideChar): PWideChar; begin if s <> nil then begin getmem(result, IEStrLenW(s) * 2 + 2); IEStrCopyW(result, s); end else result := nil; end; function IEFileExists(const FileName: string): Boolean; var Attr: Cardinal; begin if IEGlobalSettings().UseDefaultFileExists then result := FileExists(FileName) else begin // FileGetSize is very slow, GetFileAttributes is much faster Attr := GetFileAttributes(Pointer(Filename)); Result := (Attr <> $FFFFFFFF) and (Attr and FILE_ATTRIBUTE_DIRECTORY = 0); end; end; function IEFileExistsW(const FileName: WideString): Boolean; var Attr: Cardinal; begin {$IFDEF UNICODE} if IEGlobalSettings().UseDefaultFileExists then result := FileExists(string(FileName)) else begin {$ENDIF} if IEGlobalSettings().UnicodeOS then Attr := GetFileAttributesW(PWideChar(Filename)) else Attr := GetFileAttributesA(PAnsiChar(AnsiString(Filename))); Result := (Attr <> $FFFFFFFF) and (Attr and FILE_ATTRIBUTE_DIRECTORY = 0); {$IFDEF UNICODE} end; {$ENDIF} end; procedure IEDrawGrayedOut(Canvas: TCanvas; XDst, YDst, WidthDst, HeightDst: integer; SX1, SY1, SX2, SY2: integer); var iec: TIECanvas; begin if (SX1 < SX2) and (SY1 < SY2) then begin iec := TIECanvas.Create(Canvas, false); iec.Brush.Color := clBlack; iec.Brush.Style := bsSolid; iec.Brush.Transparency := 150; inc(WidthDst); inc(HeightDst); inc(SX1); inc(SY1); inc(SX2); inc(SY2); iec.FillRect(Rect(XDst, YDst, SX1+1, YDst+HeightDst)); iec.FillRect(Rect(SX2-1, YDst, XDst+WidthDst, YDst+HeightDst)); iec.FillRect(Rect(SX1, YDst, SX2, SY1+1)); iec.FillRect(Rect(SX1, SY2, SX2, YDst+HeightDst)); iec.Free; end; end; // A TStream.CopyFrom that adjusts "Count" (or autocalculated Count) to source size without raising exceptions function IECopyFrom(Dest: TStream; Source: TStream; Count: int64): int64; const MaxBufSize = $2FFFF; var BufSize, N: Integer; Buffer: pbyte; begin if Count = 0 then begin Source.Position := 0; Count := Source.Size; end; if not (Source is TZDecompressionStream) and not (Source is TZCompressionStream) and not (Source is TIEHashStream) then begin Count := i64max(0, i64min(Count, Source.Size-Source.Position)); end; Result := Count; if Count > MaxBufSize then BufSize := MaxBufSize else BufSize := Count; GetMem(Buffer, BufSize); try while Count <> 0 do begin if Count > BufSize then N := BufSize else N := Count; Source.ReadBuffer(Buffer^, N); Dest.WriteBuffer(Buffer^, N); Dec(Count, N); end; finally FreeMem(Buffer, BufSize); end; end; procedure IEDecimalToFraction(value: double; var numerator: integer; var denominator: integer; accuracy: double); var z: double; prevDen, sign, sVal: int64; anum, aden: int64; num, den: int64; begin if value < 0.0 then sign := -1 else sign := +1; value := abs(value); if value = trunc(value) then begin numerator := trunc(value * sign); denominator := 1; exit end; if value < 1.0E-19 then begin numerator := sign; denominator := 999999999; exit end; if value > 1.0E+19 then begin numerator := 999999999 * sign; denominator := 1; exit end; // in case of failure num := trunc(value); den := 1; z := value; prevDen := 0; aden := 1; repeat z := 1.0 / (z - trunc(z)); sVal := aden; aden := aden * trunc(z) + prevDen; prevDen := sVal; anum := trunc(value * aden + 0.5); if (anum > 2147483647) or (aden > 2147483647) then break; num := anum; den := aden; until (abs((value - (anum / aden))) < accuracy) or (z = trunc(z)); numerator := sign * num; denominator := den; end; procedure IECopyTList(source: TList; dest: TList); var i: integer; begin dest.Count := source.Count; for i := 0 to source.Count-1 do dest[i] := source[i]; end; function IESendMessageTimeout(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM; fuFlags, uTimeout: UINT; lpdwResult: pointer): LRESULT; begin {$ifdef IEUSENEWSENDMESSAGETIMEOUT} result := SendMessageTimeout(hWnd, Msg, wParam, lParam, fuFlags, uTimeout, lpdwResult); {$else} result := SendMessageTimeout(hWnd, Msg, wParam, lParam, fuFlags, uTimeout, PDWORD(lpdwResult)^); {$endif} end; function IETextWidthW(Canvas: TCanvas; const Text: WideString): integer; var Size: TSize; begin Size.cx := 0; Size.cy := 0; Windows.GetTextExtentPoint32W(Canvas.Handle, PWideChar(Text), Length(Text), Size); result := Size.cx; end; function IETextHeightW(Canvas: TCanvas; const Text: WideString): integer; var Size: TSize; begin Size.cx := 0; Size.cy := 0; Windows.GetTextExtentPoint32W(Canvas.Handle, PWideChar(Text), Length(Text), Size); result := Size.cy; end; function IETruncateStr(sCaption : WideString; TruncSide: TIEMTruncSide; ACanvas : TCanvas; iMaxWidth : Integer) : Widestring; var tw: integer; ws1: WideString; q: Integer; begin Result := sCaption; case TruncSide of iemtsLeft: begin q := 1; repeat tw := IETextWidthW(ACanvas, Result); if (tw <= iMaxWidth) or (length(Result) < 2) then break; inc(q); ws1 := TrimRight( Copy(sCaption, 1, length(sCaption) - q )); if ws1 = '' then break; Result := ws1 + '...'; until false; end; iemtsRight: begin q := 1; repeat tw := IETextWidthW(ACanvas, Result); if (tw <= iMaxWidth) or (length(Result) < 2) then break; inc(q); ws1 := TrimLeft( Copy(sCaption, q, length(sCaption))); if ws1 = '' then break; Result := '...' + ws1; until false; end; end; end; function IEFileTimeToDateTime(ft: TFileTime): TDateTime; var LocalFileTime: TFileTime; iDosDT: integer; begin Result := 0.0; if ft.dwLowDateTime + ft.dwHighDateTime = 0 then EXIT; if not FileTimeToLocalFileTime(ft, LocalFileTime) then EXIT; if not FileTimeToDosDateTime(LocalFileTime, longRec(iDosDT).hi, longRec(iDosDT).lo) then EXIT; if iDosDT <> -1 then Result := FileDateToDateTime(iDosDT); end; function IELargeFileSize(nFileSizeHigh, nFileSizeLow: DWORD) : Int64; begin Int64Rec(Result).Lo := nFileSizeLow; Int64Rec(Result).Hi := nFileSizeHigh; end; {!! IEGetFileDetails Declaration function IEGetFileDetails(const sFilename: string; out iFileSizeBytes: Int64; out dtCreateDate: TDateTime; out dtEditDate: TDateTime ): boolean; Description Return the size, create date and last edit date of a file. Result is false if an error occured. See Also - !!} function IEGetFileDetails(const sFilename: string; out iFileSizeBytes: Int64; out dtCreateDate: TDateTime; out dtEditDate: TDateTime ): boolean; var Data: TWin32FindData; H: THandle; ErrorMode: word; begin result := true; iFileSizeBytes := 0; dtCreateDate := 0; dtEditdate := 0; { turn off critical errors } ErrorMode := SetErrorMode(SEM_FailCriticalErrors); try try H := FindFirstFile(PCHAR(sFilename), Data); if H <> INVALID_HANDLE_VALUE then try iFileSizeBytes := IELargeFileSize(Data.nFileSizeHigh, Data.nFileSizeLow); dtEditDate := IEFileTimeToDateTime(Data.ftLastWriteTime); try dtCreateDate := IEFileTimeToDateTime(Data.ftCreationTime); except dtCreateDate := dtEditDate; end; finally Windows.FindClose(H); end else Result := false; except result := false; end; finally { restore old error mode } SetErrorMode(ErrorMode); end; end; {!! IEFileSetDate Declaration function FileSetDate(const sFilename: string; DateTime: TDateTime): boolean; Description Same as sysutils.FileSetDate but takes a TDateTime as a parameter. !!} function IEFileSetDate(const sFilename: string; DateTime: TDateTime): boolean; var liHandle: INTEGER; begin result := False; if DateTime <> 0 then try liHandle := FileOpen(sFileName, fmOpenReadWrite or fmShareDenyNone); if liHandle > 0 then begin result := FileSetDate(liHandle, DateTimeToFileDate(DateTime)) <> 0; FileClose(liHandle); end; except // ERROR end; end; ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// // convert a real value into a string with decimal places function IEFloatToFormatString(Value: Extended; iDecimalCount: Integer; bStripZeros: boolean): string; begin result := Format('%.' + inttostr( imax(0, iDecimalCount )) + 'f', [Value]); if bStripZeros and (pos('.', result) > 0) then while result[length(result)] = '0' do setlength(result, length(result) - 1); if result[length(result)] = '.' then setlength(result, length(result) - 1); end; ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// function IE2DPoint(X, Y: double): TIE2DPoint; begin result.X := X; result.Y := Y; end; {$ifndef IEHASUINT64} function UInt64(v : Pointer) : int64; begin result := int64(DWORD(v)); end; function UInt64(v : Integer) : int64; begin result := int64(DWORD(v)); end; {$endif} {$ifndef IEHASNATIVEINT} function Nativeint(v: Pointer): DWORD; begin result := DWORD(v); end; function Nativeint(v: Char): DWORD; begin result := DWORD(v); end; {$endif} {$IfNDef Delphi6orNewer} function Get8087CW: Word; // for D5 asm PUSH 0 FNSTCW [ESP].Word POP EAX end; {$ENDIF} {$ifdef IEVISION} function IEVisionBGR8ToTRGB(visionBGR8: TIEVisionBGR8): TRGB; begin result.b := visionBGR8.b; result.g := visionBGR8.g; result.r := visionBGR8.r; end; function IETRGBToVisionBGR8(rgb: TRGB): TIEVisionBGR8; begin result.b := rgb.b; result.g := rgb.g; result.r := rgb.r; end; // from PixleFormat to IEVision channelFormat/channelCount procedure IEVisionConvPixelFormat(PixelFormat: TIEPixelFormat; out channelFormat: TIEVisionChannelFormat; out channelCount: integer); begin channelFormat := ievUINT8; channelCount := 0; case PixelFormat of ie1g: begin channelFormat := ievUINT1; channelCount := 1; end; ie8p: begin channelFormat := ievUINT8; channelCount := 1; end; ie8g: begin channelFormat := ievUINT8; channelCount := 1; end; ie16g: begin channelFormat := ievUINT16; channelCount := 1; end; ie24RGB: begin channelFormat := ievUINT8; channelCount := 3; end; ie32f: begin channelFormat := ievFLOAT32; channelCount := 1; end; ieCMYK: begin channelFormat := ievUINT8; channelCount := 4; end; ie48RGB: begin channelFormat := ievUINT16; channelCount := 3; end; ieCIELab: begin channelFormat := ievUINT8; channelCount := 3; end; ie32RGB: begin channelFormat := ievUINT8; channelCount := 4; end; end; end; // from IEVision channelFormat/channelCount to PixleFormat function IEVisionConvPixelFormat(channelFormat: TIEVisionChannelFormat; channelCount: integer): TIEPixelFormat; begin result := ienull; // invalid case channelFormat of ievUINT1: begin case channelCount of 1: result := ie1g; end; end; ievUINT8: begin case channelCount of 1: result := ie8g; 3: result := ie24RGB; 4: result := ie32RGB; end; end; ievUINT16: begin case channelCount of 1: result := ie16g; 3: result := ie48RGB; end; end; ievFLOAT32: begin case channelCount of 1: result := ie32f; end; end; end; end; {$endif} /////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////// // Swaps two values procedure IESwap(var a: integer; var b: integer); var t: integer; begin t := a; a := b; b := t; end; procedure IESwap(var a: double; var b: double); var t: double; begin t := a; a := b; b := t; end; procedure IESwap(var a: boolean; var b: boolean); var t: boolean; begin t := a; a := b; b := t; end; procedure IESwap(var a: TIELayerMagnification; var b: TIELayerMagnification); var t: TIELayerMagnification; begin t := a; a := b; b := t; end; procedure IESwap(var a: TIERenderOperation; var b: TIERenderOperation); var t: TIERenderOperation; begin t := a; a := b; b := t; end; procedure IESwap(var a: pointer; var b: pointer); var t: pointer; begin t := a; a := b; b := t; end; procedure IESwap(var a: TResampleFilter; var b: TResampleFilter); var t: TResampleFilter; begin t := a; a := b; b := t; end; procedure IESwap(var a: AnsiString; var b: AnsiString); var t: AnsiString; begin t := a; a := b; b := t; end; {$IfDef UNICODE} procedure IESwap(var a: UnicodeString; var b: UnicodeString); var t: UnicodeString; begin t := a; a := b; b := t; end; {$EndIf} procedure IESwap(var a: TGuid; var b: TGuid); var t: TGuid; begin t := a; a := b; b := t; end; procedure IESwap(var a: TRGB; var b: TRGB); var t: TRGB; begin t := a; a := b; b := t; end; procedure IESwap(var a: TIEArrayOfTRGB; var b: TIEArrayOfTRGB); var t: TIEArrayOfTRGB; begin t := a; a := b; b := t; end; procedure IESwap(var a: TRect; var b: TRect); var t: TRect; begin t := a; a := b; b := t; end; procedure IESwap(var a: TIEShape; var b: TIEShape); var t: TIEShape; begin t := a; a := b; b := t; end; procedure IESwap(var a: TColor; var b: TColor); var t: TColor; begin t := a; a := b; b := t; end; procedure IESwap(var a: TFont; var b: TFont); var tmpCharset: TFontCharset; tmpColor: TColor; tmpHeight: Integer; tmpName: TFontName; tmpStyle: TFontStyles; begin tmpCharset := a.Charset; a.Charset := b.Charset; b.Charset := tmpCharset; tmpColor := a.Color; a.Color := b.Color; b.Color := tmpColor; tmpHeight := a.Height; a.Height := b.Height; b.Height := tmpHeight; tmpName := a.Name; a.Name := b.Name; b.Name := tmpName; tmpStyle := a.Style; a.Style := b.Style; b.Style := tmpStyle; end; procedure IESwap(var a: TPoint; var b: TPoint); var t: TPoint; begin t := a; a := b; b := t; end; /////////////////////////////////////////////////////////////////////////////////////////////////////////// // timeout support function IESetupTimeout(): dword; begin result := GetTickCount(); end; function IEIsTimeoutExpired(startTime: dword; timeout: dword): boolean; var diff: dword; curr: dword; begin curr := GetTickCount(); if startTime > curr then // overflow diff := $FFFFFFFF - startTime + curr else diff := curr - startTime; result := diff >= timeout; end; /////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////// {!! IERectangle Declaration function IERectangle(x, y, width, height: integer): ; overload; function IERectangle(Rect: TRect): ; overload; Description Create a TIERectangle structure. !!} function IERectangle(x, y, width, height: integer): TIERectangle; begin result.x := x; result.y := y; result.width := width; result.height := height; end; function IERectangle(Rect: TRect): TIERectangle; begin with Rect do begin result.x := Left; result.y := Top; result.width := Right - Left; result.height := Bottom - Top; end; end; //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // TIEClientSocket const WSADESCRIPTION_LEN = 256; WSASYS_STATUS_LEN = 128; INVALID_SOCKET = pointer(-1); SOCKET_ERROR = -1; AF_INET = 2; SOCK_STREAM = 1; AF_UNSPEC = 0; IPPROTO_TCP = 6; TCP_NODELAY = $0001; SD_BOTH = 2; type TWSAData = record wVersion: Word; wHighVersion: Word; szDescription: array[0..WSADESCRIPTION_LEN] of AnsiChar; szSystemStatus: array[0..WSASYS_STATUS_LEN] of AnsiChar; iMaxSockets: Word; iMaxUdpDg: Word; lpVendorInfo: PAnsiChar; end; SunB = packed record s_b1, s_b2, s_b3, s_b4: byte; end; SunW = packed record s_w1, s_w2: word; end; in_addr = record case integer of 0: (S_un_b: SunB); 1: (S_un_w: SunW); 2: (S_addr: dword); end; TInAddr = in_addr; sockaddr_in = record case Integer of 0: (sin_family: word; sin_port: word; sin_addr: TInAddr; sin_zero: array[0..7] of AnsiChar); 1: (sa_family: word; sa_data: array[0..13] of AnsiChar) end; TSockAddr = sockaddr_in; PSOCKADDR = ^TSockAddr; paddrinfoA = ^addrinfoA; addrinfoA = packed record ai_flags: integer; ai_family: integer; ai_socktype: integer; ai_protocol: integer; ai_addrlen: TIESizeT; ai_canonname: PAnsiChar; ai_addr: PSOCKADDR; ai_next: paddrinfoA; end; TIE_WSAStartup = function(wVersionRequired: word; var WSData: TWSAData): Integer; stdcall; TIE_WSACleanup = function(): Integer; stdcall; TIE_recv = function(s: pointer; var Buf; len, flags: Integer): Integer; stdcall; TIE_send = function(s: pointer; var Buf; len, flags: Integer): Integer; stdcall; TIE_socket = function(af, Struct, protocol: Integer): pointer; stdcall; TIE_getaddrinfo = function(nodename: PAnsiChar; servname: PAnsiChar; hints: paddrinfoA; var res: paddrinfoA): integer; stdcall; TIE_freeaddrinfo = procedure(addr: paddrinfoA); stdcall; TIE_connect = function(s: pointer; var name: TSockAddr; namelen: Integer): Integer; stdcall; TIE_setsockopt = function(s: pointer; level, optname: Integer; optval: PAnsiChar; optlen: Integer): Integer; stdcall; TIE_shutdown = function(s: pointer; how: Integer): Integer; stdcall; TIE_closesocket = function(s: pointer): Integer; stdcall; var IE_SockLibInitCS: TCriticalSection; IE_SockLib: THandle = 0; IE_SockLibCount: integer = 0; IE_WSAStartup: TIE_WSAStartup = nil; IE_WSACleanup: TIE_WSACleanup = nil; IE_recv: TIE_recv = nil; IE_send: TIE_send = nil; IE_socket: TIE_socket = nil; IE_getaddrinfo: TIE_getaddrinfo = nil; IE_freeaddrinfo: TIE_freeaddrinfo = nil; IE_connect: TIE_connect = nil; IE_setsockopt: TIE_setsockopt = nil; IE_shutdown: TIE_shutdown = nil; IE_closesocket: TIE_closesocket = nil; function IEInitializeSocketLib: boolean; begin IE_SockLibInitCS.Enter(); result := true; try if IE_SockLibCount = 0 then begin result := false; IE_SockLib := LoadLibrary('Ws2_32.dll'); if IE_SockLib<>0 then begin IE_WSAStartup := GetProcAddress(IE_SockLib, 'WSAStartup'); IE_WSACleanup := GetProcAddress(IE_SockLib, 'WSACleanup'); IE_recv := GetProcAddress(IE_SockLib, 'recv'); IE_send := GetProcAddress(IE_SockLib, 'send'); IE_socket := GetProcAddress(IE_SockLib, 'socket'); IE_getaddrinfo := GetProcAddress(IE_SockLib, 'getaddrinfo'); IE_freeaddrinfo := GetProcAddress(IE_SockLib, 'freeaddrinfo'); IE_connect := GetProcAddress(IE_SockLib, 'connect'); IE_setsockopt := GetProcAddress(IE_SockLib, 'setsockopt'); IE_shutdown := GetProcAddress(IE_SockLib, 'shutdown'); IE_closesocket := GetProcAddress(IE_SockLib, 'closesocket'); result := assigned(@IE_WSAStartup) and assigned(@IE_WSACleanup) and assigned(@IE_recv) and assigned(@IE_send) and assigned(@IE_socket) and assigned(@IE_getaddrinfo) and assigned(@IE_freeaddrinfo) and assigned(@IE_connect) and assigned(@IE_setsockopt) and assigned(@IE_shutdown) and assigned(@IE_closesocket); if not result then FreeLibrary(IE_SockLib); end; end; if result then inc(IE_SockLibCount); finally IE_SockLibInitCS.Leave(); end; end; procedure IEFinalizeSocketLib; begin IE_SockLibInitCS.Enter(); try dec(IE_SockLibCount); if IE_SockLibCount = 0 then begin FreeLibrary(IE_SockLib); IE_SockLib := 0; end; finally IE_SockLibInitCS.Leave(); end; end; constructor TIEClientSocket.Create; var versionRequired: word; WSData: TWSAData; begin inherited; m_socket := INVALID_SOCKET; m_littleEndian := false; versionRequired := 2 or (2 shl 8); if not IEInitializeSocketLib() or (IE_WSAStartUp(versionRequired, WSData)<>0) then raise EIERFBError.Create('Failed to startup WinSock'); end; destructor TIEClientSocket.Destroy; begin IE_WSACleanUp(); IEFinalizeSocketLib(); inherited; end; procedure TIEClientSocket.ReceiveBuffer(buf: pointer; len: integer); var r, tr: integer; begin tr := 0; while tr < len do begin r := IE_recv(m_socket, pbyte(buf)^, len-tr, 0); if r = 0 then raise EIERFBError.Create('Connection closed') else if r = SOCKET_ERROR then raise EIERFBError.Create('Receive error'); inc(tr, r); inc(pbyte(buf), r); end; end; function TIEClientSocket.ReceiveBufferSilent(buf: pointer; len: integer): Boolean; var r, tr: integer; begin result := true; tr := 0; while tr < len do begin r := IE_recv(m_socket, pbyte(buf)^, len-tr, 0); if (r = 0) or (r = SOCKET_ERROR) then begin result := false; break; end; inc(tr, r); inc(pbyte(buf), r); end; end; procedure TIEClientSocket.SendBuffer(buf: pointer; len: integer); var s, ts: integer; begin ts := 0; while ts < len do begin s := IE_send(m_socket, pbyte(buf)^, len-ts, 0); if s = SOCKET_ERROR then raise EIERFBError.Create('Send error'); inc(ts, s); inc(pbyte(buf), s); end; end; function TIEClientSocket.ReceiveByte(): byte; begin ReceiveBuffer(@result, 1); end; function TIEClientSocket.ReceiveByteSilent(var b: Byte): Boolean; begin result := ReceiveBufferSilent(@b, 1); end; procedure TIEClientSocket.ReceivePad(len: integer); begin while len>0 do begin ReceiveByte(); dec(len); end; end; function TIEClientSocket.ReceiveWord(): word; begin ReceiveBuffer(@result, 2); if not m_littleEndian then result := IESwapWord(result); end; function TIEClientSocket.ReceiveDWord(): dword; begin ReceiveBuffer(@result, 4); if not m_littleEndian then result := IESwapDWord(result); end; procedure TIEClientSocket.SendByte(value: byte); begin SendBuffer(@value, 1); end; procedure TIEClientSocket.SendPad(len: integer); begin while len>0 do begin SendByte(0); dec(len); end; end; procedure TIEClientSocket.SendWord(value: word); begin if not m_littleEndian then value := IESwapWord(value); SendBuffer(@value, 2); end; procedure TIEClientSocket.SendDWord(value: dword); begin if not m_littleEndian then value := IESwapDWord(value); SendBuffer(@value, 4); end; procedure TIEClientSocket.Connect(const Address: string; Port: word); var addr: paddrinfoA; hints: addrinfoA; PortStr: AnsiString; i: integer; dw: dword; begin try m_socket := IE_socket(AF_INET, SOCK_STREAM, 0); if m_socket = INVALID_SOCKET then raise EIERFBError.Create('Failed to open socket'); addr := nil; ZeroMemory(@hints, sizeof(addrinfoA)); hints.ai_family := AF_UNSPEC; hints.ai_socktype := SOCK_STREAM; hints.ai_protocol := IPPROTO_TCP; PortStr := IEIntToStr(Port); if IE_getaddrinfo(PAnsiChar(AnsiString(Address)), PAnsiChar(PortStr), @hints, addr) <> 0 then raise EIERFBError.Create('Cannot resolve host name'); i := IE_connect(m_socket, addr^.ai_addr^, addr^.ai_addrlen); IE_freeaddrinfo(addr); if i = SOCKET_ERROR then raise EIERFBError.Create('Connection error'); dw := 1; IE_setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, PAnsiChar(@dw), sizeof(BOOL)); except if m_socket<>INVALID_SOCKET then begin IE_shutdown(m_socket, SD_BOTH); IE_closesocket(m_socket); m_socket := INVALID_SOCKET; end; raise; end; end; procedure TIEClientSocket.Disconnect(); begin if Connected then begin IE_shutdown(m_socket, SD_BOTH); IE_closesocket(m_socket); m_socket := INVALID_SOCKET; end; end; function TIEClientSocket.GetConnected: boolean; begin result := m_socket <> INVALID_SOCKET; end; // TIEClientSocket //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// constructor TIEByteArray.Create(InitBlockSize: integer); begin inherited Create; fBlockSize := InitBlockSize; fSize := 0; fRSize := fBlockSize; getmem(Data, fRSize); end; destructor TIEByteArray.Destroy; begin freemem(Data); inherited; end; procedure TIEByteArray.AddByte(v: byte); begin SetSize(fSize + 1); Data^[fSize - 1] := v; end; procedure TIEByteArray.Clear; begin freemem(Data); fSize := 0; fRSize := fBlockSize; getmem(Data, fRSize); end; procedure TIEByteArray.SetSize(v: integer); var tmp: pbytearray; begin if v > fSize then begin // increase if v > fRSize then begin fRSize := v + fBlockSize; getmem(tmp, fRSize); CopyMemory(tmp, Data, fSize); freemem(Data); Data := tmp; end; end else begin // decrease if v < (fRSize - fBlockSize) then begin fRSize := v + fBlockSize; getmem(tmp, fRSize); CopyMemory(tmp, Data, v); freemem(Data); Data := tmp; end; end; fSize := v; end; // returns number of bytes written function TIEByteArray.AppendFromStream(Stream: TStream; Count: integer): integer; var l: integer; begin l := fSize; SetSize(fSize + Count); result := Stream.Read(Data^[l], Count); if result < Count then SetSize(l + result); end; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////// // Gestures support var IEGesturesUser32Lib: THandle = 0; procedure IEInitialize_gestures(); begin IEGesturesUser32Lib := LoadLibrary('User32.dll'); if IEGesturesUser32Lib <> 0 then begin IEGetGestureInfo := GetProcAddress(IEGesturesUser32Lib, 'GetGestureInfo'); IECloseGestureInfoHandle := GetProcAddress(IEGesturesUser32Lib, 'CloseGestureInfoHandle'); IESetGestureConfig := GetProcAddress(IEGesturesUser32Lib, 'SetGestureConfig'); IEUnregisterTouchWindow := GetProcAddress(IEGesturesUser32Lib, 'UnregisterTouchWindow'); if @IEGetGestureInfo = nil then IEFinalize_gestures(); end; end; procedure IEFinalize_gestures(); begin if IEGesturesUser32Lib <> 0 then begin FreeLibrary(IEGesturesUser32Lib); IEGesturesUser32Lib := 0; end; end; function IEHasGestures(): boolean; begin result := IEGesturesUser32Lib <> 0; end; // Gestures support /////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure InitIECosineTab; var i: integer; begin for i := 0 to 255 do IECosineTab[i] := Round(64 - Cos(i * Pi / 255) * 64); end; procedure IEBezier2D4Controls(p0: TPoint; c0: TPoint; c1: TPoint; p1: TPoint; pResultArray: PPointArray; nSteps: integer); var t, t_sq, t_cb, incr, r1, r2, r3, r4: double ; i: integer ; begin incr := 1.0/nSteps; t := incr; for i := 0 to nSteps-1 do begin t_sq := t * t; t_cb := t * t_sq; r1 := 1 - 3*t + 3*t_sq - t_cb; r2 := 3*t - 6*t_sq + 3*t_cb; r3 := 3*t_sq - 3*t_cb; r4 := t_cb; pResultArray[i].x := round(r1*p0.x + r2*c0.x + r3*c1.x + r4*p1.x); pResultArray[i].y := round(r1*p0.y + r2*c0.y + r3*c1.y + r4*p1.y); t := t+incr; end; end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// GRADIENT const GRADIENT_FILL_RECT_V = $00000001; GRADIENT_FILL_RECT_H = $00000000; type Trivertex = packed record X, Y: DWORD; Red, Green, Blue, Alpha: Word; end; TGradientFill = function(DC: HDC; pVertex: Pointer; dwNumVertex: DWORD; pMesh: Pointer; dwNumMesh, dwMode: DWORD): LongBool; stdcall; TRGBRec = packed record case Integer of 1: (RGBVal: LongInt); 0: (Red, Green, Blue, None: Byte); end; TGradientRect = packed record UpperLeft: ULONG; LowerRight: ULONG; end; var FhGradientFill: HMODULE; FGradientFill: TGradientFill; function LoadGradLibrary: boolean; begin result := True; if FhGradientFill = 0 then begin FhGradientFill := LoadLibrary('MSIMG32.DLL'); if FhGradientFill > 0 then FGradientFill := GetProcAddress(FhGradientFill, 'GradientFill') else result := false; // MSIMG32 could not be loaded end; end; function IEDrawGradient(R: TRect; DC: HDC; ColorStart, ColorStop: TColor; bVertical: boolean): Boolean; var Gr: TGradientRect; Vert: array[0..1] of Trivertex; StartColor, StopColor: TRGBRec; begin result := LoadGradLibrary; if not result then exit; StartColor.RGBVal := ColorToRGB(ColorStart); StopColor.RGBVal := ColorToRGB(ColorStop); Gr.UpperLeft := 0; Gr.LowerRight := 1; Vert[0].x := r.TopLeft.x; Vert[0].y := r.TopLeft.y; Vert[0].Red := StartColor.Red shl 8; Vert[0].Green := StartColor.Green shl 8; Vert[0].Blue := StartColor.Blue shl 8; Vert[0].Alpha := $0000; Vert[1].x := r.BottomRight.x; Vert[1].y := r.BottomRight.y; Vert[1].Red := StopColor.Red shl 8; Vert[1].Green := StopColor.Green shl 8; Vert[1].Blue := StopColor.Blue shl 8; Vert[1].Alpha := $0000; if bVertical then Result := FGradientFill(DC, @Vert, 2, @Gr, 1, GRADIENT_FILL_RECT_V) else Result := FGradientFill(DC, @Vert, 2, @Gr, 1, GRADIENT_FILL_RECT_H); end; // Return the standard BitsPerSample and SamplesPerPixel for a PixelFormat procedure IEPixelFormatToBPSAndSPP(PixelFormat: TIEPixelFormat; out iBitsPerSample: Integer; out iSamplesPerPixel: Integer); begin case PixelFormat of ie1g: begin iBitsPerSample := 1; iSamplesPerPixel := 1; end; ie8p, ie8g: begin iBitsPerSample := 8; iSamplesPerPixel := 1; end; ie16g: begin iBitsPerSample := 16; iSamplesPerPixel := 1; end; else { ie24RGB } begin iBitsPerSample := 8; iSamplesPerPixel := 3; end; end; end; // Return the standard BitsPerSample and SamplesPerPixel for a BitCount // bAllow32bit=False: 32 bit return the same as 24bit procedure BitCountToBPSAndSPP(BitCount: Integer; bAllow32bit: Boolean; out iBitsPerSample: Integer; out iSamplesPerPixel: Integer); begin case BitCount of 1: begin iBitsPerSample := 1; iSamplesPerPixel := 1; end; 4: begin iBitsPerSample := 4; iSamplesPerPixel := 1; end; 8: begin iBitsPerSample := 8; iSamplesPerPixel := 1; end; 15: begin iBitsPerSample := 5; iSamplesPerPixel := 3; end; 32: if bAllow32bit then begin iBitsPerSample := 8; iSamplesPerPixel := 4; end else begin iBitsPerSample := 8; iSamplesPerPixel := 3; end; else { 16, 24 } begin iBitsPerSample := 8; iSamplesPerPixel := 3; end; end; end; function ProgressRec(Sender: TObject; OnProgress: TIEProgressEvent; var bAborting: Boolean) : TProgressRec; begin Result.Sender := Sender; Result.fOnProgress := OnProgress; Result.Aborting := @bAborting; end; function ProgressRec(Sender: TObject; OnProgress: TIEProgressEvent; pAborting: PBoolean) : TProgressRec; begin Result.Sender := Sender; Result.fOnProgress := OnProgress; Result.Aborting := pAborting; end; function NullProgressRec(var bAborting: Boolean; bResetAborting : Boolean = true) : TProgressRec; begin if bResetAborting then bAborting := False; Result.Sender := nil; Result.fOnProgress := nil; Result.Aborting := @bAborting; end; function NullProgressRec(pAborting: PBoolean; bResetAborting : Boolean = true) : TProgressRec; begin if bResetAborting and ( pAborting <> nil ) then pAborting^ := False; Result.Sender := nil; Result.fOnProgress := nil; Result.Aborting := pAborting; end; {$IfNdef Delphi6orNewer} function RoundTo(const AValue: Double; ADigit: Integer): Double; var LFactor: Double; begin LFactor := IntPower(10, ADigit); Result := Round(AValue / LFactor) * LFactor; end; {$endif} {$IfNdef Delphi6orNewer} function Sign(const AValue: Double): Integer; begin if AValue < 0 then Result := -1 else if AValue > 0 then Result := 1 else Result := 0; end; {$ENDIF} procedure IESetStringA(var S: AnsiString; Buffer: PAnsiChar; Length: Integer); begin SetLength(S, Length); CopyMemory(@S[1], Buffer, Length); end; {$IfNdef Delphi7orNewer} function BoolToStr(B: Boolean): string; const cSimpleBoolStrs: array [boolean] of String = ('0', '-1'); begin Result := cSimpleBoolStrs[B]; end; {$endif} function IECreateRect(Left, Top, Right, Bottom: Integer): TRect; begin {$IfNdef Delphi7orNewer} Result.Left := Left; Result.Top := Top; Result.Right := Right; Result.Bottom := Bottom; {$else} Result := Types.Rect(Left, Top, Right, Bottom); {$endif} end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// var ieImageEnInitializedMagik: AnsiString; ieImageEnInitialized: integer; // 0=not inizialized >0 initialized n times ieImageEnInit_CS: TCriticalSection; // IEInitializeImageEn and IEFinalizeImageEn must be called in initialization/finalization section only of hyieutils // or in constructor/descructors of objects, or in functions, but not in initialization/finalization section of other units. // Attention to deadlocks (for example you cannot call IEInitializeImageEn in TImageEnIO creator). procedure IEInitializeImageEn; begin if ieImageEnInitializedMagik <> 'STATICINIT' then begin // static variables not still intialized, do it here ieImageEnInitializedMagik := 'STATICINIT'; ieImageEnInitialized := 0; ieImageEnInit_CS := TCriticalSection.Create(); end; ieImageEnInit_CS.Enter(); try if ieImageEnInitialized = 0 then begin // initialize IEInitialize_iegdiplus(); IEInitialize_hyiedefs(); IEInitialize_hyieutils(); IEInitialize_ievect(); IEInitialize_imageenio(); IEInitialize_iexBitmaps; IEInitialize_imageenproc(); IEInitialize_imageenview(); IEInitialize_tifccitt(); IEInitialize_ietextc(); IEInitialize_iepresetim(); IEInitialize_gestures(); end; inc(ieImageEnInitialized); finally ieImageEnInit_CS.Leave(); end; end; procedure IEFinalizeImageEn; var freecriticalsec: boolean; begin if ieImageEnInitializedMagik<>'STATICINIT' then exit; freecriticalsec := false; ieImageEnInit_CS.Enter(); try dec(ieImageEnInitialized); if ieImageEnInitialized = 0 then begin // finalize IEFinalize_gestures(); IEFinalize_iepresetim(); IEFinalize_ietextc(); IEFinalize_tifccitt(); IEFinalize_imageenview(); IEFinalize_imageenproc(); IEFinalize_imageenio(); IEFinalize_iexBitmaps; IEFinalize_ievect(); {$IFDEF IEINCLUDEJPEG2000} IEFinalize_iej2000(); // initialized in iej2000 reading/writing functions (not in IEInitializeImageEn) {$ENDIF} IEFinalize_hyieutils(); IEFinalize_hyiedefs(); IEFinalize_iegdiplus(); {$IFDEF IEVISION} // note: initialization done in IEVisionAvailable() and IELibAvailable() instead of IEInitializeImageEn() IEFinalize_ielib(); IEFinalize_ievision(); {$ENDIF} {$IFDEF IEINCLUDEMISCPLUGINS} TIEMiscPluginsImageMagick.Finalize(); {$ENDIF} IEGlobalSettings().DestroySingletonInstance(); ieImageEnInitializedMagik := ''; freecriticalsec := true; end; finally ieImageEnInit_CS.Leave(); if freecriticalsec then FreeAndNil(ieImageEnInit_CS); end; end; procedure IEPrintLogWrite(const ss: String); begin if iegPrintLogFileName <> '' then begin closefile(iegPrintLogFile); assignfile(iegPrintLogFile, string(iegPrintLogFileName)); append(iegPrintLogFile); WriteLn(iegPrintLogFile, datetostr(date) + ' ' + timetostr(time) + ' : ' + ss); Flush(iegPrintLogFile); end; end; ///////////////////////////////////////////////////////////////////////////////////// procedure iedswap(var d1, d2: Double); var v: Double; begin v := d1; d1 := d2; d2 := v; end; procedure i64swap(var v1, v2: int64); var v: int64; begin v := v1; v1 := v2; v2 := v; end; ///////////////////////////////////////////////////////////////////////////////////// function Floor(X: Extended): Integer; begin Result := Trunc(X); if Frac(X) < 0 then Dec(Result); end; function CreateCMYK(c, m, y, k: byte): TCMYK; begin result.c := c; result.m := m; result.y := y; result.k := k; end; function CreateRGB(r, g, b: byte): TRGB; begin result.r := r; result.g := g; result.b := b; end; function CreateRGB48(r, g, b: word): TRGB48; begin result.r := r; result.g := g; result.b := b; end; function CreateRGBA(r, g, b, a: byte): TRGBA; begin result.r := r; result.g := g; result.b := b; result.a := a; end; function CreateRGBFromInt(r, g, b: Integer): TRGB; begin result.r := blimit(r); result.g := blimit(g); result.b := blimit(b); end; ///////////////////////////////////////////////////////////////////////////////////// function TRGB2TColor(rgb: TRGB): TColor; begin with rgb do result := r or (g shl 8) or (b shl 16); end; ///////////////////////////////////////////////////////////////////////////////////// function RGB2TColor(r, g, b: Integer): TColor; begin result := r or (g shl 8) or (b shl 16); end; ///////////////////////////////////////////////////////////////////////////////////// function TColor2TRGB(cl: TColor): TRGB; var rgb: longint; begin rgb := colortorgb(cl); result.r := $FF and rgb; result.g := ($FF00 and rgb) shr 8; result.b := ($FF0000 and rgb) shr 16; end; function TColor2TRGBA(cl: TColor; transparency: Integer): TRGBA; var rgb: longint; begin rgb := colortorgb(cl); result.r := $FF and rgb; result.g := ($FF00 and rgb) shr 8; result.b := ($FF0000 and rgb) shr 16; result.a := transparency; end; // gets alpha from TColor // Cannot accept colors like clRed function TColor2TRGBA(cl: TColor): TRGBA; var rgb: longint; begin rgb := colortorgb(cl); result.r := $FF and rgb; result.g := ($FF00 and rgb) shr 8; result.b := ($FF0000 and rgb) shr 16; result.a := ($FF000000 and rgb) shr 24; end; function IEApplyAlphaToColor(rgb: TRGB; Alpha: Integer): TRGB; begin Result := rgb; if (Result.r = 255) and (Result.g = 255) and (Result.b = 255) then begin // All white Result.r := Alpha; Result.g := Alpha; Result.b := Alpha; end else begin Result.r := Trunc( Alpha / 255 * Result.r ) + ( 255 - Alpha ); Result.g := Trunc( Alpha / 255 * Result.g ) + ( 255 - Alpha ); Result.b := Trunc( Alpha / 255 * Result.b ) + ( 255 - Alpha ); end; end; function IEApplyAlphaToColor(Color: TColor; Alpha: Integer): TColor; begin Result := TRGB2TColor( IEApplyAlphaToColor( TColor2TRGB( Color ), Alpha )); end; ///////////////////////////////////////////////////////////////////////////////////// function dmin(v1, v2: Double): Double; begin if v1 < v2 then dmin := v1 else dmin := v2; end; function dmax(v1, v2: Double): Double; begin if v1 > v2 then dmax := v1 else dmax := v2; end; function dwmax(v1, v2: DWord): DWord; begin if v1 > v2 then result := v1 else result := v2; end; function imax(v1, v2: Integer): Integer; {$ifdef IEUSEASM} asm cmp edx,eax jng @1 mov eax,edx @1: end; {$else} begin if v1 > v2 then result := v1 else result := v2; end; {$endif} function imin(v1, v2: Integer): Integer; {$ifdef IEUSEASM} asm cmp eax,edx jng @1 mov eax,edx @1: end; {$else} begin if v1 < v2 then result := v1 else result := v2; end; {$endif} {$ifdef IEHASUINT64} function u64min(v1, v2: uint64): uint64; begin if v1 < v2 then result := v1 else result := v2; end; {$endif} function i64min(v1, v2: int64): int64; begin if v1 < v2 then result := v1 else result := v2; end; function i64max(v1, v2: int64): int64; begin if v1 > v2 then result := v1 else result := v2; end; // vv=eax result=eax // min=edx // max=ecx function ilimit(vv, min, max: Integer): Integer; {$ifdef IEUSEASM} asm cmp eax,edx jg @1 // vv>min mov eax,edx ret @1: cmp eax,ecx jl @2 // vv max then result := max else result := vv; end; {$endif} // limit 0 between 255 function blimit(vv: Integer): Integer; {$ifdef IEUSEASM} asm OR EAX, EAX JNS @@plus XOR EAX, EAX RET @@plus: CMP EAX, 255 JBE @@END MOV EAX, 255 @@END: end; {$else} begin if vv < 0 then result := 0 else if vv > 255 then result := 255 else result := vv; end; {$endif} function wlimit(vv: Integer): word; begin if vv < 0 then result := 0 else if vv>65535 then result := 65535 else result := vv; end; ///////////////////////////////////////////////////////////////////////////////////// {$ifdef IEUSEASM} procedure iswap(var B1, B2: LongInt); assembler; asm push EBX mov ecx, [EAX]; mov ebx, [EDX]; mov [EDX], ecx mov [EAX], ebx pop EBX end; {$else} procedure iswap(var B1, B2: LongInt); var temp: LongInt; begin temp := B1; B1 := B2; B2 := temp; end; {$endif} {$ifdef IEUSEASM} procedure dwswap(var B1, B2: dword); assembler; asm push EBX mov ecx, [EAX]; mov ebx, [EDX]; mov [EDX], ecx mov [EAX], ebx pop EBX end; {$else} procedure dwswap(var B1, B2: dword); var temp: dword; begin temp := B1; B1 := B2; B2 := temp; end; {$endif} procedure dswap(var v1, v2: Double); var t: Double; begin t := v1; v1 := v2; v2 := t; end; function EqualRGB(rgb1, rgb2: TRGB): Boolean; begin result := (rgb1.r = rgb2.r) and (rgb1.g = rgb2.g) and (rgb1.b = rgb2.b); end; function IEAverageColor(c1, c2 : TColor): TColor; begin Result := TRGB2TCOLOR( IEAverageColor( TColor2TRGB( c1 ), TColor2TRGB( c2 ) )); end; function IEAverageColor(rgb1, rgb2 : TRGB): TRGB; begin Result := CreateRGB( ( rgb1.r + rgb2.r ) div 2, ( rgb1.g + rgb2.g ) div 2, ( rgb1.b + rgb2.b ) div 2 ); end; {$ifdef IEUSEASM} procedure bswap(var B1, B2: Byte); assembler; asm mov cl, Byte Ptr [EAX]; mov ch, Byte Ptr [EDX]; mov Byte Ptr [EDX], cl mov Byte Ptr [EAX], ch end; {$else} procedure bswap(var B1, B2: byte); var temp: byte; begin temp := B1; B1 := B2; B2 := temp; end; {$endif} // order two coordinates, putting the first as top-left procedure OrdCor(var x1, y1, x2, y2: Integer); begin if x1 > x2 then iswap(x1, x2); if y1 > y2 then iswap(y1, y2); end; ////////////////////////////////////////////////////////////////////////////////////////////// // Hue, Sat, Lum from 0 to 1 procedure ColorToHSL(cl: TColor; var Hue, Sat, Lum: Double); var RGB: TRGB; begin RGB := TColor2TRGB( cl ); RGB2HSL( RGB, Hue, Sat, Lum ); end; // Hue, Sat, Lum from 0 to 1 procedure RGB2HSL(px: TRGB; var Hue, Sat, Lum: Double); var delta, r, g, b, cmax, cmin: Double; begin r := px.r / 255; g := px.g / 255; b := px.b / 255; cmax := dmax(r, dmax(g, b)); cmin := dmin(r, dmin(g, b)); Lum := (cmax + cmin) / 2; if cmax = cmin then begin Sat := 0; Hue := 0; end else begin if Lum < 0.5 then Sat := (cmax - cmin) / (cmax + cmin) else Sat := (cmax - cmin) / (2 - cmax - cmin); delta := cmax - cmin; if r = cmax then Hue := (g - b) / delta else if g = cmax then Hue := 2 + (b - r) / delta else Hue := 4 + (r - g) / delta; Hue := Hue / 6; if Hue < 0 then Hue := Hue + 1; end; end; // Hue, Sat, Lum: 0..1 function HSLToColor(Hue, Sat, Lum: Double) : TColor; var RGB: TRGB; begin HSL2RGB( RGB, Hue, Sat, Lum ); Result := TRGB2TColor( RGB ); end; // Hue, Sat, Lum: 0..1 procedure HSL2RGB(var px: TRGB; Hue, Sat, Lum: Double); function HueToRGB(m1, m2, h: Double): Double; const C1 = 2 / 3; begin if h < 0 then h := h + 1 else if h > 1 then h := h - 1; if 6 * h < 1 then result := (m1 + (m2 - m1) * h * 6) else if 2 * h < 1 then result := m2 else if 3 * h < 2 then result := (m1 + (m2 - m1) * (C1 - h) * 6) else result := m1; end; const C1 = 1 / 3; var r, g, b: Double; m1, m2: Double; begin // check limits if Hue < 0 then Hue := 1 + Hue else if Hue > 1 then Hue := Hue - 1; if Sat < 0 then Sat := 0 else if Sat > 1 then Sat := 1; if Lum < 0 then Lum := 0 else if Lum > 1 then Lum := 1; // if Sat = 0 then begin r := Lum; g := Lum; b := Lum; end else begin if Lum <= 0.5 then m2 := Lum * (1 + Sat) else m2 := Lum + Sat - Lum * Sat; m1 := 2 * Lum - m2; r := HueToRGB(m1, m2, Hue + C1); g := HueToRGB(m1, m2, Hue); b := HueToRGB(m1, m2, Hue - C1); end; px.r := blimit(round(r * 255)); px.g := blimit(round(g * 255)); px.b := blimit(round(b * 255)); end; // HSV to RGB. // H = 0 to 359 (corresponding to 0..359 degrees around hexcone) // S = 0 (shade of gray) to 99 (pure color) // V = 0 (black) to 99 {white) // // Based on C Code in "Computer Graphics -- Principles and Practice" // Foley et al, 1996, p. 594. Floating point fractions, 0..1, replaced with // integer values, 0..99. procedure HSV2RGB(var px: TRGB; H, S, V: Integer); const divisor: Integer = 99 * 60; var f: Integer; hTemp: Integer; p, q, t: Integer; VS: Integer; begin // check limits (changed at 2.1.1) if H < 0 then H := 360 + H else if H > 359 then H := H - 360; if S < 0 then S := 0 else if S > 99 then S := 99; if V < 0 then V := 0 else if V > 99 then V := 99; // if S = 0 then begin px.r := v; px.g := v; px.b := v; end else begin if H = 360 then hTemp := 0 else hTemp := H; f := hTemp mod 60; hTemp := hTemp div 60; VS := V * S; p := V - VS div 99; q := V - (VS * f) div divisor; t := V - (VS * (60 - f)) div divisor; with px do begin case hTemp of 0: begin R := V; G := t; B := p end; 1: begin R := q; G := V; B := p end; 2: begin R := p; G := V; B := t end; 3: begin R := p; G := q; B := V end; 4: begin R := t; G := p; B := V end; 5: begin R := V; G := p; B := q end; end end end; px.r := round(px.r / 99 * 255); px.g := round(px.g / 99 * 255); px.b := round(px.b / 99 * 255); end; function HSVToColor(h, s, v: Integer): TColor; var RGB: TRGB; begin HSV2RGB( RGB, h, s, v ); Result := TRGB2TColor( RGB ); end; // RGB, each 0 to 255, to HSV. // H = 0 to 359 (corresponding to 0..359 degrees around hexcone) // S = 0 (shade of gray) to 99 (pure color) // V = 0 (black) to 99 {white) // // Based on C Code in "Computer Graphics -- Principles and Practice" // Foley et al, 1996, p. 592. Floating point fractions, 0..1, replaced with // integer values, 0..99. procedure RGB2HSV(RGB: TRGB; var h, s, v: Integer); procedure MinMaxInt(const i, j, k: Integer; var min, max: Integer); begin if i > j then begin if i > k then max := i else max := k; if j < k then min := j else min := k end else begin if j > k then max := j else max := k; if i < k then min := i else min := k end; end; var Delta: Integer; MinValue: Integer; r, g, b: Integer; begin r := round(RGB.r / 255 * 99); g := round(RGB.g / 255 * 99); b := round(RGB.b / 255 * 99); MinMaxInt(R, G, B, MinValue, V); Delta := V - MinValue; if V = 0 then S := 0 else S := (99 * Delta) div V; if S = 0 then H := 0 else begin if R = V then h := (60 * (G - B)) div Delta else if G = V then h := 120 + (60 * (B - R)) div Delta else if B = V then h := 240 + (60 * (R - G)) div Delta; if H < 0 then H := H + 360; end; end; procedure ColorToHSV(cl: TColor; var h, s, v: Integer); var RGB: TRGB; begin RGB := TColor2TRGB( cl ); RGB2HSV( RGB, h, s, v ); end; // HTML Color function ColorToHex(Color : TColor): string; begin Result := '#' + { red value } IntToHex( GetRValue( Color ), 2 ) + { green value } IntToHex( GetGValue( Color ), 2 ) + { blue value } IntToHex( GetBValue( Color ), 2 ); end; procedure YUV2RGB(y, u, v: Integer; var RGB: TRGB); begin with RGB do begin b := blimit(round(1.164 * (y - 16) + 2.018 * (u - 128))); g := blimit(round(1.164 * (y - 16) - 0.813 * (v - 128) - 0.391 * (u - 128))); r := blimit(round(1.164 * (y - 16) + 1.596 * (v - 128))); end; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////// // Thanks to Roy Klever procedure IERGBtoHSB(const cRed, cGreen, cBlue: byte; var H, S, B: word); procedure MinMaxByte(const i, j, k: byte; var min: Integer; var max: word); begin if i > j then begin if i > k then max := i else max := k; if j < k then min := j else min := k end else begin if j > k then max := j else max := k; if i < k then min := i else min := k end; end; var Delta: Integer; MinValue: Integer; tmpH: Integer; begin tmpH := 0; MinMaxByte(cRed, cGreen, cBlue, MinValue, B); Delta := B - MinValue; if B = 0 then S := 0 else S := (255 * Delta) div B; if S = 0 then tmpH := 0 else begin if cRed = B then tmpH := (60 * (cGreen - cBlue)) div Delta else if cGreen = B then tmpH := 120 + (60 * (cBlue - cRed)) div Delta else if cBlue = B then tmpH := 240 + (60 * (cRed - cGreen)) div Delta; if tmpH < 0 then tmpH := tmpH + 360; end; H := tmpH; end; procedure IEHSBtoRGB(const H, S, B: word; var cRed, cGreen, cBlue: byte); const divisor: Integer = 255 * 60; var f: Integer; hTemp: Integer; p, q, t: Integer; VS: Integer; begin if s = 0 then begin cRed := B; cGreen := B; cBlue := B; end else begin if H = 360 then hTemp := 0 else hTemp := H; f := hTemp mod 60; hTemp := hTemp div 60; VS := B * S; p := B - VS div 255; q := B - (VS * f) div divisor; t := B - (VS * (60 - f)) div divisor; case hTemp of 0: begin cRed := B; cGreen := t; cBlue := p end; 1: begin cRed := q; cGreen := B; cBlue := p end; 2: begin cRed := p; cGreen := B; cBlue := t end; 3: begin cRed := p; cGreen := q; cBlue := B end; 4: begin cRed := t; cGreen := p; cBlue := B end; 5: begin cRed := B; cGreen := p; cBlue := q end; end; end; end; ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// procedure IEInitialize_hyieutils; begin begin IEGlobalSettings(); // just to create global settings object now IESetDefaultTranslationWords(); mscms := 0; InitIECosineTab(); {$ifdef IERFBPROTOCOL} IE_SockLibInitCS := TCriticalSection.Create(); {$endif} end; end; procedure IEFinalize_hyieutils; begin {$ifdef IERFBPROTOCOL} FreeAndNil(IE_SockLibInitCS); {$endif} if assigned(IEGlobalSettings().DefaultDialogFont) then begin IEGlobalSettings().DefaultDialogFont.Free(); IEGlobalSettings().DefaultDialogFont := nil; end; if mscms <> 0 then FreeLibrary(mscms); end; initialization FhGradientFill := 0; IEInitializeImageEn(); finalization IEFinalizeImageEn(); try if FhGradientFill > 0 then FreeLibrary(fhGradientFill); except end; end.