ImageEn for Delphi and C++ Builder ImageEn for Delphi and C++ Builder

 

ImageEn Forum
Profile    Join    Active Topics    Forum FAQ    Search this forumSearch
Forum membership is Free!  Click Join to sign-up
Username:
Password:
Save Password
Forgot your Password?

 All Forums
 ImageEn Library for Delphi, C++ and .Net
 ImageEn and IEvolution Support Forum
 Quickly create low-res images
 New Topic  Reply to Topic
Author Previous Topic Topic Next Topic  

skippix

USA
68 Posts

Posted - Feb 24 2015 :  10:49:25  Show Profile  Reply
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  Show Profile  Reply
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
Go to Top of Page

skippix

USA
68 Posts

Posted - Feb 24 2015 :  11:32:57  Show Profile  Reply
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!
Go to Top of Page

w2m

USA
1990 Posts

Posted - Feb 24 2015 :  12:16:48  Show Profile  Reply
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
Go to Top of Page

xequte

38608 Posts

Posted - Feb 24 2015 :  13:00:44  Show Profile  Reply
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
Go to Top of Page

skippix

USA
68 Posts

Posted - Mar 14 2015 :  12:49:33  Show Profile  Reply
thanks, bill & nigel, for the great tips. that's a nice threading example, bill!
Go to Top of Page
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
Jump To: