Нарисуйте PNG изображение на другой PNG
Как объединить два PNG вместе? Я знаю, что ты не можешь использовать PNGObject.Draw
потому что он не копирует альфа-прозрачность (я не уверен, но в любом случае это не работает), поэтому необходима специальная процедура / функция. Я не пришел с пустыми руками, у меня есть эта процедура:
procedure MergePNGLayer(Layer1,Layer2: TPNGObject; Const aLeft,aTop:Integer);
var
x, y: Integer;
SL1, SL2, SLBlended : pRGBLine;
aSL1, aSL2, aSLBlended: PByteArray;
blendCoeff: single;
blendedPNG, Lay2buff: TPNGObject;
begin
blendedPNG:=TPNGObject.Create;
blendedPNG.Assign(Layer1);
Lay2buff:=TPNGObject.Create;
Lay2buff.Assign(Layer2);
SetPNGCanvasSize(Layer2,Layer1.Width,Layer1.Height,aLeft,aTop);
for y := 0 to Layer1.Height-1 do
begin
SL1 := Layer1.Scanline[y];
SL2 := Layer2.Scanline[y];
aSL1 := Layer1.AlphaScanline[y];
aSL2 := Layer2.AlphaScanline[y];
SLBlended := blendedPNG.Scanline[y];
aSLBlended := blendedPNG.AlphaScanline[y];
for x := 0 to Layer1.Width-1 do
begin
blendCoeff:=aSL1[x] * 100/255/100;
aSLBlended[x] := round(aSL2[x] + (aSL1[x]-aSL2[x]) * blendCoeff);
SLBlended[x].rgbtRed := round(SL2[x].rgbtRed + (SL1[x].rgbtRed-SL2[x].rgbtRed) * blendCoeff);
SLBlended[x].rgbtGreen := round(SL2[x].rgbtGreen + (SL1[x].rgbtGreen-SL2[x].rgbtGreen) * blendCoeff);
SLBlended[x].rgbtBlue := round(SL2[x].rgbtBlue + (SL1[x].rgbtBlue-SL2[x].rgbtBlue) * blendCoeff);
end;
end;
Layer1.Assign(blendedPNG);
Layer2.Assign(Lay2buff);
blendedPNG.Free;
Lay2buff.Free;
end;
Но, к сожалению, это не работает так, как должно, это делает работу, но не правильно. Когда он объединяет пустое изображение с загруженным изображением, он работает нормально, но когда оба изображения не пусты, это делает их прозрачными с потерями.
procedure TForm1.FormClick(Sender: TObject);
var
PNG1, PNG2, PNG3, Dest: TPNGObject;
begin
PNG1 := TPNGObject.Create;
PNG2 := TPNGObject.Create;
PNG3 := TPNGObject.Create;
PNG1.LoadFromFile('Aero\TopLeft.png');//Width 10
PNG2.LoadFromFile('Aero\Top.png');//Width 200
PNG3.LoadFromFile('Aero\TopRight.png');//Width 10
Dest := TPNGObject.CreateBlank(COLOR_RGBALPHA, 16, 220, 10);
MergePNGLayer(Dest, PNG1, 0, 0);
MergePNGLayer(Dest, PNG2, 10, 0);
MergePNGLayer(Dest, PNG3, 210, 0);
Dest.SaveToFile('C:\OUT.PNG');
end;
Требуемый результат:
Фактический результат:
Я не уверен, видите ли вы различия между этими изображениями, но вы должны открыть их в программном обеспечении редактора PNG, и вы увидите разницу. Поэтому мне нужна другая процедура для объединения PNG. Я использую новейшую версию PNGImage
Кстати.
Спасибо и хорошего дня!
1 ответ
Это, кажется, работает просто отлично:
procedure DrawPngWithAlpha(Src, Dest: TPNGObject; const R: TRect);
var
X, Y: Integer;
Alpha: PByte;
begin
Src.Draw(Dest.Canvas, R);
// I have no idea why standard implementation of TPNGObject.Draw doesn't apply transparency.
for Y := R.Top to R.Bottom - 1 do
for X := R.Left to R.Right - 1 do
begin
Alpha := @Dest.AlphaScanline[Y]^[X];
Alpha^ := Min(255, Alpha^ + Src.AlphaScanline[Y - R.Top]^[X - R.Left]);
end;
end;