我有一个空的位图,我有一个接收TCanvas的绘图程序。绘图例程是一个更大的库的一部分,因此实际上是我无法控制的。
简单地说:如果绘图程序影响它们,我希望像素是不透明的;未触摸的每个像素应保持透明。由于我无法控制绘图程序将使用的颜色,我宁愿不必使用TransparentColor
属性。
有没有办法实现这个目标?我可以使用某种设置来指定画布应该影响它绘制的像素的alpha层吗?
更新:我正在使用Delphi 2010,并按照我尝试过的代码进行操作:
Bmp := TBitmap.Create;
try
Bmp.PixelFormat := pf32bit;
Bmp.Transparent := False;
Bmp.SetSize(Width, Height);
// Ensure all pixels are black with opacity 0 (= fully transparent)
ScanlineWidth := Width * SizeOf(TRGBQuad);
for y := 0 to Bmp.Height - 1 do begin
ZeroMemory(Bmp.ScanLine[y], ScanlineWidth);
end;
// call drawing routines here
DrawContours(Bmp.Canvas, Width, Height);
{$IFDEF DEBUG}
Bmp.SaveToFile(OwnPath + 'Contours-' + IntToStr(GetTickCount) + '.bmp');
{$ENDIF}
Result := Bmp.ReleaseHandle;
finally
Bmp.Free;
end;
答案 0 :(得分:1)
如果我理解正确:
你每次都得到一个完全透明的位图。
<强>建议强>
您可以重写DrawContours
函数,为其绘制的画布的每个区域设置一个alpha值。我会建议这条路线,但我想你曾提到某个地方,你不想重写这些功能。
我能想到的唯一其他选项是(因为你的bmp是全黑的并且都是透明的)在你将它传递给DrawContrours
函数后检查每个像素,如果它不再是黑色,那么改变alpha到255.但这与使用您已经说过不想使用的透明颜色和属性的结果相同。
<强>思想强>:
我不知道一种方式(我怀疑甚至有一种方法)改变位图,这样你传递给它的任何绘图程序都会以不同于例程设计的方式对待它。
最终答案:
重写绘图例程DrawContrours
或使用Transparent color
答案 1 :(得分:1)
如果绘图并不昂贵,可以选择以下方法。绘制三次,一次放到透明位图上,一次放到带有白色背景的1位位图,一次放到带有黑色背景的1位位图,以获得需要对alpha通道进行的更改(因为Tim是正确的 - 位图最初是完全透明的;我们需要找到不透明的像素。
编辑:第一个版本仅使用一个具有白色背景的1位位图。遗憾的是,这并未发现较轻的画作。让我们更进一步,使其成为两个1位位图。虽然有越来越多的位图,但同样不那么优雅。
var
Bmp: TBitmap;
ScanlineWidth: Integer;
x: Integer;
y: Integer;
// this one will track dark paintings
BmpBitMaskWhite:TBitmap;
// this one will track light paintings
BmpBitMaskBlack:TBitmap;
Row32bit, Row1bitWhite, Row1bitBlack:PByteArray;
ByteAccess:Byte;
// Init bitmaps needed for tracking pixels we need to change the alpha channel for
procedure InitAlphaMaskBitmaps;
begin
BmpBitMaskWhite.PixelFormat:=pf1bit; // <= one bit is enough
BmpBitMaskWhite.Transparent:=False;
BmpBitMaskWhite.SetSize(Width, Height);
BmpBitMaskWhite.Canvas.Brush.Color:=clWhite; // <= fill white; changes can then be seen as black pixels
BmpBitMaskWhite.Canvas.FillRect(Rect(0,0,Width, Height));
BmpBitMaskBlack.PixelFormat:=pf1bit; // <= one bit is enough
BmpBitMaskBlack.Transparent:=False;
BmpBitMaskBlack.SetSize(Width, Height);
BmpBitMaskBlack.Canvas.Brush.Color:=clBlack; // <= fill black; changes can then be seen as white pixels
BmpBitMaskBlack.Canvas.FillRect(Rect(0,0,Width, Height));
end;
begin
Bmp := TBitmap.Create;
BmpBitMaskWhite:=TBitmap.Create;
BmpBitMaskBlack:=TBitmap.Create;
try
Bmp.PixelFormat := pf32bit;
Bmp.Transparent := False;
Bmp.SetSize(Width, Height);
InitAlphaMaskBitmaps;
// ensure all pixels are black with opacity 0 (= fully transparent)
ScanlineWidth := Width * SizeOf(TRGBQuad);
for y := 0 to Bmp.Height - 1 do
begin
ZeroMemory(Bmp.ScanLine[y], ScanlineWidth);
end;
// call drawing routines here
DrawContours(Bmp.Canvas, Width, Height);
// call again to get areas where we need to un-transparent the Bmp (this is for dark paintings)
DrawContours(BmpBitMaskWhite.Canvas, Width, Height);
// call again to get areas where we need to un-transparent the Bmp (this is for light paintings)
DrawContours(BmpBitMaskBlack.Canvas, Width, Height);
// modify alpha channel of Bmp by checking changed pixels of BmpBitMaskWhite and BmpBitMaskBlack
// iterate all lines
for y := 0 to Bmp.Height - 1 do
begin
// iterate all pixels
for x := 0 to Bmp.Width - 1 do
begin
Row32bit:=PByteArray(Bmp.ScanLine[y]);
Row1bitWhite:=PByteArray(BmpBitMaskWhite.ScanLine[y]);
Row1bitBlack:=PByteArray(BmpBitMaskBlack.ScanLine[y]);
// Now we need to find the changed bits in BmpBitMaskWhite and BmpBitMaskBlack to modify the corresponding
// alpha-byte in Bmp. Black areas (Bit=0) in BmpBitMaskWhite are the ones that
// have been drawn to, as well as white areas (Bit=1) in BmpBitMaskBlack.
// Not pretty, but works.
ByteAccess:=1 shl (7-x mod 8);
if ((Row1bitWhite[x div 8] and ByteAccess)=0) or
((Row1bitBlack[x div 8] and ByteAccess)<>0) then
begin
Row32bit[x*4+3]:=255;
end;
end;
end;
{$IFDEF DEBUG}
Bmp.SaveToFile('C:\Temp\Contours-' + IntToStr(GetTickCount) + '.bmp');
BmpBitMaskWhite.SaveToFile('C:\Temp\Contours-' + IntToStr(GetTickCount) + '_BitMaskWhite.bmp');
BmpBitMaskBlack.SaveToFile('C:\Temp\Contours-' + IntToStr(GetTickCount) + '_BitMaskBlack.bmp');
{$ENDIF}
// Result := Bmp.ReleaseHandle;
finally
Bmp.Free;
BmpBitMaskWhite.Free;
BmpBitMaskBlack.Free;
end;
顺便说一下:唯一能够正确显示这些位图透明度的程序是PixelFormer。其他(Gimp,IrfanView,Windows Fax thingy,FastStone图像查看器,MS Paint)都将透明区域着色为黑色。
答案 2 :(得分:0)
在摆弄了几个选项后,我得到了以下工作:
AlphaFormat
设置为afIgnored
; Transparent
设为True; (这个很重要)在代码中:
Bmp := TBitmap.Create;
try
Bmp.PixelFormat := pf32bit;
Bmp.AlphaFormat := afIgnored;
Bmp.Transparent := True;
Bmp.SetSize(Width, Height);
// Make bitmap fully transparent
ScanlineWidth := Width * SizeOf(TRGBQuad);
for y := 0 to Bmp.Height - 1 do begin
ZeroMemory(Bmp.ScanLine[y], ScanlineWidth);
end;
DrawContours(Bmp.Canvas);
PNG := TPNGImage.Create;
try
PNG.Assign(Bmp);
PNG.SaveToFile('contours.png'); // => this one has the wanted transparency!
finally
PNG.Free;
end;
finally
Bmp.Free;
end;