use*_*313 4 delphi graphics32 delphi-xe
我在将ImgView32图层保存为TRANSPARENT PNG时遇到问题.我使用这个问题的代码来进行保存.但是,图像以白色背景保存.
这是我如何初始化我的ImgView32,在其上创建一个图层,然后在其上绘制一条线:
procedure TputLine.FormCreate(Sender: TObject);
var
P: TPoint;
W, H: Single;
imwidth: integer;
imheight: integer;
begin
imwidth := Iv1.Width;
imheight := Iv1.Height;
with iv1 do
begin
Selection := nil;
Layers.Clear;
Scale := 1;
Scaled := True;
Bitmap.DrawMode := dmTransparent;
Bitmap.SetSize(imwidth, imheight);
Bitmap.Canvas.Pen.Width := 4;
end;
BL := TBitmapLayer.Create(iv1.Layers);
try
BL.Bitmap.DrawMode := dmTransparent;
BL.Bitmap.SetSize(imwidth,imheight);
BL.Bitmap.Canvas.Pen.Width := penwidth;
BL.Bitmap.Canvas.Pen.Color := pencolor;
BL.Location := GR32.FloatRect(0, 0, imwidth, imheight);
BL.Scaled := False;
except
BL.Free;
raise;
end;
end;
Run Code Online (Sandbox Code Playgroud)
所以iv1是我的ImgView32的名字.然后我用这段代码画一条线:
var
bm32:TBitmapLayer;
...
begin
bm32:=(iv1.Layers[0] as TBitmapLayer).Bitmap;
bm32.canvas.pen.color:=clwhite;
bm32.canvas.brush.color:=clwhite;
bm32.canvas.rectangle(0,0,bm32.width-1, bm32.height-1);
bm32.canvas.Pen.Color:=WinColor(ColorPickerGTK1.SelectedColor);
bm32.canvas.brush.color:=clWhite;
bm32.Canvas.Pen.Width:=3;
bm32.Canvas.MoveTo(0,bm32.Height);
bm32.Canvas.LineTo(0+150,bm32.Height-250);
end;
Run Code Online (Sandbox Code Playgroud)
如果我在绘制矩形时使用clWhite32作为上面的代码,那么在保存PNG时,imgView的背景会变黑......所以我真的不明白这个问题.
我像这样保存:
procedure TputLine.Button2Click(Sender: TObject);
var
myLay:TBitmapLayer;
begin
mylay := iv1.Layers.Items[0] as TBitmapLayer;
SavePNGTransparentX(mylay.Bitmap);
end;
Run Code Online (Sandbox Code Playgroud)
和实际的保存代码(来自上述链接)
procedure TPutLine.SavePNGTransparentX(bm32:TBitmap32);
var
Y: Integer;
X: Integer;
Png: TPortableNetworkGraphic32;
function IsWhite(Color32: TColor32): Boolean;
begin
Result:= (TColor32Entry(Color32).B = 255) and
(TColor32Entry(Color32).G = 255) and
(TColor32Entry(Color32).R = 255);
end;
begin
bm32.ResetAlpha;
for Y := 0 to bm32.Height-1 do
for X := 0 to bm32.Width-1 do
begin
if IsWhite(bm32.Pixel[X, Y]) then
bm32.Pixel[X,Y]:=Color32(255,255,255,0);
end;
Png:= TPortableNetworkGraphic32.Create;
Png.Assign(bm32);
Png.SaveToFile('C:\ThisShouldBeTransparent.png');
Png.Free;
end;
Run Code Online (Sandbox Code Playgroud)
我不明白为什么它不将图层保存为透明PNG.我该如何解决?欢迎任何想法.
您可以使用上面的代码复制我的问题.它使用GR32_PNG和GR32_PortableNetworkGraphic.您只需要在表单中添加TImgView32控件并添加上面列出的代码.
问题的原因似乎是双重的.
Png.Assign(bm32);在单元中调用时GR32_PNG,它会尝试找出存储图像的最小格式.如果图像的颜色少于256种,则会创建一个调色板格式,并根据它找到的颜色数量,比特深度可以变为1,2,4或8.据我所知,只有具有TrueColor和Alpha的图像可以保存为可变透明png图像.本TPortableNetworkGraphic32类有两个属性,BitDepth并ColorType至极控制的格式png的图像,这将是有益的,如果他们设定!试图在代码中将它们设置为:
Png.BitDepth := 8;
Png.ColorType := ctTrueColorAlpha;
Run Code Online (Sandbox Code Playgroud)
导致例外
消息'位深度的EPngError可能尚未直接指定!
消息'颜色类型'的EPngError可能尚未直接指定!
从措辞上我们可以假设将来会有一些进一步的发展.
治愈
要绕过上述图像分析,您可以更改第459行GR32_PNG.pas.
procedure TPortableNetworkGraphic32.AssignPropertiesFromBitmap32()
var
...
begin
...
IsPalette := True; // <--- change to False
...
Run Code Online (Sandbox Code Playgroud)
如果少于256种颜色,那将处理位深度分析并防止调色板创建.在此hack之后,您可以使用该SavePNGTransparentX()过程将文件保存TBitmap32到.png文件并保持透明度.
然后,关于SavePNGTransparentX()程序,您可能会对此感兴趣.如您所见,它需要绘图表面的背景为白色,因为它专门Alpha为所有白色像素将通道设置为零.TBitmapLayer然而,A 被初始化为所有像素(RGBA)为全零,因此每个像素的颜色分量构成黑色(由于alpha通道为零,因此不可见).因此,您需要使用白色填充绘图图层,这会使其变得不透明,这会再次覆盖所有较低的图层(在绘图图层下方).
要对此进行更正,您可以
IsWhite功能更改为IsBlack功能代码将成为
procedure TForm8.SavePNGTransparentX(bm32:TBitmap32);
var
Y: Integer;
X: Integer;
Png: TPortableNetworkGraphic32;
function IsBlack(Color32: TColor32): Boolean;
begin
Result:= (TColor32Entry(Color32).B = 0) and
(TColor32Entry(Color32).G = 0) and
(TColor32Entry(Color32).R = 0);
end;
function IsWhite(Color32: TColor32): Boolean;
begin
Result:= (TColor32Entry(Color32).B = 255) and
(TColor32Entry(Color32).G = 255) and
(TColor32Entry(Color32).R = 255);
end;
begin
bm32.ResetAlpha;
for Y := 0 to bm32.Height-1 do
for X := 0 to bm32.Width-1 do
begin
// if IsWhite(bm32.Pixel[X, Y]) then
// bm32.Pixel[X,Y]:=Color32(255,255,255, 0);
if IsBlack(bm32.Pixel[X, Y]) then
bm32.Pixel[X,Y]:=Color32( 0, 0, 0, 0);
end;
Png:= TPortableNetworkGraphic32.Create;
Png.Assign(bm32);
Png.SaveToFile('C:\tmp\imgs\ThisShouldBeTransparent3.png');
Png.Free;
end;
Run Code Online (Sandbox Code Playgroud)
通过此更改,您可以看到绘图图层下方的图层,并且绘图图层的结果文件将使所有未绘制的像素都透明.然而,对于上述过程,一般存在一个问题,即部分透明的像素会失去其透明度,但这仍然是未来的练习.
这是一些图像,首先是在底层加载位图的ImageView:

然后,我在BL图层上绘制一个蓝色十字(参考你的代码)基本上使用你的代码,Button1Click()但没有白色矩形.

然后我将BL图层保存到.png文件并使用Windows资源管理器"预览"查看它:
