(* 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; {!! TIEImageStorageMode Declaration type TIEImageStorageMode = (isEmbeddedBlob, isLinkedFile); Description The method that images are stored or referenced by the database. Value Description isEmbeddedBlob The image is embedded within a blob field isLinkedFile A string field points to the filename of a local file
!!} TIEImageStorageMode = (isEmbeddedBlob, isLinkedFile); {!! TIEDBBitmap Description TIEDBBitmap is a descendant of , 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 ) or images stored locally and referenced by a filename field (by setting only ). You will need to set . There are two ways you can use TIEDBBitmap: • Connected to a TTable By setting the and or , the TIEDBBitmap will be connected to the database and the content will update with the movement and changes on the table, either automatically ( is true) or manually (by calling ). This is generally used to create a data-aware by setting the external bitmap to a TIEDBBitmap. // 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; • As an adhoc Bitmap with database access Use TIEDBBitmap to retrieve images embedded in a database blob field using the data-aware overload of . // Extract an image from a database and save it MyBMP := TIEDBBitmap.Create(); MyBMP.Read( MyTableImageBlob ); MyBmp.Write( 'D:\MyBlobImage.jpeg' ); MyBmp.Free; Methods and Properties General Database (Load from blob/file/stream) (Save to blob/file/stream) Assignment between Objects File I/O (inherited from ) Canvas Access Alpha Channel (Transparency) Pixel Access Palette and Color (inherited from ) (inherited from ) (inherited from ) Image Manipulation IEVision related Events 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; {!! TIEDBBitmap.ImageFormat Declaration property ImageFormat: ; Description Specifies the format that images are read and written to the database. If images are stored in a database blob field ( = isEmbeddedBlob) ImageFormat 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 ( = isLinkedFile) the ImageFormat is used only when saving image changes. If ImageFormat is ioUnknown 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; {!! TIEDBBitmap.JpegQuality Declaration property JpegQuality: integer; Description If database images are saved to JPEG then JpegQuality specifies the save quality (Range: 1 to 100. Higher is better quality, but larger). This property updates .. Default: 80 !!} property JpegQuality: integer read fJpegQuality write fJpegQuality default 80; {!! TIEDBBitmap.UseMemoryStream Declaration property UseMemoryStream: boolean Description 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} {!! TIEDBMultiBitmap Description TIEDBMultiBitmap is a descendant of , but unlike it links to a datasource to provide access to images stored in a database table. Generally a TIEDBMultiBitmap is attached to a to make it DB aware. TIEDBMultiBitmap supports both images stored within the database as a blob (by setting ) or images stored locally and referenced by a filename field (by setting only ). You will also need to set . Demo Demos\Database\DBMultiBitmap\DBMultiBitmap.dpr Example // 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; Methods and Properties General Database Database Editing Image Access Image Information Input/Output Input/Output Parameters (Meta-Data) Image Manipulation 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; {!! TIEDBMultiBitmap.FilenameFieldIsUnique Declaration property FilenameFieldIsUnique: Boolean; Description If the specified filename field, , is guaranteed to be unique (i.e. each record has a different name specified) then set FilenameFieldIsUnique to true. This will improve performance and caching. Also, if you are using = isLinkedFile and your filename field contains a full path ( = '') you can set this to true. Default: False !!} property FilenameFieldIsUnique: Boolean read fFilenameFieldIsUnique write fFilenameFieldIsUnique; {!! TIEDBMultiBitmap.DefaultFilename Declaration property DefaultFilename: string; Description 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 ( = isLinkedFile) then when appending bitmaps a file will be saved and then referenced by the database. For images referenced locally using only the is useful only if images do not have a file extension. If you have set an then DefaultFilename 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; {!! TIEDBMultiBitmap.ImageFormat Declaration property ImageFormat: ; Description Specifies the format that images are read and written to the database. If images are stored in a database blob field ( = isEmbeddedBlob) ImageFormat 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 ( = isLinkedFile) the ImageFormat is used only when saving image changes. If ImageFormat is ioUnknown (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; {!! TIEDBMultiBitmap.JpegQuality Declaration property JpegQuality: integer; Description If database images are saved to JPEG then JpegQuality specifies the save quality (Range: 1 to 100. Higher is better quality, but larger). This property updates .. Default: 80 !!} property JpegQuality: integer read fJpegQuality write fJpegQuality default 80; {!! TIEDBMultiBitmap.UseMemoryStream Declaration property UseMemoryStream: boolean Description 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 } {!! TIEDBBitmap.Create Declaration constructor Create(); overload; constructor Create(aDataSource: TDataSource; const sImageBlobField, sFilenameField: string); overload; Description Create a new TIEDBBitmap object. Second overload creates the bitmap and sets , and . Examples // 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; {!! TIEDBBitmap.DataSource Declaration property DataSource: TDataSource; Description Link the bitmap with a dataset. You will also need to set or . If is enabled the content will automatically update as the attached table changes. Otherwise you can call . Examples // 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; {!! TIEDBBitmap.ImageStorageMode Declaration property ImageStorageMode: ; (Read-Only) Description Returns the method that images are stored or referenced by the database. If you have set then ImageStorageMode will return isEmbeddedBlob. Otherwise it will return isLinkedFile. Setting has no effect on ImageStorageMode, because it can optionally provide a display name for an image stored in a blob field. Value Description isEmbeddedBlob The image is embedded within a blob field isLinkedFile A string field points to the filename of a local file
!!} function TIEDBBitmap.GetImageStorageMode: TIEImageStorageMode; begin Result := isLinkedFile; if fImageBlobField <> nil then Result := isEmbeddedBlob; end; {!! TIEDBBitmap.ImagePath Declaration property ImagePath: string; Description If your database table references images that are stored locally as files (i.e.
= isLinkedFile) then you can use ImagePath to specify the folder where the files are located, i.e. the load path is specified by ImagePath + "Filename Field content". Example usage: - If is the full path to a local file then set ImagePath to '' - If is only a name or has an invalid path then set ImagePath to the image folder ImagePath Property Value Content of Filename Field Loads Image From... C:\Some Folder\MyImage.jpg C:\Some Folder\MyImage.jpg C:\Some Folder\ MyImage.jpg C:\Some Folder\MyImage.jpg C:\Some Folder\ ..\MyImage.jpg C:\Some Folder\..\MyImage.jpg C:\Some Folder\ D:\FolderX\MyImage.jpg C:\Some Folder\MyImage.jpg http://www.imageen.com/images/ MyImage.jpg http://www.imageen.com/images/MyImage.jpg http://www.imageen.com/images/MyImage.jpg http://www.imageen.com/images/MyImage.jpg
Examples // 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; {!! TIEDBBitmap.FilenameField Declaration property FilenameField : string; Description 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
to a valid field. In this situation FilenameField 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 to ''. In this case FilenameField should either be a full path to a local file, or a name only with the folder specified by Note: Either or must be set (or both). Examples // 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; See Also - - - !!} procedure TIEDBBitmap.SetFilenameFieldName(const Value: string); begin if fFilenameFieldName <> Value then begin fFilenameFieldName := Value; ActiveChanged( nil ); end; end; {!! TIEDBBitmap.ImageBlobField Declaration property ImageBlobField : string; Description 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 is not set then images will be loaded locally (using ) If is a valid field, then images will be read from the embedded blob field. The file format will be determined using . You can optionally set to specify a field with a display name for the image. Note: Either or must be set (or both). Examples // 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; See Also - - - !!} procedure TIEDBBitmap.SetImageBlobFieldName(const Value: string); begin if fImageBlobFieldName <> Value then begin fImageBlobFieldName := Value; ActiveChanged( nil ); end; end; {!! TIEDBBitmap.AutoLoad Declaration property AutoLoad: boolean; Description If True and the TIEDBBitmap is attached to a 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 AutoLoad is false, you will need to call 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; {!! TIEDBBitmap.LoadImage Declaration function LoadImage(): boolean; Description Loads the image at the current database position into the bitmap (if it has changed). If you have enabled then you do not need to call LoadImage. Returns False on failure. Notes: - This will only work if you have set and (images stored in database table) or (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 See Also - - !!} function TIEDBBitmap.LoadImage(): boolean; begin Result := True; if fImageLoaded then exit; Result := Read(); fImageLoaded := True; end; {!! TIEDBBitmap.UpdateDatabaseImage Declaration procedure UpdateDatabaseImage(); Description Writes any changes to the image back to the blob field of the database table (at the current cursor position). Your current settings for , , and are used. This method has no effect if images are not stored within the database (i.e. must be isEmbeddedBlob). Raises exception on failure. Note: This is the same as calling: MyTable.Edit; MyDBBitmap.Write(); MyTable.Post; Example // Rotate the current image and update the database MyDBBitmap.Rotate( -90 ); MyDBBitmap.UpdateDatabaseImage(); See Also - !!} 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; {!! TIEDBBitmap.Read Declaration function Read(): boolean; overload; function Read(aBlobField: TBlobField; FileType: = 0; IOParams: = nil): boolean; overload; function Read(const FileName: string; IOParams: = nil): boolean; overload; function Read(Stream: TStream; FileType: = ioUnknown; IOParams: = nil): boolean; overload; function Read(Buffer: pointer; BufferSize: integer; FileType: = ioUnknown; IOParams: = nil): boolean; Description Load an image from a blob field, file or stream. This method supports all formats supported by class. The Read(); overload reads the image at the current database position using the properties of , and/or . When reading from a blob or stream you can optionally specify the Format. If it is not specified ImageEn will determine the file type automatically. You can optionally pass an object for the I/O parameters of the file (see also ). Returns False on failure. Examples // 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; See Also - - !!} 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; {!! TIEDBBitmap.Write Declaration function Write(): boolean; overload; function Write(aBlobField: TBlobField; FileType: ; IOParams: = nil): boolean; overload; function Write(const FileName: string; IOParams: = nil): boolean; overload; function Write(Stream: TStream; FileType: ; IOParams: = nil): boolean; overload; Description Writes image to a blob field, file or stream. This method supports all formats supported by class The Write(); overload sets the image at the current database position using the properties of , and/or .. If saving to a blob or stream you must specify the FileType You can optionally specify an object containing the I/O parameters of the file (see also ). Returns true on success. Examples // Rotate the current image in the database (assumes you have set and ) 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; See Also - - !!} 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 } {!! TIEDBMultiBitmap.Create Declaration constructor Create(); overload; constructor Create(aDataSource: TDataSource; const sImageBlobField, sFilenameField: string; bFilenameFieldIsUnique: Boolean = False); overload; Description Create a new TIEDBMultiBitmap object. Second overload creates the bitmap and sets , , and . Example // 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; {!! TIEDBMultiBitmap.Destroy Declaration destructor Destroy; Description Frees the object. !!} destructor TIEDBMultiBitmap.Destroy; begin FreeAndNil( fDataLink ); FreeAndNil( fBlobBitmap ); inherited Destroy; end; {!! TIEDBMultiBitmap.DataSource Declaration property DataSource: TDataSource; Description Link the multi-bitmap with a dataset. The content will automatically update as the attached table changes. You will also need to set or . Note: The maximum images that will be loaded is specified by Examples // 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; {!! TIEDBMultiBitmap.ReadOnly Declaration property ReadOnly: Boolean; Description 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; {!! TIEDBMultiBitmap.ImageStorageMode Declaration property ImageStorageMode: ; (Read-Only) Description Returns the method that images are stored or referenced by the database. If you have set then ImageStorageMode will return isEmbeddedBlob. Otherwise it will return isLinkedFile. Setting has no effect on ImageStorageMode, because it can optionally provide a display name for an image stored in a blob field. Value Description isEmbeddedBlob The image is embedded within a blob field isLinkedFile A string field points to the filename of a local file
!!} function TIEDBMultiBitmap.GetImageStorageMode: TIEImageStorageMode; begin Result := isLinkedFile; if fImageBlobField <> nil then Result := isEmbeddedBlob; end; {!! TIEDBMultiBitmap.ImagePath Declaration property ImagePath: string; Description If your database table references images that are stored locally as files (i.e.
= isLinkedFile) then you can use ImagePath to specify the folder where the files are located, i.e. the load path is specified by ImagePath + "Filename Field content". Example usage: - If is the full path to a local file then set ImagePath to '' - If is only a name or has an erroneous path then set ImagePath to the image folder ImagePath Property Value Content of Filename Field Loads Image From... C:\Some Folder\MyImage.jpg C:\Some Folder\MyImage.jpg C:\Some Folder\ MyImage.jpg C:\Some Folder\MyImage.jpg C:\Some Folder\ ..\MyImage.jpg C:\Some Folder\..\MyImage.jpg C:\Some Folder\ D:\FolderX\MyImage.jpg C:\Some Folder\MyImage.jpg http://www.imageen.com/images/ MyImage.jpg http://www.imageen.com/images/MyImage.jpg http://www.imageen.com/images/MyImage.jpg http://www.imageen.com/images/MyImage.jpg
Examples // 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; {!! TIEDBMultiBitmap.Update Declaration procedure Update; Description Refresh the content of the TIEDBMultiBitmap from the database and update the
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; {!! TIEDBMultiBitmap.FilenameField Declaration property FilenameField : string; Description 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 to a valid field. In this situation FilenameField specifies a display name for the image (and is optional). It will also improves performance, especially if the filename field is unique. - Reading files stored in a local folder and referenced by a database string field, by setting to ''. In this case FilenameField should either be a full path to a local file, or a name only with the folder specified by Notes: - Either or must be set (or both). - You should set if the field is unique to improve performance See Also - - - - Examples // 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; {!! TIEDBMultiBitmap.ImageBlobField Declaration property ImageBlobField : string; Description 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 is not set then images will be loaded locally (using ) If is a valid field, then images will be read from the embedded blob field. The file format will be determined using . You can optionally set to specify a field with a display name for the image. Setting will also improve performance, especially if the filename field is unique. Note: Either or must be set (or both). See Also - - - Examples // 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; {!! TIEDBMultiBitmap.MaxDisplayRecords Declaration property MaxDisplayRecords: Integer; Description TIEDBMultiBitmap will load all records of your database table into memory up to the maximum specified by MaxDisplayRecords. If your table contains more records than MaxDisplayRecords 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; {!! TIEDBMultiBitmap.FollowDBCursor Declaration property FollowDBCursor: boolean; Description If True and the TIEDBMultiBitmap is attached to a 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; {!! TIEDBMultiBitmap.InsertImage Declaration procedure InsertImage(idx: integer); overload; procedure InsertImage(Idx : integer; Stream : TStream); overload; procedure InsertImage(Idx : integer; Bitmap : ); overload; procedure InsertImage(Idx : integer; Bitmap : TBitmap); overload; procedure InsertImage(Idx : integer; MBitmap : ); overload; procedure InsertImage(Idx : integer; Width, Height : integer; PixelFormat : = ie24RGB); overload; procedure InsertImage(Idx : integer; const FileName : string); overload; Description Inserts a new image into the database at position, idx (0 is the first). The table will be positioned at the new record. Note: TDataset.Insert and TDataset.Post will be called Examples // 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' ); See Also - - !!} 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; {!! TIEDBMultiBitmap.AppendImage Declaration function AppendImage: Integer; function AppendImage(Stream: TStream): integer; function AppendImage(Bitmap: ): integer; function AppendImage(Bitmap : TBitmap): integer; function AppendImage(MBitmap : ); function AppendImage(Width, Height: Integer; PixelFormat: = ie24RGB): Integer; function AppendImage(const FileName: String): integer; Description Appends a new image at 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. Examples 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' ); See Also - - !!} 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; {!! TIEDBMultiBitmap.DeleteImage Declaration procedure DeleteImage(idx: integer); Description Removes the image, idx from the database table. Examples // 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; {!! TIEDBMultiBitmap.SetImage Declaration procedure SetImage(idx: Integer; srcImage: ); overload; procedure SetImage(idx: Integer; srcImage: TBitmap); overload; procedure SetImage(idx: Integer; width, height: Integer; PixelFormat: ); overload; function SetImage(idx: integer; const FileName: WideString; SourceImageIndex: Integer = 0; FileFormat: = ioUnknown): boolean; overload; function SetImage(idx: Integer; Stream: TStream; SourceImageIndex: Integer = 0; FileFormat: = ioUnknown): Boolean; overload Description Updates the current image in the database table. If images are stored in the database (i.e. is set), the image will be updated in the blob. If images are stored as files referenced by the database (i.e. is NOT set), the image changes will be saved to file (using and without an overwrite warning). NOTE: idx should be set to -1. Unlike TIEMultiBitmap., TIEDBMultiBitmap.SetImage always works on the CURRENT database table record. With overloads 2 and 3 the srcImage bitmap is copied internally; therefore you can free srcImage after calling SetImage. With overload 4 the image can be a local file or web page based image. With overloads 3 and 4 use SourceImageIndex to specify the image index if the source file is a multi-frame file (such as a TIFF or AVI). You can also specify the FileFormat if it cannot be determined by the file extension or content. TDataset.Edit and TDataset.Post are NOT called (Unlike and ) Examples 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; See Also - - - !!} 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; {!! TIEDBMultiBitmap.Flip Declaration procedure Flip(idx: integer; Dir: ); Description Flips (mirrors) a frame within the image across the horizontal or vertical axis and updates the image in the database. Examples // 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; {!! TIEDBMultiBitmap.Rotate Declaration procedure Rotate(idx: integer; Angle: double; AntialiasMode: = ierFast; BackgroundColor: TColor = clWhite); Description Rotates a frame of the current image by the specified angle (negative or positive degrees counter-clockwise) and updates it in the database. AntialiasMode specifies the anti-aliasing algorithm that is used to improve rotation quality: ierNone : No anti-aliasing (lowest quality) ierFast : Fast but lower quality ierBilinear : Bilinear, high quality ierBicubic : Bicubic, highest quality BackgroundColor specifies a background color to fill new regions (i.e. when not rotating at a 90 degree angle) Examples // Rotate the selected image in a TImageEnMView attached to a TIEDBMultiBitmap fDBMBitmap.Rotate( ImageEnMView1.SelectedImage, -90 ); // Rotate the first frame of an image 45° clockwise at highest quality with a white background color MBitmap.Rotate( 0, 315, ierBicubic, clWhite ); See Also - !!} procedure 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; {!! TIEDBMultiBitmap.Resample Declaration procedure Resample(idx: integer; ScaleBy: Double; FilterType: = rfNone); Description Resizes a frame of the current image and updates the database. The content of the image changes (stretched to new size). Parameter Description ScaleBy The amount to scale all images. E.g. 0.5 would halve the size of all images while respecting the proportions FilterType Resampling interpolation algorithm
Examples // Halve the size of the first image in a TImageEnMView 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; {!! TIEDBMultiBitmap.GetTIEBitmap Declaration function GetTIEBitmap(idx: Integer):
; Description Creates a object from the image at index, idx. You will need to call to free the object and optionally update the image in the database Note: If =True then the returned TIEBitmap will have . Example // 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; !!} {!! TIEDBMultiBitmap.ReleaseBitmap Declaration procedure ReleaseBitmap(idx: Integer; SaveChanges: Boolean); Description Releases the bitmap created with or method. If saveChanges then your modifications will be written to the database (TDataset.Edit/Post will be called). Parameter Description idx The image index to release. saveChanges If true (default), changes to the bitmap will be written to the database.
Example // 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.