gif、pngファイルから透明色を取得するには

解決


take  2022-10-25 04:48:28  No: 150613  IP: 192.*.*.*

TListViewとTImageListを組み合わせて、画像リストを表示させています。
画像のリストを選択状態にしたとき、画像の透明色部分がカーソルの色になるようにマスクしているのですが
gif、pngファイルから透明色を取得出来ません。

左上のピクセルを透明色として設定する場合は動作しますが
四隅が画像で中央が透明というのもあるので
透明色が取得出来ればと思うのですがうまくいきません。

どのようにすれば取得できるのでしょうか?

透明色の設定方法を参考にしています。
https://fishers.mydns.jp/pc/delphi/transgif.html

ファイルを読み込んだ後の gif.Images[0].ColorMap.Count の値は 0になっています。

Windows10 コンパイル環境はDelphiXE5です。
透明の画像データは、何種類かのアプリで作成しています。
アプリで読み込むときは透明色として読み込めています。

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ImgList, Vcl.ComCtrls, Vcl.ExtCtrls;

type
  TFormMain = class(TForm)
    ListView1: TListView;
    ImageList1: TImageList;
    procedure FormShow(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  FormMain: TFormMain;

implementation

uses PNGImage,GIFImg;

{$R *.dfm}


procedure TFormMain.FormShow(Sender: TObject);
var
  item : TListItem;
  bmp : TBitmap;
  mask : TBitmap;
  png : TPngImage;
  gif : TGIFImage;
  GCE : TGIFGraphicControlExtension;
  r : TRect;
begin
  ImageList1.Height := 64;
  ImageList1.Width  := 64;

  r := Rect(0,0,64,64);
  bmp := TBitmap.Create;
  mask := TBitmap.Create;
  gif := TGIFImage.Create;
  try
    bmp.SetSize(64,64);
    gif.LoadFromFile('imagetest.gif');
    GCE := TGIFGraphicControlExtension.Create(gif.Images[0]);
    bmp.Canvas.StretchDraw(r,gif);
    mask.Assign(bmp);
    mask.Mask(GCE.TransparentColor);
    ImageList1.Add(bmp,mask);
  finally
    gif.Free;
    mask.Free;
    bmp.Free;
  end;

  r := Rect(0,0,64,64);
  bmp := TBitmap.Create;
  png := TPngImage.Create;
  mask := TBitmap.Create;
  try
    bmp.SetSize(64,64);
    png.LoadFromFile('imagetest.png');
    bmp.Canvas.StretchDraw(r,png);
    mask.Assign(bmp);
    mask.Mask(png.TransparentColor);
    ImageList1.Add(bmp,mask);
  finally
    mask.free;
    png.Free;
    bmp.Free;
  end;

  ListView1.LargeImages := ImageList1;
  ListView1.SmallImages := ImageList1;
  ListView1.ViewStyle := vsList;
  item := ListView1.Items.Add;
  item.Caption := 'gif';
  item.ImageIndex := 0;
  item := ListView1.Items.Add;
  item.Caption := 'img';
  item.ImageIndex := 1;
end;

編集 削除
AAAAA  2022-10-25 10:03:06  No: 150616  IP: 192.*.*.*

var
    PNG: TPNGImage;
    MSK: TBitmap;
begin
    MSK := TBitmap.Create;
    PNG := TPNGImage.Create;
    PNG.LoadFromFile('83232_sample.png');
    MSK.Assign(PNG);

    Image4.Picture.Bitmap.SetSize(200,200);
    Image4.Picture.Bitmap.Canvas.Brush.Color := clRed;
    Image4.Picture.Bitmap.Canvas.FillRect(Rect(0,0,200,200));
    Image4.Picture.Bitmap.Mask(clRed);
    Image4.Picture.Bitmap.Canvas.StretchDraw(Rect(0,0,200,200),PNG);

    PNG.Free;
    MSK.Free;
    Exit;

透明部分は描画されないので TransparentColor でMask はできない

編集 削除
take  2022-10-26 00:15:26  No: 150620  IP: 192.*.*.*

AAAAAさん、ありがとうございます。
pngの処理を下記のようにすることで希望通りの動作になりました。

疑問なのが画像ファイルで clRed 赤 RBG(255,0,0)を使っていても
その部分は透明にはならず描画されます。

理想の動作ですが画像によっては意図しないところが透明になったりするのでしょうか?

  r := Rect(0,0,64,64);
  bmp := TBitmap.Create;
  png := TPngImage.Create;
  mask := TBitmap.Create;
  try
    bmp.SetSize(64,64);
    png.LoadFromFile('imagetest.png');
    bmp.Canvas.Brush.Color := clRed;
    bmp.Canvas.FillRect(bmp.Canvas.ClipRect);
    bmp.Canvas.StretchDraw(r,png);
    mask.Assign(bmp);
    mask.Mask(clRed);
    ImageList1.Add(bmp,mask);
  finally
    mask.free;
    png.Free;
    bmp.Free;
  end;

編集 削除
take  2022-10-26 03:40:17  No: 150624  IP: 192.*.*.*

AAAAAさん、ありがとうございました。

今まで苦労していたのがウソのようです。
StretchDrawを使うと赤の部分が若干残ったので
使用する色は、その時の背景色とすることで解決しました。

編集 削除
Mr.XRAY  2022-10-26 22:14:40  No: 150633  IP: 192.*.*.*

問題に対する解決策ということではありませんが.
( GIF ファイルではなく ) GIF 画像の透過色を取得して,
ビットマップのマスク画像を作成する作成する例です.
LBitmapMask が TImageList.Add の第 2 引数に渡す値です.

取得するのは透明色ではなく,透過色です.
R, G, B, A の値が全て 0 が「透明色」です.
PNG 画像の透明色のピクセルは,透過状態となります.
  
  
procedure TForm1.Button1Click(Sender: TObject);
var
  LBitmap     : TBitmap;
  LBitmapMask : TBitmap;
  LGifImg     : TGIFImage;
begin
  LBitmap     := TBitmap.Create;
  LBitmapMask := TBitmap.Create;
  LGifImg     := TGIFImage.Create;
  try
    LBitmap.SetSize(128, 128);

    LGifImg.LoadFromFile('128X128_GIF_01.gif');

    LGifImg.Transparent := False;
    LBitmap.Canvas.Draw(0, 0, LGifImg);
    LBitmapMask.Assign(LBitmap);
    LBitmapMask.Mask(LGifImg.Bitmap.TransparentColor);

    Image1.Canvas.Draw(0, 0, LBitmap);
    Image2.Canvas.Draw(0, 0, LBitmapMask);
  finally
    FreeAndNil(LBitmap);
    FreeAndNil(LBitmapMask);
    FreeAndNil(LGifImg);
  end;
end;

編集 削除