我想在不透明的画布上绘制位图,其中位图具有透明色.
我可以创建一个透明色的位图,并将其绘制成一个
canvas我可以创建一个位图并将其绘制到具有不透明度的画布上
但我无法结合它.如果我合并它,则忽略不透明度.
这是我写的代码:
procedure TForm1.FormPaint(Sender: TObject); var b1,b2:TBitmap; begin // Example how it opacity works: b1 := TBitmap.Create; b1.SetSize(20,20); b1.Canvas.Brush.Color := clBlue; b1.Canvas.Rectangle(0,0,20,20); Canvas.Draw(10,10,b1,$ff); // Works Canvas.Draw(40,10,b1,$66); // Works // I need it in combination with TransparentColor: b2 := TBitmap.Create; // next 3 lines are different from above b2.Transparent := true; b2.TransparentColor := clFuchsia; b2.Canvas.Brush.Color := clFuchsia; b2.SetSize(20,20); b2.Canvas.Brush.Color := clBlue; b2.Canvas.Ellipse(0,0,20,20); Canvas.Draw(10,40,b2,$ff); // Works (full opacity) Canvas.Draw(40,40,b2,$66); // Ignores the $66 Opacity b1.Free; b2.Free; end;
生产:
我怎么能用透明背景绘制(一个蓝色的圆圈),只有40%的不透明度?
如果可能的话,我会优先选择没有直接winapi的解决方案(如bitblt,...).
我尝试了几个hacks,比如将alpha通道转换为TColor值,但它不起作用.
在这里我尝试了什么:
procedure TForm1.FormPaint(Sender: TObject); var b:TBitmap; begin b := TBitmap.Create; b.PixelFormat := pf32bit; b.AlphaFormat := afDefined; b.Canvas.Brush.Color := 0 and ($ff shl 32); // Background Transperency b.SetSize(20,20); b.Canvas.Brush.Color := clBlue + (($ff-$66) shl 32); b.Canvas.Ellipse(0,0,20,20); Canvas.Draw(10,10,b); b.Free; end;
生产:
提前致谢!
编辑:我的系统:windows 7 64bit上的delphi xe 5(但使用32位编译器)
可以procedure TBitmap.DrawTransparent
在单位图形中看到发生的情况.
如果图像的属性设置为透明,如示例中的b2所示,将Graphics.TransparentStretchBlt
使用StretchBlt
不同的蒙版绘制位图
以绘制图像,并且无法使用Alpha通道.不透明的位图,你的b1,将使用AlphaBlend绘制
.
要达到目标,您可以使用另一个位图b2,将Alphachannel设置为0,在b3上使用不透明度$ 66绘制b2,将每个像素的Alphachannel设置为255,这是b2中的clFuchsia,然后使用所需的不透明度绘制此位图
type pRGBQuadArray = ^TRGBQuadArray; TRGBQuadArray = ARRAY [0 .. 0] OF TRGBQuad; TRefChanel=(rcBlue,rcRed,rcGreen); procedure SetBitmapAlpha(ABitmap: TBitMap; Alpha: Byte); var pscanLine32: pRGBQuadArray; nScanLineCount, nPixelCount : Integer; begin with ABitmap do begin PixelFormat := pf32Bit; HandleType := bmDIB; ignorepalette := true; alphaformat := afDefined; for nScanLineCount := 0 to Height - 1 do begin pscanLine32 := Scanline[nScanLineCount]; for nPixelCount := 0 to Width - 1 do with pscanLine32[nPixelCount] do begin rgbReserved := Alpha; end; end; end; end; procedure AdaptBitmapAlpha(ABitmap,TranspBitmap:TBitmap); var pscanLine32,pscanLine32_2: pRGBQuadArray; nScanLineCount, nPixelCount : Integer; begin with ABitmap do begin PixelFormat := pf32Bit; HandleType := bmDIB; ignorepalette := true; alphaformat := afDefined; for nScanLineCount := 0 to Height - 1 do begin pscanLine32 := Scanline[nScanLineCount]; pscanLine32_2 := TranspBitmap.Scanline[nScanLineCount]; for nPixelCount := 0 to Width - 1 do with pscanLine32[nPixelCount] do begin // all picels with are not clFuchsia in the transparent bitmap if NOT ((pscanLine32_2[nPixelCount].rgbBlue=255) AND (pscanLine32_2[nPixelCount].rgbRed=255) AND (pscanLine32_2[nPixelCount].rgbGreen=0) ) then begin rgbReserved := 255; end else begin rgbBlue := 0; rgbRed := 0; rgbGreen := 0; end; end; end; end; end; procedure TAForm.FormPaint(Sender: TObject); var b1,b2,b3:TBitmap; BF: TBlendFunction; begin // Example how it opacity works: b1 := TBitmap.Create; b1.SetSize(20,20); b1.Canvas.Brush.Color := clBlue; b1.Canvas.Rectangle(0,0,20,20); Canvas.Draw(10,10,b1,$ff); // Works Canvas.Draw(40,10,b1,$66); // Works // I need it in combination with TransparentColor: b3 := TBitmap.Create; b3.PixelFormat := pf32Bit; b2 := TBitmap.Create; b2.PixelFormat := pf32Bit; // next 3 lines are different from above b2.Transparent := true; b2.TransparentColor := clFuchsia; b2.Canvas.Brush.Color := clFuchsia; b2.SetSize(20,20); b2.Canvas.Brush.Color := clBlue; b2.Canvas.Ellipse(0,0,20,20); Canvas.Draw(10,40,b2,$ff); // Works (full opacity) b3.SetSize(20,20); SetBitmapAlpha(b3,0); b3.Canvas.Draw(0,0,b2,$66); AdaptBitmapAlpha(b3,b2); Canvas.Draw(40,40,b3,$66); b1.Free; b2.Free; b3.Free; end;