Imageコントロールにbitmapファイルをを読み込んだとします(Image1.Picture.LoadFromFile・・・)
Image1に読み込んだ画像ファイルが表示されている状態でボタンを押すたびに透明度が減って半透明のようになっていき、最終的には完全に透明になって見えなくなる
・・・というような処理を行いたいのですが、どのように実現すればよいかわかりません
どなたかご教授お願いします
書き忘れてしまって申し訳ないのですが、Windows7 pro + Turbo Delphiです
透明というのをどのようなことを意図しているのかが分からないのですが、
例えば、
だんだん真っ白になる
だんだん真っ黒になる
だんだん薄くなって、Imageの下にあるコントロールが見えだしてくる
などがあると思いますが、どうなればいいのでしょうか?
こんなのかな?
http://www.geocities.jp/asumaroyuumaro/program/winapi/bitmap/alphablend.html
私も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;
皆さん回答ありがとうございます
ちなみに自分が言っている透明になっていくとは
まさに「背景に溶け込んでいき、ついには背景しか見えなくなる」です
皆さんの回答を踏まえてコードを作ってみました
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;
どちらかと言わずゲームプログラミングですよね。
初心者的には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ではユニットがないと思います。
背景が透けて見えなくていいのかな?
Image2.Picture.Bitmap.PixelFormat := pf24bit;
image2.Transparent:=true;
ちょっと長いですが、ボタンを押すとだんだんと透明度が上がるサンプルです。
なお、上にある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;
ツイート | ![]() |