Author |
Topic |
|
skippix
USA
68 Posts |
Posted - Feb 24 2015 : 10:49:25
|
Help! I've been going in circles and need some direction.
I need to quickly create low-res copies of images. I am trying to use a non-visible TImageEnView component, but I am quite sure I don't have it configured correctly. My files average 7MB and it takes an average of 3 seconds per file to load, resize, and save the low-res version.
Here's my code
ImageEnView1 := TImageEnView.Create(nil);
ImageEnView1.IO.Params.JPEG_EnableAdjustOrientation := True;
ImageEnView1.IO.Params.Width := 720;
ImageEnView1.IO.Params.Height := 720;
ImageEnView1.IO.Params.JPEG_Scale := ioJPEG_AUTOCALC;
ImageEnView1.IO.LoadFromFileJpeg(PChar(sFileName));
h := ImageEnView1.Bitmap.Height;
w := ImageEnView1.Bitmap.Width;
if (h > w) then
begin
h2 := 720;
if (h <> h2) then
w2 := Round ( w * (h2 / h) );
end
else
begin
w2 := 720;
if (w <> w2) then
h2 := Round ( h * (w2 / w) );
end;
ImageEnView1.Proc.Resample(w2, h2, rfNone);
ImageEnView1.Proc.AutoSharp(5);
ImageEnView1.IO.SaveToFileJpeg(sSaveTo);
FreeAndNil(ImageEnView1);
I am really hoping this can be done a lot quicker than in 3 seconds. Medium image quality is fine. Currently, my downsized files average about 65KB and are perfectly acceptable quality-wise. It's just the amount of time that it takes to get them.
Thanks! |
|
w2m
USA
1990 Posts |
Posted - Feb 24 2015 : 10:59:12
|
How many images are you trying to resample and save at a time? One (1)?
Try iexHelperFunctions:
unit iexHelperFunctions
1. TIEBitmap.IELoadFromFileFast Declaration function IELoadFromFileFast(const sFilename: string; iMaxX, iMaxY: integer; bAutoAdjustOrientation: Boolean = False ): Boolean; Description Allows you to load an image into a TIEBitmap using the fastest method by specifying the maximum size it is required. It uses: - JPEG_Scale for JPEGs - RAW_GetExifThumbnail and RAW_HalfSize for Camera Raw files
You can also set EnableAdjustOrientation to automatically re-orient JPEG camera images.
Returns True if loading was successful, or False on error.
2. TIEBitmap.IEConvertToThumbnail
Declaration procedure IEConvertToThumbnail(iMaxX, iMaxY: integer; bCanStretch: Boolean; QualityFilter : TResampleFilter = rfLanczos3;
bAddBorder: Boolean = False; cBorderColor: TColor = clBlack;
bAddShadow: Boolean = False; iBlurRadius : Integer = 4; iShadowOffset : Integer = 4; cShadowColor: TColor = clBlack; cBGColor: TColor = clWhite);
Description Resize an image in a TIEBitmap to the specified size (while maintaining the aspect ratio, thus one of the dimensions is likely to be less than the specified value).
3. TIEBitmap.IESaveToFile
Declaration function IESaveToFile(const sFilename : string; iJPEGQuality : Integer): Boolean;
Description Allows a TIEBitmap to save to any format supported by ImageEn. If you are saving to JPEG you can also specify the JPEG_Quality. Returns True if saving was successful, or False on error.
Also ImageEnView1.Proc.AutoSharp(5) can be very time consuming... If you eliminate this it will probably be a lot faster... or you could do all of this in a secondary thread.
Bill Miller Adirondack Software & Graphics Email: w2m@hughes.net EBook: http://www.imageen.com/ebook/ Custom Commercial ImageEn Development |
|
|
skippix
USA
68 Posts |
Posted - Feb 24 2015 : 11:32:57
|
thanks, bill!
i got the TIEBitmap process to work, but couldn't get the quality up to an acceptable level.
HOWEVER, eliminating AutoSharp did the trick! Images now load, resize, and save in about a half a second.
THANKS! |
|
|
w2m
USA
1990 Posts |
Posted - Feb 24 2015 : 12:16:48
|
The file loading, resampling, auto sharpening and saving the file can all be done in a thread that takes less than 1/2 second here. Note I have the code that saves the thumbnail remarked for my test.
TProcessingThread = class(TThread)
private
{ Private declarations }
procedure ImageEnProcFinishWork(Sender: TObject);
procedure ImageEnProcProgress(Sender: TObject; per: Integer);
protected
{ Protected declarations }
procedure Execute; override;
public
{ Public declarations }
constructor Create(CreateSuspended: Boolean);
end;
{ TProcessingThread }
constructor TProcessingThread.Create(CreateSuspended: Boolean);
{ Create the thread. }
begin
inherited;
end;
procedure TProcessingThread.ImageEnProcProgress(Sender: TObject; per: Integer);
{ Set the progressbar position. }
begin
Synchronize(
procedure
begin
{ Ensure progress is painted when themes are enabled }
Form1.ProgressBar1.Position := per;
Form1.ProgressBar1.Position := per - 10;
Form1.ProgressBar1.Position := per;
end);
end;
procedure TProcessingThread.ImageEnProcFinishWork(Sender: TObject);
{ Reset the progressbar position. }
begin
Synchronize(
procedure
begin
Form1.ProgressBar1.Position := 0;
end);
end;
procedure TProcessingThread.Execute;
{ Process the image in the thread.
Note: All references to GUI elements must occur inside a Synchronize method.
Synchronize suspends the current thread and has the main thread call the procedure. When
the procedure finishes, control returns to the current thread. The actual image processing
is done by an imageenproc (non GUI element) directly in the thread. All of the GUI elements
are accessed with Synchronize. }
var
iImageEnProc: TImageEnProc;
iIEBitmap: TIEBitmap;
iFilename: string;
iNewFilename: string;
begin
inherited;
{ Set the LabelThread caption }
if not Terminated then
begin
{ Synchronize GUI elements }
Synchronize(
procedure
begin
Form1.LabelThread1.Caption := 'Thread is running...';
Form1.LabelThread1.Update;
iFilename := Form1.ImageEnView1.IO.Params.FileName;
end);
end;
if not Terminated then
begin
{ Synchronize GUI elements }
Synchronize(
procedure
begin
Form1.LabelThread1.Caption := 'Loading the image and creating thumbnail...';
Form1.LabelThread1.Update;
end);
end;
{ Get the IEBitmap }
if not Terminated then
begin
iIEBitmap := TIEBitmap.Create;
try
iIEBitmap.IELoadFromFileFast(iFilename, 720, 0, True);
{ Create a copy of ImageEnView bitmap }
iImageEnProc := TImageEnProc.CreateFromBitmap(iIEBitmap);
try
{ Set the OnProgress and OnFinishWork events }
iImageEnProc.OnProgress := ImageEnProcProgress;
iImageEnProc.OnFinishWork := ImageEnProcFinishWork;
{ resample the image }
iIEBitmap.IEConvertToThumbnail(720, -1, False, rfLanczos3, False,
clBlack, False, 4, 4, clBlack, clWhite);
{ AutoSharp Filter }
if not Terminated then
begin
{ Synchronize GUI elements }
Synchronize(
procedure
begin
Form1.LabelProcedure1.Caption := 'Applying Auto Sharp Filter...';
Form1.LabelProcedure1.Update;
Form1.Undo1.Hint := 'Applying Auto Sharp Filter…';
Form1.ImageEnView1.Proc.SaveUndoCaptioned('AutoSharp Filter');
Form1.StatusBar1.Panels[4].Text := 'Undo: ' +
IntToStr(Form1.ImageEnView1.Proc.UndoCount);
end);
{ Actual work done here in the secondary thread }
iImageEnProc.AutoSharp(5);
{ Save the thumbnail }
//iNewFilename :=
//iIEBitmap.IESaveToFile(iNewFilename, 80);
{ Synchronize GUI elements }
Synchronize(
procedure
begin
Form1.ImageEnView1.IEBitmap.Assign(iIEBitmap);
{ update image seen by the user }
Form1.ImageEnView1.Update;
Form1.StatusBar1.Panels[2].Text := 'Width: ' +
IntegerToStr(iIEBitmap.Width);
Form1.StatusBar1.Panels[3].Text := 'Height: ' +
IntegerToStr(iIEBitmap.Height);
end);
end;
finally
{ Free iImageEnProc }
iImageEnProc.Free;
end;
finally
{ Free iIEBitmap }
iIEBitmap.Free;
end;
end;
end;
Main Form
public
{ Public declarations }
AThread: TProcessingThread; { Image processing thread }
procedure TForm1.Process1Click(Sender: TObject);
begin
{ Create the thread suspended }
AThread := TProcessingThread.Create(True);
{ Free the thread onTerminate }
AThread.FreeOnTerminate := True;
{ Start the thread }
AThread.Start;
{ Processing will occur in the TProcessingThread.Execute event }
end;
Bill Miller Adirondack Software & Graphics Email: w2m@hughes.net EBook: http://www.imageen.com/ebook/ Custom Commercial ImageEn Development |
|
|
xequte
38608 Posts |
Posted - Feb 24 2015 : 13:00:44
|
Please also note that you can replace:
if (h > w) then
begin
h2 := 720;
if (h <> h2) then
w2 := Round ( w * (h2 / h) );
end
else
begin
w2 := 720;
if (w <> w2) then
h2 := Round ( h * (w2 / w) );
end;
ImageEnView1.Proc.Resample(w2, h2, rfNone);
With this:
ImageEnView1.Proc.Resample(720, 720, rfNone, True);
And rfFastLinear should give you better quality with little decrease in speed
Nigel Xequte Software www.xequte.com nigel@xequte.com
|
|
|
skippix
USA
68 Posts |
Posted - Mar 14 2015 : 12:49:33
|
thanks, bill & nigel, for the great tips. that's a nice threading example, bill! |
|
|
|
Topic |
|
|
|