English 中文(简体)
Delphi,GR32 + PngObject:皈依比图32的t工作
原标题:Delphi, GR32 + PngObject: converting to Bitmap32 doesn t work as expected

I m using GR32 for drawing multiple semi-transparent PNG images. So far I ve been using the following method:

  png:= TPNGObject.Create;
  png.LoadFromFile(...);
  PaintBox321.Buffer.Canvas.Draw(120, 20, png);

however I wanted to switch to the method proposed on GR32 website (http://graphics32.org/wiki/FAQ/ImageFormatRelated) :

  tmp:= TBitmap32.Create;
  LoadPNGintoBitmap32(tmp, ..., foo);
  tmp.DrawMode:= dmBlend;
  PaintBox321.Buffer.Draw(Rect(20, 20, 20+ tmp.Width, 20+tmp.Height),
   tmp.ClipRect, tmp);

虽然第一种方法非常精细,但第二种方法——应当得出同样的结果——造成甲型频道的非常奇怪的问题,见图像(这还显示与油漆中的同一形象的比较)。 NET——在编辑的层次上都开设了背景和icon。 图像显示,Bitmap32的装载量或精选。 任何ti?

“Problem

页: 1

我发现,这并不是要提一下,而是把PNG装到BMP32。 从BMP32返回PNG,会产生不正确、“犹豫”的PNG形象。

最佳回答

The reason seems to be that the transparency is applied two times to the image when loaded with LoadPNGintoBitmap32, giving it a more transparent and greyish look (more on this later).

First the transparency:

这是原来的<代码>LoadPNGintoBitmap32的代码,关键部分有以下评论意见:

 PNGObject := TPngObject.Create;
 PNGObject.LoadFromStream(srcStream);

 destBitmap.Assign(PNGObject);  // <--- paint to destBitmap s canvas with transparency (!)
 destBitmap.ResetAlpha;         

 case PNGObject.TransparencyMode of  // <--- the following code sets the transparency again for the TBitmap32
 { ... }

<代码>destBitmap.Assign Internal do与你以往的做法相同:它让PNG形象反映自己。 这项行动尊重全国过渡政府的甲型频道。 但没有必要这样做,因为甲型频道被分配到<代码>。 TBitmap32s pixels in a second step!

如今,《刑法》的修改如下,关键部分再次以评论标示:

 PNGObject := TPngObject.Create;
 PNGObject.LoadFromStream(srcStream);

 PNGObject.RemoveTransparency;  // <--- paint PNG without any transparency...
 destBitmap.Assign(PNGObject);  // <--- ...here
 destBitmap.ResetAlpha;

 srcStream.Position:=0;
 PNGObject.LoadFromStream(srcStream); // <--- read the image again to get the alpha channel back

 case PNGObject.TransparencyMode of   // <--- this is ok now, the alpha channel now only exists in the TBitmap32
 { ... }

上述解决办法效率不高,因为其形象是两倍。 但这表明,你的第二种做法产生了更透明的形象。

灰色: 原始代码中还有一个问题:destBitmap.Assign首先填满了cl White32的背景,然后以透明的方式描述了图像。 之后,“LoadPNGintoBitmap32出现并增加了另一层透明度。

问题回答

问题可能是,全国过渡政府错误地转换为TBitmap32,从而失去了过境的透明度信息。 巴布亚新几内亚的图像是常见的情况。 否则,你就不必使用„Bit地图。 Draw Col Col 如果从PNG获得的跨国信息将正确转移到TBitmpa32, 绘画: d) Blend本来会奏效,无需设置外部Color。

What matters most is how did you load a PNG into the TBitmap32. The TPngImage from Vcl.Imaging.pngimage unit (implemented in Delphi XE2 and later) can draw transparently on bitmaps, preserving what was on that bitmaps, combining colors using the PNG alpha layer, etc, but it doesn’t allow to easily convert various formats of PNG transparency (including paletted) into the alpha component of each pixel of TBitmap32. Once TPngImage have drawn an image, you get the combined RGB for each pixel, but the alpha component is not transferred to the target bitmap.

现有的帮助者例行做法试图以透明方式将一个PNG装入一个TBitmap32,但也有缺点:

(1) “LoadPNGintoBitmap32” from http://graphics32.org/wiki/FAQ/ImageFormatRelated - it applies the transparency twice, so the images with alpha values other than 0 or 255 will look differently than in other software (most noticeable on translucent images with glass effects). This code will first apply alpha to RGB and then sets alpha as a separate layer, so when you paint, alpha will be applied again. You can find more information on this issue here: Delphi, GR32 + PngObject: converting to Bitmap32 doesn t work as expected . Besides that, it doesn t convert correctly transparency from paletted images into the alpha layer of TBitmap32. They manually set alpha transparency for the pixels of a certain color of the output bitmap (rendered to RGB) rather doing that before rendering to RGB, so the actual transparency is lost as on your sample image when all white pixels are transparent.

(2) “LoadBitmap32FromPNG” from gr32ex library: https://code.google.com/archive/p/gr32ex/ - a slightly different implementation of the same algorithm as (1), and has the same issues as (1).

So, the solutions are:

  1. Do not use TBitmap32; use Vcl.Imaging.pngimage.TPngImage do draw directly on target bitmap (screen, etc.) – this is the most compatible way that deals correctly with various PNG formats.
  2. Use a helper routing to transfer transparency information from Vcl.Imaging.pngimage.TPngImage to TBitmap32.
  3. Use the GR32 PNG library that can natively load a PNG into TBitmap32 https://sourceforge.net/projects/gr32pnglibrary/ Since you now have all the information on this issue, you may get the right solution for you.

How to load the alpha layer in one pass

Heinrich Ulbricht made a nice suggestion to remove the transparency layer before paining and then to read the image again. To avoid loading the image twice, you can save the alpha layer before calling PNGObject.RemoveTransparency. Here is the code that correctly applies the alpha layer and loads the image only once. Unfortunately, it does not work with paletted images. If you know how to correctly fill the alpha layer of TBitmap32 from any paletted image, without the effects described at Transparent Png to TBitmap32 please let me know.

procedure LoadPNGintoBitmap32(DstBitmap: TBitmap32; SrcStream: TStream; out AlphaChannelUsed: Boolean);
var
  PNGObject: TPngImage;
  PixelPtr: PColor32;
  AlphaPtr: PByte;
  SaveAlpha: PByte;
  I, AlphaSize: Integer;
begin
  AlphaChannelUsed := False;
  PNGObject := TPngImage.Create;
  try
    PNGObject.LoadFromStream(SrcStream);
    AlphaPtr := PByte(PNGObject.AlphaScanline[0]);
    if Assigned(AlphaPtr) then
    begin
      AlphaSize := PNGObject.Width * PNGObject.Height;
      if AlphaSize <= 0 then raise Exception.Create( PNG files with zero dimensions are not supported to be loaded to TBitmap32 );
      GetMem(SaveAlpha, AlphaSize);
      try
        Move(AlphaPtr^, SaveAlpha^, AlphaSize);
        PNGObject.RemoveTransparency;
        DstBitmap.Assign(PNGObject);
        DstBitmap.ResetAlpha;
        PixelPtr := PColor32(@DstBitmap.Bits[0]);
        AlphaPtr := SaveAlpha;
        for I := 0 to AlphaSize-1 do
        begin
          PixelPtr^ := (PixelPtr^ and $00FFFFFF) or (TColor32(AlphaPtr^) shl 24);
          Inc(PixelPtr);
          Inc(AlphaPtr);
        end;
      finally
        FreeMem(SaveAlpha, AlphaSize);
      end;
      AlphaChannelUsed := True;
    end else
    if PNGObject.TransparencyMode = ptmNone then
    begin
      DstBitmap.Assign(PNGObject);
    end else
    begin
      raise Exception.Create( Paletted PNG images are not supported in LoadPNGintoBitmap32, transparency cannot be stored to TBitmap32 );
    end;
  finally
    FreeAndNil(PNGObject);
  end;
end;




相关问题
determining the character set to use

my delphi 2009 app has a basic translation system that uses GNUGetText. i had used some win API calls to prepare the fonts. i thought it was working correctly until recently when someone from Malta ...

Help with strange Delphi 5 IDE problems

Ok, I m going nuts here. For the last (almost) four years, I ve been putting up with some extremely bad behavior from my Delphi 5 IDE. Problems include: Seemingly random errors in coride50.bpl ...

How to write a Remote DataModule to run on a linux server?

i would like to know if there are any solution to do this. Does anyone? The big picture: I want to access data over the web, using my delphi thin clients. But i´would like to keep my server/service ...

How convert string to integer in Oxygene

In Delphi, there is a function StrToInt() that converts a string to an integer value; there is also IntToStr(), which does the reverse. These functions doesn t appear to be part of Oxygene, and I can ...

Quick padding of a string in Delphi

I was trying to speed up a certain routine in an application, and my profiler, AQTime, identified one method in particular as a bottleneck. The method has been with us for years, and is part of a "...

热门标签