I want to rotate a bitmap that has been loaded from a jpeg file into a TImage by 90 degrees. Don't want to save it or anything else. I have done a search and what I could find was procedures for arbitrary degree rotation, or did not work (or both). I have done this before back in the days when I wrote in assembler, but when I tried to do it using the TCanvas.Pixels property my image kept disappearing (dimensions set to 0). I also tried Charles Hacker's procedure (in the "How to rotate a png image?" thread further down (currently) in this forum. Same thing. Image disappears. Can anybody give me a procedure that will do the rotation on a visible TImage? TIA, Malcolm
![]() |
0 |
![]() |
Do you know this page? http://www.efg2.com/Lab/ImageProcessing/RotateScanline.htm He's using scanline what makes the procedure much quicker instead of doing it pixel by pixel. If your picture is not square you have to enlarge the canvas somehow.. If you have the latest Delphi XE's with FireMonkey you can use this graphic library and use just1 parameter to rotate images (2D and 3D)
![]() |
0 |
![]() |
Thanks for your reply Robert. I was aware of the link you give. It does not help. I have been using the scan lines, but the problem appears to be more fundamental than that. Consider the following code:- {code} Image1.Picture.LoadFromFile(TestFile); with Image1.Picture do Label1.caption := '('+IntToStr(Width)+'.'+IntToStr(Height)+')'; Image1.Picture.Bitmap; with Image1.Picture do Label2.caption := '('+IntToStr(Width)+'.'+IntToStr(Height)+')'; {code} After this the caption for Label1 {with my test image) is (800,600); while label2 caption is (0,0); Malcolm The same happens if one uses the bitmap width: e.g. W := Image1.Picture.Bitmap.Width; *It used to be that writing a function with undocumented side effects was the most heinous crime a programmer could commit.* This no longer appears to be the case. I am ttrying to find a work around. > {quote:title=Robert Triest wrote:}{quote} > Do you know this page? > > http://www.efg2.com/Lab/ImageProcessing/RotateScanline.htm > > He's using scanline what makes the procedure much quicker instead of doing it pixel by pixel. > If your picture is not square you have to enlarge the canvas somehow.. > > If you have the latest Delphi XE's with FireMonkey you can use this graphic library and > use just1 parameter to rotate images (2D and 3D)
![]() |
0 |
![]() |
Giving actual working code (with eg the names of files you load included) is usually preferable That way someone might notice that you loaded a jpg into the tpicture and then accessed the properties of tpictures bitmap, clearing the jpg data in the process (or something like that)
![]() |
0 |
![]() |
Malcolm Coulter wrote: > I want to rotate a bitmap that has been loaded from a jpeg file into a TImage by 90 degrees. > Don't want to save it or anything else. > > I have done a search and what I could find was procedures for arbitrary degree rotation, or did > not work (or both). > > I have done this before back in the days when I wrote in assembler, but when I tried to do it > using the TCanvas.Pixels property my image kept disappearing (dimensions set to 0). Hi Malcolm, You did not mention which Delphi version you have so the following might be different in your version (I'm using D2010). The TImage.Picture can hold various picture formats, jpg, bmp etc. TImage.Picture.Bitmap is usable only if you have loaded a bitmap into TImage. Specifically, if you have loaded any other graphic format and attempt to access the Bitmap, the current image will be cleared as you have seen. TImage.Picture.Bitmap is not the internal representation of what the TImage shows on screen for other than bitmaps. > > I also tried Charles Hacker's procedure (in the "How to rotate a png image?" thread further down > (currently) in this forum. Same thing. Image disappears. You must operate on in-memory bitmaps just as Charles Hackers procedure does. Regardless of what file format you have loaded into TImage, you can assign the image to a temporary bitmap like: {code} OrigBmp.Assign(Image1.Picture.Graphic); {code} then rotate into a TempBmp and assign back to TImage: {code} Image1.Picture.Assign(TempBmp); {code} I understand that you are familiar with the rotating algorithm, so I leave it here, unless you need assistance with that. Cheers -- Tom Brunberg firstname.lastname@welho.com
![]() |
0 |
![]() |
look at the comment of Tom below.. You should use image.picture.graphic for your operations. First put the graphic into a memory space and do your manipulations. After you assign the memory back to the TImage.
![]() |
0 |
![]() |
It seems that my problem has nothing to do with rotation, but with accessing the bitmap for Jpeg files (BMP bitmaps give no problems.) I am using XE3 It seems that, for Jpeg files, TPicture.LoadFromFile does not create a recognisable TBitmap When one tries to access the Bitmap, {code}TPicture.GetBitmap{code} is called. The first thing this does is to call {code}ForceType(TBitmap){code} This checks if the graphic created by LoadFromFile is a TBitmap (if a Jpeg image is loaded the class is TJpegImage) Since the check fails, the graphic is cleared by creating a new (empty)Graphic and the image is lost. *So my problem is: How do I access the in-memory jpeg image data?* I see that if the vcl routines are compiled with the *CLR* compiler directive, then a Jpeg image is of class TBitmap *+What is the CLR compiler directive?+* The problem, as I experience it, may be be dependent on the Delphi version. I no longer have earlier versions, so perhaps someone who has an earlier version can try out my code: {code} procedure Form1.Button1Click(Sender: TObject); begin Image1.Picture.LoadFromFile('AnyJpegImage.jpg'); with Image1.Picture do Label1.caption := '('+IntToStr(Width)+'.'+IntToStr(Height)+')'; Image1.Picture.Bitmap; with Image1.Picture do Label2.caption := '('+IntToStr(Width)+'.'+IntToStr(Height)+')'; end; {code} (If Image1.Picture.Bitmap is not a function call in your version you may have to use {code}IntegerVariable := Image1.Picture.Bitmap.Height){code} After this the caption for Label1 {with my test image) is (800,600); while Label2 caption is (0,0); Without the Bitmap reference both captions are the same (800,600). Malcolm
![]() |
0 |
![]() |
Malcolm Coulter wrote: > It seems that my problem has nothing to do with rotation, but with accessing the bitmap for Jpeg > files (BMP bitmaps give no problems.) Correct! > I am using XE3 > > It seems that, for Jpeg files, TPicture.LoadFromFile does not create a recognisable TBitmap Also correct in the sense I told you: "TImage.Picture.Bitmap is not the internal representation of what the TImage shows on screen for other than bitmaps." Emphasis on *not*. > When one tries to access the Bitmap, {code}TPicture.GetBitmap{code} is called. > > The first thing this does is to call {code}ForceType(TBitmap){code} > This checks if the graphic created by LoadFromFile is a TBitmap (if a Jpeg image is loaded the > class is TJpegImage) > > Since the check fails, the graphic is cleared by creating a new (empty)Graphic and the image is > lost. > > *So my problem is: How do I access the in-memory jpeg image data?* You can not acces it directly. If you try by erroneously accessing the TImage.Picture.Bitmap, the jpeg image is cleared. You must copy the jpeg image to a separate bitmap, manipulate that bitmap and then copy it back to the TImage. Rotating can not be done in one bitmap, so you actually need two separate bitmaps: one to hold the original image and one into you build the rotated. Finally you copy the rotated back to the TImage. > I see that if the vcl routines are compiled with the CLR compiler directive, then a Jpeg image is > of class TBitmap *+What is the CLR compiler directive?+* It is for compiling for dot net Common Language Runtime. > The problem, as I experience it, may be be dependent on the Delphi version. I no longer have > earlier versions, so perhaps someone who has an earlier version can try out my code: {code} > procedure Form1.Button1Click(Sender: TObject); > begin > Image1.Picture.LoadFromFile('AnyJpegImage.jpg'); > with Image1.Picture do Label1.caption := '('+IntToStr(Width)+'.'+IntToStr(Height)+')'; > Image1.Picture.Bitmap; > with Image1.Picture do Label2.caption := '('+IntToStr(Width)+'.'+IntToStr(Height)+')'; > end; > {code} > > (If Image1.Picture.Bitmap is not a function call in your version you may have to use > {code}IntegerVariable := Image1.Picture.Bitmap.Height){code} > > After this the caption for Label1 {with my test image) is (800,600); while Label2 caption is > (0,0); Without the Bitmap reference both captions are the same (800,600). Which just prooves what I told you: "Specifically, if you have loaded any other graphic format and attempt to access the Bitmap, the current image will be cleared as you have seen." Once again, here's an outline of what you need to do: {code} //Load the file into TImage. Image1.Picture.LoadFromFile('testfile.jpg'); //Create two temporary bitmaps OrigBmp := TBitmap.Create; RotatedBmp := TBitmap.Create; // Copy the image from TImage to one of the bitmaps OrigBmp.Assign(Image1.Picture.Graphic); // Set the size of the other bitmap swapping width and height RotatedBmp.SetSize(OrigBmp.Height, OrigBmp.Width); // Apply the rotating algorithm by copying pixels // from OrigBmp to RotatedBmp // .... // Copy the Rotated bitmap back to the TImage Image1.Picture.Assign(RotatedBmp); {code} Cheers -- Tom Brunberg firstname.lastname@welho.com
![]() |
0 |
![]() |
I did try assigning the graphic to a bitmap and using it in Charles Hacker's routine. However I got inaccessible values for the scanline elements. Working with a BMP bitmap the scanline values are valid, so it seems something more is needed. Type-casting the graphic to a TJpegImage did no produce anything useful that I could see. A TPNGInage does have scanlines, but I am not interested in PNG for the current purpose. (This was meant to be a reply to Robert - oops) Edited by: Malcolm Coulter on Jun 8, 2013 10:24 AM
![]() |
0 |
![]() |
> {quote:title=Tom Brunberg wrote:}{quote} > Which just prooves what I told you: "Specifically, if you have loaded any other graphic format and > attempt to access the Bitmap, the current image will be cleared as you have seen." > > Once again, here's an outline of what you need to do: > {code} > //Load the file into TImage. > Image1.Picture.LoadFromFile('testfile.jpg'); > //Create two temporary bitmaps > OrigBmp := TBitmap.Create; > RotatedBmp := TBitmap.Create; > // Copy the image from TImage to one of the bitmaps > OrigBmp.Assign(Image1.Picture.Graphic); > // Set the size of the other bitmap swapping width and height > RotatedBmp.SetSize(OrigBmp.Height, OrigBmp.Width); > // Apply the rotating algorithm by copying pixels > // from OrigBmp to RotatedBmp > // .... > // Copy the Rotated bitmap back to the TImage > Image1.Picture.Assign(RotatedBmp); > {code} > Thanks, Tom. That is exactly what I did, but I still get inaccessible values for the elements of the scanline. Malcolm
![]() |
0 |
![]() |
Malcolm Coulter wrote: > > {quote:title=Tom Brunberg wrote:}{quote} > > Which just prooves what I told you: "Specifically, if you have loaded any other graphic format > > and attempt to access the Bitmap, the current image will be cleared as you have seen." > > > > Once again, here's an outline of what you need to do: > > {code} > > //Load the file into TImage. > > Image1.Picture.LoadFromFile('testfile.jpg'); > > //Create two temporary bitmaps > > OrigBmp := TBitmap.Create; > > RotatedBmp := TBitmap.Create; > > // Copy the image from TImage to one of the bitmaps > > OrigBmp.Assign(Image1.Picture.Graphic); > > // Set the size of the other bitmap swapping width and height > > RotatedBmp.SetSize(OrigBmp.Height, OrigBmp.Width); > > // Apply the rotating algorithm by copying pixels > > // from OrigBmp to RotatedBmp > > // .... > > // Copy the Rotated bitmap back to the TImage > > Image1.Picture.Assign(RotatedBmp); > > {code} > > > Thanks, Tom. > > That is exactly what I did, but I still get inaccessible values for the elements of the scanline. Malcolm, OK, here's a testcode I just wrote (in a form with a TImage and two TButtons): {code} implementation uses jpeg; type TRGBPixel = record b: byte; g: byte; r: byte; end; TRGBArray = array[0..65535] of TRGBPixel; PRGBArray = ^TRGBArray; procedure TForm1.Button1Click(Sender: TObject); begin Image1.Picture.LoadFromFile('1sink.jpg'); end; procedure TForm1.Button2Click(Sender: TObject); var bmpA, bmpB: TBitmap; ix, iy: integer; rowIn: pRGBArray; begin bmpA := TBitmap.Create; bmpA.Assign(Image1.Picture.Graphic); bmpA.PixelFormat := pf24bit; bmpB := TBitmap.Create; bmpB.PixelFormat := pf24bit; bmpB.SetSize(bmpA.Height, bmpA.Width); for iy := 0 to bmpA.Height - 1 do begin rowIn := bmpA.ScanLine[iy]; for ix := 0 to bmpA.Width - 1 do pRGBARray(bmpB.ScanLine[ix])[bmpA.Height - iy - 1] := rowIn[ix]; end; Image1.Picture.Assign(bmpB); end; {code} Cheers -- Tom Brunberg firstname.lastname@welho.com
![]() |
0 |
![]() |
Thanks Tom... My problem was that Charles Hacker did not define pRGBArray, and +without thinking+ I took it to be a pointer to an integer/tColor/32bit array!!! Thanks again for all your trouble. Regards... ....Malcolm
![]() |
0 |
![]() |
> {quote:title=Malcolm Coulter wrote:}{quote} > It seems that my problem has nothing to do with rotation, but with accessing the bitmap for Jpeg files (BMP bitmaps give no problems.) > > I am using XE3 > > It seems that, for Jpeg files, TPicture.LoadFromFile does not create a recognisable TBitmap > > When one tries to access the Bitmap, {code}TPicture.GetBitmap{code} is called. > > The first thing this does is to call {code}ForceType(TBitmap){code} > This checks if the graphic created by LoadFromFile is a TBitmap (if a Jpeg image is loaded the class is TJpegImage) > > Since the check fails, the graphic is cleared by creating a new (empty)Graphic and the image is lost. > > *So my problem is: How do I access the in-memory jpeg image data?* > > I see that if the vcl routines are compiled with the *CLR* compiler directive, then a Jpeg image is of class TBitmap > *+What is the CLR compiler directive?+* > > The problem, as I experience it, may be be dependent on the Delphi version. I no longer have earlier versions, so perhaps someone who has an earlier version can try out my code: > {code} > procedure Form1.Button1Click(Sender: TObject); > begin > Image1.Picture.LoadFromFile('AnyJpegImage.jpg'); > with Image1.Picture do Label1.caption := '('+IntToStr(Width)+'.'+IntToStr(Height)+')'; > Image1.Picture.Bitmap; > with Image1.Picture do Label2.caption := '('+IntToStr(Width)+'.'+IntToStr(Height)+')'; > end; > {code} > > (If Image1.Picture.Bitmap is not a function call in your version you may have to use {code}IntegerVariable := Image1.Picture.Bitmap.Height){code} > > After this the caption for Label1 {with my test image) is (800,600); while Label2 caption is (0,0); > Without the Bitmap reference both captions are the same (800,600). > > Malcolm hi, is there anyone doing this with .net? I came across [url=http://www.rasteredge.com/how-to/csharp-imaging/rotate-image/]image rotate component[/url] on web ,is it possible to be integrated into XE3. Any idea? if possible ,Plz let me know how to start. Edited by: John M on Jul 24, 2013 11:50 PM
![]() |
0 |
![]() |
Since you use XE3 why don't you use FireMonkey to do these graphical things? Instead of trying to integrate .NET techniques you could see if you can integrate FireMonkey 2D or 3D in your project. Not sure if that will work for you but I would try it. http://docwiki.embarcadero.com/RADStudio/XE2/en/Using_FireMonkey_Animation_Effects http://stackoverflow.com/questions/7315050/delphi-xe2-possible-to-instantiate-a-firemonkey-form-in-vcl-application
![]() |
0 |
![]() |