When i call canvas.stretchdraw with a bitmap, the bitmap will be mirrored/flipped when left>right. This does not happen for a PNG. Is this a bug? What can I do to fix it?
To replicate, try this code:
procedure TForm1.TestStretchdraw;
var
vBMP: TBitmap;
vPNG: TPNGImage;
X0,Y0,X1,Y1 : integer;
R : TRect;
procedure FlipRect;
var
T : integer;
begin
T := R.Left;
R.Left := R.Right;
R.Right := T;
end;
begin
vBMP := TBitmap.Create;
vPNG := TPNGImage.Create;
try
vBMP.LoadFromFile('c:\temp\pic\pic.bmp');
vPNG.LoadFromFile('c:\temp\pic\pic.png');
X0 := 0;
Y0 := 0;
X1 := X0 + vBMP.Width;
Y1 := Y0 + vBMP.Height;
R := Rect(X0,Y0,X1,Y1);
FlipRect;
Canvas.StretchDraw(R,vBMP); //This image will be drawn mirrored
X0 := vBMP.Width+10;
Y0 := 0;
X1 := X0 + vPNG.Width;
Y1 := Y0 + vPNG.Height;
R := Rect(X0,Y0,X1,Y1);
FlipRect;
Canvas.StretchDraw(R,vPNG); //This will not
finally
vPNG.Free;
vBMP.Free;
end;
end;
(but replace my testimages with some of your own)
Here I wrote a function that flips a png without any libraries like Gr32. Transparency remains in the flipped PNG.
procedure FlipPNG(aSource, aDest: TPngImage);
var
X, Y: Integer;
AlphaPtr: PByteArray;
RGBLine: pRGBLine;
PalleteLine: PByteArray;
AlphaPtrDest: PByteArray;
RGBLineDest: pRGBLine;
PalleteLineDest: PByteArray;
begin
aDest.Assign(aSource);
if (aSource.Header.ColorType = COLOR_PALETTE) or
(aSource.Header.ColorType = COLOR_GRAYSCALEALPHA) or
(aSource.Header.ColorType = COLOR_GRAYSCALE) then
begin
for y := 0 to aSource.Height - 1 do
begin
AlphaPtr := aSource.AlphaScanline[y];
PalleteLine := aSource.Scanline[y];
AlphaPtrDest := aDest.AlphaScanline[y];
PalleteLineDest := aDest.Scanline[y];
for x := 0 to aSource.Width - 1 do
begin
PalleteLineDest^[aSource.Width - x -1] := PalleteLine^[x];
if Assigned(AlphaPtr) then
AlphaPtrDest^[aSource.Width - x -1] := AlphaPtr^[x];
end;
end;
end else
if (aSource.Header.ColorType = COLOR_RGBALPHA) or
(aSource.Header.ColorType = COLOR_RGB) then
begin
for y := 0 to aSource.Height - 1 do
begin
AlphaPtr := aSource.AlphaScanline[y];
RGBLine := aSource.Scanline[y];
AlphaPtrDest := aDest.AlphaScanline[y];
RGBLineDest := aDest.Scanline[y];
for x := 0 to aSource.Width - 1 do
begin
RGBLineDest^[aSource.Width - x -1] := RGBLine^[x];
if Assigned(AlphaPtr) then
AlphaPtrDest^[aSource.Width - x -1] := AlphaPtr^[x];
end;
end;
end;
end;
Yes, this is correct. StretchDraw
calls the Draw
method of the appropriate descendant of TGraphic
. You can compare TBitmap.Draw
with TPngImage.Draw
yourself. TBitmap.Draw
, naturally, simply calls the Windows API function StretchBlt
. TPngImage.Draw
, however, first calls AdjustRect
:
procedure AdjustRect(var Rect: TRect);
var
t: Integer;
begin
if Rect.Right < Rect.Left then
begin
t := Rect.Right;
Rect.Right := Rect.Left;
Rect.Left := t;
end;
if Rect.Bottom < Rect.Top then
begin
t := Rect.Bottom;
Rect.Bottom := Rect.Top;
Rect.Top := t;
end
end;
As you can see, it ruthlessly undoes your swapping of left
and right
.
I would not consider the case, where Left
is larger than Right
, a valid rectangle definition, so my answer would be: don't call it like that. You can ensure that the rectangle definition is valid before calling StretchDraw
:
if (R.Left > R.Right) then
Swap (R.Left, R.Right);
if (R.Top> R.Bottom) then
Swap (R.Top, R.Bottom);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.