How to resize PNG image with Alpha channels using GDI+?
Asked Answered
O

2

5

After looking for a way to resize TPngObject and maintain the transparency + alpha channels to no avail, I'm trying to use GDI+

Here is my code, and it seems to work fine. it will down/up scale a PNG. Tested on XP so far:

uses GDIPAPI, GDIPOBJ, GDIPUTIL; 

procedure TForm1.Button1Click(Sender: TObject);
var
  encoderClsid: TGUID;
  stat: TStatus;
  img, img_out: TGPImage;
begin
  img := TGPImage.Create('in.png'); // 200 x 200  
  img_out := img.GetThumbnailImage(100, 100, nil, nil);
  GetEncoderClsid('image/png', encoderClsid);
  img_out.Save('out.png', encoderClsid);
  img_out.free;
  img.Free;
end;

My question: is using GetThumbnailImage the correct way of doing this? I did not find any other method.

Overburden answered 7/7, 2015 at 14:34 Comment(0)
A
7

I don't think that GetThumbnailImage method is a good way to go because I doubt that you will get a high quality resampled image. In this article you can find how to rescale the image. They're using the DrawImage method for that, so I would do the same. Just before that I would set also the high quality graphics modes to get high quality output. Here is an example:

procedure TForm1.Button1Click(Sender: TObject);
var
  Input: TGPImage;
  Output: TGPBitmap;
  Encoder: TGUID;
  Graphics: TGPGraphics;
begin
  Input := TGPImage.Create('C:\InputImage.png');
  try
    // create the output bitmap in desired size
    Output := TGPBitmap.Create(100, 100, PixelFormat32bppARGB);
    try
      // create graphics object for output image
      Graphics := TGPGraphics.Create(Output);
      try
        // set the composition mode to copy
        Graphics.SetCompositingMode(CompositingModeSourceCopy);
        // set high quality rendering modes
        Graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);
        Graphics.SetPixelOffsetMode(PixelOffsetModeHighQuality);
        Graphics.SetSmoothingMode(SmoothingModeHighQuality);
        // draw the input image on the output in modified size
        Graphics.DrawImage(Input, 0, 0, Output.GetWidth, Output.GetHeight);
      finally
        Graphics.Free;
      end;
      // get encoder and encode the output image
      if GetEncoderClsid('image/png', Encoder) <> -1 then
        Output.Save('C:\OutputImage.png', Encoder)
      else
        raise Exception.Create('Failed to get encoder.');
    finally
      Output.Free;
    end;
  finally
    Input.Free;
  end;
end;
Auricle answered 7/7, 2015 at 15:51 Comment(7)
I fail to understand why/how the transparency/alpha maintains here, but it works :) thank you!Overburden
You're welcome! The alpha channel is preserved because of the output bitmap format (which I've had to explicitly specify even if it's default due to ambiguous overload). If you'd use e.g. PixelFormat32bppRGB, you would lose the alpha channel. And rendering itself considers transparency (even in pure GDI).Auricle
Thanks. BTW, GetThumbnailImage seems to re-sample the image quite nicely too.Overburden
Yep, it looks fine as well. Though I have noticed the difference.Auricle
A small question with your permission: How can I make it work faster but make the output considerably good? Do you think I could omit the set high quality rendering modes section and still get a fine looking output (I would use a boolean switch IsHighQuality)? How can you know which is the default?Overburden
Yes, you can omit them. But then you might get the same result as for that thumbnail (that's just a guess, but I believe they are doing internally something similar as the above code just without increasing the quality). The settings used here are for the highest quality output which costs some extra computing time. You can try to modify them to use even lower than default quality, but in the end you may get ugly results. Default modes are InterpolationModeDefault = ?, PixelOffsetModeDefault = PixelOffsetModeNone and SmoothingModeDefault = no smoothing (source MSDN).Auricle
You're welcome! P.S. you can find documentation for every used method if you search the web for e.g. SetInterpolationMode, then you get to MSDN site and from there you can go to the enumeration InterpolationMode description.Auricle
S
2

I don't think using of GetThumbnailImage method is the correct approach. Why?

The main use of GetThumbnailImage method is getting a thumbnail that you can use as a preview of some higher resolution image.

Therefore I assume the algorithm that is used behind is developed to be as fast as possible but it probably doesn't care about end result quality much. So using of this method can lead to resized images with pretty bad quality.


Now if you are realy interested in image manipulation using Delphi then you should definitely check the Graphics32 library (http://graphics32.org/wiki/).

It supports all Delphi versions from Delphi 7 and up. It provides many advanced image manipulation algorithms. And best of all it does support hardware acceleration meaning that it can actually make use of your GPU processing power to make those image manipulations.

Supertax answered 7/7, 2015 at 15:2 Comment(1)
Can you point to the GPU related code in Graphics32? I skimmed through the sources and only found references to CPU hardware acceleration (MMX/SSE2/etc).Ordinary

© 2022 - 2024 — McMap. All rights reserved.