Imageに読み込んだ画像の透明度を変化させるには?


panache  2013-07-17 07:54:16  No: 44877

Imageコントロールにbitmapファイルをを読み込んだとします(Image1.Picture.LoadFromFile・・・)
Image1に読み込んだ画像ファイルが表示されている状態でボタンを押すたびに透明度が減って半透明のようになっていき、最終的には完全に透明になって見えなくなる

・・・というような処理を行いたいのですが、どのように実現すればよいかわかりません
どなたかご教授お願いします


panache  2013-07-17 08:12:09  No: 44878

書き忘れてしまって申し訳ないのですが、Windows7 pro + Turbo Delphiです


deldel  2013-07-18 18:00:46  No: 44879

透明というのをどのようなことを意図しているのかが分からないのですが、
例えば、
だんだん真っ白になる
だんだん真っ黒になる
だんだん薄くなって、Imageの下にあるコントロールが見えだしてくる
などがあると思いますが、どうなればいいのでしょうか?


deldel  2013-07-18 20:26:38  No: 44880

こんなのかな?
http://www.geocities.jp/asumaroyuumaro/program/winapi/bitmap/alphablend.html


Harry  2013-07-19 00:50:50  No: 44881

私もdeldelさんと同じく「透明とは?」と思ったので、まずはツッコミから。

>ボタンを押すたびに透明度が減って半透明のようになっていき、
これ、「透明度が高くなって」ですよね。

>最終的には完全に透明になって見えなくなる
言葉のアヤもあると思うんですが、「完全に透過して背景色/背景画像だけが見えるようになる」とか、
「背景に溶け込んでいき、ついには背景しか見えなくなる」かと。これ結構重要なので…失礼しました。

こういった処理は一般にアルファブレンディング(アルファブレンド)と呼ばれています。
今回作ったサンプルでは、その名もAlphaBlendという、古くWindows98時代から存在する標準的なAPIを
使いましたが、この他にも様々なライブラリ等でアルファブレンドが利用できます。
例:GDI+、buinGL(TABitmap)、OpenCV、DelphiX(DirectX)など …らしい。

※ちょうどdeldelさんが挙げてくれたAsuyuさんのHP、私も以前にそこを見てAlphaBlendを習いました。

下記サンプルは背景色を指定した上で透明度を上げ下げ出来るようにしたので、色々試してみてください。

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    OpenPictureDialog1: TOpenPictureDialog;
    ColorDialog1: TColorDialog;
    Button3: TButton;
    Button4: TButton;
    Image1: TImage;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private 宣言 }
    FBmp: TBitmap;
    FAlpha: Integer;
    procedure AlphaBlendDraw();
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  Jpeg; // ・GIFImg   の追加でGIFファイルが読める(Delphi2007から標準で搭載)
        // ・PNGImage の追加でPNGファイルが読める(Delphi2009から標準で搭載)
        // ・何も追加せずともTIFFファイルが読める(Delphi2010から)
        // 参考: TImage にイロイロな画像を読み込む - DEKOのアヤシいお部屋。
        // http://ht-deko.minim.ne.jp/tech054.html

procedure TForm1.FormCreate(Sender: TObject);
begin
  FBmp:=TBitmap.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FBmp.Free;
end;

// 参考: AlphaBlend解説 - Delphi de Win32API - Asuyu Homepage
// http://www.geocities.jp/asumaroyuumaro/program/winapi/bitmap/alphablend.html
procedure TForm1.AlphaBlendDraw();
var
  BF:  TBlendFunction;
begin
  if FAlpha<0 then FAlpha:=0;     // 透明度を 0〜255 の範囲におさめる
  if FAlpha>255 then FAlpha:=255; //

  Image1.Canvas.Brush.Color:=ColorDialog1.Color;  // 書き込み先であるImage1を、
  Image1.Canvas.FillRect(Image1.Canvas.ClipRect); // 背景色で塗りつぶしておく

  BF.BlendOp:=             AC_SRC_OVER;
  BF.BlendFlags:=          0;
  BF.SourceConstantAlpha:= FAlpha; //透過度 (255→0 透明度大)
  BF.AlphaFormat:=         0;

  // 背景色が塗ってあるImage1に、透明度を変化させた画像をかぶせる、というイメージ?
  Windows.AlphaBlend(Image1.Canvas.Handle, 0, 0, FBmp.Width, FBmp.Height,
                     FBmp.Canvas.Handle,   0, 0, FBmp.Width, FBmp.Height, BF);

  Self.Caption:=Format('透明度: %d', [FAlpha]);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if OpenPictureDialog1.Execute then begin // 画像ファイルを指定
    Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
    FBmp.Assign(Image1.Picture.Graphic);   // 読み込んだ画像をTBitmapにコピー、保持しておく
    Image1.Picture.Assign(nil);            // Image1.Pictureが保持した画像形式をリセット(BMP以外はCanvasをいじれない)
    FAlpha:=255;                           // 透明度を255にリセット
    AlphaBlendDraw();                      // とりあえず普通に描画
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if ColorDialog1.Execute then AlphaBlendDraw(); // 背景色を指定、それで再描画
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  Dec(FAlpha, 25); // 透明度を上げる
  AlphaBlendDraw();
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  Inc(FAlpha, 25); // 透明度を下げる
  AlphaBlendDraw();
end;


panache  2013-07-20 07:57:56  No: 44882

皆さん回答ありがとうございます
ちなみに自分が言っている透明になっていくとは
まさに「背景に溶け込んでいき、ついには背景しか見えなくなる」です

皆さんの回答を踏まえてコードを作ってみました
Alpha値を入力してボタンを押すとその透明度で画像が表示されるようになりました

しかし、ここで新たな問題が出てきました

Image1とImage2を重ねて配置、
Image1に背景画像(1.bmp)、Image2にキャラクター画像(2.bmp)を読み込み、キャラクター画像の透明度を変化させます

すると確かにImage2のキャラクター画像は透明度が調節されて表示されます
しかし、キャラクター画像の背景まで表示されてしまうのです
最初に読み込むときはTransparentをTrueにしているのでちゃんと背景は透明のまま表示されますが、透明度をいじってからだとTransparentをいくらTrueにし直しても
背景が表示されてしまいます
しかし透明度を255にするとちゃんとキャラクター画像の背景は消えます(完全に不透明だから?)

どうすれば背景を透明のままキャラのみの透明度を変化させることが出来るのでしょうか
度々申し訳ございません
よろしくお願いします

参考までにコードとプログラム、画像を一通りおいていきます

http://firestorage.jp/download/5be96873e8c3a0e007504927e65e3631a66d9dac

--------------------------
procedure TForm1.Button1Click(Sender: TObject);
begin
image1.Picture.LoadFromFile('1.bmp');
image2.Picture.LoadFromFile('2.bmp');
end;

procedure TForm1.Button2Click(Sender: TObject);
var
 BF  :TBlendfunction;
  bmp :TBitmap;
begin
   bmp :=TBitmap.Create;
   try
    bmp.LoadFromFile('2.bmp');

    BF.Blendop             :=AC_SRC_OVER;
    BF.BlendFlags          :=0;
    BF.SourceconstantAlpha :=StrToInt(Edit1.Text);
    BF.Alphaformat         :=0;

    image2.Picture:=nil;
    Windows.AlphaBlend(image2.Canvas.Handle, 0, 0, bmp.Width, bmp.Height,
                       bmp.Canvas.Handle, 0, 0, bmp.Width, bmp.Height,
                       BF);

    image2.Transparent:=true;
    image2.Repaint;
  finally
    bmp.Free;
  end;
end;


monaa  2013-07-22 21:28:13  No: 44883

どちらかと言わずゲームプログラミングですよね。
初心者的にはTImageコントロールを貼りあわせて動かして…
というのが最も思いつきやすく簡単かと思いますが、
TImageはそもそもゲームのテクスチャ的に使われることを前提にしていません。
なので、TImageでこのような目的を達成しようとすると、
王道よりずっと難しかったり面倒だったり遅かったりします。
やはり王道はWindowsコントロールは最後の表示だけで他では使わないで行く方法です。

究極の速さとクオリティを求めたらDirectX一択になりますが、
Turbo Delphiには最新のDirectX用ユニットは用意されていないと思われます。
(XE2には少なくともDirectX9がありますが、いつから実装されているのかは知りません。)
有名どころのDelphiXはD8のDirectDrawメインですので、半透明の実装は簡単ではないと思います。
http://www.micrel.cz/Dx/
DDDDは私がよく知りません。
http://karen.saiin.net/~hayase/dddd/

半透明画像合成だけでよければGDI Plusをおすすめします。
非常に簡単ですし、WindowsXPから使用可能です。
それ以前にも対応したければ、自力合成しか無いと思いますが、
「半透明  合成  delphi」でググれば出てくると思います。
目的にピッタリあったサンプルが見つからず、
なおかつ動けば良いのであればサンプルを作るのも構いませんよ。

Windows7以降ではDirect2Dなんてのもありますが、
Turbo Delphiではユニットがないと思います。


おかぽん  2013-07-23 02:15:17  No: 44884

背景が透けて見えなくていいのかな?
  Image2.Picture.Bitmap.PixelFormat := pf24bit;
  image2.Transparent:=true;


deldel  2013-07-23 20:20:08  No: 44885

ちょっと長いですが、ボタンを押すとだんだんと透明度が上がるサンプルです。
なお、上にあるImage2を移動させることは考えていませんので、
その場合はちょっと工夫がいると思います。

  private
    { Private 宣言 }
    BmpBase, BmpTrans: TBitmap;

function AdjustByte(value: extended): Byte;
begin
  if value < 0 then
    result := 0
  else
  if value > 255 then
    result := 255
  else
    result := Round(value);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  BmpBase := TBitmap.Create;
  BmpBase.Width := Image2.Width;
  BmpBase.Height := Image2.Height;
  BmpBase.PixelFormat := pf24bit;
  BitBlt(BmpBase.Canvas.Handle, 0, 0, Image2.Width, Image2.Height,
         Image1.Picture.Bitmap.Canvas.Handle, Image2.Left - Image1.Left, Image2.Top - Image1.Top, SRCCOPY);

  BmpTrans := TBitmap.Create;
  BmpTrans.Width := Image2.Width;
  BmpTrans.Height := Image2.Height;
  BmpTrans.PixelFormat := pf24bit;
  BitBlt(BmpTrans.Canvas.Handle, 0, 0, Image2.Width, Image2.Height,
         Image2.Picture.Bitmap.Canvas.Handle, 0, 0, SRCCOPY);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  x, y: Integer;
  Pb: PByteArray;
  Pt: PByteArray;
  Pp: PByteArray;
  ibR, ibG, ibB: Byte;
const
  wariai: Single = 0;
begin
  wariai := wariai + 0.01;
  if wariai > 1  then wariai := 0;
  Button1.Caption := Format('%.2f', [wariai]);

  for y := 0 to Pred(Image2.Height) do begin
    Pb := BmpBase.ScanLine[y];
    Pt := BmpTrans.ScanLine[y];
    Pp := Image2.Picture.Bitmap.ScanLine[y];
    for x := 0 to Pred(Image2.Width) do begin
      ibB := AdjustByte(Pb[X*3+0] * wariai + Pt[X*3+0] * (1 - wariai));
      ibG := AdjustByte(Pb[X*3+1] * wariai + Pt[X*3+1] * (1 - wariai));
      ibR := AdjustByte(Pb[X*3+2] * wariai + Pt[X*3+2] * (1 - wariai));

      Pp[X*3+0] := ibB;
      Pp[X*3+1] := ibG;
      Pp[X*3+2] := ibR;
    end;
  end;

  Image2.Refresh;
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  BmpBase.Free;
  BmpTrans.Free;
end;


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加