BSOne.SFC/EM.Lib/ImageEn_SRC/Source/iexDBBitmaps.pas

3063 lines
102 KiB
Plaintext
Raw Permalink Blame History

(* 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 1002
*)
unit iexDBBitmaps;
{$R-}
{$Q-}
{$I ie.inc}
{$IFDEF IEINCLUDEDB}
interface
uses
Windows, Messages, classes, Graphics, Db, ImageEnView, ImageEnio, hyiedefs, iexBitmaps, hyieutils, ExtCtrls;
type
TIEDataLink = class(TDataLink)
private
fModified: Boolean;
fOnDataChanged: TNotifyEvent;
fOnEditingChanged: TNotifyEvent;
fOnDataUpdated: TNotifyEvent;
fOnActiveChanged: TNotifyEvent;
fOnRecordChanged: TFieldNotifyEvent;
fOnScrolled: TNotifyEvent;
fInternalScroll: Boolean;
protected
procedure ActiveChanged; override;
procedure DataSetChanged; override;
procedure DataSetScrolled(Distance: Integer); override;
procedure EditingChanged; override;
procedure RecordChanged(Field: TField); override;
procedure UpdateData; override;
public
constructor Create();
destructor Destroy; override;
procedure Modified;
procedure MoveToRecord(idx: Integer; bSilent: Boolean = True);
property OnDataChanged: TNotifyEvent read fOnDataChanged write fOnDataChanged;
property OnEditingChanged: TNotifyEvent read fOnEditingChanged write fOnEditingChanged;
property OnDataUpdated: TNotifyEvent read fOnDataUpdated write fOnDataUpdated;
property OnActiveChanged: TNotifyEvent read fOnActiveChanged write fOnActiveChanged;
property OnRecordChanged: TFieldNotifyEvent read fOnRecordChanged write fOnRecordChanged;
property OnScrolled: TNotifyEvent read fOnScrolled write fOnScrolled;
end;
{!!
<FS>TIEImageStorageMode
<FM>Declaration<FC>
type TIEImageStorageMode = (isEmbeddedBlob, isLinkedFile);
<FM>Description<FN>
The method that images are stored or referenced by the database.
<TABLE>
<R> <H>Value</H> <H>Description</H> </R>
<R> <C>isEmbeddedBlob</C> <C>The image is embedded within a blob field</C> </R>
<R> <C>isLinkedFile</C> <C>A string field points to the filename of a local file</C> </R>
</TABLE>
!!}
TIEImageStorageMode = (isEmbeddedBlob, isLinkedFile);
{!!
<FS>TIEDBBitmap
<FM>Description<FN>
TIEDBBitmap is a descendant of <A TIEBitmap>, but it links to a datasource to provide access to images stored in a database table.
TIEDBBitmap supports both images stored within the database as a blob (by setting <A TIEDBBitmap.ImageBlobField>) or images stored locally and referenced by a filename field (by setting only <A TIEDBBitmap.FilenameField>). You will need to set <A TIEDBBitmap.DataSource>.
There are two ways you can use TIEDBBitmap:
<FB><3E> Connected to a TTable<FN>
By setting the <A TIEDBBitmap.DataSource> and <A TIEDBBitmap.ImageBlobField> or <A TIEDBBitmap.FilenameField>, the TIEDBBitmap will be connected to the database and the content will update with the movement and changes on the table, either automatically (<A TIEDBBitmap.AutoLoad> is true) or manually (by calling <A TIEDBBitmap.LoadImage>). This is generally used to create a data-aware <A TImageEnView> by setting the <L TImageEnView.SetExternalBitmap>external bitmap</L> to a TIEDBBitmap.
<FC>
// Create DB Aware TImageEnView
procedure TMainForm.FormCreate(Sender: TObject);
begin
... Open a database table ...
fDBBitmap := TIEDBBitmap.create( DataSource1, 'Image', 'Name' );
ImageEnView1.SetExternalBitmap( fDBBitmap );
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FreeAndNil( fDBBitmap );
end;
<FB><3E> As an adhoc Bitmap with database access<FN>
Use TIEDBBitmap to retrieve images embedded in a database blob field using the data-aware overload of <A TIEDBBitmap.Read>.
<FC>
// Extract an image from a database and save it
MyBMP := TIEDBBitmap.Create();
MyBMP.Read( MyTableImageBlob );
MyBmp.Write( 'D:\MyBlobImage.jpeg' );
MyBmp.Free;
<FM>Methods and Properties<FN>
<FI>General<FN>
<TABLE2>
<R> <C_IMG_METHOD> <C><A TIEBitmap.AdjustmentsMask></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.Allocate></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.BitAlignment></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.BitCount></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Clear></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Contrast></C> </R>
<R> <C_IMG_METHOD> <C><A TIEDBBitmap.Create> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CreateDIB></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CreateROIBitmap></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CreateROICanvas></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.Destroy></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.FreeImage></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.FixChannelOffset></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.FixContrast></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Height></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.IsEmpty></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.IsVirtual></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Location></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.MemoryAllocator></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.MinFileSize></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Origin></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.PixelFormat></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.Resize></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.VclBitmap></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Width></C> </R>
</TABLE>
<FI>Database<FN>
<TABLE2>
<R> <C_IMG_PROPERTY> <C><A TIEDBBitmap.DataSource> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBBitmap.AutoLoad> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBBitmap.FilenameField> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBBitmap.ImageBlobField> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBBitmap.ImageFormat> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBBitmap.ImagePath> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBBitmap.ImageStorageMode> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBBitmap.JpegQuality> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBBitmap.UseMemoryStream> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_METHOD> <C><A TIEDBBitmap.Read> (Load from blob/file/stream) <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_METHOD> <C><A TIEDBBitmap.Write> (Save to blob/file/stream) <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_METHOD> <C><A TIEDBBitmap.LoadImage> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_METHOD> <C><A TIEDBBitmap.UpdateDatabaseImage> <IMG help_images\Star.gif></C> </R>
</TABLE>
<FI>Assignment between Objects<FN>
<TABLE2>
<R> <C_IMG_METHOD> <C><A TIEBitmap.Assign></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.AssignImage></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CopyAndConvertFormat></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CopyFromDIB></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CopyFromMemory></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CopyFromTBitmap></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CopyFromTDibBitmap></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CopyFromTIEMask></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CopyRectTo></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CopyToTBitmap></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CopyToTDibBitmap></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CopyToTIEMask></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CopyWithMask1></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CopyWithMask2></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.DrawToTIEBitmap></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.EncapsulatedFromMemory></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.EncapsulatedFromTBitmap></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.EncapsulateMemory></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.EncapsulateTBitmap></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.MergeFromTDibBitmap></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.RenderToTBitmap></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.RenderToTBitmapEx></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.RenderToTIEBitmap></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.RenderToTIEBitmapEx></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.RestoreState></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.SaveState></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.StretchRectTo></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.SwitchTo></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.UpdateFromTBitmap></C> </R>
</TABLE>
<FI>File I/O<FN>
<TABLE2>
<R> <C_IMG_PROPERTY> <C><A TIEBaseBitmap.Access> (inherited from <A TIEBaseBitmap>)</C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CalcRAWSize></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.GetHash></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.LoadFromResource></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.LoadRAWFromBufferOrStream></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.ParamsEnabled></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Params></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.SaveRAWToBufferOrStream></C> </R>
</TABLE>
<FI>Canvas Access<FN>
<TABLE2>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.IECanvas></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Canvas></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.DrawToCanvas></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.Fill></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.FillRect></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.MoveRegion></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.RenderToCanvas></C> </R>
</TABLE>
<FI>Alpha Channel (Transparency)<FN>
<TABLE2>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Alpha></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.AlphaChannel></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.AlphaChannelOpt></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.CanvasCurrentAlpha></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.DrawToCanvasWithAlpha></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.FeatherAlphaEdges></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.HasAlphaChannel></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.IsAlpha></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.MergeAlphaRectTo></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.MergeWithAlpha></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.RemoveAlphaChannel></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.RenderToCanvasWithAlpha></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.SynchronizeRGBA></C> </R>
</TABLE>
<FI>Pixel Access<FN>
<TABLE2>
<R> <C_IMG_METHOD> <C><A TIEBitmap.FreeRow></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.GetRow></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.GetSegment></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Memory></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Pixels_ie16g></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Pixels_ie1g></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Pixels_ie24RGB></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Pixels_ie32f></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Pixels_ie32RGB></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Pixels_ie48RGB></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Pixels_ie8></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Pixels_ieCIELab></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Pixels_ieCMYK></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Pixels></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.PPixels_ie24RGB></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.PPixels_ie32RGB></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.PPixels_ie48RGB></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Rowlen></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.ScanLine></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.TBitmapScanlines></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.VirtualBitmapProvider></C> </R>
</TABLE>
<FI>Palette and Color<FN>
<TABLE2>
<R> <C_IMG_PROPERTY> <C><A TIEBaseBitmap.Palette> (inherited from <A TIEBaseBitmap>)</C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBaseBitmap.PaletteLength> (inherited from <A TIEBaseBitmap>)</C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBaseBitmap.PaletteUsed> (inherited from <A TIEBaseBitmap>)</C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.AutoCalcBWValues></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.BlackValue></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.ChannelCount></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.ChannelOffset></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.ColorProfile></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.CopyPaletteTo></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.DefaultDitherMethod></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.Full></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.IsAllBlack></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.IsGrayScale></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.StretchValues></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.SyncFull></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEBitmap.WhiteValue></C> </R>
</TABLE>
<FI>Image Manipulation<FN>
<TABLE2>
<R> <C_IMG_METHOD> <C><A TIEBitmap.Flip></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.Resample></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.Rotate></C> </R>
</TABLE>
<FI>IEVision related<FN>
<TABLE2>
<R> <C_IMG_METHOD> <C><A TIEBitmap.GetIEVisionImage></C> </R>
<R> <C_IMG_METHOD> <C><A TIEBitmap.AssignIEVisionImage></C> </R>
</TABLE>
<FI>Events<FN>
<TABLE2>
<R> <C_IMG_EVENT> <C><A TIEBitmap.OnRenderVirtualPixel></C> </R>
</TABLE>
<IMG help_images\Star.gif> Unique functionality to TIEDBBitmap
!!}
TIEDBBitmap = class(TIEBitmap)
private
fDataLink: TIEDataLink;
fImageFormat: TIOFileType;
fLastImageFormat: TIOFileType;
fImagePath: string;
fUseMemoryStream: boolean;
fAutoLoad : boolean;
fFilenameFieldName: string;
fFilenameField: TField;
fImageBlobFieldName: string;
fImageBlobField: TField;
fJPEGQuality: Integer;
fImageLoaded: Boolean;
fAutoLoadTimer: TTimer;
function GetDataSource: TDataSource;
procedure SetDataSource(Value: TDataSource);
procedure SetImagePath(const v: string);
procedure ActiveChanged(Sender: TObject);
procedure SetFilenameFieldName(const Value: string);
procedure SetImageBlobFieldName(const Value: string);
procedure SetAutoLoad(Value: Boolean);
function GetImageStorageMode: TIEImageStorageMode;
procedure DatabaseEvent(Sender: TObject);
procedure UpdateImage(bDelayed: Boolean);
procedure AutoLoadTimerEvent(Sender: TObject);
protected
public
constructor Create(); override;
constructor Create(aDataSource: TDataSource; const sImageBlobField, sFilenameField: string); overload;
destructor Destroy; override;
function LoadImage(): boolean;
procedure UpdateDatabaseImage();
function Read(): boolean; overload;
function Read(aBlobField: TBlobField; FileType: TIOFileType = 0; IOParams: TIOParams = nil): boolean; overload;
function Write(): boolean; overload;
function Write(aBlobField: TBlobField; FileType: TIOFileType; IOParams: TIOParams = nil): boolean; overload;
property ImagePath: string read fImagePath write SetImagePath;
property DataSource: TDataSource read GetDataSource write SetDataSource;
property ImageStorageMode: TIEImageStorageMode read GetImageStorageMode;
{!!
<FS>TIEDBBitmap.ImageFormat
<FM>Declaration<FC>
property ImageFormat: <A TIOFileType>;
<FM>Description<FN>
Specifies the format that images are read and written to the database.
If images are stored in a database blob field (<A TIEDBBitmap.ImageStorageMode> = <FC>isEmbeddedBlob<FN>) <FC>ImageFormat<FN> specifies their image type. The format will be used when loading, and images will be saved to the database in this format.
For images referenced locally (<A TIEDBBitmap.ImageStorageMode> = <FC>isLinkedFile<FN>) the <FC>ImageFormat<FN> is used only when saving image changes.
If <FC>ImageFormat<FN> is <FC>ioUnknown<FN> then the file content is analyzed to determine the format when loading, and the last detected file type is used when saving.
Default: ioUnknown
!!}
property ImageFormat: TIOFileType read fImageFormat write fImageFormat default ioUnknown;
{!!
<FS>TIEDBBitmap.JpegQuality
<FM>Declaration<FC>
property JpegQuality: integer;
<FM>Description<FN>
If database images are <L TIEDBBitmap.ImageFormat>saved to JPEG</L> then <FC>JpegQuality<FN> specifies the save quality (Range: 1 to 100. Higher is better quality, but larger).
This property updates <A TIEBitmap.Params>.<A TIOParams.JPEG_Quality>.
Default: 80
!!}
property JpegQuality: integer read fJpegQuality write fJpegQuality default 80;
{!!
<FS>TIEDBBitmap.UseMemoryStream
<FM>Declaration<FC>
property UseMemoryStream: boolean
<FM>Description<FN>
If True, TIEDBBitmap will use a temporary memory stream to retrieve data from blob stream. Otherwise CreateBlobStream is used.
Default: True
!!}
property UseMemoryStream: boolean read fUseMemoryStream write fUseMemoryStream default true;
property AutoLoad: boolean read fAutoLoad write SetAutoLoad default False;
property FilenameField: string read fFilenameFieldName write SetFilenameFieldName;
property ImageBlobField: string read fImageBlobFieldName write SetImageBlobFieldName;
end;
{$IFDEF IEINCLUDEMULTIVIEW}
{!!
<FS>TIEDBMultiBitmap
<FM>Description<FN>
TIEDBMultiBitmap is a descendant of <A TIECustomMultiBitmap>, but unlike <A TIEMultiBitmap> it links to a datasource to provide access to images stored in a database table.
Generally a TIEDBMultiBitmap is <L TImageEnMView.SetExternalMBitmap>attached</L> to a <A TImageEnMView> to make it DB aware.
TIEDBMultiBitmap supports both images stored within the database as a blob (by setting <A TIEDBMultiBitmap.ImageBlobField>) or images stored locally and referenced by a filename field (by setting only <A TIEDBMultiBitmap.FilenameField>). You will also need to set <A TIEDBMultiBitmap.DataSource>.
<FM>Demo<FN>
<TABLE2>
<R> <C_IMG_DEMO> <C>Demos\Database\DBMultiBitmap\DBMultiBitmap.dpr </C> </R>
</TABLE>
<FM>Example<FC>
// Create DB Aware TImageEnMView
procedure TMainForm.FormCreate(Sender: TObject);
begin
... Open a database table ...
fDBMBitmap := TIEDBMultiBitmap.create( DataSource1, 'Image', 'Name' );
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FreeAndNil( fDBMBitmap );
end;
<FM>Methods and Properties<FN>
<FI>General<FN>
<TABLE2>
<R> <C_IMG_METHOD> <C><A TIEDBMultiBitmap.Create> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_METHOD> <C><A TIEDBMultiBitmap.Destroy></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEMultiBitmap.Count></C> </R>
<R> <C_IMG_METHOD> <C><A TIECustomMultiBitmap.LockUpdate></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIECustomMultiBitmap.LockUpdateCount></C> </R>
<R> <C_IMG_METHOD> <C><A TIECustomMultiBitmap.UnLockUpdate></C> </R>
</TABLE>
<FI>Database<FN>
<TABLE2>
<R> <C_IMG_PROPERTY> <C><A TIEDBMultiBitmap.DataSource> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBMultiBitmap.FollowDBCursor> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBMultiBitmap.FilenameField> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBMultiBitmap.FilenameFieldIsUnique> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBMultiBitmap.ImageBlobField> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBMultiBitmap.ImageFormat> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBMultiBitmap.ImagePath> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBMultiBitmap.ImageStorageMode> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBMultiBitmap.MaxDisplayRecords> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_METHOD> <C><A TIEDBMultiBitmap.Update> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBMultiBitmap.UseMemoryStream> <IMG help_images\Star.gif></C> </R>
</TABLE>
<FI>Database Editing<FN>
<TABLE2>
<R> <C_IMG_METHOD> <C><A TIEDBMultiBitmap.AppendImage> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBMultiBitmap.DefaultFilename> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_METHOD> <C><A TIEDBMultiBitmap.DeleteImage> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_METHOD> <C><A TIEDBMultiBitmap.InsertImage> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBMultiBitmap.JpegQuality> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEDBMultiBitmap.ReadOnly> <IMG help_images\Star.gif></C> </R>
</TABLE>
<FI>Image Access<FN>
<TABLE2>
<R> <C_IMG_METHOD> <C><A TIEMultiBitmap.CopyToIEBitmap></C> </R>
<R> <C_IMG_METHOD> <C><A TIEMultiBitmap.GetBitmap></C> </R>
<R> <C_IMG_METHOD> <C><A TIEDBMultiBitmap.GetTIEBitmap></C> </R>
<R> <C_IMG_METHOD> <C><A TIEDBMultiBitmap.ReleaseBitmap> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_METHOD> <C><A TIEDBMultiBitmap.SetImage> <IMG help_images\Star.gif></C> </R>
</TABLE>
<FI>Image Information<FN>
<TABLE2>
<R> <C_IMG_PROPERTY> <C><A TIEMultiBitmap.ImageBitCount></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEMultiBitmap.ImageFilename></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEMultiBitmap.ImageHeight></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEMultiBitmap.ImageTag></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEMultiBitmap.ImageUserPointer></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEMultiBitmap.ImageWidth></C> </R>
</TABLE>
<FI>Input/Output<FN>
<TABLE2>
<R> <C_IMG_PROPERTY> <C><A TIEMultiBitmap.ImageCacheSize></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEMultiBitmap.ImageCacheUseDisk></C> </R>
<R> <C_IMG_METHOD> <C><A TIEMultiBitmap.GetImageToFile></C> </R>
<R> <C_IMG_METHOD> <C><A TIEMultiBitmap.GetImageToStream></C> </R>
</TABLE>
<FI>Input/Output Parameters (Meta-Data)<FN>
<TABLE2>
<R> <C_IMG_PROPERTY> <C><A TIEMultiBitmap.ParamsEnabled></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEMultiBitmap.Params></C> </R>
</TABLE>
<FI>Image Manipulation<FN>
<TABLE2>
<R> <C_IMG_METHOD> <C><A TIEDBMultiBitmap.Flip> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_METHOD> <C><A TIEDBMultiBitmap.Resample> <IMG help_images\Star.gif></C> </R>
<R> <C_IMG_METHOD> <C><A TIEDBMultiBitmap.Rotate> <IMG help_images\Star.gif></C> </R>
</TABLE>
<IMG help_images\Star.gif> Unique functionality to TIEDBMultiBitmap
!!}
TIEDBMultiBitmap = class(TIECustomMultiBitmap)
procedure UpdateActive;
private
fDataLink: TIEDataLink;
fMaxDisplayRecords: Integer;
fImageFormat: TIOFileType;
fLastImageFormat: TIOFileType;
fImagePath: string;
fUseMemoryStream: boolean;
fFollowDBCursor : boolean;
fFilenameFieldName: string;
fFilenameField: TField;
fImageBlobFieldName: string;
fImageBlobField: TField;
fBlobBitmap: TIEBitmap;
fDefaultFilename: string;
fJPEGQuality: Integer;
fUpdatePendingIsFull : Boolean; // True if the pending update should also clear the cache (See TIECustomMultiBitmap.fUpdatePending)
fFilenameFieldIsUnique: Boolean;
function GetDataSource: TDataSource;
function GetReadOnly: Boolean;
procedure SetDataSource(Value: TDataSource);
procedure SetReadOnly(Value: Boolean);
procedure SetImagePath(const v: string);
procedure ActiveChanged(Sender: TObject);
procedure DataChanged(Sender: TObject);
procedure DataUpdated(Sender: TObject);
procedure Scrolled(Sender: TObject);
procedure RecordChanged(Field: TField);
procedure SetFilenameFieldName(const Value: string);
procedure SetImageBlobFieldName(const Value: string);
procedure SetFollowDBCursor(Value: Boolean);
procedure SetMaxDisplayRecords(Value: Integer);
procedure InsertOrAppend(idx: integer);
function GetImageStorageMode: TIEImageStorageMode;
protected
procedure CheckAllocated(idx: integer); override;
public
constructor Create(); override;
constructor Create(aDataSource: TDataSource; const sImageBlobField, sFilenameField: string; bFilenameFieldIsUnique: Boolean = False); overload;
destructor Destroy; override;
function AppendImage(): integer; overload; override;
function AppendImage(Stream: TStream): integer; overload; override;
function AppendImage(Bitmap: TIEBitmap): integer; overload; override;
function AppendImage(MBitmap: TIECustomMultiBitmap): integer; overload; override;
function AppendImage(Bitmap : TBitmap): integer; overload; override;
function AppendImage(Width, Height: Integer; PixelFormat: TIEPixelFormat = ie24RGB): Integer; overload; override;
function AppendImage(const FileName: String): integer; overload; override;
procedure InsertImage(Idx : integer); overload; override;
procedure InsertImage(Idx : integer; Stream : TStream); overload; override;
procedure InsertImage(Idx : integer; Bitmap : TIEBitmap); overload; override;
procedure InsertImage(Idx : integer; MBitmap : TIECustomMultiBitmap); overload; override;
procedure InsertImage(Idx : integer; Bitmap : TBitmap); overload; override;
procedure InsertImage(Idx : integer; Width, Height : integer; PixelFormat : TIEPixelFormat = ie24RGB); overload; override;
procedure InsertImage(Idx : integer; const FileName : string); overload; override;
// Internal use only
procedure SetActiveImage(idx: integer); override;
property ImagePath: string read fImagePath write SetImagePath;
procedure Update; override;
procedure UpdateEx(bFullUpdate: Boolean = true); override;
property DataSource: TDataSource read GetDataSource write SetDataSource;
property ReadOnly: Boolean read GetReadOnly write SetReadOnly default False;
property ImageStorageMode: TIEImageStorageMode read GetImageStorageMode;
{!!
<FS>TIEDBMultiBitmap.FilenameFieldIsUnique
<FM>Declaration<FC>
property FilenameFieldIsUnique: Boolean;
<FM>Description<FN>
If the specified filename field, <A TIEDBMultiBitmap.FilenameField>, is guaranteed to be unique (i.e. each record has a different name specified) then set <FC>FilenameFieldIsUnique<FN> to true. This will improve performance and caching.
Also, if you are using <A TIEDBMultiBitmap.ImageStorageMode> = <FC>isLinkedFile<FN> and your filename field contains a full path (<A TIEDBMultiBitmap.ImagePath> = '') you can set this to true.
Default: False
!!}
property FilenameFieldIsUnique: Boolean read fFilenameFieldIsUnique write fFilenameFieldIsUnique;
{!!
<FS>TIEDBMultiBitmap.DefaultFilename
<FM>Declaration<FC>
property DefaultFilename: string;
<FM>Description<FN>
Specifies a filename to use when an image needs to be saved (if the file already exists a numbered filename will be generated).
If images are stored as local files (<A TIEDBMultiBitmap.ImageStorageMode> = <FC>isLinkedFile<FN>) then when <L TIEDBMultiBitmap.AppendImage>appending</L> bitmaps a file will be saved and then referenced by the database.
For images referenced locally using only <A TIEDBMultiBitmap.FilenameField> the is useful only if images do not have a file extension.
If you have set an <A TIEDBMultiBitmap.ImagePath> then <FC>DefaultFilename<FN> need only be a name, such as "Image". Otherwise a full path must be set, e.g. "C:\My Image Folder\Image"
Default: 'Image'
!!}
property DefaultFilename: string read fDefaultFilename write fDefaultFilename;
{!!
<FS>TIEDBMultiBitmap.ImageFormat
<FM>Declaration<FC>
property ImageFormat: <A TIOFileType>;
<FM>Description<FN>
Specifies the format that images are read and written to the database.
If images are stored in a database blob field (<A TIEDBMultiBitmap.ImageStorageMode> = <FC>isEmbeddedBlob<FN>) <FC>ImageFormat<FN> specifies their image type. The format will be used when loading, and images will be saved to the database in this format.
For images referenced locally (<A TIEDBMultiBitmap.ImageStorageMode> = <FC>isLinkedFile<FN>) the <FC>ImageFormat<FN> is used only when saving image changes.
If <FC>ImageFormat<FN> is <FC>ioUnknown<FN> (Default) then the file content is analyzed to determine the format when loading, and the last detected file type is used when saving.
Default: ioUnknown
!!}
property ImageFormat: TIOFileType read fImageFormat write fImageFormat default ioUnknown;
{!!
<FS>TIEDBMultiBitmap.JpegQuality
<FM>Declaration<FC>
property JpegQuality: integer;
<FM>Description<FN>
If database images are <L TIEDBMultiBitmap.ImageFormat>saved to JPEG</L> then <FC>JpegQuality<FN> specifies the save quality (Range: 1 to 100. Higher is better quality, but larger).
This property updates <A TIEMultiBitmap.Params>.<A TIOParams.JPEG_Quality>.
Default: 80
!!}
property JpegQuality: integer read fJpegQuality write fJpegQuality default 80;
{!!
<FS>TIEDBMultiBitmap.UseMemoryStream
<FM>Declaration<FC>
property UseMemoryStream: boolean
<FM>Description<FN>
If True, TIEDBMultiBitmap will use a temporary memory stream to retrieve data from blob stream. Otherwise CreateBlobStream is used.
Default: True
!!}
property UseMemoryStream: boolean read fUseMemoryStream write fUseMemoryStream default true;
property FollowDBCursor: boolean read fFollowDBCursor write SetFollowDBCursor default False;
property MaxDisplayRecords: Integer read fMaxDisplayRecords write SetMaxDisplayRecords default 10000;
property FilenameField: string read fFilenameFieldName write SetFilenameFieldName;
property ImageBlobField: string read fImageBlobFieldName write SetImageBlobFieldName;
procedure DeleteImage(idx: integer); override;
procedure SetImage(idx: Integer; srcImage: TBitmap); overload; override;
procedure SetImage(idx: integer; srcImage: TIEBaseBitmap); overload; override;
procedure SetImage(idx: Integer; width, height: Integer; PixelFormat: TIEPixelFormat); overload; override;
function SetImage(idx: integer; const FileName: WideString; SourceImageIndex: Integer = 0; FileFormat: TIOFileType = ioUnknown): boolean; overload; override;
function SetImage(idx: integer; Stream: TStream; SourceImageIndex: Integer = 0; FileFormat: TIOFileType = ioUnknown): boolean; overload; override;
// Public, but not exposed in documentation
procedure SetCurrentImage(srcImage: TIEBaseBitmap; const sDisplayName: string; bCanOverwriteExisting: Boolean = False);
procedure Flip(idx: integer; Dir: TFlipDir); override;
procedure Rotate(idx: integer; Angle: double; AntialiasMode: TIEAntialiasMode = ierFast; BackgroundColor: TColor = clWhite); override;
procedure Resample(idx: integer; ScaleBy: Double; FilterType: TResampleFilter = rfNone); override;
procedure ReleaseBitmap(idx: Integer; SaveChanges: Boolean); override;
// Internal use only
function SetImageFromStreamOrFile(idx: integer; Stream: TStream; const FileName: WideString; SourceImageIndex: Integer; FileFormat: TIOFileType; MIO: TObject = nil): Boolean; override;
function InternalLoadImageByID_Assigned(): Boolean; override;
procedure InternalLoadImageByID(Sender: TObject; Index, ID: Integer; var Bitmap: TIEBitmap; var IOParams: TIOParams); override;
end;
{$endif}
{$IFDEF UNITTESTING}
var
gUnitTesting_ImagesPath: string;
{$ENDIF}
implementation
uses
controls, sysutils, iemview, iesettings;
{$R-}
const
Cannot_Respotion_Error_Str = 'TIEDBMultiBitmap.SetImage cannot reposition table';
{ TIEDataLink }
constructor TIEDataLink.Create();
begin
inherited Create;
VisualControl := True;
fInternalScroll := False;
end;
destructor TIEDataLink.Destroy;
begin
//
inherited Destroy;
end;
procedure TIEDataLink.ActiveChanged;
begin
if assigned( fOnActiveChanged ) then
fOnActiveChanged( Self );
fModified := False;
end;
procedure TIEDataLink.Modified;
begin
fModified := True;
end;
procedure TIEDataLink.DataSetChanged;
begin
if assigned( fOnDataChanged ) then
fOnDataChanged( Self );
fModified := False;
end;
procedure TIEDataLink.DataSetScrolled(Distance: Integer);
begin
if ( fInternalScroll = False ) and assigned( fOnScrolled ) then
fOnScrolled( Self );
end;
procedure TIEDataLink.EditingChanged;
begin
if assigned( fOnEditingChanged ) then
fOnEditingChanged( Self );
end;
procedure TIEDataLink.RecordChanged(Field: TField);
begin
if assigned( fOnRecordChanged ) and ( Dataset.State <> dsEdit ) then
fOnRecordChanged( Field );
fModified := False;
end;
procedure TIEDataLink.UpdateData;
begin
if fModified and assigned( fOnDataUpdated ) then
fOnDataUpdated( Self );
fModified := False;
end;
// if bSilent then OnScrolled event is not called
procedure TIEDataLink.MoveToRecord(idx: Integer; bSilent: Boolean = True);
var
iMoveBy: Integer;
begin
if bSilent then
fInternalScroll := True;
try
iMoveBy := idx - ActiveRecord;
if iMoveBy <> 0 then
MoveBy( iMoveBy );
finally
fInternalScroll := False;
end;
end;
function HasAbsolutePath(const wFilename: WideString) : Boolean;
begin
Result := ( IECopy( AnsiString( wFilename ), 2, 2) = ':\' ) or // File path: D:\MyImage.jpg
( IECopy( AnsiString( wFilename ), 1, 2) = '\\' ); // UNC Path: \\SILVER_LAPTOP\D_On_E4440
end;
procedure IEBitmap_ReadFromBlob(Bitmap: TIEBitmap; var IOParams: TIOParams; BlobField: TBlobField; bUseMemoryStream: Boolean; out iFileFormat: TIOFileType);
var
aStream: TStream;
begin
if BlobField.BlobSize = 0 then
raise EIEException.create( 'Null Blob' );
aStream := nil;
try
if bUseMemoryStream then
begin
// Retrieve image via temporary memory stream
aStream := TMemoryStream.Create;
BlobField.SaveToStream( aStream );
aStream.Position := 0;
end
else
begin
// Directly retrieve the image
aStream := BlobField.DataSet.CreateBlobStream( BlobField, bmRead );
end;
if iFileFormat = ioUnknown then
iFileFormat := FindStreamFormat( aStream );
if Bitmap.Read( aStream, iFileFormat, IOParams ) = False then
raise EIEException.create( 'Read Error' );
finally
aStream.Free();
end;
end;
// DataSet can be nil
procedure IEBitmap_WriteToBlob(Bitmap: TIEBitmap; var IOParams: TIOParams; BlobField: TBlobField; bUseMemoryStream: Boolean; iFileFormat: TIOFileType);
var
aMemStream: TMemoryStream;
aBlobStream: TStream;
begin
if bUseMemoryStream then
begin
// SAVE BITMAP TO BLOB (MEM STREAM)
aMemStream := TMemoryStream.Create;
try
if Bitmap.Write( aMemStream, iFileFormat, IOParams ) = False then
raise EIEException.create( 'Write Error' );
aMemStream.Position := 0;
// Transfer from the memory stream to the blobstream
aBlobStream := BlobField.DataSet.CreateBlobStream( BlobField, bmWrite );
try
aMemStream.SaveToStream( aBlobStream );
finally
aBlobStream.Free;
end;
finally
aMemStream.free;
end;
end
else
begin
// SAVE BITMAP TO BLOB (DIRECT)
aBlobStream := BlobField.DataSet.CreateBlobStream( BlobField, bmWrite );
try
if Bitmap.Write( aBlobStream, iFileFormat, IOParams ) = False then
raise EIEException.create( 'Write Error' );
finally
aBlobStream.Free;
end;
end;
end;
{ TIEDBBitmap }
{!!
<FS>TIEDBBitmap.Create
<FM>Declaration<FC>
constructor Create(); overload;
constructor Create(aDataSource: TDataSource; const sImageBlobField, sFilenameField: string); overload;
<FM>Description<FN>
Create a new TIEDBBitmap object.
Second overload creates the bitmap and sets <A TIEDBBitmap.DataSource>, <A TIEDBBitmap.ImageBlobField> and <A TIEDBBitmap.FilenameField>.
<FM>Examples<FC>
// Create DB Aware TImageEnView
procedure TMainForm.FormCreate(Sender: TObject);
begin
... Open a database table ...
fDBBitmap := TIEDBBitmap.create( DataSource1, 'Image', 'Name' );
ImageEnView1.SetExternalBitmap( fDBBitmap );
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FreeAndNil( fDBBitmap );
end;
// Extract an image from a database and save it
MyBMP := TIEDBBitmap.Create();
MyBMP.Read( MyTableImageBlob );
MyBmp.Write( 'D:\MyBlobImage.jpeg' );
MyBmp.Free;
!!}
constructor TIEDBBitmap.Create();
begin
inherited Create();
fDataLink := TIEDataLink.Create();
fDataLink.OnDataChanged := DatabaseEvent;
fDataLink.OnDataUpdated := DatabaseEvent;
fDataLink.OnScrolled := DatabaseEvent;
fDataLink.OnActiveChanged := ActiveChanged;
fAutoLoadTimer := nil;
fImagePath := '';
fImageFormat := ioUnknown;
fJpegQuality := 80;
fUseMemoryStream := true;
fAutoLoad := True;
fLastImageFormat := ioJPEG;
fImageLoaded := False;
end;
constructor TIEDBBitmap.Create(aDataSource: TDataSource; const sImageBlobField, sFilenameField: string);
begin
Create();
fDataLink.DataSource := aDataSource;
fFilenameFieldName := sFilenameField;
fImageBlobFieldName := sImageBlobField;
ActiveChanged( nil );
Modified := False;
end;
destructor TIEDBBitmap.Destroy;
begin
FreeAndNil( fAutoLoadTimer );
FreeAndNil( fDataLink );
inherited Destroy;
end;
{!!
<FS>TIEDBBitmap.DataSource
<FM>Declaration<FC>
property DataSource: TDataSource;
<FM>Description<FN>
Link the bitmap with a dataset. You will also need to set <A TIEDBBitmap.FilenameField> or <A TIEDBBitmap.ImageBlobField>.
If <A TIEDBBitmap.AutoLoad> is enabled the content will automatically update as the attached table changes. Otherwise you can call <A TIEDBBitmap.LoadImage>.
<FM>Examples<FC>
// Display content of a table where images are stored in a blob field
fDBBitmap := TIEDBBitmap.create();
fDBBitmap.DataSource := DataSource1;
fDBBitmap.ImageBlobField := 'ImageBlob';
ImageEnView1.SetExternalBitmap( fDBBitmap );
// Display content of a table where images are stored in a blob field and name of image is stored in "ImageName" field
fDBBitmap := TIEDBBitmap.create();
fDBBitmap.DataSource := DataSource1;
fDBBitmap.FilenameField := 'ImageName';
fDBBitmap.ImageBlobField := 'ImageBlob';
ImageEnView1.SetExternalBitmap( fDBBitmap );
// Display content of a table where images are stored in a folder and their path and filename is referenced by the "ImageFilename" field
fDBBitmap := TIEDBBitmap.create();
fDBBitmap.DataSource := DataSource1;
fDBBitmap.FilenameField := 'ImageFilename';
ImageEnView1.SetExternalBitmap( fDBBitmap );
// Display content of a table where images are stored in a folder named "My Folder" and their filename is referenced by the "ImageName" field
fDBBitmap := TIEDBBitmap.create();
fDBBitmap.DataSource := DataSource1;
fDBBitmap.ImagePath := 'C:\My Folder\';
fDBBitmap.FilenameField := 'ImageName';
ImageEnView1.SetExternalBitmap( fDBBitmap );
Note: Don't forget to free the object...
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FreeAndNil( fDBBitmap );
end;
!!}
function TIEDBBitmap.GetDataSource: TDataSource;
begin
Result := fDataLink.DataSource;
end;
procedure TIEDBBitmap.SetDataSource(Value: TDataSource);
begin
if Value <> fDataLink.Datasource then
begin
fDataLink.DataSource := Value;
ActiveChanged( nil );
end;
end;
{!!
<FS>TIEDBBitmap.ImageStorageMode
<FM>Declaration<FC>
property ImageStorageMode: <A TIEImageStorageMode>; (Read-Only)
<FM>Description<FN>
Returns the method that images are stored or referenced by the database.
If you have set <A TIEDBBitmap.ImageBlobField> then ImageStorageMode will return <FC>isEmbeddedBlob<FN>. Otherwise it will return <FC>isLinkedFile<FN>.
Setting <A TIEDBBitmap.FilenameField> has no effect on <FC>ImageStorageMode<FN>, because it can optionally provide a display name for an image stored in a blob field.
<TABLE>
<R> <H>Value</H> <H>Description</H> </R>
<R> <C>isEmbeddedBlob</C> <C>The image is embedded within a blob field</C> </R>
<R> <C>isLinkedFile</C> <C>A string field points to the filename of a local file</C> </R>
</TABLE>
!!}
function TIEDBBitmap.GetImageStorageMode: TIEImageStorageMode;
begin
Result := isLinkedFile;
if fImageBlobField <> nil then
Result := isEmbeddedBlob;
end;
{!!
<FS>TIEDBBitmap.ImagePath
<FM>Declaration<FC>
property ImagePath: string;
<FM>Description<FN>
If your database table references images that are stored locally as files (i.e. <A TIEDBBitmap.ImageStorageMode> = <FC>isLinkedFile<FN>) then you can use <FC>ImagePath<FN> to specify the folder where the files are located, i.e. the load path is specified by <FC>ImagePath<FN> + "Filename Field content".
Example usage:
- If <A TIEDBBitmap.FilenameField> is the full path to a local file then set <FC>ImagePath<FN> to ''
- If <A TIEDBBitmap.FilenameField> is only a name or has an invalid path then set <FC>ImagePath<FN> to the image folder
<TABLE>
<R> <H>ImagePath Property Value</H> <H>Content of Filename Field</H> <H>Loads Image From...</H> </R>
<R> <C></C> <C>C:\Some Folder\MyImage.jpg</C> <C>C:\Some Folder\MyImage.jpg</C> </R>
<R> <C>C:\Some Folder\</C> <C>MyImage.jpg</C> <C>C:\Some Folder\MyImage.jpg</C> </R>
<R> <C>C:\Some Folder\</C> <C>..\MyImage.jpg</C> <C>C:\Some Folder\..\MyImage.jpg</C> </R>
<R> <C>C:\Some Folder\</C> <C>D:\FolderX\MyImage.jpg</C> <C>C:\Some Folder\MyImage.jpg</C> </R>
<R> <C>http://www.imageen.com/images/</C> <C>MyImage.jpg</C> <C>http://www.imageen.com/images/MyImage.jpg</C> </R>
<R> <C></C> <C>http://www.imageen.com/images/MyImage.jpg</C> <C>http://www.imageen.com/images/MyImage.jpg</C> </R>
</TABLE>
<FM>Examples<FC>
// Display content of a table where images are stored in a folder and their path and filename is referenced by the "ImageFilename" field
fDBBitmap := TIEDBBitmap.create();
fDBBitmap.DataSource := DataSource1;
fDBBitmap.FilenameField := 'ImageFilename';
ImageEnView1.SetExternalBitmap( fDBBitmap );
// Display content of a table where images are stored in a folder named "My Folder" and their filename is referenced by the "ImageName" field
fDBBitmap := TIEDBBitmap.create();
fDBBitmap.DataSource := DataSource1;
fDBBitmap.ImagePath := 'C:\My Folder\';
fDBBitmap.FilenameField := 'ImageName';
ImageEnView1.SetExternalBitmap( fDBBitmap );
Note: Don't forget to free the object...
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FreeAndNil( fDBBitmap );
end;
!!}
procedure TIEDBBitmap.SetImagePath(const v: string);
begin
if fImagePath <> v then
begin
fImagePath := v;
UpdateImage( False );
end;
end;
procedure TIEDBBitmap.ActiveChanged(Sender: TObject);
begin
if fDataLink.Active and ( fFilenameFieldName <> '' ) then
begin
fFilenameField := fDataLink.DataSet.FindField( fFilenameFieldName );
if ( fFilenameField <> nil ) and ( TStringField( fFilenameField ).Size < 13 ) then
raise EIEException.create( 'Invalid Field Size' );
end
else
fFilenameField := nil;
if fDataLink.Active and ( fImageBlobFieldName <> '' ) then
fImageBlobField := fDataLink.DataSet.FindField( fImageBlobFieldName )
else
fImageBlobField := nil;
UpdateImage( False );
end;
// Handles: OnScrolled, OnDataChanged and OnDataUpdated
procedure TIEDBBitmap.DatabaseEvent(Sender: TObject);
begin
UpdateImage( True );
end;
procedure TIEDBBitmap.UpdateImage(bDelayed: Boolean);
begin
{$IFDEF UNITTESTING}
bDelayed := false;
{$ENDIF}
fImageLoaded := False;
if fAutoLoad then
begin
if bDelayed = False then
LoadImage
else
begin
// Delayed load
if not assigned(fAutoLoadTimer) then
begin
fAutoLoadTimer := TTimer.Create(nil);
fAutoLoadTimer.Interval := 210;
fAutoLoadTimer.OnTimer := AutoLoadTimerEvent;
end;
fAutoLoadTimer.enabled := False;
fAutoLoadTimer.enabled := True;
end;
end;
end;
procedure TIEDBBitmap.AutoLoadTimerEvent(Sender: TObject);
begin
LoadImage;
end;
{!!
<FS>TIEDBBitmap.FilenameField
<FM>Declaration<FC>
property FilenameField : string;
<FM>Description<FN>
Specifies the database field that contains the name or filename of the image. It must be the name of a TStringField.
TIEDBBitmap can be used in two ways:
- Reading images directly from a database blob field, by setting <A TIEDBBitmap.ImageBlobField> to a valid field. In this situation <FC>FilenameField<FN> specifies a display name for the image (and is optional).
- Reading files stored in a local folder and referenced by a database string field, by setting <A TIEDBBitmap.ImageBlobField> to ''. In this case <FC>FilenameField<FN> should either be a full path to a local file, or a name only with the folder specified by <A TIEDBBitmap.ImagePath>
Note: Either <A TIEDBBitmap.ImageBlobField> or <A TIEDBBitmap.FilenameField> must be set (or both).
<FM>Examples<FC>
// Display content of a table where images are stored in a blob field
fDBBitmap := TIEDBBitmap.create();
fDBBitmap.DataSource := DataSource1;
fDBBitmap.ImageBlobField := 'ImageBlob';
ImageEnView1.SetExternalBitmap( fDBBitmap );
// Display content of a table where images are stored in a blob field and name of image is stored in "ImageName" field
fDBBitmap := TIEDBBitmap.create();
fDBBitmap.DataSource := DataSource1;
fDBBitmap.FilenameField := 'ImageName';
fDBBitmap.ImageBlobField := 'ImageBlob';
ImageEnView1.SetExternalBitmap( fDBBitmap );
// Display content of a table where images are stored in a folder and their path and filename is referenced by the "ImageFilename" field
fDBBitmap := TIEDBBitmap.create();
fDBBitmap.DataSource := DataSource1;
fDBBitmap.FilenameField := 'ImageFilename';
ImageEnView1.SetExternalBitmap( fDBBitmap );
// Display content of a table where images are stored in a folder named "My Folder" and their filename is referenced by the "ImageName" field
fDBBitmap := TIEDBBitmap.create();
fDBBitmap.DataSource := DataSource1;
fDBBitmap.ImagePath := 'C:\My Folder\';
fDBBitmap.FilenameField := 'ImageName';
ImageEnView1.SetExternalBitmap( fDBBitmap );
Note: Don't forget to free the object...
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FreeAndNil( fDBBitmap );
end;
<FM>See Also<FN>
- <A TIEDBBitmap.ImagePath>
- <A TIEDBBitmap.ImageBlobField>
- <A TIEDBBitmap.ImageStorageMode>
!!}
procedure TIEDBBitmap.SetFilenameFieldName(const Value: string);
begin
if fFilenameFieldName <> Value then
begin
fFilenameFieldName := Value;
ActiveChanged( nil );
end;
end;
{!!
<FS>TIEDBBitmap.ImageBlobField
<FM>Declaration<FC>
property ImageBlobField : string;
<FM>Description<FN>
Specifies the database blob field that embeds image files. It must be the name of a TBlobField.
TIEDBBitmap can be used in two ways:
- Reading images directly from a database blob field
- Reading files stored in a local folder and referenced by a database string field
If <A TIEDBBitmap.ImageBlobField> is not set then images will be loaded locally (using <A TIEDBBitmap.FilenameField>)
If <A TIEDBBitmap.ImageBlobField> is a valid field, then images will be read from the embedded blob field. The file format will be determined using <A TIEDBBitmap.ImageFormat>. You can optionally set <A TIEDBBitmap.FilenameField> to specify a field with a display name for the image.
Note: Either <A TIEDBBitmap.ImageBlobField> or <A TIEDBBitmap.FilenameField> must be set (or both).
<FM>Examples<FC>
// Display content of a table where images are stored in a blob field
fDBBitmap := TIEDBBitmap.create();
fDBBitmap.DataSource := DataSource1;
fDBBitmap.ImageBlobField := 'ImageBlob';
ImageEnView1.SetExternalBitmap( fDBBitmap );
// Display content of a table where images are stored in a blob field and name of image is stored in "ImageName" field
fDBBitmap := TIEDBBitmap.create();
fDBBitmap.DataSource := DataSource1;
fDBBitmap.FilenameField := 'ImageName';
fDBBitmap.ImageBlobField := 'ImageBlob';
ImageEnView1.SetExternalBitmap( fDBBitmap );
// Display content of a table where images are stored in a folder and their path and filename is referenced by the "ImageFilename" field
fDBBitmap := TIEDBBitmap.create();
fDBBitmap.DataSource := DataSource1;
fDBBitmap.FilenameField := 'ImageFilename';
ImageEnView1.SetExternalBitmap( fDBBitmap );
// Display content of a table where images are stored in a folder named "My Folder" and their filename is referenced by the "ImageName" field
fDBBitmap := TIEDBBitmap.create();
fDBBitmap.DataSource := DataSource1;
fDBBitmap.ImagePath := 'C:\My Folder\';
fDBBitmap.FilenameField := 'ImageName';
ImageEnView1.SetExternalBitmap( fDBBitmap );
Note: Don't forget to free the object...
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FreeAndNil( fDBBitmap );
end;
<FM>See Also<FN>
- <A TIEDBBitmap.ImageFormat>
- <A TIEDBBitmap.FilenameField>
- <A TIEDBBitmap.ImageStorageMode>
!!}
procedure TIEDBBitmap.SetImageBlobFieldName(const Value: string);
begin
if fImageBlobFieldName <> Value then
begin
fImageBlobFieldName := Value;
ActiveChanged( nil );
end;
end;
{!!
<FS>TIEDBBitmap.AutoLoad
<FM>Declaration<FC>
property AutoLoad: boolean;
<FM>Description<FN>
If True and the TIEDBBitmap is attached to a <A TImageEnView> then changes to the database table cursor will be reflected in the TImageEnView. In other words, navigating the table will change the selected image in the TImageEnView.
If <FC>AutoLoad<FN> is false, you will need to call <A TIEDBBitmap.LoadImage> to refresh the image when the database cursor changes position.
Default: True
!!}
procedure TIEDBBitmap.SetAutoLoad(Value: Boolean);
begin
if fAutoLoad <> Value then
begin
fAutoLoad := Value;
UpdateImage( False );
end;
end;
{!!
<FS>TIEDBBitmap.LoadImage
<FM>Declaration<FC>
function LoadImage(): boolean;
<FM>Description<FN>
Loads the image at the current database position into the bitmap (if it has changed). If you have enabled <A TIEDBBitmap.AutoLoad> then you do not need to call <FC>LoadImage<FN>.
Returns <FC>False<FN> on failure.
Notes:
- This will only work if you have set <A TIEDBBitmap.DataSource> and <A TIEDBBitmap.ImageBlobField> (images stored in database table) or <A TIEDBBitmap.FilenameField> (images stored locally and referenced by the database table).
- This is the same as calling Read() except that loading is skipped if content has not changed
<FM>See Also<FN>
- <A TIEDBBitmap.AutoLoad>
- <A TIEDBBitmap.Read>
!!}
function TIEDBBitmap.LoadImage(): boolean;
begin
Result := True;
if fImageLoaded then
exit;
Result := Read();
fImageLoaded := True;
end;
{!!
<FS>TIEDBBitmap.UpdateDatabaseImage
<FM>Declaration<FC>
procedure UpdateDatabaseImage();
<FM>Description<FN>
Writes any changes to the image back to the blob field of the database table (at the current cursor position). Your current settings for <A TIEDBBitmap.DataSource>, <A TIEDBBitmap.ImageBlobField>, <A TIEDBBitmap.ImageStorageMode> and <A TIEDBBitmap.JpegQuality> are used.
This method has no effect if images are not stored within the database (i.e. <A TIEDBBitmap.ImageStorageMode> must be <FC>isEmbeddedBlob<FN>).
Raises exception on failure.
Note: This is the same as calling:<FC>
MyTable.Edit;
MyDBBitmap.Write();
MyTable.Post;
<FM>Example<FC>
// Rotate the current image and update the database
MyDBBitmap.Rotate( -90 );
MyDBBitmap.UpdateDatabaseImage();
<FM>See Also<FN>
- <A TIEDBBitmap.Write>
!!}
procedure TIEDBBitmap.UpdateDatabaseImage();
begin
try
fDataLink.DataSet.Edit;
if not Write then
raise EIEException.create('Unable to write image to file');
fDataLink.DataSet.Post;
except
fDataLink.DataSet.Cancel;
Raise;
end;
end;
{!!
<FS>TIEDBBitmap.Read
<FM>Declaration<FC>
function Read(): boolean; overload;
function Read(aBlobField: TBlobField; FileType: <A TIOFileType> = 0; IOParams: <A TIOParams> = nil): boolean; overload;
function Read(const FileName: string; IOParams: <A TIOParams> = nil): boolean; overload;
function Read(Stream: TStream; FileType: <A TIOFileType> = ioUnknown; IOParams: <A TIOParams> = nil): boolean; overload;
function Read(Buffer: pointer; BufferSize: integer; FileType: <A TIOFileType> = ioUnknown; IOParams: <A TIOParams> = nil): boolean;
<FM>Description<FN>
Load an image from a blob field, file or stream. This method supports all formats supported by <A TImageEnIO> class.
The Read(); overload reads the image at the current database position using the properties of <A TIEDBBitmap.DataSource>, <A TIEDBBitmap.ImageBlobField> and/or <A TIEDBBitmap.FilenameField>.
When reading from a blob or stream you can optionally specify the <L TIOFileType>Format</L>. If it is not specified ImageEn will determine the file type automatically.
You can optionally pass an <A TIOParams> object for the I/O parameters of the file (see also <A TIEBitmap.ParamsEnabled>).
Returns <FC>False<FN> on failure.
<FM>Examples<FC>
// Extract an image from a database and save it
MyBMP := TIEDBBitmap.Create();
MyBMP.Read( MyTableImageBlob );
MyBmp.Write( 'D:\MyBlobImage.jpeg' );
MyBmp.Free;
// Reduce the size of an image in the database
MyBMP := TIEDBBitmap.Create();
MyBMP.Read( MyTableImageBlobField );
MyBmp.Resample( 800, 600, rfLanczos3, true);
MyBmp.JpegQuality := 75;
MyBmp.Write( MyTableImageBlobField, ioJPEG );
MyBmp.Free;
<FM>See Also<FN>
- <A TIEDBBitmap.LoadImage>
- <A TIEDBBitmap.Write>
!!}
function TIEDBBitmap.Read(): boolean;
var
IOParams: TIOParams;
wFilename: Widestring;
begin
IOParams := nil;
if ( fOwner <> nil ) and ( fOwner is TImageEnView ) then
IOParams := TImageEnView( fOwner ).IO.Params;
// Read Filename field
wFilename := '';
if fFilenameField <> nil then
wFilename := WideString( TStringField( fFilenameField ).Value );
{$IFDEF UNITTESTING}
if Pos( Widestring( 'XXX\' ), wFilename ) = 1 then
wFilename := StringReplace( wFilename, 'XXX\', IEAddBackSlash( gUnitTesting_ImagesPath ), []);
{$ENDIF}
if wFilename <> '' then
begin
if ( fImagePath <> '' ) and HasAbsolutePath( wFilename ) then
wFilename := ExtractFileName( wFilename );
wFilename := IEAddBackSlash( fImagePath ) + wFilename;
end;
// Load Image
if ImageStorageMode = isLinkedFile then
begin
if wFilename = '' then
Result := False
else
Result := Read( wFilename, IOParams );
end
else
// ImageStorageMode = isEmbeddedBlob
begin
Result := Read( TBlobField( fImageBlobField ), fImageFormat, IOParams );
if Result and ( wFilename <> '' ) then
begin
Filename := wFilename;
if IOParams <> nil then
IOParams.FileName := wFilename;
if ParamsEnabled then
fIOParams.FileName := wFilename;
end;
end;
end;
function TIEDBBitmap.Read(aBlobField: TBlobField; FileType: TIOFileType = 0; IOParams: TIOParams = nil): boolean;
var
bFreeParams: Boolean;
iFileFormat: TIOFileType;
begin
Result := True;
bFreeParams := False;
try
if ( IOParams = nil ) and ParamsEnabled then
begin
bFreeParams := True;
IOParams := TIOParams.Create;
IOParams.Assign( fIOParams );
end;
try
iFileFormat := FileType;
IEBitmap_ReadFromBlob( Self, IOParams, aBlobField, fUseMemoryStream, iFileFormat );
if iFileFormat > 0 then
fLastImageFormat := iFileFormat;
if ParamsEnabled then
fIOParams.Assign( IOParams );
Modified := False;
except
// Read error
Result := False;
end;
finally
if bFreeParams then
FreeAndNil( IOParams );
end;
end;
{!!
<FS>TIEDBBitmap.Write
<FM>Declaration<FC>
function Write(): boolean; overload;
function Write(aBlobField: TBlobField; FileType: <A TIOFileType>; IOParams: <A TIOParams> = nil): boolean; overload;
function Write(const FileName: string; IOParams: <A TIOParams> = nil): boolean; overload;
function Write(Stream: TStream; FileType: <A TIOFileType>; IOParams: <A TIOParams> = nil): boolean; overload;
<FM>Description<FN>
Writes image to a blob field, file or stream. This method supports all formats supported by <A TImageEnIO> class
The Write(); overload sets the image at the current database position using the properties of <A TIEDBBitmap.DataSource>, <A TIEDBBitmap.ImageBlobField> and/or <A TIEDBBitmap.FilenameField>..
If saving to a blob or stream you must specify the <L TIOFileType>FileType</L>
You can optionally specify an <A TIOParams> object containing the I/O parameters of the file (see also <A TIEBitmap.ParamsEnabled>).
Returns true on success.
<FM>Examples<FC>
// Rotate the current image in the database (assumes you have set <A TIEDBBitmap.DataSource> and <A TIEDBBitmap.ImageBlobField>)
fDBBitmap.Rotate( -90 );
MyTable.Edit;
MyTableName.AsString := 'Rotated 90';
fDBBitmap.Write( MyTableImageBlob, ioJPEG );
MyTable.Post;
// Append an image to the database
MyBMP := TIEDBBitmap.Create();
MyBMP.Read( 'D:\MyBlobImage.jpeg' );
MyTable.Append;
MyTableName.AsString := 'My Cool Image';
MyBmp.Write( MyTableImageBlob, ioJPEG );
MyTable.Post;
MyBmp.Free;
<FM>See Also<FN>
- <A TIEDBBitmap.UpdateDatabaseImage>
- <A TIEDBBitmap.Read>
!!}
function TIEDBBitmap.Write(): boolean;
var
IOParams: TIOParams;
bFreeParams: Boolean;
begin
bFreeParams := False;
IOParams := nil;
try
if ParamsEnabled then
IOParams := fIOParams
else
if ( fOwner <> nil ) and ( fOwner is TImageEnView ) then
IOParams := TImageEnView( fOwner ).IO.Params
else
begin
IOParams := TIOParams.Create;
bFreeParams := True;
end;
IOParams.JPEG_Quality := fJPEGQuality;
if fImageFormat <> ioUnknown then
fLastImageFormat := fImageFormat;
// Load Image
if ImageStorageMode = isLinkedFile then
begin
if IOParams.Filename = '' then
Result := False
else
Result := Write( IOParams.Filename, IOParams );
end
else
// ImageStorageMode = isEmbeddedBlob
begin
Result := Write( TBlobField( fImageBlobField ), fLastImageFormat, IOParams );
end;
finally
if bFreeParams then
FreeAndNil( IOParams );
end;
// Note: Update will be called automatically due to db changes
end;
function TIEDBBitmap.Write(aBlobField: TBlobField; FileType: TIOFileType; IOParams: TIOParams = nil): boolean;
begin
Result := True;
try
if ( IOParams = nil ) and ParamsEnabled then
IOParams := fIOParams;
IEBitmap_WriteToBlob( Self, IOParams, aBlobField, fUseMemoryStream, FileType );
except
// Write error
Result := False;
end;
end;
{$IFDEF IEINCLUDEMULTIVIEW}
{ TIEDBMultiBitmap }
{!!
<FS>TIEDBMultiBitmap.Create
<FM>Declaration<FC>
constructor Create(); overload;
constructor Create(aDataSource: TDataSource; const sImageBlobField, sFilenameField: string; bFilenameFieldIsUnique: Boolean = False); overload;
<FM>Description<FN>
Create a new TIEDBMultiBitmap object.
Second overload creates the bitmap and sets <A TIEDBMultiBitmap.DataSource>, <A TIEDBMultiBitmap.ImageBlobField>, <A TIEDBMultiBitmap.FilenameField> and <A TIEDBMultiBitmap.FilenameFieldIsUnique>.
<FM>Example<FC>
// Create DB Aware TImageEnMView
procedure TMainForm.FormCreate(Sender: TObject);
begin
... Open a database table ...
fDBMBitmap := TIEDBMultiBitmap.create( DataSource1, 'Image', 'Name' );
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FreeAndNil( fDBMBitmap );
end;
!!}
constructor TIEDBMultiBitmap.Create();
begin
inherited Create();
fDataLink := TIEDataLink.Create();
fDataLink.OnDataChanged := DataChanged;
fDataLink.OnDataUpdated := DataUpdated;
fDataLink.OnActiveChanged := ActiveChanged;
fDataLink.OnRecordChanged := RecordChanged;
fDataLink.OnScrolled := Scrolled;
fImagePath := '';
fImageFormat := ioUnknown;
fJpegQuality := 80;
fUseMemoryStream := true;
fFollowDBCursor := False;
fMaxDisplayRecords := 10000;
fLastImageFormat := ioJPEG;
fBlobBitmap := nil;
fDefaultFilename := 'Image';
fFilenameFieldIsUnique := False;
end;
constructor TIEDBMultiBitmap.Create(aDataSource: TDataSource; const sImageBlobField, sFilenameField: string; bFilenameFieldIsUnique: Boolean = False);
begin
Create();
LockUpdate;
try
fDataLink.DataSource := aDataSource;
fFilenameFieldName := sFilenameField;
fImageBlobFieldName := sImageBlobField;
fFilenameFieldIsUnique := bFilenameFieldIsUnique;
ActiveChanged( nil );
finally
UnlockUpdate;
end;
Modified := False;
end;
{!!
<FS>TIEDBMultiBitmap.Destroy
<FM>Declaration<FC>
destructor Destroy;
<FM>Description<FN>
Frees the object.
!!}
destructor TIEDBMultiBitmap.Destroy;
begin
FreeAndNil( fDataLink );
FreeAndNil( fBlobBitmap );
inherited Destroy;
end;
{!!
<FS>TIEDBMultiBitmap.DataSource
<FM>Declaration<FC>
property DataSource: TDataSource;
<FM>Description<FN>
Link the multi-bitmap with a dataset. The content will automatically update as the attached table changes. You will also need to set <A TIEDBMultiBitmap.FilenameField> or <A TIEDBMultiBitmap.ImageBlobField>.
Note: The maximum images that will be loaded is specified by <A TIEDBMultiBitmap.MaxDisplayRecords>
<FM>Examples<FC>
// Display content of a table where images are stored in a blob field
fDBMBitmap := TIEDBMultiBitmap.create();
fDBMBitmap.DataSource := DataSource1;
fDBMBitmap.ImageBlobField := 'ImageBlob';
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
// Display content of a table where images are stored in a blob field and name of image is stored in "ImageName" field
fDBMBitmap := TIEDBMultiBitmap.create();
fDBMBitmap.DataSource := DataSource1;
fDBMBitmap.FilenameField := 'ImageName';
fDBMBitmap.ImageBlobField := 'ImageBlob';
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
// Display content of a table where images are stored in a folder and their path and filename is referenced by the "ImageFilename" field
fDBMBitmap := TIEDBMultiBitmap.create();
fDBMBitmap.DataSource := DataSource1;
fDBMBitmap.FilenameField := 'ImageFilename';
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
// Display content of a table where images are stored in a folder named "My Folder" and their filename is referenced by the "ImageName" field
fDBMBitmap := TIEDBMultiBitmap.create();
fDBMBitmap.DataSource := DataSource1;
fDBMBitmap.ImagePath := 'C:\My Folder\';
fDBMBitmap.FilenameField := 'ImageName';
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
Note: Don't forget to free the object...
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FreeAndNil( fDBMBitmap );
end;
!!}
function TIEDBMultiBitmap.GetDataSource: TDataSource;
begin
Result := fDataLink.DataSource;
end;
procedure TIEDBMultiBitmap.SetDataSource(Value: TDataSource);
begin
if Value <> fDataLink.Datasource then
begin
fDataLink.DataSource := Value;
ActiveChanged( nil );
end;
end;
{!!
<FS>TIEDBMultiBitmap.ReadOnly
<FM>Declaration<FC>
property ReadOnly: Boolean;
<FM>Description<FN>
Determines whether the user can change the contents of the field using the image control.
!!}
function TIEDBMultiBitmap.GetReadOnly: Boolean;
begin
Result := fDataLink.ReadOnly;
end;
procedure TIEDBMultiBitmap.SetReadOnly(Value: Boolean);
begin
fDataLink.ReadOnly := Value;
end;
{!!
<FS>TIEDBMultiBitmap.ImageStorageMode
<FM>Declaration<FC>
property ImageStorageMode: <A TIEImageStorageMode>; (Read-Only)
<FM>Description<FN>
Returns the method that images are stored or referenced by the database.
If you have set <A TIEDBMultiBitmap.ImageBlobField> then ImageStorageMode will return <FC>isEmbeddedBlob<FN>. Otherwise it will return <FC>isLinkedFile<FN>.
Setting <A TIEDBMultiBitmap.FilenameField> has no effect on <FC>ImageStorageMode<FN>, because it can optionally provide a display name for an image stored in a blob field.
<TABLE>
<R> <H>Value</H> <H>Description</H> </R>
<R> <C>isEmbeddedBlob</C> <C>The image is embedded within a blob field</C> </R>
<R> <C>isLinkedFile</C> <C>A string field points to the filename of a local file</C> </R>
</TABLE>
!!}
function TIEDBMultiBitmap.GetImageStorageMode: TIEImageStorageMode;
begin
Result := isLinkedFile;
if fImageBlobField <> nil then
Result := isEmbeddedBlob;
end;
{!!
<FS>TIEDBMultiBitmap.ImagePath
<FM>Declaration<FC>
property ImagePath: string;
<FM>Description<FN>
If your database table references images that are stored locally as files (i.e. <A TIEDBMultiBitmap.ImageStorageMode> = <FC>isLinkedFile<FN>) then you can use <FC>ImagePath<FN> to specify the folder where the files are located, i.e. the load path is specified by <FC>ImagePath<FN> + "Filename Field content".
Example usage:
- If <A TIEDBMultiBitmap.FilenameField> is the full path to a local file then set <FC>ImagePath<FN> to ''
- If <A TIEDBMultiBitmap.FilenameField> is only a name or has an erroneous path then set <FC>ImagePath<FN> to the image folder
<TABLE>
<R> <H>ImagePath Property Value</H> <H>Content of Filename Field</H> <H>Loads Image From...</H> </R>
<R> <C></C> <C>C:\Some Folder\MyImage.jpg</C> <C>C:\Some Folder\MyImage.jpg</C> </R>
<R> <C>C:\Some Folder\</C> <C>MyImage.jpg</C> <C>C:\Some Folder\MyImage.jpg</C> </R>
<R> <C>C:\Some Folder\</C> <C>..\MyImage.jpg</C> <C>C:\Some Folder\..\MyImage.jpg</C> </R>
<R> <C>C:\Some Folder\</C> <C>D:\FolderX\MyImage.jpg</C> <C>C:\Some Folder\MyImage.jpg</C> </R>
<R> <C>http://www.imageen.com/images/</C> <C>MyImage.jpg</C> <C>http://www.imageen.com/images/MyImage.jpg</C> </R>
<R> <C></C> <C>http://www.imageen.com/images/MyImage.jpg</C> <C>http://www.imageen.com/images/MyImage.jpg</C> </R>
</TABLE>
<FM>Examples<FC>
// Display content of a table where images are stored in a folder and their path and filename is referenced by the "ImageFilename" field
fDBMBitmap := TIEDBMultiBitmap.create();
fDBMBitmap.DataSource := DataSource1;
fDBMBitmap.FilenameField := 'ImageFilename';
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
// Display content of a table where images are stored in a folder named "My Folder" and their filename is referenced by the "ImageName" field
fDBMBitmap := TIEDBMultiBitmap.create();
fDBMBitmap.DataSource := DataSource1;
fDBMBitmap.ImagePath := 'C:\My Folder\';
fDBMBitmap.FilenameField := 'ImageName';
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
Note: Don't forget to free the object...
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FreeAndNil( fDBMBitmap );
end;
!!}
procedure TIEDBMultiBitmap.SetImagePath(const v: string);
begin
if fImagePath <> v then
begin
fImagePath := v;
UpdateEx( True );
end;
end;
procedure TIEDBMultiBitmap.ActiveChanged(Sender: TObject);
begin
if fDataLink.Active and ( fFilenameFieldName <> '' ) then
begin
fFilenameField := fDataLink.DataSet.FindField( fFilenameFieldName );
if ( fFilenameField <> nil ) and ( TStringField( fFilenameField ).Size < 13 ) then
raise EIEException.create( 'Invalid Field Size' );
end
else
fFilenameField := nil;
if fDataLink.Active and ( fImageBlobFieldName <> '' ) then
fImageBlobField := fDataLink.DataSet.FindField( fImageBlobFieldName )
else
fImageBlobField := nil;
UpdateEx( True );
end;
procedure TIEDBMultiBitmap.DataChanged(Sender: TObject);
begin
UpdateEx( False );
end;
procedure TIEDBMultiBitmap.Scrolled(Sender: TObject);
begin
UpdateActive;
end;
procedure TIEDBMultiBitmap.RecordChanged(Field: TField);
var
bUpdate: Boolean;
begin
bUpdate := (( fFilenameField <> nil ) and ( Field = fFilenameField )) or
(( fImageBlobField<> nil ) and ( Field = fImageBlobField));
if bUpdate and assigned( fOwner ) and ( fOwner is TImageEnMView ) then
TImageEnMView( fOwner ).ClearImageCache( fDatalink.ActiveRecord );
end;
procedure TIEDBMultiBitmap.DataUpdated(Sender: TObject);
begin
UpdateEx( False );
end;
{!!
<FS>TIEDBMultiBitmap.Update
<FM>Declaration<FC>
procedure Update;
<FM>Description<FN>
Refresh the content of the TIEDBMultiBitmap from the database and update the <A TImageEnMView> if connected.
!!}
procedure TIEDBMultiBitmap.Update;
begin
UpdateEx( True );
end;
// if bFullUpdate then it clears the thumbnail cache too
procedure TIEDBMultiBitmap.UpdateEx(bFullUpdate: Boolean = true);
var
iRowCount: Integer;
begin
if LockUpdateCount > 0 then
begin
fUpdatePending := True;
if bFullUpdate then
fUpdatePendingIsFull := True;
exit;
end;
iRowCount := 0;
if fDataLink.Active and ( fDataLink.RecordCount > 0 ) then
begin
fDataLink.BufferCount := fMaxDisplayRecords;
iRowCount := fDataLink.RecordCount;
end;
AllocateVirtual( iRowCount );
fUpdatePending := False;
if assigned( fOwner ) and ( fOwner is TImageEnMView ) then
TImageEnMView( fOwner ).UpdateEx( bFullUpdate or fUpdatePendingIsFull, False );
fUpdatePendingIsFull := False;
UpdateActive;
end;
// Used to communicate changes in the selection of an owner control, TImageEnMView to underlying image sources, such as a database table
procedure TIEDBMultiBitmap.SetActiveImage(idx: integer);
begin
if Assigned( fDataLink ) and fDataLink.Active then
fDataLink.MoveToRecord( idx );
end;
// If this component has been filled "Virtually" then fImageInfo.Count has been set to the number of images available
// Without fImageInfo items being assigned. In this case it must be assigned in CheckAllocated()
procedure TIEDBMultiBitmap.CheckAllocated(idx: integer);
var
newinfo: TIEImageInfo;
wFilename: WideString;
OldActive: Integer;
begin
// Already allocated?
if fImageInfo[ idx ] <> nil then
exit;
// Have data source?
if not ( Assigned( fDataLink ) and fDataLink.Active ) then
Exit;
// Fields are valid? Need at least one
if ( fFilenameField = nil ) and
( fImageBlobField = nil ) then
raise EIEException.create( 'Valid image fields have not been specified for TIEDBMultiBitmap' );
if assigned( fOwner ) and ( fOwner is TImageEnMView ) then
begin
if fFilenameFieldIsUnique then
TImageEnMView( fOwner ).ImageCacheReusage := iecrLoose
else
TImageEnMView( fOwner ).ImageCacheReusage := iecrStrict;
end;
OldActive := fDataLink.ActiveRecord;
try
fDataLink.ActiveRecord := idx;
NewInfo := TIEImageInfo.Create(self);
NewInfo.Background := fBackground;
// Read Filename field
wFilename := '';
if fFilenameField <> nil then
wFilename := WideString( TStringField( fFilenameField ).Value );
{$IFDEF UNITTESTING}
if Pos( Widestring( 'XXX\' ), wFilename ) = 1 then
wFilename := StringReplace( wFilename, 'XXX\', IEAddBackSlash( gUnitTesting_ImagesPath ), []);
{$ENDIF}
if wFilename <> '' then
begin
if ( fImagePath <> '' ) and HasAbsolutePath( wFilename ) then
wFilename := ExtractFileName( wFilename );
wFilename := IEAddBackSlash( fImagePath ) + wFilename;
NewInfo.Filename := wFilename;
end;
if ImageStorageMode = isEmbeddedBlob then
NewInfo.ID := Idx;
if assigned( fOwner ) and ( fOwner is TImageEnMView ) then
NewInfo.cacheImage := TImageEnMView( fOwner ).FindImageInCache( idx, wFilename );
fImageInfo[ idx ] := NewInfo;
finally
fDataLink.ActiveRecord := OldActive;
end;
end;
// If descendent classes need to load images by ID on demand, then InternalLoadImageByID must be used and InternalLoadImageByID_Assigned returns true
function TIEDBMultiBitmap.InternalLoadImageByID_Assigned(): Boolean;
begin
Result := True;
end;
// If descendent classes need to load images by ID on demand, then InternalLoadImageByID must be used and InternalLoadImageByID_Assigned returns true
procedure TIEDBMultiBitmap.InternalLoadImageByID(Sender: TObject; Index, ID: Integer; var Bitmap: TIEBitmap; var IOParams: TIOParams);
var
OldActive: Integer;
iFileFormat: TIOFileType;
begin
OldActive := fDataLink.ActiveRecord;
try
fDataLink.ActiveRecord := ID;
if fBlobBitmap = nil then
fBlobBitmap := TIEBitmap.create;
// USED FOR BLOB LOADING ONLY
if ImageStorageMode <> isEmbeddedBlob then
raise EIEException.create('Unexpected error');
iFileFormat := fImageFormat;
// Exception raised on failure
IEBitmap_ReadFromBlob( fBlobBitmap, IOParams, TBlobField( fImageBlobField ), fUseMemoryStream, iFileFormat );
Bitmap := fBlobBitmap;
if iFileFormat > 0 then
fLastImageFormat := iFileFormat;
finally
fDataLink.ActiveRecord := OldActive;
end;
end;
{!!
<FS>TIEDBMultiBitmap.FilenameField
<FM>Declaration<FC>
property FilenameField : string;
<FM>Description<FN>
Specifies the database field that contains the name or filename of the image. It must be the name of a TStringField.
TIEDBMultiBitmap can be used in two ways:
- Reading images directly from a database blob field, by setting <A TIEDBMultiBitmap.ImageBlobField> to a valid field. In this situation <FC>FilenameField<FN> specifies a display name for the image (and is optional). It will also improves performance, especially if the <L TIEDBMultiBitmap.FilenameFieldIsUnique>filename field is unique</L>.
- Reading files stored in a local folder and referenced by a database string field, by setting <A TIEDBMultiBitmap.ImageBlobField> to ''. In this case <FC>FilenameField<FN> should either be a full path to a local file, or a name only with the folder specified by <A TIEDBMultiBitmap.ImagePath>
Notes:
- Either <A TIEDBMultiBitmap.ImageBlobField> or <A TIEDBMultiBitmap.FilenameField> must be set (or both).
- You should set <A TIEDBMultiBitmap.FilenameFieldIsUnique> if the field is unique to improve performance
<FM>See Also<FN>
- <A TIEDBMultiBitmap.ImagePath>
- <A TIEDBMultiBitmap.FilenameFieldIsUnique>
- <A TIEDBMultiBitmap.ImageBlobField>
- <A TIEDBMultiBitmap.ImageStorageMode>
<FM>Examples<FC>
// Display content of a table where images are stored in a blob field
fDBMBitmap := TIEDBMultiBitmap.create();
fDBMBitmap.DataSource := DataSource1;
fDBMBitmap.ImageBlobField := 'ImageBlob';
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
// Display content of a table where images are stored in a blob field and name of image is stored in "ImageName" field
fDBMBitmap := TIEDBMultiBitmap.create();
fDBMBitmap.DataSource := DataSource1;
fDBMBitmap.FilenameField := 'ImageName';
fDBMBitmap.ImageBlobField := 'ImageBlob';
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
// Display content of a table where images are stored in a folder and their path and filename is referenced by the "ImageFilename" field
fDBMBitmap := TIEDBMultiBitmap.create();
fDBMBitmap.DataSource := DataSource1;
fDBMBitmap.FilenameField := 'ImageFilename';
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
// Display content of a table where images are stored in a folder named "My Folder" and their filename is referenced by the "ImageName" field
fDBMBitmap := TIEDBMultiBitmap.create();
fDBMBitmap.DataSource := DataSource1;
fDBMBitmap.ImagePath := 'C:\My Folder\';
fDBMBitmap.FilenameField := 'ImageName';
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
Note: Don't forget to free the object...
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FreeAndNil( fDBMBitmap );
end;
!!}
procedure TIEDBMultiBitmap.SetFilenameFieldName(const Value: string);
begin
if fFilenameFieldName <> Value then
begin
fFilenameFieldName := Value;
ActiveChanged( nil );
end;
end;
{!!
<FS>TIEDBMultiBitmap.ImageBlobField
<FM>Declaration<FC>
property ImageBlobField : string;
<FM>Description<FN>
Specifies the database blob field that embeds image files. It must be the name of a TBlobField.
TIEDBMultiBitmap can be used in two ways:
- Reading images directly from a database blob field
- Reading files stored in a local folder and referenced by a database string field
If <A TIEDBMultiBitmap.ImageBlobField> is not set then images will be loaded locally (using <A TIEDBMultiBitmap.FilenameField>)
If <A TIEDBMultiBitmap.ImageBlobField> is a valid field, then images will be read from the embedded blob field. The file format will be determined using <A TIEDBMultiBitmap.ImageFormat>. You can optionally set <A TIEDBMultiBitmap.FilenameField> to specify a field with a display name for the image. Setting <A TIEDBMultiBitmap.FilenameField> will also improve performance, especially if the <L TIEDBMultiBitmap.FilenameFieldIsUnique>filename field is unique</L>.
Note: Either <A TIEDBMultiBitmap.ImageBlobField> or <A TIEDBMultiBitmap.FilenameField> must be set (or both).
<FM>See Also<FN>
- <A TIEDBMultiBitmap.ImageFormat>
- <A TIEDBMultiBitmap.FilenameField>
- <A TIEDBMultiBitmap.ImageStorageMode>
<FM>Examples<FC>
// Display content of a table where images are stored in a blob field
fDBMBitmap := TIEDBMultiBitmap.create();
fDBMBitmap.DataSource := DataSource1;
fDBMBitmap.ImageBlobField := 'ImageBlob';
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
// Display content of a table where images are stored in a blob field and name of image is stored in "ImageName" field
fDBMBitmap := TIEDBMultiBitmap.create();
fDBMBitmap.DataSource := DataSource1;
fDBMBitmap.FilenameField := 'ImageName';
fDBMBitmap.ImageBlobField := 'ImageBlob';
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
// Display content of a table where images are stored in a folder and their path and filename is referenced by the "ImageFilename" field
fDBMBitmap := TIEDBMultiBitmap.create();
fDBMBitmap.DataSource := DataSource1;
fDBMBitmap.FilenameField := 'ImageFilename';
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
// Display content of a table where images are stored in a folder named "My Folder" and their filename is referenced by the "ImageName" field
fDBMBitmap := TIEDBMultiBitmap.create();
fDBMBitmap.DataSource := DataSource1;
fDBMBitmap.ImagePath := 'C:\My Folder\';
fDBMBitmap.FilenameField := 'ImageName';
ImageEnMView1.SetExternalMBitmap( fDBMBitmap );
Note: Don't forget to free the object...
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FreeAndNil( fDBMBitmap );
end;
!!}
procedure TIEDBMultiBitmap.SetImageBlobFieldName(const Value: string);
begin
if fImageBlobFieldName <> Value then
begin
fImageBlobFieldName := Value;
ActiveChanged( nil );
end;
end;
{!!
<FS>TIEDBMultiBitmap.MaxDisplayRecords
<FM>Declaration<FC>
property MaxDisplayRecords: Integer;
<FM>Description<FN>
TIEDBMultiBitmap will load all records of your database table into memory up to the maximum specified by <FC>MaxDisplayRecords<FN>. If your table contains more records than <FC>MaxDisplayRecords<FN> they will not be displayed, so you should use table filtering to ensure the record count does not become too large and affect performance.
Default: 10,000
!!}
procedure TIEDBMultiBitmap.SetMaxDisplayRecords(Value: Integer);
begin
if fMaxDisplayRecords <> Value then
begin
fMaxDisplayRecords := Value;
UpdateEx( True );
end;
end;
{!!
<FS>TIEDBMultiBitmap.FollowDBCursor
<FM>Declaration<FC>
property FollowDBCursor: boolean;
<FM>Description<FN>
If True and the TIEDBMultiBitmap is attached to a <A TImageEnMView> then changes to the database table cursor will be reflected in the TImageEnMView. In other words, navigating the table will change the selected image in the TImageEnMView.
Default: false (the position of the database table cursor is ignored)
!!}
procedure TIEDBMultiBitmap.SetFollowDBCursor(Value: Boolean);
begin
if fFollowDBCursor <> Value then
begin
fFollowDBCursor := Value;
UpdateActive;
end;
end;
procedure TIEDBMultiBitmap.UpdateActive;
begin
if fFollowDBCursor and
Assigned( fDataLink ) and
fDataLink.Active and
assigned( fOwner ) and
( fOwner is TImageEnMView ) then
TImageEnMView( fOwner ).SelectedImage := fDataLink.ActiveRecord;
end;
{!!
<FS>TIEDBMultiBitmap.InsertImage
<FM>Declaration<FC>
procedure InsertImage(idx: integer); overload;
procedure InsertImage(Idx : integer; Stream : TStream); overload;
procedure InsertImage(Idx : integer; Bitmap : <A TIEBitmap>); overload;
procedure InsertImage(Idx : integer; Bitmap : TBitmap); overload;
procedure InsertImage(Idx : integer; MBitmap : <A TIECustomMultiBitmap>); overload;
procedure InsertImage(Idx : integer; Width, Height : integer; PixelFormat : <A TIEPixelFormat> = ie24RGB); overload;
procedure InsertImage(Idx : integer; const FileName : string); overload;
<FM>Description<FN>
Inserts a new image into the database at position, <FC>idx<FN> (0 is the first). The table will be positioned at the new record.
Note: TDataset.Insert and TDataset.Post will be called
<FM>Examples<FC>
// Prompt to insert a new image into the database after the selected record
if dlgOpenImage.Execute then
fDBMBitmap.InsertImage( ImageEnMView1.SelectedImage, dlgOpenImage.Filename );
// Compare the following...
ImageEnView1.IO.LoadFromFile('C:\000.tif');
MBitmap.InsertImage( 0 );
MyTable.Edit;
MBitmap.SetImage( -1, ImageEnView1.Bitmap );
MyTable.Post;
// Which is the same as...
MBitmap.InsertImage( 0, 'C:\000.tif' );
// Insert 256 x 256 bitmap
MBitmap.InsertImage(0, 256, 256, ie24RGB);
// Insert a file from the web
MBitmap.InsertImage( 0, 'http://www.imageen.com/graphics/imageen.gif' );
<FM>See Also<FN>
- <A TIEDBMultiBitmap.AppendImage>
- <A TIEDBMultiBitmap.SetImage>
!!}
procedure TIEDBMultiBitmap.InsertOrAppend(idx: integer);
begin
if idx >= fImageInfo.Count then
begin
// Append
fDataLink.DataSet.Append;
end
else
begin
// Insert
fDataLink.ActiveRecord := idx;
fDataLink.DataSet.Insert;
end;
end;
procedure TIEDBMultiBitmap.InsertImage(idx: integer);
begin
LockUpdate;
try
try
InsertOrAppend( idx );
fDataLink.DataSet.Post;
except
fDataLink.DataSet.Cancel;
raise;
end;
finally
UnlockUpdate;
end;
end;
procedure TIEDBMultiBitmap.InsertImage(Idx : integer; Stream : TStream);
begin
LockUpdate;
try
try
InsertOrAppend( idx );
SetImage( -1, Stream );
fDataLink.DataSet.Post;
except
fDataLink.DataSet.Cancel;
raise;
end;
finally
UnlockUpdate;
end;
end;
procedure TIEDBMultiBitmap.InsertImage(Idx : integer; MBitmap : TIECustomMultiBitmap);
var
I: Integer;
bmp: TIEBitmap;
begin
LockUpdate;
try
for I := 0 to MBitmap.Count - 1 do
begin
bmp := MBitmap.GetTIEBitmap( I );
InsertImage( Idx + I, bmp );
MBitmap.ReleaseBitmap( I, False );
end;
finally
UnlockUpdate;
end;
end;
procedure TIEDBMultiBitmap.InsertImage(Idx : integer; Bitmap : TIEBitmap);
begin
LockUpdate;
try
try
InsertOrAppend( idx );
SetCurrentImage( Bitmap, '' );
fDataLink.DataSet.Post;
except
fDataLink.DataSet.Cancel;
raise;
end;
finally
UnlockUpdate;
end;
end;
procedure TIEDBMultiBitmap.InsertImage(Idx : integer; Bitmap : TBitmap);
begin
LockUpdate;
try
try
InsertOrAppend( idx );
SetImage( -1, Bitmap );
fDataLink.DataSet.Post;
except
fDataLink.DataSet.Cancel;
raise;
end;
finally
UnlockUpdate;
end;
end;
procedure TIEDBMultiBitmap.InsertImage(Idx : integer; Width, Height : integer; PixelFormat : TIEPixelFormat);
var
temp: TIEBitmap;
begin
LockUpdate;
temp := TIEBitmap.Create;
try
try
InsertOrAppend( idx );
temp.Allocate( Width, Height, PixelFormat );
temp.Fill( clBlack );
SetCurrentImage( temp, '' );
fDataLink.DataSet.Post;
except
fDataLink.DataSet.Cancel;
raise;
end;
finally
temp.free;
UnlockUpdate;
end;
end;
procedure TIEDBMultiBitmap.InsertImage(Idx : integer; const FileName : string);
begin
LockUpdate;
try
try
InsertOrAppend( idx );
SetImage( -1, FileName );
fDataLink.DataSet.Post;
except
fDataLink.DataSet.Cancel;
raise;
end;
finally
UnlockUpdate;
end;
end;
{!!
<FS>TIEDBMultiBitmap.AppendImage
<FM>Declaration<FC>
function AppendImage: Integer;
function AppendImage(Stream: TStream): integer;
function AppendImage(Bitmap: <A TIEBitmap>): integer;
function AppendImage(Bitmap : TBitmap): integer;
function AppendImage(MBitmap : <A TIECustomMultiBitmap>);
function AppendImage(Width, Height: Integer; PixelFormat: <A TIEPixelFormat> = ie24RGB): Integer;
function AppendImage(const FileName: String): integer;
<FM>Description<FN>
Appends a new image at the end of the database and returns the new image position. The table will be positioned at the new record.
Note: TDataset.Append and TDataset.Post will be called.
<FM>Examples<FC>
if dlgOpenImage.Execute then
fDBMBitmap.AppendImage( dlgOpenImage.Filename );
// Compare the following...
ImageEnView1.IO.LoadFromFile('C:\000.tif');
MBitmap.AppendImage();
MyTable.Edit;
MBitmap.SetImage( -1, ImageEnView1.Bitmap );
MyTable.Post;
// Which is the same as...
MBitmap.AppendImage( 'C:\000.tif' );
// Append 256 x 256 bitmap
MBitmap.AppendImage( 256, 256, ie24RGB );
// Append a file from the web
MBitmap.AppendImage( 'http://www.imageen.com/graphics/imageen.gif' );
<FM>See Also<FN>
- <A TIEDBMultiBitmap.InsertImage>
- <A TIEDBMultiBitmap.SetImage>
!!}
function TIEDBMultiBitmap.AppendImage(): integer;
begin
result := fImageInfo.Count;
InsertImage( Result );
end;
function TIEDBMultiBitmap.AppendImage(Stream: TStream): integer;
begin
result := fImageInfo.Count;
InsertImage( Result, Stream );
end;
function TIEDBMultiBitmap.AppendImage(MBitmap: TIECustomMultiBitmap): integer;
begin
result := fImageInfo.Count;
InsertImage( Result, MBitmap );
end;
function TIEDBMultiBitmap.AppendImage(Bitmap: TIEBitmap): integer;
begin
result := fImageInfo.Count;
InsertImage( Result, Bitmap );
end;
function TIEDBMultiBitmap.AppendImage(Bitmap : TBitmap): integer;
begin
result := fImageInfo.Count;
InsertImage( Result, Bitmap );
end;
function TIEDBMultiBitmap.AppendImage(Width, Height: Integer; PixelFormat: TIEPixelFormat): Integer;
begin
result := fImageInfo.Count;
InsertImage( Result, Width, Height, PixelFormat );
end;
function TIEDBMultiBitmap.AppendImage(const FileName: String): integer;
begin
result := fImageInfo.Count;
InsertImage( Result, FileName );
end;
{!!
<FS>TIEDBMultiBitmap.DeleteImage
<FM>Declaration<FC>
procedure DeleteImage(idx: integer);
<FM>Description<FN>
Removes the image, <FC>idx<FN> from the database table.
<FM>Examples<FC>
// Delete the selected image in a TImageEnMView attached to a TIEDBMultiBitmap from the database
fDBMBitmap.DeleteImage( ImageEnMView1.SelectedImage );
!!}
procedure TIEDBMultiBitmap.DeleteImage(idx: integer);
var
OldActive: Integer;
begin
if ValidateIndex( idx ) = False then
exit;
OldActive := fDataLink.ActiveRecord;
try
fDataLink.ActiveRecord := idx;
fDatalink.DataSet.Delete;
finally
fDataLink.ActiveRecord := OldActive;
end;
end;
{!!
<FS>TIEDBMultiBitmap.SetImage
<FM>Declaration<FC>
procedure SetImage(idx: Integer; srcImage: <A TIEBaseBitmap>); overload;
procedure SetImage(idx: Integer; srcImage: TBitmap); overload;
procedure SetImage(idx: Integer; width, height: Integer; PixelFormat: <A TIEPixelFormat>); overload;
function SetImage(idx: integer; const FileName: WideString; SourceImageIndex: Integer = 0; FileFormat: <A TIOFileType> = ioUnknown): boolean; overload;
function SetImage(idx: Integer; Stream: TStream; SourceImageIndex: Integer = 0; FileFormat: <A TIOFileType> = ioUnknown): Boolean; overload
<FM>Description<FN>
Updates the current image in the database table. If images are stored in the database (i.e. <A TIEDBMultiBitmap.ImageBlobField> is set), the image will be updated in the blob. If images are stored as files referenced by the database (i.e. <A TIEDBMultiBitmap.ImageBlobField> is NOT set), the image changes will be saved to file (using <A TIEDBMultiBitmap.DefaultFilename> and <FB>without an overwrite warning<FN>).
NOTE: <FB>idx should be set to -1<FN>. Unlike TIEMultiBitmap.<A TIEMultiBitmap.SetImage>, <FC>TIEDBMultiBitmap.SetImage<FN> always works on the CURRENT database table record.
With overloads 2 and 3 the <FC>srcImage<FN> bitmap is copied internally; therefore you can free <FC>srcImage<FN> after calling SetImage.
With overload 4 the image can be a local file or web page based image.
With overloads 3 and 4 use SourceImageIndex to specify the image index if the source file is a multi-frame file (such as a TIFF or AVI). You can also specify the <FC>FileFormat<FN> if it cannot be determined by the file extension or content.
TDataset.Edit and TDataset.Post are NOT called (Unlike <A TIEDBMultiBitmap.AppendImage> and <A TIEDBMultiBitmap.InsertImage>)
<FM>Examples<FC>
ImageEnView1.IO.LoadFromFile('C:\000.tif');
MBitmap.InsertImage( 0 );
MyTable.Edit;
MBitmap.SetImage( -1, ImageEnView1.Bitmap );
MyTable.Post;
MyTable.Edit;
MyTableFilename.AsString := 'My Cool Image.jpg';
ImageEnMView1.SetImage( -1, stream );
MyTable.Post;
MyTable.Edit;
MyTableFilename.AsString := 'myfile.jpg';
ImageEnMView1.SetImage( -1, 'D:\myfile.jpg' );
MyTable.Post;
MyTable.Edit;
MyTableFilename.AsString := 'My Web Image';
ImageEnMView1.SetImage( -1, 'http://www.imageen.com/image.jpg' );
MyTable.Post;
<FM>See Also<FN>
- <A TIEDBMultiBitmap.InsertImage>
- <A TIEDBMultiBitmap.AppendImage>
- <A TIEDBMultiBitmap.DefaultFilename>
!!}
procedure TIEDBMultiBitmap.SetImage(idx: Integer; width, height: Integer; PixelFormat: TIEPixelFormat);
var
temp: TIEBitmap;
begin
if ( idx > -1 ) and ( idx <> fDataLink.ActiveRecord ) then
raise EIEException.create( Cannot_Respotion_Error_Str );
temp := TIEBitmap.Create(Width, Height, PixelFormat);
try
SetCurrentImage( temp, '' );
finally
temp.free;
end;
end;
procedure TIEDBMultiBitmap.SetImage(idx: integer; srcImage: TBitmap);
var
tbmp: TIEBitmap;
begin
if ( idx > -1 ) and ( idx <> fDataLink.ActiveRecord ) then
raise EIEException.create( Cannot_Respotion_Error_Str );
if srcImage <> nil then
begin
tbmp := TIEBitmap.Create;
try
tbmp.EncapsulateTBitmap(srcImage, true);
SetCurrentImage( tbmp, '' );
finally
FreeAndNil(tbmp);
end;
end;
end;
procedure TIEDBMultiBitmap.SetImage(idx: integer; srcImage: TIEBaseBitmap);
begin
if ( idx > -1 ) and ( idx <> fDataLink.ActiveRecord ) then
raise EIEException.create( Cannot_Respotion_Error_Str );
SetCurrentImage( srcImage, '' );
end;
// Writes changes to the current image
// If images are stored in the database (i.e. TIEDBMultiBitmap.ImageBlob is set), the image will be updated in the blob.
// If images are stored as files referenced by the database (i.e. TIEDBMultiBitmap.ImageBlob is NOT set), the image changes will be saved to file (without an overwrite warning).
// sDisplayName is used as display name in the database and also a default save filename
// bCanOverwriteExisting is true only when we are updating an existing image and can replace it
procedure TIEDBMultiBitmap.SetCurrentImage(srcImage: TIEBaseBitmap; const sDisplayName: string; bCanOverwriteExisting: Boolean = False);
const
Number_Suffix_Length = 5; // a reasonable number of characters to allow for the number suffix when there are duplicate files
var
sDBFilename: string;
sSaveName: string;
sSavePath: string;
aParams: TIOParams;
sSaveFilename: String;
begin
if srcImage = nil then
exit;
aParams := nil;
try
if TIEBitmap( srcImage ).ParamsEnabled then
TIEBitmap( srcImage ).Params.JPEG_Quality := fJPEGQuality
else
begin
aParams := TIOParams.Create;
aParams.JPEG_Quality := fJPEGQuality;
end;
if fImageFormat <> ioUnknown then
fLastImageFormat := fImageFormat;
sDBFilename := '';
if fFilenameField <> nil then
sDBFilename := TStringField( fFilenameField ).AsString;
{$IFDEF UNITTESTING}
if Pos( 'XXX\', sDBFilename ) = 1 then
sDBFilename := StringReplace( sDBFilename, 'XXX\', IEAddBackSlash( gUnitTesting_ImagesPath ), []);
{$ENDIF}
// Get a name for the file
sSaveName := ExtractFilename( sDisplayName );
if sSaveName = '' then
sSaveName := ExtractFilename( sDBFilename );
if sSaveName = '' then
sSaveName := ExtractFilename( fDefaultFilename );
// And an extension
if IEFilenameToFileFormat( sSaveName ) <> fLastImageFormat then
sSaveName := ChangeFileExt( sSaveName, '.' + IEFileFormatGetInfo( fLastImageFormat ).SuitableExtension );
// Get a path
sSavePath := IEAddBackSlash( fImagePath );
if sSavePath = '' then
sSavePath := IEAddBackSlash( ExtractFilePath( fDefaultFilename ));
// Check for filenames that are too long for the field length
if ( fFilenameField <> nil ) and
(( ImageStorageMode <> isLinkedFile ) or ( fImagePath <> '' )) and // Not practical to do if we must store the full path
( Length( sSaveName ) > TStringField( fFilenameField ).Size - Number_Suffix_Length ) then
begin
sSaveName := IEExtractFilenameWithoutExt( sSaveName );
SetLength( sSaveName, TStringField( fFilenameField ).Size - Length( '.' + IEFileFormatGetInfo( fLastImageFormat ).SuitableExtension ) - Number_Suffix_Length );
sSaveName := sSaveName + '.' + IEFileFormatGetInfo( fLastImageFormat ).SuitableExtension;
end;
// Concat result
sSaveFilename := IEAddBackSlash( sSavePath ) + sSaveName;
if ImageStorageMode = isLinkedFile then
begin
// SAVE BITMAP TO FILE
if sSavePath = '' then
raise EIEException.create( 'No valid save folder' );
// Are we just updating the image???
if bCanOverwriteExisting and
( SameText( sDBFilename, sSaveFilename ) or
SameText( sDBFilename, sSaveName )) then
begin { OVERWRITE sSaveFilename } end
else
// Generate numbered filename
sSaveFilename := IEGetNewFilename( sSaveFilename );
TIEBitmap( srcImage ).Write( sSaveFilename, aParams );
end
else
begin
// BLOB
// Exception raised on error
IEBitmap_WriteToBlob( TIEBitmap( srcImage ), aParams, TBlobField( fImageBlobField ), fUseMemoryStream, fLastImageFormat );
end;
// WRITE OUR FILENAME
if fFilenameField <> nil then
begin
{$IFDEF UNITTESTING}
if ( ImageStorageMode = isLinkedFile ) and ( fImagePath = '' ) and
( pos( IEAddBackSlash( gUnitTesting_ImagesPath ), sSaveFilename ) = 1 ) then
TStringField( fFilenameField ).AsString := StringReplace( sSaveFilename, IEAddBackSlash( gUnitTesting_ImagesPath ), 'XXX\', [] )
else
{$ENDIF}
if ( ImageStorageMode = isLinkedFile ) and ( fImagePath = '' ) then
TStringField( fFilenameField ).AsString := sSaveFilename
else
TStringField( fFilenameField ).AsString := ExtractFileName( sSaveFilename );
end;
finally
FreeAndNil( aParams );
end;
// Note: Update will be called automatically due to db changes
end;
function TIEDBMultiBitmap.SetImage(idx: integer; const FileName: WideString; SourceImageIndex: Integer = 0; FileFormat: TIOFileType = ioUnknown): boolean;
var
bFormatIsCorrect: Boolean;
begin
bFormatIsCorrect := True;
if fImageFormat <> ioUnknown then
bFormatIsCorrect := IEFilenameToFileFormat( FileName ) = fImageFormat;
if ( ImageStorageMode = isLinkedFile ) and // Linked images
( fImagePath <> '' ) and // Have a default save folder
SameText( IEAddBackSlash( ExtractFilePath( FileName )),
IEAddBackSlash( fImagePath )) and // Image is already in save folder
bFormatIsCorrect then // File type is as desired
begin
// File is already correct for our needs. Just update the file path in the db
if fImagePath = '' then
TStringField( fFilenameField ).AsString := FileName
else
TStringField( fFilenameField ).AsString := IEExtractFilenameW( FileName );
Result := True;
end
else
begin
// All other handling
result := SetImageFromStreamOrFile(idx, nil, FileName, SourceImageIndex, FileFormat);
end;
end;
function TIEDBMultiBitmap.SetImage(idx: integer; Stream: TStream; SourceImageIndex: Integer = 0; FileFormat: TIOFileType = ioUnknown): boolean;
begin
result := SetImageFromStreamOrFile(idx, Stream, '', SourceImageIndex, FileFormat);
end;
// If loading is successful the result is the file type of the image. Othewise it returns -1 on error
function TIEDBMultiBitmap.SetImageFromStreamOrFile(idx: integer; Stream: TStream; const FileName: WideString; SourceImageIndex: Integer; FileFormat: TIOFileType; MIO: TObject = nil): Boolean;
var
bmp: TIEBitmap;
IO: TImageEnIO;
ms: TMemoryStream;
bAborting: Boolean;
FileExt: string;
begin
result := False;
if idx >= fImageInfo.Count then
exit;
if ( idx > -1 ) and ( idx <> fDataLink.ActiveRecord ) then
raise EIEException.create( Cannot_Respotion_Error_Str );
// URL HANDLING
if ( Stream = nil ) and ( IEGetURLTypeW(FileName) <> ieurlUNKNOWN ) then
begin
// LOAD FROM URL
ms := TMemoryStream.Create;
try
bAborting := False;
if IEGetFromURL(FileName, ms,
IEGlobalSettings().ProxyAddress,
IEGlobalSettings().ProxyUser,
IEGlobalSettings().ProxyPassword,
nil, nil, @bAborting, FileExt) then
begin
ms.Position := 0;
Result := SetImageFromStreamOrFile(Idx, ms, '', SourceImageIndex, FileFormat);
end;
finally
FreeAndNil(ms);
end;
exit;
end;
IO := TImageEnIO.Create( nil );
bmp := TIEBitmap.Create;
try
IO.AttachedIEBitmap := bmp;
IO.Params.ImageIndex := SourceImageIndex;
try
if Stream <> nil then
IO.LoadFromStream( Stream, FileFormat )
else
begin
if FileFormat = ioUnknown then
FileFormat := FindFileFormat( FileName, ffFallbackToExtension );
IO.LoadFromFile( FileName, FileFormat );
end;
except
IO.Aborting := true;
end;
if IO.Aborting then
exit;
// Disconnect from TImageEnIO and assign its meta-data - v6.3.1
IO.AttachedIEBitmap := nil;
bmp.ParamsEnabled := true;
bmp.Params.Assign( io.Params );
SetCurrentImage( bmp, FileName );
result := True;
finally
IO.attachediebitmap := nil;
FreeAndNil(bmp);
FreeAndNil(IO);
end;
end;
{!!
<FS>TIEDBMultiBitmap.Flip
<FM>Declaration<FC>
procedure Flip(idx: integer; Dir: <A TFlipDir>);
<FM>Description<FN>
Flips (mirrors) a frame within the image across the horizontal or vertical axis and updates the image in the database.
<FM>Examples<FC>
// Rotate the selected image in a TImageEnMView attached to a TIEDBMultiBitmap
fDBMBitmap.Rotate( ImageEnMView1.SelectedImage, -90 );
!!}
procedure TIEDBMultiBitmap.Flip(idx: integer; Dir: TFlipDir);
var
bmp: TIEBitmap;
begin
bmp := GetTIEBitmap( idx );
bmp.Flip( Dir );
ReleaseBitmap( idx, True );
end;
{!!
<FS>TIEDBMultiBitmap.Rotate
<FM>Declaration<FC>
procedure Rotate(idx: integer; Angle: double; AntialiasMode: <A TIEAntialiasMode> = ierFast; BackgroundColor: TColor = clWhite);
<FM>Description<FN>
Rotates a frame of the current image by the specified angle (negative or positive degrees counter-clockwise) and updates it in the database.
<FC>AntialiasMode<FN> specifies the anti-aliasing algorithm that is used to improve rotation quality:
ierNone : No anti-aliasing (lowest quality)
ierFast : Fast but lower quality
ierBilinear : Bilinear, high quality
ierBicubic : Bicubic, highest quality
<FC>BackgroundColor<FN> specifies a background color to fill new regions (i.e. when not rotating at a 90 degree angle)
<FM>Examples<FC>
// Rotate the selected image in a TImageEnMView attached to a TIEDBMultiBitmap
fDBMBitmap.Rotate( ImageEnMView1.SelectedImage, -90 );
// Rotate the first frame of an image 45<34> clockwise at highest quality with a white background color
MBitmap.Rotate( 0, 315, ierBicubic, clWhite );
<FM>See Also<FN>
- <A AngleToImageEnRotateAngle>
!!}
procedure TIEDBMultiBitmap.Rotate(idx: integer; Angle: double; AntialiasMode: TIEAntialiasMode = ierFast; BackgroundColor: TColor = clWhite);
var
bmp: TIEBitmap;
begin
bmp := GetTIEBitmap( idx );
bmp.Rotate( Angle, AntialiasMode, BackgroundColor );
ReleaseBitmap( idx, True );
end;
{!!
<FS>TIEDBMultiBitmap.Resample
<FM>Declaration<FC>
procedure Resample(idx: integer; ScaleBy: Double; FilterType: <A TResampleFilter> = rfNone);
<FM>Description<FN>
Resizes a frame of the current image and updates the database. The content of the image changes (stretched to new size).
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>ScaleBy<FN></C> <C>The amount to scale all images. E.g. 0.5 would halve the size of all images while respecting the proportions</C> </R>
<R> <C><FC>FilterType<FN></C> <C>Resampling interpolation algorithm</C> </R>
</TABLE>
<FM>Examples<FC>
// Halve the size of the first image in a TImageEnMView attached to a TIEDBMultiBitmap
fDBMBitmap.Resample( 0, 0.5, rfLanczos3 );
!!}
procedure TIEDBMultiBitmap.Resample(idx: integer; ScaleBy: Double; FilterType: TResampleFilter = rfNone);
var
bmp: TIEBitmap;
begin
bmp := GetTIEBitmap( idx );
bmp.Resample( ScaleBy, FilterType );
ReleaseBitmap( idx, True );
end;
{!!
<FS>TIEDBMultiBitmap.GetTIEBitmap
<FM>Declaration<FC>
function GetTIEBitmap(idx: Integer): <A TIEBitmap>;
<FM>Description<FN>
Creates a <A TIEBitmap> object from the image at index, <FC>idx<FN>.
You will need to call <A TIEDBMultiBitmap.ReleaseBitmap> to free the <A TIEBitmap> object and optionally update the image in the database
Note: If <A TIEMultiBitmap.ParamsEnabled>=True then the returned TIEBitmap will have <A TIEBitmap.Params>.
<FM>Example<FC>
// Prompt the user to apply effects to a database image
var
bmp: TIEBitmap;
proc: TImageEnProc;
bChanged: Boolean;
begin
if ImageEnMView1.SelectedImage < 0 then
exit;
bmp := fDBMBitmap.GetTIEBitmap( ImageEnMView1.SelectedImage );
proc := TImageEnProc.CreateFromBitmap( bmp );
proc.PreviewsParams := proc.PreviewsParams + [ prppDefaultLockPreview ];
bChanged := proc.DoPreviews();
fDBMBitmap.ReleaseBitmap( ImageEnMView1.SelectedImage, bChanged );
FreeAndNil( proc );
end;
!!}
{!!
<FS>TIEDBMultiBitmap.ReleaseBitmap
<FM>Declaration<FC>
procedure ReleaseBitmap(idx: Integer; SaveChanges: Boolean);
<FM>Description<FN>
Releases the bitmap created with <A TIEMultiBitmap.GetBitmap> or <A TIEMultiBitmap.GetTIEBitmap> method.
If saveChanges then your modifications will be written to the database (TDataset.Edit/Post will be called).
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>idx<FN></C> <C>The image index to release.</C> </R>
<R> <C><FC>saveChanges<FN></C> <C>If true (default), changes to the bitmap will be written to the database.</C> </R>
</TABLE>
<FM>Example<FC>
// Prompt the user to apply effects to a database image
var
bmp: TIEBitmap;
proc: TImageEnProc;
bChanged: Boolean;
begin
if ImageEnMView1.SelectedImage < 0 then
exit;
bmp := fDBMBitmap.GetTIEBitmap( ImageEnMView1.SelectedImage );
proc := TImageEnProc.CreateFromBitmap( bmp );
proc.PreviewsParams := proc.PreviewsParams + [ prppDefaultLockPreview ];
bChanged := proc.DoPreviews();
fDBMBitmap.ReleaseBitmap( ImageEnMView1.SelectedImage, bChanged );
FreeAndNil( proc );
end;
!!}
procedure TIEDBMultiBitmap.ReleaseBitmap(idx: Integer; SaveChanges: Boolean);
var
aBMP: TIEBitmap;
OldActive: Integer;
begin
OldActive := fDataLink.ActiveRecord;
LockUpdate;
try
try
if SaveChanges then
try
fDataLink.ActiveRecord := idx;
fDataLink.DataSet.Edit;
aBMP := fImageList.GetBitmap( GetImageInfo( idx ).image );
SetCurrentImage( aBMP, '', True );
fDataLink.DataSet.Post;
if assigned( fOwner ) and ( fOwner is TImageEnMView ) then
TImageEnMView( fOwner ).ClearImageCache( idx );
Changed( idx );
except
fDataLink.DataSet.Cancel;
Raise;
end;
finally
fImageList.ReleaseBitmapByImage( TIEImageInfo(fImageInfo[idx]).image, False );
end;
finally
fDataLink.ActiveRecord := OldActive;
UnlockUpdate;
end;
end;
{$endif}
{$ELSE} // {$ifdef IEINCLUDEDB}
interface
implementation
{$ENDIF}
end.