1

I built this example to quickly rotate images 90 degrees but I always get a cut of the image on the sides. After many tests, unfortunately I still don't understand the cause of the problem.

void rotate()
{
    Graphics::TBitmap *SrcBitmap = new Graphics::TBitmap;
    Graphics::TBitmap *DestBitmap = new Graphics::TBitmap;
    
    SrcBitmap->LoadFromFile("Crayon.bmp");
    
    DestBitmap->Width=SrcBitmap->Width;
    DestBitmap->Height=SrcBitmap->Height;

    SetGraphicsMode(DestBitmap->Canvas->Handle, GM_ADVANCED);
    
    double myangle = (double)(90.0 / 180.0) * 3.1415926;
    int x0=SrcBitmap->Width/2;
    int y0=SrcBitmap->Height/2; 
    double cx=x0 - cos(myangle)*x0 + sin(myangle)*y0;
    double cy=y0 - cos(myangle)*y0 - sin(myangle)*x0;
    
    xForm.eM11 = (FLOAT) cos(myangle);
    xForm.eM12 = (FLOAT) sin(myangle);
    xForm.eM21 = (FLOAT) -sin(myangle);
    xForm.eM22 = (FLOAT) cos(myangle);
    xForm.eDx  = (FLOAT) cx;
    xForm.eDy  = (FLOAT) cy;

    SetWorldTransform(DestBitmap->Canvas->Handle, &xForm);  
    
    BitBlt(DestBitmap->Canvas->Handle,
    0,
    0,
    SrcBitmap->Width,
    SrcBitmap->Height,
    SrcBitmap->Canvas->Handle,
    0,
    0,
    SRCCOPY);
    
    DestBitmap->SaveToFile("Crayon2.bmp");
    
    delete DestBitmap;
    delete SrcBitmap;
}   
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
David
  • 39
  • 2
  • 6
  • 1
    rotated rectangle has bigger AABB as you set your destination bitmap to the same size as source it logically can not fit and its cut of. You have to set the destination bitmap size to square with size equal to diameter of outscribed circle to the original bitmap (diagonal size) so `a = sqrt(width^2 + height^2)` – Spektre Oct 13 '21 at 07:15
  • thanks, I also tried this suggestion but: for an image of 400x3000 pixels, if I set it, exaggerating: DestBitmap-> Width = 6000; DestBitmap-> Height = 6000; I get an image of 6000x6000 pixels but the "useful" area of the image becomes 3500x3000 pixels. In practice, the width of the image is compressed by 500 pixels and the image appears squashed. – David Oct 13 '21 at 09:30
  • 1
    *"I always get a cut of the image on the sides"* This is hard to understand. You can demonstrate the problem with an image. You are not changing width/height, so it's excepted that the image will be cropped. – Barmak Shemirani Oct 13 '21 at 16:52
  • after rotation: [link](https://ibb.co/yy74zkz) – David Oct 13 '21 at 17:26
  • before rotation: [link](https://ibb.co/2ZLMmdW) after rotation: [link](https://ibb.co/yy74zkz) – David Oct 13 '21 at 17:33

2 Answers2

2

If rotating the whole image, the width and height for destination image should be flipped:

DestBitmap->Width = SrcBitmap->Height;
DestBitmap->Height = SrcBitmap->Width;

The transform routine was centering the image based on original width/height. We want to adjust x/y position to push the starting point to left/top for BitBlt

int offset = (SrcBitmap->Width - SrcBitmap->Height) / 2;
BitBlt(DestBitmap->Canvas->Handle, offset, offset, SrcBitmap->Width, SrcBitmap->Height,
    SrcBitmap->Canvas->Handle, 0, 0, SRCCOPY);
Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
1

Once I had a similar problem. I'm wanted to rotate two images around a common rotation point. But I couldn't do it with the standard function, because it doesn't allow a rotation point decentralized to the center. Nevertheless I had made notes to the standard function at that time. Maybe they help you. I'm remember that it was important that the size of the target image is correct! If a portrait image becomes a landscape image, the image becomes wider, therefore the BitBlt function must also specify the size of the target image.

Here my note to standard function. Filling the xForm parameters was not quite the same for me as in your code snippet.

enter image description here


This was then the function I used to rotate around any center.

enter image description here

LuPiMexx
  • 37
  • 6
  • 4
    Please add code and data as text ([using code formatting](//stackoverflow.com/editing-help#code)), not images. Images: A) don't allow us to copy-&-paste the code/errors/data for testing; B) don't permit searching based on the code/error/data contents; and [many more reasons](//meta.stackoverflow.com/a/285557). Images should only be used, in addition to text in code format, if having the image adds something significant that is not conveyed by just the text code/error/data. – Adrian Mole Oct 13 '21 at 08:39
  • 1
    see https://stackoverflow.com/a/44299929/2521214 which is more or less the same as your answer and check how the formatting is done... You can see markdown code in edit history ... code is intended by 4 spaces and or by selecting it and hit the code button in editor, you can specify syntax highlight by adding `` before your code block. Images are links references with `!` before it for example `![image name](https://i.stack.imgur.com/L3VWh.png)` – Spektre Oct 13 '21 at 08:52
  • I tried your method but it's too slow. 5 seconds to rotate a 4000x3000 pixels image. Using the windows API instead, as shown in my code, in the best case it can even reach 80 ms to rotate the same image. – David Oct 13 '21 at 09:45
  • 1
    @David using `Pixels[x][y]` is 1000-100000x times slower than direct pixel access try to use `ScanLine[y]` instead (if used properly you obtain great speed up) see the linked answer in my previous comment – Spektre Oct 13 '21 at 13:33
  • @Spektre I also tried Scanline, but it takes at least 1 second to rotate an image. – David Oct 13 '21 at 16:37
  • 1
    @David that seems too slow did you read the `ScanLines[]` ahead into your own array (so you used it only once per each row of each bitmap) ? if not then that is the reason for slowness as `ScanLine` is similarly slow to `Pixels` The difference is you can use it to read ahead into your own array of row pointers and then use the pointers instead which is lighting fast. However big resolution still require a lot of operations. Another thing I hope you precomputes the `sin` and `cos` values before for loops ... In case your rotated image always fit you can remove the clipping `if` – Spektre Oct 14 '21 at 06:29