0

I'm using Delphi 10.4.2 and I have an application that scales images (BMP, GIF, PNG, ...).

My problem is that if the input image is a transparent BMP the output BMP is not transparent, instead it has a black backgound. This also happens when the input is a transparent PNG and I want to output a BMP. How can I avoid that?

Sample code:

procedure TFrmTestGenImg.Resize;
var
  LInputImgPath, LOutputImgPath: string;
  LImageIn, LImageOut: TWICImage;
  LBitmap: TBitmap;
begin
  LInputImgPath := 'C:\temp\Input.bmp';

  LOutputImgPath := 'C:\temp\Output.bmp';

  LImageIn := TWICImage.Create;
  try
    LImageOut := TWICImage.Create;
    try
      LImageIn.Transparent := True;
      LImageIn.LoadFromFile(Trim(LInputImgPath));

      LBitmap := TBitmap.Create;
      try
        LBitmap.PixelFormat := pf32bit;
        LBitmap.Assign(LImageIn);
        LBitmap.Transparent := True;
        { ... Resizing bitmap ... }

        LImageOut.Assign(LBitmap);
        LImageOut.ImageFormat := wifBmp;
        LImageOut.Transparent := LImageIn.Transparent;
        LImageOut.SaveToFile(LOutputImgPath);
      finally
        LBitmap.Free;
      end;
    finally
      LImageOut.Free;
    end;
  finally
    LImageIn.Free;
  end;
end;
AmigoJack
  • 5,234
  • 1
  • 15
  • 31
  • Does `pf32bit` format remain for LImageOut ? – MBo Sep 22 '21 at 10:40
  • Why using a `TBitmap` at all? Why not sticking to `TWICImage` only? See [Resize TWICImage without losing transparency](https://stackoverflow.com/a/58113571/4299358) – AmigoJack Sep 22 '21 at 11:40
  • @MBo `PixelFormat` does not exist on `TWICImage`, is there anything similar I can check? – Marina Finetti Sep 22 '21 at 12:26
  • @AmigoJack I tried the code linked, I wasn't using any `TBitmap` var this time but I still have black backgound. Using the code linked, if I skip resizing the transparency is kept so I guess it's related to the resizing method – Marina Finetti Sep 22 '21 at 12:55

2 Answers2

0

There is no support for alpha channel transparency in the VCL which it seems like is what you want. I have never used TWCImage and googling for it did not reveal anything so I'm not sure how to advise how you to use that.

An easy way to be able to do what you want is to use the Image32 library free to download on SourceForge - it can read files including PNG with transparency. You can the render the image with transparency and you can use it with both VCL and FMX.

https://sourceforge.net/projects/image32/

(I suggest this not to promote Image32 (although I think it's excellent) but to answer the OP question on how to handle transparency.

Rob Lambden
  • 2,175
  • 6
  • 15
  • Thank you! Why does this happen only with BMP files though? `TWICImage` can handle transparency on all the other image formats.. – Marina Finetti Sep 22 '21 at 13:15
  • Without knowing more about TWICImage I suspect it's because you are not using it with a 32 bit (including alpha channel) mode. You would have to check the settings for that control and that mode. If it's ignoring the alpha channel then any pixel set to $00000000 will be black, not fully transparent. – Rob Lambden Sep 22 '21 at 13:32
0

By default the Windows Imaging Component (WIC) codec for BMP does not write 32-bit BMPs for backwards compatibly for readers that don't support the "V5" header. You can, however, enable it via the EnableV5Header32bppBGRA property.

I don't know how you do that in Delphi, but here's some C++ sample code:

// pWIC is a pointer to IWICImagingFactory
ComPtr<IWICBitmapEncoder> encoder;
HRESULT hr = pWIC->CreateEncoder(containerFormat, nullptr, encoder.GetAddressOf());
if (FAILED(hr))
    return hr;

ComPtr<IWICBitmapFrameEncode> frame;
ComPtr<IPropertyBag2> props;
hr = encoder->CreateNewFrame(frame.GetAddressOf(), props.GetAddressOf());
if (FAILED(hr))
    return hr;

// Opt-in to the WIC2 support for writing 32-bit Windows BMP files with an alpha channel
PROPBAG2 option = {};
option.pstrName = const_cast<wchar_t*>(L"EnableV5Header32bppBGRA");

VARIANT varValue;
varValue.vt = VT_BOOL;
varValue.boolVal = VARIANT_TRUE;
(void)props->Write(1, &option, &varValue);

hr = frame->Initialize(props);
if (FAILED(hr))
    return hr;
...

See Microsoft Docs.

Chuck Walbourn
  • 38,259
  • 2
  • 58
  • 81