Следующим подходом может быть вариант, если рисование не дорого.Нарисуйте три раза, один раз на прозрачном растровом изображении, один раз на 1-битное растровое изображение с белым фоном и один раз на 1-битное растровое изображение с черным фоном, чтобы получить изменения, которые необходимо внести в альфа-канал (поскольку Тим прав -изначально растровое изображение полностью прозрачно, нам нужно найти непрозрачные пиксели).
Редактировать: В первой версии использовался только один 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 Fessy, FastStone Image Viewer, MS Paint) все окрашивали прозрачную область в черный цвет.