unit FreeBitmap; // ========================================================== // // Delphi wrapper for FreeImage 3 // // Design and implementation by // - Anatoliy Pulyaevskiy (xvel84@rambler.ru) // // Contributors: // - Enzo Costantini (enzocostantini@libero.it) // // This file is part of FreeImage 3 // // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER // THIS DISCLAIMER. // // Use at your own risk! // // ========================================================== // // From begining all code of this file is based on C++ wrapper to // FreeImage - FreeImagePlus. // // ========================================================== {$IFDEF FPC} {$MODE Delphi} {$H+} // use long strings {$ENDIF} interface uses SysUtils, Classes, Windows, FreeImage; type { TFreeObject } TFreeObject = class(TObject) public function IsValid: Boolean; virtual; end; { TFreeTag } TFreeTag = class(TFreeObject) private // fields FTag: PFITAG; // getters & setters function GetCount: Cardinal; function GetDescription: string; function GetID: Word; function GetKey: string; function GetLength: Cardinal; function GetTagType: FREE_IMAGE_MDTYPE; function GetValue: Pointer; procedure SetCount(const Value: Cardinal); procedure SetDescription(const Value: string); procedure SetID(const Value: Word); procedure SetKey(const Value: string); procedure SetLength(const Value: Cardinal); procedure SetTagType(const Value: FREE_IMAGE_MDTYPE); procedure SetValue(const Value: Pointer); public // construction & destruction constructor Create(ATag: PFITAG = nil); virtual; destructor Destroy; override; // methods function Clone: TFreeTag; function IsValid: Boolean; override; function ToString(Model: FREE_IMAGE_MDMODEL; Make: PChar = nil): string; // properties property Key: string read GetKey write SetKey; property Description: string read GetDescription write SetDescription; property ID: Word read GetID write SetID; property TagType: FREE_IMAGE_MDTYPE read GetTagType write SetTagType; property Count: Cardinal read GetCount write SetCount; property Length: Cardinal read GetLength write SetLength; property Value: Pointer read GetValue write SetValue; property Tag: PFITAG read FTag; end; { forward declarations } TFreeBitmap = class; TFreeMemoryIO = class; { TFreeBitmap } TFreeBitmapChangingEvent = procedure(Sender: TFreeBitmap; var OldDib, NewDib: PFIBITMAP; var Handled: Boolean) of object; TFreeBitmap = class(TFreeObject) private // fields FDib: PFIBITMAP; FOnChange: TNotifyEvent; FOnChanging: TFreeBitmapChangingEvent; procedure SetDib(Value: PFIBITMAP); protected function DoChanging(var OldDib, NewDib: PFIBITMAP): Boolean; dynamic; function Replace(NewDib: PFIBITMAP): Boolean; dynamic; public constructor Create(ImageType: FREE_IMAGE_TYPE = FIT_BITMAP; Width: Integer = 0; Height: Integer = 0; Bpp: Integer = 0); destructor Destroy; override; function SetSize(ImageType: FREE_IMAGE_TYPE; Width, Height, Bpp: Integer; RedMask: Cardinal = 0; GreenMask: Cardinal = 0; BlueMask: Cardinal = 0): Boolean; procedure Change; dynamic; procedure Assign(Source: TFreeBitmap); function CopySubImage(Left, Top, Right, Bottom: Integer; Dest: TFreeBitmap): Boolean; function PasteSubImage(Src: TFreeBitmap; Left, Top: Integer; Alpha: Integer = 256): Boolean; procedure Clear; virtual; function Load(const FileName: string; Flag: Integer = 0): Boolean; function LoadU(const FileName: WideString; Flag: Integer = 0): Boolean; function LoadFromHandle(IO: PFreeImageIO; Handle: fi_handle; Flag: Integer = 0): Boolean; function LoadFromMemory(MemIO: TFreeMemoryIO; Flag: Integer = 0): Boolean; function LoadFromStream(Stream: TStream; Flag: Integer = 0): Boolean; // save functions function CanSave(fif: FREE_IMAGE_FORMAT): Boolean; function Save(const FileName: string; Flag: Integer = 0): Boolean; function SaveU(const FileName: WideString; Flag: Integer = 0): Boolean; function SaveToHandle(fif: FREE_IMAGE_FORMAT; IO: PFreeImageIO; Handle: fi_handle; Flag: Integer = 0): Boolean; function SaveToMemory(fif: FREE_IMAGE_FORMAT; MemIO: TFreeMemoryIO; Flag: Integer = 0): Boolean; function SaveToStream(fif: FREE_IMAGE_FORMAT; Stream: TStream; Flag: Integer = 0): Boolean; // image information function GetImageType: FREE_IMAGE_TYPE; function GetWidth: Integer; function GetHeight: Integer; function GetScanWidth: Integer; function IsValid: Boolean; override; function GetInfo: PBitmapInfo; function GetInfoHeader: PBitmapInfoHeader; function GetImageSize: Cardinal; function GetBitsPerPixel: Integer; function GetLine: Integer; function GetHorizontalResolution: Double; function GetVerticalResolution: Double; procedure SetHorizontalResolution(Value: Double); procedure SetVerticalResolution(Value: Double); // palette operations function GetPalette: PRGBQUAD; function GetPaletteSize: Integer; function GetColorsUsed: Integer; function GetColorType: FREE_IMAGE_COLOR_TYPE; function IsGrayScale: Boolean; // pixels access function AccessPixels: PByte; function GetScanLine(ScanLine: Integer): PByte; function GetPixelIndex(X, Y: Cardinal; var Value: PByte): Boolean; function GetPixelColor(X, Y: Cardinal; Value: PRGBQUAD): Boolean; function SetPixelIndex(X, Y: Cardinal; Value: PByte): Boolean; function SetPixelColor(X, Y: Cardinal; Value: PRGBQUAD): Boolean; // convertion function ConvertToStandardType(ScaleLinear: Boolean): Boolean; function ConvertToType(ImageType: FREE_IMAGE_TYPE; ScaleLinear: Boolean): Boolean; function Threshold(T: Byte): Boolean; function ConvertTo4Bits: Boolean; function ConvertTo8Bits: Boolean; function ConvertTo16Bits555: Boolean; function ConvertTo16Bits565: Boolean; function ConvertTo24Bits: Boolean; function ConvertTo32Bits: Boolean; function ConvertToGrayscale: Boolean; function ColorQuantize(Algorithm: FREE_IMAGE_QUANTIZE): Boolean; function Dither(Algorithm: FREE_IMAGE_DITHER): Boolean; function ConvertToRGBF: Boolean; function ToneMapping(TMO: FREE_IMAGE_TMO; FirstParam, SecondParam: Double): Boolean; // transparency function IsTransparent: Boolean; function GetTransparencyCount: Cardinal; function GetTransparencyTable: PByte; procedure SetTransparencyTable(Table: PByte; Count: Integer); function HasFileBkColor: Boolean; function GetFileBkColor(var BkColor: PRGBQuad): Boolean; function SetFileBkColor(BkColor: PRGBQuad): Boolean; // channel processing routines function GetChannel(Bitmap: TFreeBitmap; Channel: FREE_IMAGE_COLOR_CHANNEL): Boolean; function SetChannel(Bitmap: TFreeBitmap; Channel: FREE_IMAGE_COLOR_CHANNEL): Boolean; function SplitChannels(RedChannel, GreenChannel, BlueChannel: TFreeBitmap): Boolean; function CombineChannels(Red, Green, Blue: TFreeBitmap): Boolean; // rotation and flipping function RotateEx(Angle, XShift, YShift, XOrigin, YOrigin: Double; UseMask: Boolean): Boolean; function Rotate(Angle: Double): Boolean; function FlipHorizontal: Boolean; function FlipVertical: Boolean; // color manipulation routines function Invert: Boolean; function AdjustCurve(Lut: PByte; Channel: FREE_IMAGE_COLOR_CHANNEL): Boolean; function AdjustGamma(Gamma: Double): Boolean; function AdjustBrightness(Percentage: Double): Boolean; function AdjustContrast(Percentage: Double): Boolean; function GetHistogram(Histo: PDWORD; Channel: FREE_IMAGE_COLOR_CHANNEL = FICC_BLACK): Boolean; // upsampling / downsampling procedure MakeThumbnail(const Width, Height: Integer; DestBitmap: TFreeBitmap); function Rescale(NewWidth, NewHeight: Integer; Filter: FREE_IMAGE_FILTER; Dest: TFreeBitmap = nil): Boolean; // metadata routines function FindFirstMetadata(Model: FREE_IMAGE_MDMODEL; var Tag: TFreeTag): PFIMETADATA; function FindNextMetadata(MDHandle: PFIMETADATA; var Tag: TFreeTag): Boolean; procedure FindCloseMetadata(MDHandle: PFIMETADATA); function SetMetadata(Model: FREE_IMAGE_MDMODEL; const Key: string; Tag: TFreeTag): Boolean; function GetMetadata(Model: FREE_IMAGE_MDMODEL; const Key: string; var Tag: TFreeTag): Boolean; function GetMetadataCount(Model: FREE_IMAGE_MDMODEL): Cardinal; // properties property Dib: PFIBITMAP read FDib write SetDib; property OnChange: TNotifyEvent read FOnChange write FOnChange; property OnChanging: TFreeBitmapChangingEvent read FOnChanging write FOnChanging; end; { TFreeWinBitmap } { TFreeMemoryIO } TFreeMemoryIO = class(TFreeObject) private FHMem: PFIMEMORY; public // construction and destruction constructor Create(Data: PByte = nil; SizeInBytes: DWORD = 0); destructor Destroy; override; function GetFileType: FREE_IMAGE_FORMAT; function Read(fif: FREE_IMAGE_FORMAT; Flag: Integer = 0): PFIBITMAP; function Write(fif: FREE_IMAGE_FORMAT; dib: PFIBITMAP; Flag: Integer = 0): Boolean; function Tell: Longint; function Seek(Offset: Longint; Origin: Word): Boolean; function Acquire(var Data: PByte; var SizeInBytes: DWORD): Boolean; // overriden methods function IsValid: Boolean; override; end; { TFreeMultiBitmap } TFreeMultiBitmap = class(TFreeObject) private FMPage: PFIMULTIBITMAP; FMemoryCache: Boolean; public // constructor and destructor constructor Create(KeepCacheInMemory: Boolean = False); destructor Destroy; override; // methods function Open(const FileName: string; CreateNew, ReadOnly: Boolean; Flags: Integer = 0): Boolean; function Close(Flags: Integer = 0): Boolean; function GetPageCount: Integer; procedure AppendPage(Bitmap: TFreeBitmap); procedure InsertPage(Page: Integer; Bitmap: TFreeBitmap); procedure DeletePage(Page: Integer); function MovePage(Target, Source: Integer): Boolean; procedure LockPage(Page: Integer; DestBitmap: TFreeBitmap); procedure UnlockPage(Bitmap: TFreeBitmap; Changed: Boolean); function GetLockedPageNumbers(var Pages: Integer; var Count: Integer): Boolean; // overriden methods function IsValid: Boolean; override; // properties // change of this property influences only on the next opening of a file property MemoryCache: Boolean read FMemoryCache write FMemoryCache; end; implementation const ThumbSize = 150; // marker used for clipboard copy / paste procedure SetFreeImageMarker(bmih: PBitmapInfoHeader; dib: PFIBITMAP); begin // Windows constants goes from 0L to 5L // Add $FF to avoid conflicts bmih.biCompression := $FF + FreeImage_GetImageType(dib); end; function GetFreeImageMarker(bmih: PBitmapInfoHeader): FREE_IMAGE_TYPE; begin Result := FREE_IMAGE_TYPE(bmih.biCompression - $FF); end; { TFreePersistent } function TFreeObject.IsValid: Boolean; begin Result := False end; { TFreeBitmap } function TFreeBitmap.AccessPixels: PByte; begin Result := FreeImage_GetBits(FDib) end; function TFreeBitmap.AdjustBrightness(Percentage: Double): Boolean; begin if FDib <> nil then begin Result := FreeImage_AdjustBrightness(FDib, Percentage); Change; end else Result := False end; function TFreeBitmap.AdjustContrast(Percentage: Double): Boolean; begin if FDib <> nil then begin Result := FreeImage_AdjustContrast(FDib, Percentage); Change; end else Result := False end; function TFreeBitmap.AdjustCurve(Lut: PByte; Channel: FREE_IMAGE_COLOR_CHANNEL): Boolean; begin if FDib <> nil then begin Result := FreeImage_AdjustCurve(FDib, Lut, Channel); Change; end else Result := False end; function TFreeBitmap.AdjustGamma(Gamma: Double): Boolean; begin if FDib <> nil then begin Result := FreeImage_AdjustGamma(FDib, Gamma); Change; end else Result := False end; procedure TFreeBitmap.Assign(Source: TFreeBitmap); var SourceBmp: TFreeBitmap; Clone: PFIBITMAP; begin if Source = nil then begin Clear; Exit; end; if Source is TFreeBitmap then begin SourceBmp := TFreeBitmap(Source); if SourceBmp <> Self then begin if SourceBmp.IsValid then begin Clone := FreeImage_Clone(SourceBmp.FDib); Replace(Clone); end else Clear; end; end; end; function TFreeBitmap.CanSave(fif: FREE_IMAGE_FORMAT): Boolean; var ImageType: FREE_IMAGE_TYPE; Bpp: Word; begin Result := False; if not IsValid then Exit; if fif <> FIF_UNKNOWN then begin // check that the dib can be saved in this format ImageType := FreeImage_GetImageType(FDib); if ImageType = FIT_BITMAP then begin // standard bitmap type Bpp := FreeImage_GetBPP(FDib); Result := FreeImage_FIFSupportsWriting(fif) and FreeImage_FIFSupportsExportBPP(fif, Bpp); end else // special bitmap type Result := FreeImage_FIFSupportsExportType(fif, ImageType); end; end; procedure TFreeBitmap.Change; begin if Assigned(FOnChange) then FOnChange(Self) end; procedure TFreeBitmap.Clear; begin if FDib <> nil then begin FreeImage_Unload(FDib); FDib := nil; Change; end; end; function TFreeBitmap.ColorQuantize( Algorithm: FREE_IMAGE_QUANTIZE): Boolean; var dib8: PFIBITMAP; begin if FDib <> nil then begin dib8 := FreeImage_ColorQuantize(FDib, Algorithm); Result := Replace(dib8); end else Result := False; end; function TFreeBitmap.CombineChannels(Red, Green, Blue: TFreeBitmap): Boolean; var Width, Height: Integer; begin if FDib = nil then begin Width := Red.GetWidth; Height := Red.GetHeight; FDib := FreeImage_Allocate(Width, Height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); end; if FDib <> nil then begin Result := FreeImage_SetChannel(FDib, Red.FDib, FICC_RED) and FreeImage_SetChannel(FDib, Green.FDib, FICC_GREEN) and FreeImage_SetChannel(FDib, Blue.FDib, FICC_BLUE); Change end else Result := False; end; function TFreeBitmap.ConvertTo16Bits555: Boolean; var dib16_555: PFIBITMAP; begin if FDib <> nil then begin dib16_555 := FreeImage_ConvertTo16Bits555(FDib); Result := Replace(dib16_555); end else Result := False end; function TFreeBitmap.ConvertTo16Bits565: Boolean; var dib16_565: PFIBITMAP; begin if FDib <> nil then begin dib16_565 := FreeImage_ConvertTo16Bits565(FDib); Result := Replace(dib16_565); end else Result := False end; function TFreeBitmap.ConvertTo24Bits: Boolean; var dibRGB: PFIBITMAP; begin if FDib <> nil then begin dibRGB := FreeImage_ConvertTo24Bits(FDib); Result := Replace(dibRGB); end else Result := False end; function TFreeBitmap.ConvertTo32Bits: Boolean; var dib32: PFIBITMAP; begin if FDib <> nil then begin dib32 := FreeImage_ConvertTo32Bits(FDib); Result := Replace(dib32); end else Result := False end; function TFreeBitmap.ConvertTo4Bits: Boolean; var dib4: PFIBITMAP; begin Result := False; if IsValid then begin dib4 := FreeImage_ConvertTo4Bits(FDib); Result := Replace(dib4); end; end; function TFreeBitmap.ConvertTo8Bits: Boolean; var dib8: PFIBITMAP; begin if FDib <> nil then begin dib8 := FreeImage_ConvertTo8Bits(FDib); Result := Replace(dib8); end else Result := False end; function TFreeBitmap.ConvertToGrayscale: Boolean; var dib8: PFIBITMAP; begin Result := False; if IsValid then begin dib8 := FreeImage_ConvertToGreyscale(FDib); Result := Replace(dib8); end end; function TFreeBitmap.ConvertToRGBF: Boolean; var ImageType: FREE_IMAGE_TYPE; NewDib: PFIBITMAP; begin Result := False; if not IsValid then Exit; ImageType := GetImageType; if (ImageType = FIT_BITMAP) then begin if GetBitsPerPixel < 24 then if not ConvertTo24Bits then Exit end; NewDib := FreeImage_ConvertToRGBF(FDib); Result := Replace(NewDib); end; function TFreeBitmap.ConvertToStandardType(ScaleLinear: Boolean): Boolean; var dibStandard: PFIBITMAP; begin if IsValid then begin dibStandard := FreeImage_ConvertToStandardType(FDib, ScaleLinear); Result := Replace(dibStandard); end else Result := False; end; function TFreeBitmap.ConvertToType(ImageType: FREE_IMAGE_TYPE; ScaleLinear: Boolean): Boolean; var dib: PFIBITMAP; begin if FDib <> nil then begin dib := FreeImage_ConvertToType(FDib, ImageType, ScaleLinear); Result := Replace(dib) end else Result := False end; function TFreeBitmap.CopySubImage(Left, Top, Right, Bottom: Integer; Dest: TFreeBitmap): Boolean; begin if FDib <> nil then begin Dest.FDib := FreeImage_Copy(FDib, Left, Top, Right, Bottom); Result := Dest.IsValid; end else Result := False; end; constructor TFreeBitmap.Create(ImageType: FREE_IMAGE_TYPE; Width, Height, Bpp: Integer); begin inherited Create; FDib := nil; if (Width > 0) and (Height > 0) and (Bpp > 0) then SetSize(ImageType, Width, Height, Bpp); end; destructor TFreeBitmap.Destroy; begin if FDib <> nil then FreeImage_Unload(FDib); inherited; end; function TFreeBitmap.Dither(Algorithm: FREE_IMAGE_DITHER): Boolean; var dib: PFIBITMAP; begin if FDib <> nil then begin dib := FreeImage_Dither(FDib, Algorithm); Result := Replace(dib); end else Result := False; end; function TFreeBitmap.DoChanging(var OldDib, NewDib: PFIBITMAP): Boolean; begin Result := False; if (OldDib <> NewDib) and Assigned(FOnChanging) then FOnChanging(Self, OldDib, NewDib, Result); end; procedure TFreeBitmap.FindCloseMetadata(MDHandle: PFIMETADATA); begin FreeImage_FindCloseMetadata(MDHandle); end; function TFreeBitmap.FindFirstMetadata(Model: FREE_IMAGE_MDMODEL; var Tag: TFreeTag): PFIMETADATA; begin Result := FreeImage_FindFirstMetadata(Model, FDib, Tag.FTag); end; function TFreeBitmap.FindNextMetadata(MDHandle: PFIMETADATA; var Tag: TFreeTag): Boolean; begin Result := FreeImage_FindNextMetadata(MDHandle, Tag.FTag); end; function TFreeBitmap.FlipHorizontal: Boolean; begin if FDib <> nil then begin Result := FreeImage_FlipHorizontal(FDib); Change; end else Result := False end; function TFreeBitmap.FlipVertical: Boolean; begin if FDib <> nil then begin Result := FreeImage_FlipVertical(FDib); Change; end else Result := False end; function TFreeBitmap.GetBitsPerPixel: Integer; begin Result := FreeImage_GetBPP(FDib) end; function TFreeBitmap.GetChannel(Bitmap: TFreeBitmap; Channel: FREE_IMAGE_COLOR_CHANNEL): Boolean; begin if FDib <> nil then begin Bitmap.Dib := FreeImage_GetChannel(FDib, Channel); Result := Bitmap.IsValid; end else Result := False end; function TFreeBitmap.GetColorsUsed: Integer; begin Result := FreeImage_GetColorsUsed(FDib) end; function TFreeBitmap.GetColorType: FREE_IMAGE_COLOR_TYPE; begin Result := FreeImage_GetColorType(FDib); end; function TFreeBitmap.GetFileBkColor(var BkColor: PRGBQuad): Boolean; begin Result := FreeImage_GetBackgroundColor(FDib, BkColor) end; function TFreeBitmap.GetHeight: Integer; begin Result := FreeImage_GetHeight(FDib) end; function TFreeBitmap.GetHistogram(Histo: PDWORD; Channel: FREE_IMAGE_COLOR_CHANNEL): Boolean; begin if FDib <> nil then Result := FreeImage_GetHistogram(FDib, Histo, Channel) else Result := False end; function TFreeBitmap.GetHorizontalResolution: Double; begin Result := FreeImage_GetDotsPerMeterX(FDib) / 100 end; function TFreeBitmap.GetImageSize: Cardinal; begin Result := FreeImage_GetDIBSize(FDib); end; function TFreeBitmap.GetImageType: FREE_IMAGE_TYPE; begin Result := FreeImage_GetImageType(FDib); end; function TFreeBitmap.GetInfo: PBitmapInfo; begin Result := FreeImage_GetInfo(FDib^) end; function TFreeBitmap.GetInfoHeader: PBITMAPINFOHEADER; begin Result := FreeImage_GetInfoHeader(FDib) end; function TFreeBitmap.GetLine: Integer; begin Result := FreeImage_GetLine(FDib) end; function TFreeBitmap.GetMetadata(Model: FREE_IMAGE_MDMODEL; const Key: string; var Tag: TFreeTag): Boolean; begin Result := FreeImage_GetMetaData(Model, FDib, PChar(Key), Tag.FTag); end; function TFreeBitmap.GetMetadataCount(Model: FREE_IMAGE_MDMODEL): Cardinal; begin Result := FreeImage_GetMetadataCount(Model, FDib); end; function TFreeBitmap.GetPalette: PRGBQUAD; begin Result := FreeImage_GetPalette(FDib) end; function TFreeBitmap.GetPaletteSize: Integer; begin Result := FreeImage_GetColorsUsed(FDib) * SizeOf(RGBQUAD) end; function TFreeBitmap.GetPixelColor(X, Y: Cardinal; Value: PRGBQUAD): Boolean; begin Result := FreeImage_GetPixelColor(FDib, X, Y, Value) end; function TFreeBitmap.GetPixelIndex(X, Y: Cardinal; var Value: PByte): Boolean; begin Result := FreeImage_GetPixelIndex(FDib, X, Y, Value) end; function TFreeBitmap.GetScanLine(ScanLine: Integer): PByte; var H: Integer; begin H := FreeImage_GetHeight(FDib); if ScanLine < H then Result := FreeImage_GetScanLine(FDib, ScanLine) else Result := nil; end; function TFreeBitmap.GetScanWidth: Integer; begin Result := FreeImage_GetPitch(FDib) end; function TFreeBitmap.GetTransparencyCount: Cardinal; begin Result := FreeImage_GetTransparencyCount(FDib) end; function TFreeBitmap.GetTransparencyTable: PByte; begin Result := FreeImage_GetTransparencyTable(FDib) end; function TFreeBitmap.GetVerticalResolution: Double; begin Result := FreeImage_GetDotsPerMeterY(Fdib) / 100 end; function TFreeBitmap.GetWidth: Integer; begin Result := FreeImage_GetWidth(FDib) end; function TFreeBitmap.HasFileBkColor: Boolean; begin Result := FreeImage_HasBackgroundColor(FDib) end; function TFreeBitmap.Invert: Boolean; begin if FDib <> nil then begin Result := FreeImage_Invert(FDib); Change; end else Result := False end; function TFreeBitmap.IsGrayScale: Boolean; begin Result := (FreeImage_GetBPP(FDib) = 8) and (FreeImage_GetColorType(FDib) = FIC_PALETTE); end; function TFreeBitmap.IsTransparent: Boolean; begin Result := FreeImage_IsTransparent(FDib); end; function TFreeBitmap.IsValid: Boolean; begin Result := FDib <> nil end; function TFreeBitmap.Load(const FileName: string; Flag: Integer): Boolean; var fif: FREE_IMAGE_FORMAT; begin // check the file signature and get its format fif := FreeImage_GetFileType(PChar(Filename), 0); if fif = FIF_UNKNOWN then // no signature? // try to guess the file format from the file extention fif := FreeImage_GetFIFFromFilename(PChar(FileName)); // check that the plugin has reading capabilities ... if (fif <> FIF_UNKNOWN) and FreeImage_FIFSupportsReading(FIF) then begin // free the previous dib if FDib <> nil then FreeImage_Unload(dib); // load the file FDib := FreeImage_Load(fif, PChar(FileName), Flag); Change; Result := IsValid; end else Result := False; end; function TFreeBitmap.LoadFromHandle(IO: PFreeImageIO; Handle: fi_handle; Flag: Integer): Boolean; var fif: FREE_IMAGE_FORMAT; begin // check the file signature and get its format fif := FreeImage_GetFileTypeFromHandle(IO, Handle, 16); if (fif <> FIF_UNKNOWN) and FreeImage_FIFSupportsReading(fif) then begin // free the previous dib if FDib <> nil then FreeImage_Unload(FDib); // load the file FDib := FreeImage_LoadFromHandle(fif, IO, Handle, Flag); Change; Result := IsValid; end else Result := False; end; function TFreeBitmap.LoadFromMemory(MemIO: TFreeMemoryIO; Flag: Integer): Boolean; var fif: FREE_IMAGE_FORMAT; begin // check the file signature and get its format fif := MemIO.GetFileType; if (fif <> FIF_UNKNOWN) and FreeImage_FIFSupportsReading(fif) then begin // free the previous dib if FDib <> nil then FreeImage_Unload(FDib); // load the file FDib := MemIO.Read(fif, Flag); Result := IsValid; Change; end else Result := False; end; function TFreeBitmap.LoadFromStream(Stream: TStream; Flag: Integer): Boolean; var MemIO: TFreeMemoryIO; Data: PByte; MemStream: TMemoryStream; Size: Cardinal; begin Size := Stream.Size; MemStream := TMemoryStream.Create; try MemStream.CopyFrom(Stream, Size); Data := MemStream.Memory; MemIO := TFreeMemoryIO.Create(Data, Size); try Result := LoadFromMemory(MemIO); finally MemIO.Free; end; finally MemStream.Free; end; end; function TFreeBitmap.LoadU(const FileName: WideString; Flag: Integer): Boolean; var fif: FREE_IMAGE_FORMAT; begin // check the file signature and get its format fif := FreeImage_GetFileTypeU(PWideChar(Filename), 0); if fif = FIF_UNKNOWN then // no signature? // try to guess the file format from the file extention fif := FreeImage_GetFIFFromFilenameU(PWideChar(FileName)); // check that the plugin has reading capabilities ... if (fif <> FIF_UNKNOWN) and FreeImage_FIFSupportsReading(FIF) then begin // free the previous dib if FDib <> nil then FreeImage_Unload(dib); // load the file FDib := FreeImage_LoadU(fif, PWideChar(FileName), Flag); Change; Result := IsValid; end else Result := False; end; procedure TFreeBitmap.MakeThumbnail(const Width, Height: Integer; DestBitmap: TFreeBitmap); type PRGB24 = ^TRGB24; TRGB24 = packed record B: Byte; G: Byte; R: Byte; end; var x, y, ix, iy: integer; x1, x2, x3: integer; xscale, yscale: single; iRed, iGrn, iBlu, iRatio: Longword; p, c1, c2, c3, c4, c5: TRGB24; pt, pt1: PRGB24; iSrc, iDst, s1: integer; i, j, r, g, b, tmpY: integer; RowDest, RowSource, RowSourceStart: integer; w, h: Integer; dxmin, dymin: integer; ny1, ny2, ny3: integer; dx, dy: integer; lutX, lutY: array of integer; SrcBmp, DestBmp: PFIBITMAP; begin if not IsValid then Exit; if (GetWidth <= ThumbSize) and (GetHeight <= ThumbSize) then begin DestBitmap.Assign(Self); Exit; end; w := Width; h := Height; // prepare bitmaps if GetBitsPerPixel <> 24 then SrcBmp := FreeImage_ConvertTo24Bits(FDib) else SrcBmp := FDib; DestBmp := FreeImage_Allocate(w, h, 24); Assert(DestBmp <> nil, 'TFreeBitmap.MakeThumbnail error'); { iDst := (w * 24 + 31) and not 31; iDst := iDst div 8; //BytesPerScanline iSrc := (GetWidth * 24 + 31) and not 31; iSrc := iSrc div 8; } // BytesPerScanline iDst := FreeImage_GetPitch(DestBmp); iSrc := FreeImage_GetPitch(SrcBmp); xscale := 1 / (w / FreeImage_GetWidth(SrcBmp)); yscale := 1 / (h / FreeImage_GetHeight(SrcBmp)); // X lookup table SetLength(lutX, w); x1 := 0; x2 := trunc(xscale); for x := 0 to w - 1 do begin lutX[x] := x2 - x1; x1 := x2; x2 := trunc((x + 2) * xscale); end; // Y lookup table SetLength(lutY, h); x1 := 0; x2 := trunc(yscale); for x := 0 to h - 1 do begin lutY[x] := x2 - x1; x1 := x2; x2 := trunc((x + 2) * yscale); end; Dec(w); Dec(h); RowDest := integer(FreeImage_GetScanLine(DestBmp, 0)); RowSourceStart := integer(FreeImage_GetScanLine(SrcBmp, 0)); RowSource := RowSourceStart; for y := 0 to h do // resampling begin dy := lutY[y]; x1 := 0; x3 := 0; for x := 0 to w do // loop through row begin dx:= lutX[x]; iRed:= 0; iGrn:= 0; iBlu:= 0; RowSource := RowSourceStart; for iy := 1 to dy do begin pt := PRGB24(RowSource + x1); for ix := 1 to dx do begin iRed := iRed + pt.R; iGrn := iGrn + pt.G; iBlu := iBlu + pt.B; inc(pt); end; RowSource := RowSource + iSrc; end; iRatio := 65535 div (dx * dy); pt1 := PRGB24(RowDest + x3); pt1.R := (iRed * iRatio) shr 16; pt1.G := (iGrn * iRatio) shr 16; pt1.B := (iBlu * iRatio) shr 16; x1 := x1 + 3 * dx; inc(x3,3); end; RowDest := RowDest + iDst; RowSourceStart := RowSource; end; // resampling if FreeImage_GetHeight(DestBmp) >= 3 then // Sharpening... begin s1 := integer(FreeImage_GetScanLine(DestBmp, 0)); iDst := integer(FreeImage_GetScanLine(DestBmp, 1)) - s1; ny1 := Integer(s1); ny2 := ny1 + iDst; ny3 := ny2 + iDst; for y := 1 to FreeImage_GetHeight(DestBmp) - 2 do begin for x := 0 to FreeImage_GetWidth(DestBmp) - 3 do begin x1 := x * 3; x2 := x1 + 3; x3 := x1 + 6; c1 := pRGB24(ny1 + x1)^; c2 := pRGB24(ny1 + x3)^; c3 := pRGB24(ny2 + x2)^; c4 := pRGB24(ny3 + x1)^; c5 := pRGB24(ny3 + x3)^; r := (c1.R + c2.R + (c3.R * -12) + c4.R + c5.R) div -8; g := (c1.G + c2.G + (c3.G * -12) + c4.G + c5.G) div -8; b := (c1.B + c2.B + (c3.B * -12) + c4.B + c5.B) div -8; if r < 0 then r := 0 else if r > 255 then r := 255; if g < 0 then g := 0 else if g > 255 then g := 255; if b < 0 then b := 0 else if b > 255 then b := 255; pt1 := pRGB24(ny2 + x2); pt1.R := r; pt1.G := g; pt1.B := b; end; inc(ny1, iDst); inc(ny2, iDst); inc(ny3, iDst); end; end; // sharpening if SrcBmp <> FDib then FreeImage_Unload(SrcBmp); DestBitmap.Replace(DestBmp); end; function TFreeBitmap.PasteSubImage(Src: TFreeBitmap; Left, Top, Alpha: Integer): Boolean; begin if FDib <> nil then begin Result := FreeImage_Paste(FDib, Src.Dib, Left, Top, Alpha); Change; end else Result := False; end; function TFreeBitmap.Replace(NewDib: PFIBITMAP): Boolean; begin Result := False; if NewDib = nil then Exit; if not DoChanging(FDib, NewDib) and IsValid then FreeImage_Unload(FDib); FDib := NewDib; Result := True; Change; end; function TFreeBitmap.Rescale(NewWidth, NewHeight: Integer; Filter: FREE_IMAGE_FILTER; Dest: TFreeBitmap): Boolean; var Bpp: Integer; DstDib: PFIBITMAP; begin Result := False; if FDib <> nil then begin Bpp := FreeImage_GetBPP(FDib); if Bpp < 8 then if not ConvertToGrayscale then Exit else if Bpp = 16 then // convert to 24-bit if not ConvertTo24Bits then Exit; // perform upsampling / downsampling DstDib := FreeImage_Rescale(FDib, NewWidth, NewHeight, Filter); if Dest = nil then Result := Replace(DstDib) else Result := Dest.Replace(DstDib) end end; function TFreeBitmap.Rotate(Angle: Double): Boolean; var Bpp: Integer; Rotated: PFIBITMAP; begin Result := False; if IsValid then begin Bpp := FreeImage_GetBPP(FDib); if Bpp in [1, 8, 24, 32] then begin Rotated := FreeImage_RotateClassic(FDib, Angle); Result := Replace(Rotated); end end; end; function TFreeBitmap.RotateEx(Angle, XShift, YShift, XOrigin, YOrigin: Double; UseMask: Boolean): Boolean; var Rotated: PFIBITMAP; begin Result := False; if FDib <> nil then begin if FreeImage_GetBPP(FDib) >= 8 then begin Rotated := FreeImage_RotateEx(FDib, Angle, XShift, YShift, XOrigin, YOrigin, UseMask); Result := Replace(Rotated); end end; end; function TFreeBitmap.Save(const FileName: string; Flag: Integer): Boolean; var fif: FREE_IMAGE_FORMAT; begin Result := False; // try to guess the file format from the file extension fif := FreeImage_GetFIFFromFilename(PChar(Filename)); if CanSave(fif) then Result := FreeImage_Save(fif, FDib, PChar(FileName), Flag); end; function TFreeBitmap.SaveToHandle(fif: FREE_IMAGE_FORMAT; IO: PFreeImageIO; Handle: fi_handle; Flag: Integer): Boolean; begin Result := False; if CanSave(fif) then Result := FreeImage_SaveToHandle(fif, FDib, IO, Handle, Flag) end; function TFreeBitmap.SaveToMemory(fif: FREE_IMAGE_FORMAT; MemIO: TFreeMemoryIO; Flag: Integer): Boolean; begin Result := False; if CanSave(fif) then Result := MemIO.Write(fif, FDib, Flag) end; function TFreeBitmap.SaveToStream(fif: FREE_IMAGE_FORMAT; Stream: TStream; Flag: Integer): Boolean; var MemIO: TFreeMemoryIO; Data: PByte; Size: Cardinal; begin MemIO := TFreeMemoryIO.Create; try Result := SaveToMemory(fif, MemIO, Flag); if Result then begin MemIO.Acquire(Data, Size); Stream.WriteBuffer(Data^, Size); end; finally MemIO.Free; end; end; function TFreeBitmap.SaveU(const FileName: WideString; Flag: Integer): Boolean; var fif: FREE_IMAGE_FORMAT; begin Result := False; // try to guess the file format from the file extension fif := FreeImage_GetFIFFromFilenameU(PWideChar(Filename)); if CanSave(fif) then Result := FreeImage_SaveU(fif, FDib, PWideChar(FileName), Flag); end; function TFreeBitmap.SetChannel(Bitmap: TFreeBitmap; Channel: FREE_IMAGE_COLOR_CHANNEL): Boolean; begin if FDib <> nil then begin Result := FreeImage_SetChannel(FDib, Bitmap.FDib, Channel); Change; end else Result := False end; procedure TFreeBitmap.SetDib(Value: PFIBITMAP); begin Replace(Value); end; function TFreeBitmap.SetFileBkColor(BkColor: PRGBQuad): Boolean; begin Result := FreeImage_SetBackgroundColor(FDib, BkColor); Change; end; procedure TFreeBitmap.SetHorizontalResolution(Value: Double); begin if IsValid then begin FreeImage_SetDotsPerMeterX(FDib, Trunc(Value * 100 + 0.5)); Change; end; end; function TFreeBitmap.SetMetadata(Model: FREE_IMAGE_MDMODEL; const Key: string; Tag: TFreeTag): Boolean; begin Result := FreeImage_SetMetadata(Model, FDib, PChar(Key), Tag.Tag); end; function TFreeBitmap.SetPixelColor(X, Y: Cardinal; Value: PRGBQUAD): Boolean; begin Result := FreeImage_SetPixelColor(FDib, X, Y, Value); Change; end; function TFreeBitmap.SetPixelIndex(X, Y: Cardinal; Value: PByte): Boolean; begin Result := FreeImage_SetPixelIndex(FDib, X, Y, Value); Change; end; function TFreeBitmap.SetSize(ImageType: FREE_IMAGE_TYPE; Width, Height, Bpp: Integer; RedMask, GreenMask, BlueMask: Cardinal): Boolean; var Pal: PRGBQuad; I: Cardinal; begin Result := False; if FDib <> nil then FreeImage_Unload(FDib); FDib := FreeImage_Allocate(Width, Height, Bpp, RedMask, GreenMask, BlueMask); if FDib = nil then Exit; if ImageType = FIT_BITMAP then case Bpp of 1, 4, 8: begin Pal := FreeImage_GetPalette(FDib); for I := 0 to FreeImage_GetColorsUsed(FDib) - 1 do begin Pal.rgbBlue := I; Pal.rgbGreen := I; Pal.rgbRed := I; Inc(Pal, SizeOf(RGBQUAD)); end; end; end; Result := True; Change; end; procedure TFreeBitmap.SetTransparencyTable(Table: PByte; Count: Integer); begin FreeImage_SetTransparencyTable(FDib, Table, Count); Change; end; procedure TFreeBitmap.SetVerticalResolution(Value: Double); begin if IsValid then begin FreeImage_SetDotsPerMeterY(FDib, Trunc(Value * 100 + 0.5)); Change; end; end; function TFreeBitmap.SplitChannels(RedChannel, GreenChannel, BlueChannel: TFreeBitmap): Boolean; begin if FDib <> nil then begin RedChannel.FDib := FreeImage_GetChannel(FDib, FICC_RED); GreenChannel.FDib := FreeImage_GetChannel(FDib, FICC_GREEN); BlueChannel.FDib := FreeImage_GetChannel(FDib, FICC_BLUE); Result := RedChannel.IsValid and GreenChannel.IsValid and BlueChannel.IsValid; end else Result := False end; function TFreeBitmap.Threshold(T: Byte): Boolean; var dib1: PFIBITMAP; begin if FDib <> nil then begin dib1 := FreeImage_Threshold(FDib, T); Result := Replace(dib1); end else Result := False end; function TFreeBitmap.ToneMapping(TMO: FREE_IMAGE_TMO; FirstParam, SecondParam: Double): Boolean; var NewDib: PFIBITMAP; begin Result := False; if not IsValid then Exit; NewDib := FreeImage_ToneMapping(Fdib, TMO, FirstParam, SecondParam); Result := Replace(NewDib); end; { TFreeMultiBitmap } procedure TFreeMultiBitmap.AppendPage(Bitmap: TFreeBitmap); begin if IsValid then FreeImage_AppendPage(FMPage, Bitmap.FDib); end; function TFreeMultiBitmap.Close(Flags: Integer): Boolean; begin Result := FreeImage_CloseMultiBitmap(FMPage, Flags); FMPage := nil; end; constructor TFreeMultiBitmap.Create(KeepCacheInMemory: Boolean); begin inherited Create; FMemoryCache := KeepCacheInMemory; end; procedure TFreeMultiBitmap.DeletePage(Page: Integer); begin if IsValid then FreeImage_DeletePage(FMPage, Page); end; destructor TFreeMultiBitmap.Destroy; begin if FMPage <> nil then Close; inherited; end; function TFreeMultiBitmap.GetLockedPageNumbers(var Pages, Count: Integer): Boolean; begin Result := False; if not IsValid then Exit; Result := FreeImage_GetLockedPageNumbers(FMPage, Pages, Count) end; function TFreeMultiBitmap.GetPageCount: Integer; begin Result := 0; if IsValid then Result := FreeImage_GetPageCount(FMPage) end; procedure TFreeMultiBitmap.InsertPage(Page: Integer; Bitmap: TFreeBitmap); begin if IsValid then FreeImage_InsertPage(FMPage, Page, Bitmap.FDib); end; function TFreeMultiBitmap.IsValid: Boolean; begin Result := FMPage <> nil end; procedure TFreeMultiBitmap.LockPage(Page: Integer; DestBitmap: TFreeBitmap); begin if not IsValid then Exit; if Assigned(DestBitmap) then begin DestBitmap.Replace(FreeImage_LockPage(FMPage, Page)); end; end; function TFreeMultiBitmap.MovePage(Target, Source: Integer): Boolean; begin Result := False; if not IsValid then Exit; Result := FreeImage_MovePage(FMPage, Target, Source); end; function TFreeMultiBitmap.Open(const FileName: string; CreateNew, ReadOnly: Boolean; Flags: Integer): Boolean; var fif: FREE_IMAGE_FORMAT; begin Result := False; // try to guess the file format from the filename fif := FreeImage_GetFIFFromFilename(PChar(FileName)); // check for supported file types if (fif <> FIF_UNKNOWN) and (not fif in [FIF_TIFF, FIF_ICO, FIF_GIF]) then Exit; // open the stream FMPage := FreeImage_OpenMultiBitmap(fif, PChar(FileName), CreateNew, ReadOnly, FMemoryCache, Flags); Result := FMPage <> nil; end; procedure TFreeMultiBitmap.UnlockPage(Bitmap: TFreeBitmap; Changed: Boolean); begin if IsValid then begin FreeImage_UnlockPage(FMPage, Bitmap.FDib, Changed); // clear the image so that it becomes invalid. // don't use Bitmap.Clear method because it calls FreeImage_Unload // just clear the pointer Bitmap.FDib := nil; Bitmap.Change; end; end; { TFreeMemoryIO } function TFreeMemoryIO.Acquire(var Data: PByte; var SizeInBytes: DWORD): Boolean; begin Result := FreeImage_AcquireMemory(FHMem, Data, SizeInBytes); end; constructor TFreeMemoryIO.Create(Data: PByte; SizeInBytes: DWORD); begin inherited Create; FHMem := FreeImage_OpenMemory(Data, SizeInBytes); end; destructor TFreeMemoryIO.Destroy; begin FreeImage_CloseMemory(FHMem); inherited; end; function TFreeMemoryIO.GetFileType: FREE_IMAGE_FORMAT; begin Result := FreeImage_GetFileTypeFromMemory(FHMem); end; function TFreeMemoryIO.IsValid: Boolean; begin Result := FHMem <> nil end; function TFreeMemoryIO.Read(fif: FREE_IMAGE_FORMAT; Flag: Integer): PFIBITMAP; begin Result := FreeImage_LoadFromMemory(fif, FHMem, Flag) end; function TFreeMemoryIO.Seek(Offset: Longint; Origin: Word): Boolean; begin Result := FreeImage_SeekMemory(FHMem, Offset, Origin) end; function TFreeMemoryIO.Tell: Longint; begin Result := FreeImage_TellMemory(FHMem) end; function TFreeMemoryIO.Write(fif: FREE_IMAGE_FORMAT; dib: PFIBITMAP; Flag: Integer): Boolean; begin Result := FreeImage_SaveToMemory(fif, dib, FHMem, Flag) end; { TFreeTag } function TFreeTag.Clone: TFreeTag; var CloneTag: PFITAG; begin Result := nil; if not IsValid then Exit; CloneTag := FreeImage_CloneTag(FTag); Result := TFreeTag.Create(CloneTag); end; constructor TFreeTag.Create(ATag: PFITAG); begin inherited Create; if ATag <> nil then FTag := ATag else FTag := FreeImage_CreateTag; end; destructor TFreeTag.Destroy; begin if IsValid then FreeImage_DeleteTag(FTag); inherited; end; function TFreeTag.GetCount: Cardinal; begin Result := 0; if not IsValid then Exit; Result := FreeImage_GetTagCount(FTag); end; function TFreeTag.GetDescription: string; begin Result := ''; if not IsValid then Exit; Result := FreeImage_GetTagDescription(FTag); end; function TFreeTag.GetID: Word; begin Result := 0; if not IsValid then Exit; Result := FreeImage_GetTagID(FTag); end; function TFreeTag.GetKey: string; begin Result := ''; if not IsValid then Exit; Result := FreeImage_GetTagKey(FTag); end; function TFreeTag.GetLength: Cardinal; begin Result := 0; if not IsValid then Exit; Result := FreeImage_GetTagLength(FTag); end; function TFreeTag.GetTagType: FREE_IMAGE_MDTYPE; begin Result := FIDT_NOTYPE; if not IsValid then Exit; Result := FreeImage_GetTagType(FTag); end; function TFreeTag.GetValue: Pointer; begin Result := nil; if not IsValid then Exit; Result := FreeImage_GetTagValue(FTag); end; function TFreeTag.IsValid: Boolean; begin Result := FTag <> nil; end; procedure TFreeTag.SetCount(const Value: Cardinal); begin if IsValid then FreeImage_SetTagCount(FTag, Value); end; procedure TFreeTag.SetDescription(const Value: string); begin if IsValid then FreeImage_SetTagDescription(FTag, PChar(Value)); end; procedure TFreeTag.SetID(const Value: Word); begin if IsValid then FreeImage_SetTagID(FTag, Value); end; procedure TFreeTag.SetKey(const Value: string); begin if IsValid then FreeImage_SetTagKey(FTag, PChar(Value)); end; procedure TFreeTag.SetLength(const Value: Cardinal); begin if IsValid then FreeImage_SetTagLength(FTag, Value); end; procedure TFreeTag.SetTagType(const Value: FREE_IMAGE_MDTYPE); begin if IsValid then FreeImage_SetTagType(FTag, Value); end; procedure TFreeTag.SetValue(const Value: Pointer); begin if IsValid then FreeImage_SetTagValue(FTag, Value); end; function TFreeTag.ToString(Model: FREE_IMAGE_MDMODEL; Make: PChar): string; begin Result := FreeImage_TagToString(Model, FTag, Make); end; end.