Frequently Asked Questions about ImageEn:
There are two common causes for this error:
1. You have multiple copies of the ImageEn BPL files on your system (generally error is for DPKIECtrl*.bpl)
Search your system for any PKIE*.* and DPKIE*.* files and remove them (it might help to review the library paths under Tools > Options, Library). Then reinstall ImageEn.
2. You have another package that uses the ImageEn BPL (generally error is for PKIECtrl*.bpl)
A package - either one of ImageEn's or one of your own - is trying to access PKIECtrl26.bpl, but is failing because PKIECtrl26.bpl has been recompiled more recently. The error may be followed by another one that advised you which package is giving you the error: "Xyz package could not be loaded. Would you like to load it next time you run Delphi...".
If you know which package has caused the problem, open it's DPK file and recompile it. Otherwise, go through each of your packages and recompile any that use ImageEn.
Unfortunately, most scanner manufacturers do not offer 64bit Twain drivers. Instead, they usually include a "WIA over Twain" driver. So, you are better to use WIA instead of Twain. You can use the
TIEAcquireParams class in ImageEn to provide generic access to scanner devices whether they use WIA, Twain, etc.
If you need to test 64bit Twain support, you can use the FreeImage Software scanner driver:
sourceforge.net/projects/twain-samples/files/TWAIN%202%20Sample%20Data%20Source/
You can use
MouseWheelParams:
ImageEnView1.MouseWheelParams.Action := iemwNone;
Other values are iemwVScroll and iemwZoom (default).
PDF loading requires one of the following plug-ins:
◼ImageEn PDFium Plug-in from:
www.imageen.com/download/
◼WPViewPDF commercial plug-in
◼ImageMagick + GhostScript
There are several ways. The simplest is to use
TIEMultiBitmap:
var
mbmp: TIEMultiBitmap;
begin
mbmp := TIEMultiBitmap.Create;
mbmp.LoadFromFile('D:\in.gif');
mbmp.SaveToFile('D:\out.tiff');
mbmp.Free();
end;
You need to set the following properties (which are all enabled by default):
◼Disable
TImageEnView.KeyboardShortcuts
◼Remove loKeyboardShortcuts from
TImageEnView.LayerOptions
◼Remove ieboEnableFileShortcuts from
TImageEnFolderMView.FolderInteract
◼Disable
TIERichEdit.KeyboardShortcuts
◼Disable
TImageEnViewToolbar/TIERichEditToolbar.KeyboardShortcuts
◼Remove Shortcuts from any
ImageEn Actions
Configure or disable individual keyboard shortcuts using
KeyboardShortcuts
Ensure you have optimized your settings to ensure the best performance:
- Most importantly, decide whether to load and store full size images, or just preview thumbnails. If you are loading the content of a multi-page file, such as TIFF, for editing and display, then generally you will want StoreType=ietNormal. However, if you are displaying thousands of photos from a folder, for example, then you are better to use load only thumbnails (StoreType is ietThumb or ietFastThumb)
- Load images only on demand (i.e. as they are displayed or needed). To do this, ensure the LoadOnDemand parameter is set for AppendImage, InsertImage, FillFromDirectory or FillFromList. Or if you are just loading a single file with many pages, use LoadFromFileOnDemand
- Lock updating while performing batch operations (LockUpdate/UnlockUpdate)
- Consider options to load EXIF thumbnails or Windows Explorer thumbnails
- Choose a good balance between quality and speed when setting the ThumbnailResampleFilter
- Increasing the size of the image cache can help with general performance, especially when StoreType=ietFastThumb
Also see the Performance demo: \Demos\Multi\MViewPerformance\Performance.dpr
You can
automatically register the plug-in DLLs using:
IEGlobalSettings().RegisterPlugIns();
Yes, load each page using:
ImageEnView1.IO.LoadFromFile('C:\page1.tif');
Then set
TIFF_ImageIndex and save the page:
ImageEnView1.IO.Params.TIFF_ImageIndex := 0; // increment this value for each page
ImageEnView1.IO.InsertToFileTIFF('D:\multipage.tif');
Otherwise you can use a
TImageEnMView component or a
TIEMultiBitmap. See the "multi" demo for more detail.
There are two ways to load several pages from a TIFF:
1) Load a page at the time, using TImageEnView and
TIFF_ImageIndex, e.g.
ImageEnView1.IO.Params.TIFF_ImageIndex := page_number; // where page_number is the page to load and starts from 0 (first page)
ImageEnView1.IO.LoadFromFile('mytiff.tiff');
To determine many pages there are:
page_count := EnumTIFFIm('mytiff.tiff');
2) load all pages using a
TImageEnMView:
ImageEnMView1.MIO.LoadFromFile('mytiff.tiff');
After loading an ImageEn layer file you can iterate through all of the fonts to ensure they are valid, for example:
ImageEnView1.IO.LoadFromFileIEN(...);
// Validate fonts are installed on this system
for i := 0 to ImageEnView1.LayersCount do
begin
if ImageEnView1.Layers[i].Kind = ielkText then
fontName := TIETextLayer( ImageEnView1.Layers[i] ).Font
else
if ImageEnView1.Layers[i].Kind = ielkLine then
fontName := TIELineLayer( ImageEnView1.Layers[i] ).LabelFont
else
continue;
if Screen.Fonts.IndexOf( fontName ) = -1 then
begin
// This font is not installed. Substitute or install it...
end;
end;
Using
DuplicateCompressionInfo you must change the compression property for all pages:
ImageEnMView1.MIO.LoadFromFile('original.tif');
// change compression for the first page
ImageEnMView1.MIO.Params[0].TIFF_Compression := ioTIFF_G4FAX;
// change compression for the other pages
ImageEnMView1.MIO.DuplicateCompressionInfo();
// now save
ImageEnMView1.Mio.SaveToFile('output.tif');
The main performance properties are:
◼LayersCaching: Caches the view of each layer. Much faster but uses more memory.
◼LayersFastDrawing: Display quality of layers (and whether the quality view is delayed).
◼ZoomFilter/
DelayZoomFilter: Display quality of images (and whether the quality view is delayed). This option is ignored if LayersFastDrawing is active
◼LayersRotationUseFilterOnPreview: Whether the quality filter (LayersRotationFilter) is previewed without applying the rotation using LayersFixRotations
Here is some example code from the Layers_AllTypes demo:
procedure Tfmain.cmbPreviewQualityChange(Sender: TObject);
const
_cmbPreviewQuality_Fast = 0;
_cmbPreviewQuality_Delayed_Best = 1;
_cmbPreviewQuality_Best = 2;
begin
// Separate code to make it easier to understand
if cmbPreviewQuality.ItemIndex = _cmbPreviewQuality_Fast then
begin
// FASTEST DISPLAY
// Zoom filter
ImageEnView1.ZoomFilter := rfNone;
ImageEnView1.DelayZoomFilter := False;
// Rotation anti-alias
ImageEnView1.LayersRotationFilter := ierBicubic;
// Fast drawing
ImageEnView1.LayersFastDrawing := iefFast;
end
else
if cmbPreviewQuality.ItemIndex = _cmbPreviewQuality_Delayed_Best then
begin
// DELAYED HIGH QUALITY
// Zoom filter
ImageEnView1.ZoomFilter := rfLanczos3;
ImageEnView1.DelayZoomFilter := True;
// Rotation anti-alias
ImageEnView1.LayersRotationFilter := ierBicubic;
// Fast drawing
ImageEnView1.LayersFastDrawing := iefDelayed;
end
else
begin
// HIGH QUALITY
// Zoom filter
ImageEnView1.ZoomFilter := rfLanczos3;
ImageEnView1.DelayZoomFilter := False;
// Rotation anti-alias
ImageEnView1.LayersRotationFilter := ierBicubic;
// Fast drawing
ImageEnView1.LayersFastDrawing := iefNormal;
end;
ImageEnView1.Update();
end;
procedure Tfmain.chkLayerCachingClick(Sender: TObject);
begin
if chkLayerCaching.Checked then
ImageEnView1.LayersCaching := -1
else
ImageEnView1.LayersCaching := 0;
end;
There are several ways to display images "on demand":
1) If you have a folder containing your images, use
FillFromDirectory:
ImageEnMView1.FillFromDirectory('c:\myimages');
2) When you add a new image just set its
ImageFileName[], and ImageEn will automatically load the specified file when needed. For example:
idx := ImageEnMView1.AppendImage;
ImageEnMView1.ImageFileName[idx] := 'first.jpg';
3) When you add a new image just set the
ImageID[] property. You must create an array of filenames where images are to be loaded. For example:
var
files: array [0..1] of string;
begin
files[0] := 'first.jpg';
files[1] := 'second.jpg';
ImageEnMView1.ImageID[ ImageEnMView1.AppendImage ] := 0;
ImageEnMView1.ImageID[ ImageEnMView1.AppendImage ] := 1;
end;
You must also implement the
OnImageIDRequest event, e.g.:
procedure TForm1.OnImageIDRequest(Sender: TObject; ID: integer; var Bitmap: TBitmap);
var
io: TImageEnIO;
begin
io := TImageEnIO.Create(self);
io.AttachedBitmap := bmp; // bmp is a TBitmap object, defined at class level (must exists after the OnImageIDRequest exits)
io.LoadFromFile( files[ID] );
io.Free();
Bitmap := bmp;
end;
4) If the images are frames of a media file (like AVI, MPEG, etc..) you can use
LoadFromFileOnDemand:
ImageEnMView1.LoadFromFileOnDemand('video.mpeg');
Lines, ellipses and other layers added to a TImageEnView can be merged to the background using the
LayersMergeAll method, then save the image.
The IPTC info is automatically loaded when you load the JPEG image using the LoadFromFile method. After this all IPTC information is loaded into the
TImageEnView.IO.Params.IPTC_Info object. To read the caption you can write:
ImageEnView.IO.LoadFromFile('image.jpg');
Idx := ImageEnView.IO. Params.IPTC_Info.IndexOf(2, 120);
Caption := ImageEnView.IO.Params.IPTC_Info.StringItem[idx];
To modify the caption:
ImageEnView.IO.Params.IPTC_Info.StringItem[idx] := 'new caption';
ImageEnView.IO.SaveToFile('image2.jpg');
To modify IPTC info without loading the image use
ParamsFromFile and
InjectJpegIPTC methods, as follows:
ImageEnView.IO.ParamsFromFile('D:\Image.jpg');
...After modifying the IPTC info, save it
ImageEnView.IO.InjectJpegIPTC('D:\Image_ChangedMeta.jpg');
Call
ResetInfo. For example:
ImageEnView.IO.LoadFromFile('input.jpg');
ImageEnView.IO.Params.ResetInfo();
ImageEnView.IO.SaveToFile('output.jpg');
To empty the component use the "Blank" method. To check if it is empty use
IsEmpty:
If ImageEnView1.IsEmpty() then
...
1. To handle the display automatically specify your TImageEnView for
AttachedImageEnView
ImageEnMView1.AttachedImageEnView := ImageEnView1;
2. To manually handle the image selection use the
OnImageSelect event. To get the currently selected image simply use the
Assign method:
procedure TForm1.ImageEnMView1ImageSelect(Sender: TObject; idx: Integer);
begin
ImageEnView1.Assign( ImageEnMView1.IEBitmap );
end;
Here is an example:
TResourceStream *ResourceImage;
// Load from resource the About image ( a JPEG file).
ResourceImage = new TResourceStream((int)HInstance, "ABOUTBITMAP", RT_RCDATA);
MainForm->ImageAbout->IO->LoadFromStreamJpeg(ResourceImage);
delete ResourceImage;
Create a text file named "resource.rc" with the single line:
ABOUTBITMAP RCDATA "about.jpg"
Then add the Resource file to the project and compile.
This example shows how to read
EXIF tags saved by Canon cameras:
var
ms: TMemoryStream;
tagReader1, tagReader2, tagReader3: TIETifTagsReader;
i: integer;
// some Canon tags
m_nMacroMode, m_nLenghtTimer, m_Quality: integer;
m_ImageType: string;
begin
ImageEnView1.IO.LoadFromFile('Capture_00006.JPG');
with ImageEnView1.IO.Params.JPEG_MarkerList do
begin
i := IndexOf( JPEG_APP1 );
if i >= 0 then
begin
// there is EXIF info
ms := TMemoryStream.Create;
ms.Write( MarkerData[i][6], MarkerLength[i] ); // bypass first 4 bytes (must contain 'Exif')
ms.Position := 0;
tagReader1 := TIETifTagsReader.CreateFromStream( ms, 0 ); // read TIFF's IFD
tagReader2 := TIETifTagsReader.CreateFromIFD( tagReader1, 34665 ); // read IFD in tag 34665 (SubEXIF)
tagReader3 := TIETifTagsReader.CreateFromIFD( tagReader2, $927c ); // read IFD in tag $927C (MarkerData - Canon IFD data)
// read Canon EXIF tags
m_nMacroMode := tagReader3.GetIntegerIndexed(1, 1);
m_nLenghtTimer := tagReader3.GetIntegerIndexed(1, 2);
m_Quality := tagReader3.GetIntegerIndexed(1, 3);
m_ImageType := tagReader3.GetString(6);
tagReader3.Free();
tagReader2.Free();
tagReader1.Free();
ms.Free();
end;
end;
end;
Jpeg is a file format with variable compression rate. The property that regulates the compression (and the quality) is
JPEG_Quality. So you should set this property before saving. For example:
ImageEnView.IO.LoadFromFile('input.jpg');
ImageEnView.IO.Params.JPEG_Quality := 70;
ImageEnView.IO.SaveToFile('output.jpg');
The default is 80, which provides a good balance between quality and file size.
To estimate the value used to create your file, use:
Quality := IECalcJpegFileQuality('input.jpg');
So you could write:
ImageEnView.IO.LoadFromFile('input.jpg');
ImageEnView.IO.Params.JPEG_Quality := IECalcJpegFileQuality('input.jpg');
ImageEnView.IO.SaveToFile('output.jpg');
If the file is still too large it may contain metatags (text info). To remove them, call
ResetInfo before saving:
ImageEnView.IO.Params.ResetInfo();
Use the
RAW_GetEmbeddedJpeg property:
// Load the embedded JPEG (loading a half size raw if there is no embedded JPEG)
ImageEnView.IO.Params.RAW_GetEmbeddedJpeg := True;
ImageEnView.IO.Params.RAW_HalfSize := True;
Just set
LayersAutoClosePolylines:
// Always close polylines
ImageEnView1.LayersAutoClosePolylines := iecmAlways;
To read Camera RAW files you must add
ielib.dll to your EXE folder, or set IEGlobalSettings().
CameraRawEngine to ieenWIC.
This can happen on shared printers due to a bug in the VCL or printer drivers. Try
disabling FPU exceptions by executing this before your printing code:
Set8087CW($133F);
Yes, you can add the ImageEn exception type,
EIEException to Tools > Options, Debugger, Embarcadero Debuggers, Language Exceptions.
For more detail on common exceptions, see
ImageEn Standard Exceptions