LuvRAD
LuvRAD

Reputation: 118

png to bmp conversion (maintaining transparency)

I am using delphi XE-5 and I am loading button information from a JSON file, in order to create buttons on a TMS ADVToolBar control. Each button is 50X35 and in png format with transparency.

I am getting each url, using the idHTTP component to retrieve it to a stream and then load it into a png. I then draw it onto a transparent BMP. However, I dont think this is the correct way. Anyway, the bmp is then added to a TImageList where it is assigned to a button using the index. The Image shows up on the button, but with no transparency.

see my code below:

 imgUrl:= //code to get img url from JSON file;

 MS := TMemoryStream.Create;
 png := TPngImage.Create;
 png.Transparent:= True;
 try
  idHTTP1.get(imgUrl,MS);
  Ms.Seek(0,soFromBeginning);
  png.LoadFromStream(MS);
  bmp:= TBitmap.Create;
  bmp.Transparent:= True;
  bmp.Width:= 50;
  bmp.Height:= 50;
  png.Draw(bmp.Canvas, Rect(7, 7, png.Width, png.Height));
  ImageList1.Add(bmp, nil);
  AdvGlowBtn.Images:= ImageList1;
  AdvGlowBtn.Layout:= blGlyphTop;
  AdvGlowBtn.WordWrap:= False;
  AdvGlowBtn.AutoSize:= True;

  AdvGlowBtn.ImageIndex:= ImageList1.Count-1;

  bmp.Free;
 finally
 FreeAndNil(png);
 FreeAndNil(MS);
 end;

Upvotes: 0

Views: 11229

Answers (4)

dwrbudr
dwrbudr

Reputation: 817

Use it like that:

ABitmap.SetSize(png.Width, png.Height);
png.AssignTo(ABitmap);

Upvotes: 1

Sylvio Ruiz Neto
Sylvio Ruiz Neto

Reputation: 192

I have an old project in Delphi 5 and I still using it sometimes. This is my solution using the png object.

procedure ImageList2Alpha(const ImageList: TImageList);
const
  Mask: array[Boolean] of Longint = (0, ILC_MASK);
var
  TempList: TImageList;
begin
  if Assigned(ImageList) then
  begin
    TempList := TImageList.Create(nil);
    try
      TempList.Assign(ImageList);
      with ImageList do
      begin
        Handle := ImageList_Create(Width, Height, ILC_COLOR32 or Mask[Masked], 0, AllocBy);
        if not HandleAllocated then
          raise EInvalidOperation.Create(SInvalidImageList);
      end;
      Imagelist.AddImages(TempList);
    finally
      FreeAndNil(TempList);
    end;
  end;
end;

procedure LoadPngToBmp(var Dest: TBitmap; AFilename: TFilename);
type 
  TRGB32 = packed record 
    B, G, R, A : Byte;
  end; 
  PRGBArray32 = ^TRGBArray32; 
  TRGBArray32 = array[0..0] of TRGB32;
type
  TRG24 = packed record
    rgbtBlue, rgbtGreen, rgbtRed : Byte;
  end;
  PRGBArray24 = ^TPRGBArray24;
  TPRGBArray24 = array[0..0] of TRG24;
type
  TByteArray = Array[Word] of Byte;
  PByteArray = ^TByteArray;
  TPByteArray = array[0..0] of TByteArray;
var
  BMP : TBitmap;
  PNG: TPNGObject;
  x, y: Integer; 
  BmpRow: PRGBArray32;
  PngRow : PRGBArray24;
  AlphaRow: PByteArray;
begin

  Bmp := TBitmap.Create;
  PNG := TPNGObject.Create;

  try

    if AFilename <> '' then
    begin

      PNG.LoadFromFile(AFilename);
      BMP.PixelFormat := pf32bit;
      BMP.Height := PNG.Height;
      BMP.Width := PNG.Width;

      if ( PNG.TransparencyMode = ptmPartial ) then
      begin

        for Y := 0 to BMP.Height-1 do
        begin

          BmpRow := PRGBArray32(BMP.ScanLine[Y]);
          PngRow := PRGBArray24(PNG.ScanLine[Y]);
          AlphaRow := PByteArray(PNG.AlphaScanline[Y]);

          for X := 0 to BMP.Width - 1 do
          begin
            with BmpRow[X] do
            begin
              with PngRow[X] do
              begin
                R := rgbtRed; G := rgbtGreen; B := rgbtBlue;
              end;
              A := Byte(AlphaRow[X]);
            end;
          end;

        end;

      end else
      begin

        for Y := 0 to BMP.Height-1 do
        begin

          BmpRow := PRGBArray32(BMP.ScanLine[Y]);
          PngRow := PRGBArray24(PNG.ScanLine[Y]);

          for X := 0 to BMP.Width - 1 do
          begin
            with BmpRow[X] do
            begin
              with PngRow[X] do
              begin
                R := rgbtRed; G := rgbtGreen; B := rgbtBlue;
              end;
              A := 255;
            end;
          end;

        end;

      end;

      Dest.Assign(BMP);

    end;

  finally
    Bmp.Free;
    PNG.Free;
  end;
end;

Call ImageList2Alpha(YourImageList) on the OnCreate of the Form (FormCreate), and the ImageList will be ready to store your Bitmaps32 keeping the transparency.

Call the LoadPngToBmp procedure to convert a PNG to Bitmap32 and then, store it on your ImageList.

Upvotes: 2

Sir Rufo
Sir Rufo

Reputation: 19096

At first you have to enable the runtime themes (Project Manager) otherwise you will have no transparency of your images.

And this is the code to load the PNG image into your ImageList1

bmp := TBitmap.Create;
try
  // everything done before to bmp has no effect
  bmp.Assign( png );
  // if for some reason the loaded image is smaller
  // set the size to avoid the invalid image size error
  bmp.Width := ImageList1.Width;
  bmp.Height := ImageList1.Height;

  AdvGlowBtn.Images:= ImageList1;
  ...
  // now add the Bitmap to the ImageList
  AdvGlowBtn.ImageIndex := ImageList1.Add( bmp, nil );
finally
  bmp.Free;
end;

Upvotes: 3

The TBitmap class uses Windows own libraries to manipulate Bitmaps. Depending on you Windows version, the underlying Operating System libraries does not support 32 bits BMPs, despite the libraries header files declares a BITMAPQUAD struct.

For newer versions of Windows (Vista and above afaik), the field BITMAPQUAD.reserved is used to store the alpha channel. For older versions, this field must remain zero (0x00).

If you are using a "recent" version of Windows, the only possible explanation I see is that the TBitmap class were not updated to support the alpha channel.

Using the class TPNGImage should not be an issue instead of converting it to BMP before using, unless you have some more specific needs.

Upvotes: 1

Related Questions