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

 

ImageEn Forum
Profile    Join    Active Topics    Forum FAQ    Search this forumSearch
 All Forums
 ImageEn Library for Delphi, C++ and .Net
 ImageEn and IEvolution Support Forum
 Resizing/resampling

Note: You must be registered in order to post a reply.
To register, click here. Registration is FREE!

View 
UserName:
Password:
Format  Bold Italicized Underline  Align Left Centered Align Right  Horizontal Rule  Insert Hyperlink   Browse for an image to attach to your post Browse for a zip to attach to your post Insert Code  Insert Quote Insert List
   
Message 

 

Emoji
Smile [:)] Big Smile [:D] Cool [8D] Blush [:I]
Tongue [:P] Evil [):] Wink [;)] Black Eye [B)]
Frown [:(] Shocked [:0] Angry [:(!] Sleepy [|)]
Kisses [:X] Approve [^] Disapprove [V] Question [?]

 
Check here to subscribe to this topic.
   

T O P I C    R E V I E W
tvdien Posted - Jan 16 2012 : 12:17:56
I have a TImageEnView that has a layer with a (large) picture loaded from a file. The user should be able to resize this picture by scrolling over it. Currently, this is functioning by writing e.g.
ImageEnView1.Layers[1].Width := Round(ImageEnView1.Layers[1].Width * 1.10);
ImageEnView1.Layers[1].Height := Round(ImageEnView1.Layers[1].Height * 1.10);
in the OnMouseWheelUp/Down event handlers.

1. Is it correct that resizing a layer in this way does not affect the quality, i.e. making a layer smaller and then the previous size again gives the same result as when the layer was never resized? At least, it seems so...

2. How do resample filters affect the result? E.g., when I set
ImageEnView1.Layers[1].ResampleFilter := rfLanczos3;
ImageEnView1.Layers[1].UseResampleFilter := True;
does that only affect the view or also the result when the image is saved to a file?

3. What I'm trying to achieve is that resizing the image back and forth does not affect the quality. Also resizing and moving a layer should be fast (rfLanczos3 isn't, but rfFastLinear is); quality in the view doesn't matter that much, as long as the saved result is as good as it gets. Even better would be if rfFastLinear were used during resizing/moving a layer (to make it responsive) and then rfLanczos3 when the interaction is done, to make the final result slightly better. How to achieve this?
4   L A T E S T    R E P L I E S    (Newest First)
tvdien Posted - Jan 21 2012 : 07:42:09
quote:
Well, but this depends on what your application needs to do (reading first post the Layers solution was better).
I don't mind the view looking better, but after saving, the user should be able to make adjustments still, including scaling. :)

My program loads an image of 15MP using the following code:

//Background
ImageEnView1.Layers[0].Bitmap.Width := 640;
ImageEnView1.Layers[0].Bitmap.Height := 640;
ImageEnView1.Layers[0].Selectable := False;
ImageEnView1.Layers[0].Locked := True;
ImageEnView1.Layers[0].Bitmap.Canvas.Brush.Color := clWhite;
ImageEnView1.Layers[0].Bitmap.Canvas.FillRect(Rect(Point(0, 0), Point(640, 640)));

//Image
ImageEnView1.LayersAdd;
ImageEnView1.Layers[1].ResampleFilter := rfFastLinear;
ImageEnView1.Layers[1].UseResampleFilter := True;
ImageEnView1.Layers[1].Cropped := True;
ImageEnView1.Layers[1].VisibleBox := False;
ImageEnView1.IO.Params.EnableAdjustOrientation := True;
ImageEnView1.IO.Params.JPEG_DCTMethod := ioJPEG_IFAST;
// The user should be able to make no more than half of the
// image visible in the 640x640 frame without loss of quality,
// so we need the original at twice the size of the frame.
ImageEnView1.IO.Params.Width := 2*640; 
ImageEnView1.IO.Params.Height := 2*640;
ImageEnView1.IO.Params.JPEG_Scale := ioJPEG_AUTOCALC;
ImageEnView1.IO.LoadFromFile('image.jpg');
OriginalWidth := ImageEnView1.Layers[1].Width;
OriginalHeight := ImageEnView1.Layers[1].Height;
ScaleFactor := 640/Min(ImageEnView1.Layers[1].Width, ImageEnView1.Layers[1].Height);
ImageEnView1.Layers[1].Width := Round(ScaleFactor * ImageEnView1.Layers[1].Width);
ImageEnView1.Layers[1].Height := Round(ScaleFactor * ImageEnView1.Layers[1].Height);
ImageEnView1.Layers[1].PosX :=
  Round((ImageEnView1.Layers[0].Width - ImageEnView1.Layers[1].Width)/2);
ImageEnView1.Layers[1].PosY :=
  Round((ImageEnView1.Layers[0].Height - ImageEnView1.Layers[1].Height)/2);

The image has to be positioned on the 640x640 background by the user (MouseInteract := [miMoveLayers]), The view on which the user acts can be smaller, e.g. 400x400 (AutoFit := True), but the result is always to be saved to 640x640 by the click of a button when done.

Just dragging this image at any size, but especially ones at which the whole image is visible, is not very smooth.
fab Posted - Jan 21 2012 : 07:15:24
quote:
OK, but since I don't want to change the view at all, I decided to go with a number of RenderToCanvas instructions to a secondary IEBitmap which will then be saved. This works well.


Well, but this depends on what your application needs to do (reading first post the Layers solution was better).

quote:
The main thing I'm worried about is that dragging the scaled layer of the big image around is still relatively slow, even though I'm using no more than rfFastLinear. I'm comparing to Graphics32 which seems much more responsive in this aspect. Are there any optimizations that I'm missing?



I don't know how your code is organized, maybe do you call RenderToCanvas more than it is actually necessary?
Fastest than rfFastLinear there is only rfNone, of course.

quote:
When I was using rfLanczos3 in the view as well, the continuous starting and exiting of threads made it obvious that the layer is rendered again even when it only changed position within the view and therefore still looks exactly the same. Can this be prevented?



At the moment this is not avoidable. Just for future optimizations, which is the size of your layers (actual pixels)?
tvdien Posted - Jan 21 2012 : 06:50:54
OK, but since I don't want to change the view at all, I decided to go with a number of RenderToCanvas instructions to a secondary IEBitmap which will then be saved. This works well.

The main thing I'm worried about is that dragging the scaled layer of the big image around is still relatively slow, even though I'm using no more than rfFastLinear. I'm comparing to Graphics32 which seems much more responsive in this aspect. Are there any optimizations that I'm missing?

When I was using rfLanczos3 in the view as well, the continuous starting and exiting of threads made it obvious that the layer is rendered again even when it only changed position within the view and therefore still looks exactly the same. Can this be prevented? I should mention that the view is scaled, but still, moving a completely visible layer around changes nothing but some coordinates.
fab Posted - Jan 21 2012 : 00:52:14
quote:
1. Is it correct that resizing a layer in this way does not affect the quality, i.e. making a layer smaller and then the previous size again gives the same result as when the layer was never resized? At least, it seems so...


The method you have chosen (Layers[].Width/Height) doesn't actually resize the image, but only the layer (how the image is displayed). For this reason this way doesn't affect the quality (until you make the resizing permanent calling LayersFixSizes() method).

quote:
2. How do resample filters affect the result? E.g., when I set
ImageEnView1.Layers[1].ResampleFilter := rfLanczos3;
ImageEnView1.Layers[1].UseResampleFilter := True;
does that only affect the view or also the result when the image is saved to a file?


It does affect the view only.
Anyway (see above) if you want to make size permanent you have to call layersFixSizes(). In this case it uses ReampleFilter filter to resample the original image if UseResampleFilter is true or ZoomFilter otherwise.

quote:
3. What I'm trying to achieve is that resizing the image back and forth does not affect the quality. Also resizing and moving a layer should be fast (rfLanczos3 isn't, but rfFastLinear is); quality in the view doesn't matter that much, as long as the saved result is as good as it gets. Even better would be if rfFastLinear were used during resizing/moving a layer (to make it responsive) and then rfLanczos3 when the interaction is done, to make the final result slightly better. How to achieve this?


You can set rfFastLinear in Layers[].ResampleFilter and execute following code just before save:

ImageEnView1.Layers[1].ResampleFilter := rfLanczos3;
ImageEnView1.LayersFixSizes();