Recent

Author Topic: how to Horizontal flip or Vertical flip a bmp picture with TBitmap or TImage?  (Read 13596 times)

greenzyzyzy

  • Full Member
  • ***
  • Posts: 249
how to Horizontal flip or Vertical flip a bmp picture with TBitmap or TImage?

Eugene Loza

  • Hero Member
  • *****
  • Posts: 674
    • My games in Pascal
I have never done this, but I think it'll work: Copyrect(...width,0,height,0); I.e. make an 'inverse rectangle' on copy.
My FOSS games in FreePascal&CastleGameEngine: https://decoherence.itch.io/ (Sources: https://gitlab.com/EugeneLoza)

greenzyzyzy

  • Full Member
  • ***
  • Posts: 249
I have never done this, but I think it'll work: Copyrect(...width,0,height,0); I.e. make an 'inverse rectangle' on copy.

i am sorry to say ,copyrect can not done it,but it can work in delphi.

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
This works when TImage has loaded a BMP image. .. edit: correction, seems to work with some PNG's too.

Code: [Select]
var src, dest: TRect;
begin
  dest:=bounds(0, 0, image1.Picture.Width, image1.Picture.Height);
  //src:=rect(0, image1.Picture.Height-1, image1.Picture.Width-1, 0); // Vertical flip
  //src:=rect(image1.Picture.Width-1, 0, 0, image1.Picture.Height-1); // Horizontal flip
  src:=rect(image1.Picture.Width-1, image1.Picture.Height-1, 0, 0); // Both flip
  image1.Picture.Bitmap.Canvas.CopyRect(dest, image1.Picture.Bitmap.Canvas, src);
« Last Edit: May 12, 2015, 07:47:44 pm by User137 »

greenzyzyzy

  • Full Member
  • ***
  • Posts: 249
This works when TImage has loaded a BMP image. .. edit: correction, seems to work with some PNG's too.

Code: [Select]
var src, dest: TRect;
begin
  dest:=bounds(0, 0, image1.Picture.Width, image1.Picture.Height);
  //src:=rect(0, image1.Picture.Height-1, image1.Picture.Width-1, 0); // Vertical flip
  //src:=rect(image1.Picture.Width-1, 0, 0, image1.Picture.Height-1); // Horizontal flip
  src:=rect(image1.Picture.Width-1, image1.Picture.Height-1, 0, 0); // Both flip
  image1.Picture.Bitmap.Canvas.CopyRect(dest, image1.Picture.Bitmap.Canvas, src);

thank you very much.

greenzyzyzy

  • Full Member
  • ***
  • Posts: 249
This works when TImage has loaded a BMP image. .. edit: correction, seems to work with some PNG's too.

Code: [Select]
var src, dest: TRect;
begin
  dest:=bounds(0, 0, image1.Picture.Width, image1.Picture.Height);
  //src:=rect(0, image1.Picture.Height-1, image1.Picture.Width-1, 0); // Vertical flip
  //src:=rect(image1.Picture.Width-1, 0, 0, image1.Picture.Height-1); // Horizontal flip
  src:=rect(image1.Picture.Width-1, image1.Picture.Height-1, 0, 0); // Both flip
  image1.Picture.Bitmap.Canvas.CopyRect(dest, image1.Picture.Bitmap.Canvas, src);

i had a test,this codes still can not works ok with laz4android v1.5

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
I can't test for android, but i did see that 32-bit PNG's don't work, and 24-bit works (without alpha channel). Here's a new function that both uses temporary TBitmap buffer and removes alpha channel. (Background should be black by default, or it might in some cases be undefined. Then fill bmp with color before Draw(). Only notable point with images that have transparent pixels.)

Code: [Select]
var src, dest: TRect;
    bmp: TBitmap;
    w, h: integer;
begin
  w:=image1.Picture.Width; h:=image1.Picture.Height;
  dest:=bounds(0, 0, w, h);
  //src:=rect(0, h-1, w-1, 0); // Vertical flip
  //src:=rect(w-1, 0, 0, h-1); // Horizontal flip
  src:=rect(w-1, h-1, 0, 0); // Both flip

  bmp:=TBitmap.Create;
  bmp.PixelFormat:=pf24bit;
  bmp.SetSize(w, h);
  bmp.Canvas.Draw(0, 0, image1.Picture.Bitmap);
  image1.Picture.Bitmap.Canvas.CopyRect(dest, bmp.Canvas, src);
  bmp.Free;
end;
« Last Edit: May 17, 2015, 12:17:00 pm by User137 »

greenzyzyzy

  • Full Member
  • ***
  • Posts: 249
I can't test for android, but i did see that 32-bit PNG's don't work, and 24-bit works (without alpha channel). Here's a new function that both uses temporary TBitmap buffer and removes alpha channel.

Code: [Select]
var src, dest: TRect;
    bmp: TBitmap;
    w, h: integer;
begin
  w:=image1.Picture.Width; h:=image1.Picture.Height;
  dest:=bounds(0, 0, w, h);
  //src:=rect(0, h-1, w-1, 0); // Vertical flip
  //src:=rect(w-1, 0, 0, h-1); // Horizontal flip
  src:=rect(w-1, h-1, 0, 0); // Both flip

  bmp:=TBitmap.Create;
  bmp.PixelFormat:=pf24bit;
  bmp.SetSize(w, h);
  bmp.Canvas.Draw(0, 0, image1.Picture.Bitmap);
  image1.Picture.Bitmap.Canvas.CopyRect(dest, bmp.Canvas, src);
  bmp.Free;
end;

thank you very much ,i will get some time to test it.

ChrisR

  • Full Member
  • ***
  • Posts: 247
I know this is an old topic, but it was my first hit when I searched for an answer. I think my code below works with all image formats and is exceptionally fast

procedure FlipVertical (var px: TPicture);
var
  p: array of byte;
  i, half, b: integer;
  LoPtr, HiPtr: PInteger;
begin
    if px.Height < 3 then exit;
    half := (px.Height div 2);
    b := px.Bitmap.RawImage.Description.BytesPerLine;
    LoPtr := PInteger(px.Bitmap.RawImage.Data);
    HiPtr := PInteger(px.Bitmap.RawImage.Data+ ((px.Height -1) * b));
    setlength(p, b);
    for i := 1 to half do begin
          System.Move(LoPtr^,p[0],b); //(src, dst,sz)
          System.Move(HiPtr^,LoPtr^,b); //(src, dst,sz)
          System.Move(p[0],HiPtr^,b); //(src, dst,sz)
          Inc(PByte(LoPtr), b );
          Dec(PByte(HiPtr), b);
    end;
end; //FlipVertical() 

han

  • Jr. Member
  • **
  • Posts: 96
An old topic but  the copyrect method doesn't work perfectly in Lazarus 1.84.  For horizontal flip the last column is always forgotten. Similar problem with vertical swap. Maybe a bug in the compiler but I could not fix it. Some post add a -1 in the height or width but that didn't fixed it either.

The method proposed by ChrisR didn't work for me.

Below my method using scanline.  I tried to skip the temporary bitmap but without it is doesn't work without. This scanline method is also fast and more important accurate for all pixels:

Code: [Select]
procedure Tmainwindow.Flipvertical1Click(Sender: TObject);
var bmp: TBitmap;
    w, h, x, y: integer;
type
  PRGBTripleArray = ^TRGBTripleArray; {for fast pixel routine}
  {$ifdef mswindows}
  TRGBTripleArray = array[0..trunc(bufwide/3)] of TRGBTriple; {for fast pixel routine}
  {$else} {unix}
  TRGBTripleArray = array[0..trunc(bufwide/3)] of tagRGBQUAD; {for fast pixel routine}
  {$endif}
var
   pixelrow1 : PRGBTripleArray;{for fast pixel routine}
   pixelrow2 : PRGBTripleArray;{for fast pixel routine}
begin
  w:=image1.Picture.Width; h:=image1.Picture.Height;
  bmp:=TBitmap.Create;
  bmp.PixelFormat:=pf24bit;

  bmp.SetSize(w, h);
  for y := 0 to h -1 do
  begin // scan each line and swap top and bottom}
    pixelrow1:=image1.Picture.Bitmap.ScanLine[h-1-y];
    pixelrow2:=bmp.ScanLine[y];
    for x := 0 to w-1 do pixelrow2[x] := pixelrow1[x];
  end;
  image1.Picture.Bitmap.Canvas.Draw(0,0, bmp);// move bmp to source
  bmp.Free;
end;       

procedure Tmainwindow.Fliphorizontal1Click(Sender: TObject);
var bmp: TBitmap;
    w, h, x, y: integer;
type
  PRGBTripleArray = ^TRGBTripleArray; {for fast pixel routine}
  {$ifdef mswindows}
  TRGBTripleArray = array[0..trunc(bufwide/3)] of TRGBTriple; {for fast pixel routine}
  {$else} {unix}
  TRGBTripleArray = array[0..trunc(bufwide/3)] of tagRGBQUAD; {for fast pixel routine}
  {$endif}
var
   pixelrow1 : PRGBTripleArray;{for fast pixel routine}
   pixelrow2 : PRGBTripleArray;{for fast pixel routine}
begin
  w:=image1.Picture.Width; h:=image1.Picture.Height;
  bmp:=TBitmap.Create;
  bmp.PixelFormat:=pf24bit;

  bmp.SetSize(w, h);
  for y := 0 to h -1 do
  begin // scan each line
    pixelrow1:=image1.Picture.Bitmap.ScanLine[y];
    pixelrow2:=bmp.ScanLine[y];
    for x := 0 to w-1 do {swap left and right}
       pixelrow2[x] := pixelrow1[w-1 -x];
  end;
  image1.Picture.Bitmap.Canvas.Draw(0,0, bmp);// move bmp to source
  bmp.Free;
end;

« Last Edit: October 07, 2018, 06:40:22 pm by han »

wp

  • Hero Member
  • *****
  • Posts: 11916
For vertical flipping you can also invert the Height field in the BitmapInfo header of the file (stream) - this makes the bitmap being painted in the opposite vertical direction:
Code: Pascal  [Select][+][-]
  1. uses
  2.   BmpComn;
  3.  
  4. procedure FlipBmpVert(ABitmap: TBitmap);
  5. var
  6.   filehdr: TBitmapFileHeader;
  7.   infohdr: TBitmapInfoHeader;
  8.   s: TMemoryStream;
  9. begin
  10.   s := TMemorystream.Create;
  11.   try
  12.     ABitmap.SaveToStream(s);
  13.     s.Position := 0;
  14.     s.Read(filehdr, SizeOf(filehdr));
  15.     s.Read(infohdr, SizeOf(infohdr));
  16.     infohdr.Height := -infoHdr.Height;
  17.     s.Position := s.Position - SizeOf(infoHdr);
  18.     s.Write(infoHdr, SizeOf(infoHdr));
  19.     s.Position := 0;
  20.     ABitmap.LoadfromStream(s);
  21.   finally
  22.     s.Free;
  23.   end;
  24. end;
  25.  
  26. procedure TForm1.Button1Click(Sender: TObject);
  27. begin
  28.   FlipBmpVert(Image1.Picture.Bitmap);
  29.   Image1.Invalidate;
  30. end;  

 

TinyPortal © 2005-2018