Jump to content
wadepm

smooth scaling of bitmaps

Recommended Posts

Hello!

 

I am looking for a something that will scale bitmaps with a "nice" result.  Something better than stretchdraw, which does exactly what I want but looks horrible.  

 

Thanks for your help.  I hope I can return the favor some day...

Share this post


Link to post

After a quick look it appears (to me) that it is not what I am looking for.  If I am reading the documentation correctly this is more for vector drawings?    

Share this post


Link to post
4 hours ago, wadepm said:

I am looking for a something that will scale bitmaps with a "nice" result.  Something better than stretchdraw, which does exactly what I want but looks horrible.

When making an image larger than his original resolution (enlargement) always gives a bad result. One way to mitigate this is to use bilinear interpolation but don't expect marvelous results.

 

Making an image smaller than his original may be better but will also make it a little bit less nice. Suppressing pixel is the faster but worse solution. You need to merge several pixels into one and apply a weight on the existing pixel depending if it is far or near the new pixel position.

 

Share this post


Link to post
Guest

Of the options, the least worst, for me, would be to have an image of the largest size, and to scale down to an acceptable limit so as not to lose the desired quality at the minimum desired scale.

 

Otherwise, you should buy an RTX 3080 (or another one from the 30xx series) and rent the NVIDia DLSS source code to help.  😂 😂

Share this post


Link to post

The JVCL also comes with some graphics manipulation functions. They look very similar to those in Graphics32 to me, so they might come from the same origin.

Share this post


Link to post
Guest

AphaControls from AlphaSkins does have a very nice API 

TFilterType = (ftBox {fastest}, ftTriangle, ftHermite, ftBell {if Dest is smaller}, ftSpline, ftLanczos3 {Slowest}, ftMitchell);
procedure Stretch(const Src, Dst: TBitmap; const DstWidth, DstHeight: Integer; const Filter: TFilterType);

And for me the algorithm called https://en.wikipedia.org/wiki/Mitchell-Netravali_filters is better as it does not lose contrast of the color as much as https://en.wikipedia.org/wiki/Lanczos_resampling

Also (I didn't this this but tried it) one can use different low level and tweak for the above mentioned filters by utilizing DrawLine and CreateContributors, in other words you can tweak the default filter parameters, to do this you have to duplicate the Stretch function.

Share this post


Link to post
On 12/27/2020 at 2:13 AM, wadepm said:

I am looking for a something that will scale bitmaps with a "nice" result.

I've attached an old library (from 1999) that can do it for you. I believe it's been incorporated in several other libraries over the years. I haven't used it since D5 so you might need to tweak it a bit for newer versions.

Apart from that I would probably use Graphics32.

resample.pas

Share this post


Link to post

Thanks Anders.  I will take a look at it - it uses assembler and pointers(!) - both things I need to work on.

Share this post


Link to post
44 minutes ago, wadepm said:

it uses assembler and pointers(!)

Remove the "{$define OPTIMIZED}" to disable the assembler. That probably won't work with the 64-bit compiler anyway.

The pointers are unavoidable.

 

But like I said, I would use Graphics32 instead. It has a high learning curve but the results are better and the library is maintained.

Something like this:

procedure Test;
var
  Source: TBitmap32;
  Target: TBitmap32;
  Resampler: TKernelResampler;
begin
  Target := TBitmap32.Create;
  try
    Source := TBitmap32.Create;
    try

      Source.LoadFromFile('foobar.bmp');

      // Make new bitmap twice the size. You can also make it smaller.
      Target.SetSize(Source.Width*2, Source.Height*2);

      Resampler := TKernelResampler.Create(Source); // Resampler is now owned by TBitmap32
      Resampler.Kernel := TLanczosKernel.Create; // Kernel is now owned by resampler

      // Stretch using kernel resampler
      Target.Draw(Target.BoundsRect, Source.BoundsRect, Source);

    finally
      Source.Free;
    end;

    // Do something with target bitmap...

  finally
    Target.Free;
  end;
end;

 

Share this post


Link to post

What I want to do is even easier than that.  I do everything with the "full size" bitmap and then assign it to an image on the form and just resize the image:

 

TKernelResampler(Image.Bitmap.Resampler).Kernel := TMitchellKernel.create;  
Image.ScaleMode := smScale;  
Image.Scale := x;

 

Works great.  

Edited by wadepm
missing text

Share this post


Link to post

After working with it for awhile I see that the Graphics32 Image component does not respond to my code the same way the native image component does.  May have to go back to working with bitmaps in the background, rescaling and then assigning to the image.  Can I assign a tbitmap32 to a timage?   

Share this post


Link to post
1 hour ago, wadepm said:

After working with it for awhile I see that the Graphics32 Image component does not respond to my code the same way the native image component does.

What's the problem?

 

1 hour ago, wadepm said:

Can I assign a tbitmap32 to a timage?

No but you can assign a TBitmap32 to a TBitmap so this works:

var Bitmap: TBitmap32;
var Image: TImage;
...
Image.Picture.Bitmap.Assign(Bitmap);

Note though that if your TBitmap32 uses alpha (i.e. transparency) then you'll need to handle that somehow.

Share this post


Link to post

I have some routines that allow me to drag the image around inside of a scrollbox.  When the image is full size it works fine, but when it is scaled its all choppy.

 

I think your assignment will work nicely. 

Share this post


Link to post
6 minutes ago, wadepm said:

I have some routines that allow me to drag the image around inside of a scrollbox.  When the image is full size it works fine, but when it is scaled its all choppy. 

First of all you have to use a scale mode that doesn't control the position of the drawn image.

Then it's pretty simple. Save the start cursor position in MouseDown, calculate the delta in MouseMove and scroll the image and end the drag in MouseUp.

Here's some code:

type
  TBitmapEditorPreview = class(TWinControl)
  private
    FImage: TImgView32;
    FStartPos: TPoint;
    FPanning: boolean;
    procedure ImageMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
    procedure ImageMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer; Layer: TCustomLayer);
    procedure ImageMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  public
    constructor Create(AOwner: TComponent); override;
  end;

constructor TBitmapEditorPreview.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  FImage := TImgView32.Create(Self);
  FImage.Parent := Self;
  FImage.Align := alClient;
  FImage.Height := 200;
  FImage.SizeGrip := sgNone;
  FImage.OverSize := 16;
  FImage.ScaleMode := smScale;
  FImage.Centered := True;
  FImage.Bitmap.Delete;
  FImage.Bitmap.DrawMode := dmBlend;
  FImage.Bitmap.CombineMode := cmMerge;
  FImage.OnMouseDown := ImageMouseDown;
  FImage.OnMouseMove := ImageMouseMove;
  FImage.OnMouseUp := ImageMouseUp;
end;

procedure TBitmapEditorPreview.ImageMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
begin
  if (ssLeft in Shift) then
  begin
    FStartPos := FImage.ControlToBitmap(Point(X, Y));
    FImage.Cursor := crSizeAll;
    FPanning := True;
  end;
end;

procedure TBitmapEditorPreview.ImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
var
  NewPos: TPoint;
  dX, dY: integer;
begin
  if (FPanning) then
  begin
    NewPos := FImage.ControlToBitmap(Point(X, Y));
    dX := FStartPos.X - NewPos.X;
    dY := FStartPos.Y - NewPos.Y;

    if (dX <> 0) or (dY <> 0) then
    begin
      FImage.Scroll(dX, dY);
      FImage.Update;
    end;
    Changed;
  end;
end;

procedure TBitmapEditorPreview.ImageMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
begin
  if (FPanning) then
  begin
    FPanning := False;
    FImage.Cursor := crDefault;
  end;
end;

 

I've attached the unit I copied the above from. It's part of a larger framework so you will not be able to use it as-is.
Here's what it looks like in action (it's the lower pane displaying your avatar):

  image.thumb.png.f81cf6f9f3c2ebf06db639e6ba0b9ea6.png

amBitmapEditorPreview.pas

Share this post


Link to post
13 minutes ago, wadepm said:

What's the difference between TImage32 and TImgView32? 

Yeah, I figured that question would be coming :classic_smile:

To be honest I simply can't remember and the documentation doesn't provide any clues. I'll see if I can figure it out tomorrow unless someone else comes up with the answer.

Share this post


Link to post
Guest

give a look in "Graphics32" by Zhao Yipeng

 

https://raw.githubusercontent.com/zhaoyipeng/graphics32-for-Firemonkey/master/Snapshots/FMXGR32Demo.gif

 

https://github.com/zhaoyipeng/graphics32-for-Firemonkey

Quote
  • Graphics32 is a graphics library for Delphi and Lazarus. Optimized for 32-bit pixel formats, it provides fast operations with pixels and graphic primitives. In most cases Graphics32 considerably outperforms the standard TBitmap/TCanvas methods.
  • The documentation can be found at https://graphics32.github.io/Docs
  • This is the Firemonkey fork of the Graphics32, It only support Firemonkey platform

 

Edited by Guest

Share this post


Link to post
10 hours ago, wadepm said:

OK, it appears TImgView32 is a combination of an image and a scroll box.  Cool. 

Yes that seems to be it; TImgView32 adds scrollbars and methods to scroll and center the image.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×