如果绘图不昂贵,则可以选择以下方法。绘制三遍,一次在透明位图上,一次在白色背景的 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 Image Viewer、MS Paint)都将透明区域涂成黑色。