Recent

Author Topic: Rotation using TBGRABitmap  (Read 1437 times)

user5

  • Sr. Member
  • ****
  • Posts: 357
Rotation using TBGRABitmap
« on: May 10, 2022, 10:45:19 am »
    I've been fooling around with different ways of rotating an image. I found the really cool example program PRotateImage
on this forum and the code is recreated below, using a different image. The attached file orig1.gif shows the original image
before rotation. The attached file rotated1.gif shows the image after it has been rotated about 45 degrees.
    If the rotation involves rotations of multiples of 90 degrees then everything is fine but any other angle produces the
'anti-aliased' edges shown in rotated1.gif. I can remove the 'edging' but I don't want to have to do that.
    1. Is there a way to rotate the image without the anti-aliasing effect or whatever it is so that the image only shows
raster scan edges?
    2. Does the TBGRABitmap named "bmp" need to be freed?

 
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
  9.   BGRAGraphicControl, BGRABitmap, BGRABitmapTypes;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     BGRAGraphicControl1: TBGRAGraphicControl;
  17.     TrackBar_Angle: TTrackBar;
  18.     procedure BGRAGraphicControl1Redraw(Sender: TObject; Bitmap: TBGRABitmap);
  19.     procedure FormCreate(Sender: TObject);
  20.     procedure TrackBar_AngleChange(Sender: TObject);
  21.   private
  22.     { private declarations }
  23.   public
  24.     { public declarations }
  25.     bmp: TBGRABitmap;
  26.   end;
  27.  
  28. var
  29.   Form1: TForm1;
  30.  
  31. implementation
  32.  
  33. {$R *.lfm}
  34.  
  35. { TForm1 }
  36.  
  37. procedure TForm1.BGRAGraphicControl1Redraw(Sender: TObject; Bitmap: TBGRABitmap
  38.   );
  39. begin
  40.   Bitmap.PutImageAngle(Bitmap.Width/2-0.5,Bitmap.Height/2-0.5,bmp,TrackBar_Angle.Position,bmp.Width/2-0.5,bmp.Height/2-0.5);
  41. end;
  42.  
  43. procedure TForm1.FormCreate(Sender: TObject);
  44. begin
  45.  
  46.   //bmp := TBGRABitmap.Create('48px-Gnome-document-open-recent.svg.png');
  47.   bmp := TBGRABitmap.Create('new1.png');
  48. end;
  49.  
  50. procedure TForm1.TrackBar_AngleChange(Sender: TObject);
  51. begin
  52.   BGRAGraphicControl1.RedrawBitmap;
  53. end;
  54.  
  55. end.


winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Rotation using TBGRABitmap
« Reply #1 on: May 10, 2022, 02:03:04 pm »
Hi!

Use the BGRA function BGRAfilterRotate.

You need a  CenterPoint, the Degrees and the boolean Flag CorrectBlur and get as return a rotated BGRAbitmap.


Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var bmp: TBGRAbitmap;
  3. begin
  4.   bmp := TBGRAbitmap.create ('SomePicture.png');
  5.   BGRAReplace (bmp, bmp.FilterRotate(PointF (bmp.width/2, bmp.Height/2), 42.42, false));
  6.   bmp.Draw (SomeCanvas,0,0);
  7.   bmp.free;
  8. end;        

And you have to free the created BGRAbitmap.

Winni

user5

  • Sr. Member
  • ****
  • Posts: 357
Re: Rotation using TBGRABitmap
« Reply #2 on: May 10, 2022, 03:13:03 pm »
    winni, is PointF in your example the centerpoint? Where does degrees go and where do I put CorrectBlur?
Also, what is "42.42"?

    I loaded the Graphics32 package and used the code shown below which works very well though it might be
slower than TBGRABitmap, I don't know. It did the rotation of a 200x200 image in 0.0073 sec. Is that good?
    The program probably doesn't need all those listed headers.
    It produced the image shown in the attached file rotated45deg.gif which was rotated 45 degrees and the
edges are raster scan like I wanted. The edges are of course rough which is unavoidable but it looks okay after
edge softening has been applied to it as shown in the attached image edged1.gif.

   
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   wincrt,FileUtil,intfgraphics, windows, SysUtils,
  9.   Forms,  Controls, Graphics, LResources,FPimage, GraphUtil,
  10.   Process, ExtCtrls, Dialogs, StdCtrls,  LCLProc,  ActnList, LCLIntf,
  11.   Interfaces, Buttons, ExtDlgs, Menus,  ComCtrls,  strutils,GR32, GR32_Transforms,
  12.   Classes, GraphType,LCLType, Variants;
  13.  
  14. type
  15.  
  16.   { TForm1 }
  17.  
  18.   TForm1 = class(TForm)
  19.     Button1: TButton;
  20.     Image1: TImage;
  21.     procedure Button1Click(Sender: TObject);
  22.   private
  23.  
  24.   public
  25.  
  26.   end;
  27.  
  28. var
  29.   Form1: TForm1;
  30.  
  31. implementation
  32.  
  33. {$R *.lfm}
  34.  
  35. { TForm1 }
  36.  
  37. procedure TForm1.Button1Click(Sender: TObject);
  38. var Bmp:TBitmap32;
  39.     mybitmap,mybitmap2:TBitmap;
  40.     Degs:extended;
  41.     AdjustSizeNow:boolean;
  42.     BkColor:TColor;
  43.     Transparent:boolean;
  44.     Tmp: TBitmap32;
  45.     Transformation: TAffineTransformation;
  46.     inf1,inf2:TLazIntfImage;
  47.     ImgFormatDescription: TRawImageDescription;
  48. begin
  49.  Bmp := TBitmap32.create;
  50.  Bmp.width := 200;
  51.  Bmp.height := 200;
  52.  Bmp.loadfromfile('new1.bmp');
  53.  Degs := 45;
  54.  AdjustSizeNow := true;
  55.  BkColor := clNone;
  56.  Transparent := false;
  57.  
  58.  Tmp := TBitmap32.Create;
  59.  Transformation := TAffineTransformation.Create;
  60.  try
  61.   Transformation.BeginUpdate;
  62.   Transformation.SrcRect := FloatRect(0, 0, Bmp.Width, Bmp.Height);
  63.   Transformation.Translate(-0.5 * Bmp.Width, -0.5 * Bmp.Height);
  64.   Transformation.Rotate(0, 0, -Degs);
  65.   if AdjustSizeNow then
  66.    with Transformation.GetTransformedBounds do
  67.     Tmp.SetSize(Round(Right - Left), Round(Bottom - Top))
  68.   else
  69.    Tmp.SetSize(Bmp.Width, Bmp.Height);
  70.   Transformation.Translate(0.5 * Tmp.Width, 0.5 * Tmp.Height);
  71.   Transformation.EndUpdate;
  72.   Tmp.Clear(Color32(BkColor));
  73.   if not Transparent then
  74.    Bmp.DrawMode := dmTransparent;
  75.   Transform(Tmp, Bmp, Transformation);
  76.   Bmp.Assign(Tmp);
  77.   Bmp.OuterColor := Color32(BkColor);
  78.   if Transparent then
  79.    Bmp.DrawMode := dmTransparent;
  80.  finally
  81.   Transformation.Free;
  82.   Tmp.Free;
  83.  end;
  84.  
  85.  mybitmap := TBitmap.create;
  86.  mybitmap.width := Bmp.width;
  87.  mybitmap.height := Bmp.height;
  88.  mybitmap2 := TBitmap.create;
  89.  mybitmap2.width := mybitmap.width;
  90.  mybitmap2.height := mybitmap.height;
  91.  
  92.  mybitmap.assign(Bmp);
  93.  
  94.  //The TLazIntfImage stuff ensures that the bitmap is 24 bit.
  95.  inf2:=TLazIntfImage.Create(mybitmap.Width,mybitmap.Height);
  96.  inf1:= mybitmap.CreateIntfImage;
  97.  try
  98.  ImgFormatDescription.Init_BPP24_B8G8R8_BIO_TTB(mybitmap.Width,mybitmap.Height);
  99.  inf2.DataDescription:=ImgFormatDescription;
  100.  inf2.CopyPixels(inf1);
  101.  mybitmap2.PixelFormat:=pf24bit;
  102.  mybitmap2.LoadFromIntfImage(inf2);
  103.  mybitmap2.PixelFormat:=pf24bit;
  104.  finally
  105.    inf1.free;
  106.    inf2.Free;
  107.  end;
  108.  
  109.  image1.width := Bmp.width;
  110.  image1.height := Bmp.height;
  111.  image1.picture.bitmap.Assign(mybitmap2);
  112.  
  113.  mybitmap.free;
  114.  mybitmap2.free;
  115.  Bmp.free;
  116. end;
  117.  
  118.  
  119. end.




user5

  • Sr. Member
  • ****
  • Posts: 357
Re: Rotation using TBGRABitmap
« Reply #3 on: May 10, 2022, 04:13:55 pm »
    winni, if I understand you correctly then I need something like the code shown below. The only problem is that it won't
compile. The compiler keeps reporting that the parenthesis somewhere in  BGRAReplace is not correct.

   
Code: Pascal  [Select][+][-]
  1. pointf.X := 100; //center point X
  2.  pointf.Y := 100; //centerpoint Y
  3.  
  4.  mybitmap := TBitmap.create;
  5.  mybitmap.Width := 200;
  6.  mybitmap.height := 200;
  7.  mybitmap.loadfromfile('new1.bmp');
  8.  
  9.  bgra := TBGRAbitmap.create;
  10.  bgra.assign(mybitmap);
  11.  BGRAReplace (bgra, bgra.FilterRotate (pointf (bgra.width/2, bgra.Height/2), 45, true));
  12.  bgra.Draw (image1.canvas,0,0);
  13.  bgra.free;
  14.  mybitmap.free;


user5

  • Sr. Member
  • ****
  • Posts: 357
Re: Rotation using TBGRABitmap
« Reply #4 on: May 10, 2022, 04:47:21 pm »
    I got the code below to work. Thank you winni. It did the job in 0.0034 sec. Your suggested code is considerably faster.

   
Code: Pascal  [Select][+][-]
  1. image18.width := image13.width;
  2.  image18.height := image13.height;
  3.  image18.visible := true;
  4.  
  5.  mybitmap := TBitmap.create;
  6.  mybitmap.Width := 200;
  7.  mybitmap.height := 200;
  8.  mybitmap.assign(image13.picture.bitmap);
  9.  
  10.  bgra := TBGRAbitmap.create;
  11.  bgra.assign(mybitmap);
  12.  BGRAReplace (bgra, bgra.FilterRotate(PointF (mybitmap.width/2, mybitmap.Height/2), 45, true));
  13.  bgra.Draw (image18.canvas,0,0);
  14.  bgra.free;
  15.  mybitmap.free;


winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Rotation using TBGRABitmap
« Reply #5 on: May 10, 2022, 05:05:38 pm »
Hi!

Some hints for working with BGRAbitmap:

You can create and load a file into a BGRAbitmap in one line of code:

Code: Pascal  [Select][+][-]
  1. BGRA:= TBGRAbitmap.create ('Nice.png');

This works with the most graphic file types like png, bmp, jpg, tiff, webp and some others

And you can create and copy an existing TBitmap in one line of code:

Code: Pascal  [Select][+][-]
  1. BGRA := TBGRAbitmap.Create(myTBitmap);
  2.  

or

Code: Pascal  [Select][+][-]
  1. BGRA := TBGRAbitmap.create(Image1.picture.bitmap);


There are a lot of usefull short ways in the BGRAbitmap.

Winni

user5

  • Sr. Member
  • ****
  • Posts: 357
Re: Rotation using TBGRABitmap
« Reply #6 on: May 11, 2022, 01:40:52 pm »
    There have been some developments so in case anyone is interested I am reporting them.
    Fig. 1 shows the original TImage picture. Fig. 2 shows the TImage after rotation using the BGRABitmap code that
winni suggested but when it is saved to a file then the result is a picture that is totally black. Perhaps it needs to be
converted to a 24 bit image, I don't know. The same exact code used to produce an image that retained the red
background but for some reason it doesn't do that anymore. Weird.
    Fig. 3 shows the TImage after it's been rotated and saved to a file using the Graphics32 system that I posted
earlier. After the program does a flood fill on it then the result is shown in Fig. 4.
    I did more testing and it turns out that both systems work at about the same speed with a variance of about +- 4
thousandths of a sec.

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Rotation using TBGRABitmap
« Reply #7 on: May 11, 2022, 02:13:32 pm »
Hi!

If you are working with BGRAbitmap then there is no reason anymore to work with a TBitmap.

TBitmap and transparency were allways a big problem. So get rid of it.

How to load a file to a BGRAbitmap is shown above.

This way you save a file:

Code: Pascal  [Select][+][-]
  1. BGRA.savetofile ('Transparent.png');
  2.  

Notice that there are some file types that can't handle transpareny like jpg or bmp.

Drawing on any canvas you like:

Code: Pascal  [Select][+][-]
  1. BGRA.draw (SomeCanvas,0,0);
  2.  


There is no need to use a TBitmap anymore. And this avoids trouble!

Winni
« Last Edit: May 11, 2022, 04:12:07 pm by winni »

user5

  • Sr. Member
  • ****
  • Posts: 357
Re: Rotation using TBGRABitmap
« Reply #8 on: May 11, 2022, 07:36:52 pm »
    I agree with some of what you say but bitmaps can be very useful and in some cases indispensable.
    For example, a BGRABitmap cannot be assigned directly to a TImage. Lazarus won't allow it. The BGRABitmap must first be assigned to a bitmap and then the bitmap assigned to the TImage.
    Like you said, JPGs can't be made transparent as far as I know, but I use transparent BMPs and PNGs all the time. Bitmaps are uncompressed and they make excellent transparencies.
    PNGs are great because they can be compressed into very small file sizes while still retaining their ability to go transparent and I also used them extensively.
    I used "bgra.savetofile('test12.bmp');" and it made a transparent BMP! However, for my purposes I don't want a BMP or PNG file that is stored as a transparent file though I do want BMPs and PNGs that can be made transparent on command after they are imported into a program.
    When it comes to making a transparent video, BMPs are absolutely required. A high-quality transparent video can only be made in the AVI uncompressed format and the frames used to make that AVI must be BMPs if you want the best quality and transparency.
    It's really fascinating... For example, if you have a 24 bit and 32 bit transparent-capable pictures containing the same image then different parts of them will go transparent when they are made to be transparent using "somepix.transparent := true;".
    Bitmaps are also required when using the RawImage technique for altering the frames of a video. RawImage is very fast, as fast or faster than BGRABitmap though the latter is much more useful since its pixel access is much greater and better. The RawImage method uses a pointer to point to say, each pixel in a loop. Maybe someone in the world knows how to get RawImage to point to pixels other than the current pixel being pointed to but that person isn't me.
    Nothing has the quality of a BMP and an AVI. You can make as many generational copies of them without losing a drop of quality but not so with compressed formats, even PNGs. MPGs are compressed so they have slightly less quality than AVIs though in most cases with quality originals the quality loss cannot be detected except when they contain the color red. In fact, it's a little known fact that this disadvantage can be turned into an advantage when using edge softened images since a slightly diffused MPG will also diffuse and further soften the existing edge softening if the overall quality is good.
    Thanks again. I'm very appreciative of your interest and help.

user5

  • Sr. Member
  • ****
  • Posts: 357
Re: Rotation using TBGRABitmap
« Reply #9 on: May 11, 2022, 09:58:05 pm »
    This rotation stuff has really opened up some big possibilities for me. Using Graphics32 AND BGRABitmap I can offer the user a
choice about respectively saving a picture as a non-transparent image that can be made transparent when imported or as an image
that will automatically be transparent upon loading into the program.
    Using the rotation code as a foundation, the program could also rotate the image while a recording is made, just like it can now
have pictures and videos move around in the capture area during a recording. The edge softening page could 'repair' the jagged
edges that result when any program rotates particular images.
    Wowser. It can really pay off to go to the Forum.
    This will result in a lot of work but most of it will be a no brainer. All the experimentation is done.

circular

  • Hero Member
  • *****
  • Posts: 4196
    • Personal webpage
Re: Rotation using TBGRABitmap
« Reply #10 on: May 21, 2022, 11:41:25 pm »
Not sure if that’s what you wanted but you can disable any antialiasing by specifying the resample filter parameter with rfBox. This works with PutImageAffine.
Conscience is the debugger of the mind

 

TinyPortal © 2005-2018