TPNGObject - 创建一个新的空白图像并在其上绘制半透明图像

问题描述 投票:5回答:4

我正在构建一个具有“虚拟窗口”的应用程序。输出是TImage对象。

1)应用程序将窗口皮肤文件加载到TPNGObject

2)然后应用程序必须创建一个新的空白TPNGObject,并将皮肤文件的大小调整为所需的大小,并在该空白图像上绘制它们。应该看起来像这样:

3)TImage的最终输出:

问题是我确实知道如何创建一个完全空白的屏幕外图像。当然,我每次都可以简单地将皮肤文件渲染到TImage,但是重新调整皮肤文件的大小并创建一次窗口会更容易也更好。 我正在使用Gustavo Daud的PNG Library,版本1.564(2006年7月31日)。

delphi png delphi-7 transparent
4个回答
5
投票

下面使用了Martijn Sally的'pngfunctions.pas'的CreatePNG程序,从扩展库(pngcomponents)到pngimage。

var
  Bmp, Mask: TBitmap;
  PNG: TPNGObject;
begin
  Bmp := TBitmap.Create;
  Bmp.PixelFormat := pf24bit;
  Bmp.SetSize(64, 64);

  Bmp.Canvas.Brush.Color := clBtnFace;
  Bmp.Canvas.Font.Color := clRed;
  Bmp.Canvas.Font.Size := 24;
  Bmp.Canvas.TextOut(4, 10, 'text');

  Mask := TBitmap.Create;
  Mask.PixelFormat := pf24bit;
  Mask.Canvas.Brush.Color := clBlack;
  Mask.SetSize(64, 64);
  Mask.Canvas.Font.Color := clWhite;
  Mask.Canvas.Font.Size := 24;
  Mask.Canvas.TextOut(4, 10, 'text');

  PNG := TPNGObject.Create;
  CreatePNG(Bmp, Mask, PNG, False);
  PNG.Draw(Canvas, Rect(10, 10, 74, 74));

  // finally, free etc...

这是输出(黑色,白色方块是TShapes):


2
投票

我的另一个答案是我建议的另一种选择。但是你的问题仍然存在问题:PNG库必须有一个错误,它阻止任何画布绘图可见(在使用带有COLOR_RGBALPHA作为颜色​​类型的CreateBlank构造函数之后)或者我们都缺少某些东西。

看起来我能看到的唯一解决方法是(正如您在编辑中提到的那样)使用位图来代替您的绘图。使用此位图的透明属性(Transparent: BoolTransparentColor: TColor)设置图像的透明区域,然后当需要透明PNG时,只需将该位图复制到新的PNG对象...

BMP.Width:= 100;
BMP.Height:= 100;
BMP.Transparent:= True;
BMP.TransparentColor:= clWhite;
BMP.Canvas.Brush.Style:= bsSolid;
BMP.Canvas.Brush.Color:= clWhite;
BMP.Canvas.FillRect(BMP.Canvas.ClipRect);
BMP.Canvas.Brush.Color:= clBlue;
BMP.Canvas.Ellipse(10, 10, 90, 90);
PNG.Assign(BMP);

并且图像的白色区域应该是透明的。还有其他方法可以完成透明区域,但这是另一个主题。

图片:

这是你想要做的吗?


2
投票

我向人们道歉,我搞砸了他们的头脑。

事实证明CreateBlank按照需要工作。问题是我在PNG画布上画了PNG(PNG.Canvas.Draw)。 Canvas并不真正支持透明度。要在另一个PNG上绘制半透明PNG,您需要一个将这两个层合并在一起的过程/函数。通过一些谷歌搜索,我最终得到了这个程序:

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;

用法:

var
  PNG1, PNG2: TPNGObject;
begin
  PNG1 := TPNGObject.CreateBlank(COLOR_RGBALPHA, 16, 500, 500);
  PNG2 := TPNGObject.Create;
  PNG2.LoadFromFile('...*.png');
  MergePNGLayer(PNG1, PNG2, 0, 0);
  // PNG1 is the output

再一次,我真的很抱歉想要帮助的用户,但由于不理解我而无法做到。


0
投票

我没有回答这个问题,但我想出了如何使用任何PNG编辑器获得相同的结果。我创建了空白的1000x1000 PNG图像并将其保存在我的应用程序目录中。然后我在我的程序中打开这个图像,并将图像调整到所需的大小(当然更小),这就是诀窍。

© www.soinside.com 2019 - 2024. All rights reserved.