1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
| unit UPng2Bmp32;
interface
uses Windows, SysUtils, Graphics, PngImage;
procedure PartialTransPng2Bmp32(aPNGImage: TPNGImage; aBMP: TBitmap);
implementation
type
// l'astuce qui permet d'avoir accès à la section Protected
// de la classe TChunckIHDR
THackChunkIHDR = class(TChunkIHDR);
{Copy a PNG to a BMP32 using partial transparency
Original code grabed from PngImage.pas:
procedure TPngImage.DrawPartialTrans(DC: HDC; Rect: TRect);
adapted by Cirec}
procedure PartialTransPng2Bmp32(aPNGImage: TPNGImage; aBMP: TBitmap);
type
{Access to pixels}
TPixelLine = Array[Word] of TRGBQuad;
pPixelLine = ^TPixelLine;
var
Header: THackChunkIHDR;
{Transparency/palette chunks}
TransparencyChunk: TChunktRNS;
PaletteChunk: TChunkPLTE;
PaletteIndex: Byte;
CurBit: Integer;
Data: PByte;
{Buffer bitmap modification}
BytesPerRowDest,
BytesPerRowSrc,
BytesPerRowAlpha: Integer;
ImageSource, ImageSourceOrg,
AlphaSource : pByteArray;
ImageData : pPixelLine;
i, j, i2, j2 : Integer;
{For bitmap stretching}
W, H : Cardinal;
Stretch : Boolean;
FactorX, FactorY: Double;
begin
if not Assigned(aBMP) then Exit;
aBMP.PixelFormat := pf32bit;
W := aBMP.Width;
H := aBMP.Height;
Header := THackChunkIHDR(aPNGImage.Header); {Fast access to header}
Stretch := (W <> Header.Width) or (H <> Header.Height);
if Stretch then FactorX := W / Header.Width else FactorX := 1;
if Stretch then FactorY := H / Header.Height else FactorY := 1;
{Obtain number of bytes for each row}
BytesPerRowAlpha := Header.Width;
BytesPerRowDest := (((32 * W) + 31) and not 31) div 8; {Number of bytes for each image row in destination}
BytesPerRowSrc := (((Header.BitmapInfo.bmiHeader.biBitCount * Header.Width) +
31) and not 31) div 8; {Number of bytes for each image row in source}
{Obtains image pointers}
ImageData := aBMP.ScanLine[0];
AlphaSource := Header.ImageAlpha;
Longint(ImageSource) := Longint(Header.ImageData) +
Header.BytesPerRow * Longint(Header.Height - 1);
ImageSourceOrg := ImageSource;
case Header.BitmapInfo.bmiHeader.biBitCount of
{R, G, B images}
24:
FOR j := 1 TO H DO
begin
{Process all the pixels in this line}
FOR i := 0 TO W - 1 DO
begin
if Stretch then i2 := trunc(i / FactorX) else i2 := i;
pRGBTriple(@ImageData[i])^ := pRGBTriple(@ImageSource[i2 * 3])^;
ImageData[i].rgbReserved := AlphaSource[i2];
end;
{Move pointers}
Dec(Longint(ImageData), BytesPerRowDest);
if Stretch then j2 := trunc(j / FactorY) else j2 := j;
Longint(ImageSource) := Longint(ImageSourceOrg) - BytesPerRowSrc * j2;
Longint(AlphaSource) := Longint(Header.ImageAlpha) + BytesPerRowAlpha * j2;
end;
{Palette images with 1 byte for each pixel}
1,4,8: if Header.ColorType = COLOR_GRAYSCALEALPHA then
FOR j := 1 TO H DO
begin
{Process all the pixels in this line}
FOR i := 0 TO W - 1 DO
with ImageData[i], Header.BitmapInfo do begin
if Stretch then i2 := trunc(i / FactorX) else i2 := i;
rgbRed := ImageSource[i2];
rgbGreen := ImageSource[i2];
rgbBlue := ImageSource[i2];
rgbReserved := AlphaSource[i2];
end;
{Move pointers}
Longint(ImageData) := Longint(ImageData) - BytesPerRowDest;
if Stretch then j2 := trunc(j / FactorY) else j2 := j;
Longint(ImageSource) := Longint(ImageSourceOrg) - BytesPerRowSrc * j2;
Longint(AlphaSource) := Longint(Header.ImageAlpha) +
BytesPerRowAlpha * j2;
end
else {Palette images}
begin//******************
{Obtain pointer to the transparency chunk}
TransparencyChunk := TChunktRNS(aPNGImage.Chunks.ItemFromClass(TChunktRNS));
PaletteChunk := TChunkPLTE(aPNGImage.Chunks.ItemFromClass(TChunkPLTE));
FOR j := 1 TO H DO
begin
{Process all the pixels in this line}
i := 0;
repeat
CurBit := 0;
if Stretch then i2 := trunc(i / FactorX) else i2 := i;
Data := @ImageSource[i2];
repeat
{Obtains the palette index}
case Header.BitDepth of
1: PaletteIndex := (Data^ shr (7-(I Mod 8))) and 1;
2,4: PaletteIndex := (Data^ shr ((1-(I Mod 2))*4)) and $0F;
else PaletteIndex := Data^;
end;
{Updates the image with the new pixel}
with ImageData[i] do
begin
rgbReserved := TransparencyChunk.PaletteValues[PaletteIndex];
rgbRed := PaletteChunk.Item[PaletteIndex].rgbRed;
rgbGreen := PaletteChunk.Item[PaletteIndex].rgbGreen;
rgbBlue := PaletteChunk.Item[PaletteIndex].rgbBlue;
end;
{Move to next data}
inc(i); inc(CurBit, Header.BitmapInfo.bmiHeader.biBitCount);
until CurBit >= 8;
until i >= Integer(W);
{Move pointers ********}
Longint(ImageData) := Longint(ImageData) - BytesPerRowDest;
if Stretch then j2 := trunc(j / FactorY) else j2 := j;
Longint(ImageSource) := Longint(ImageSourceOrg) - BytesPerRowSrc * j2;
end
end {Palette images **********}
end {case Header.BitmapInfo.bmiHeader.biBitCount};
end;
end. |
Partager