【问题标题】:Rotating an image using Borland C++ Builder and Windows API functions使用 Borland C++ Builder 和 Windows API 函数旋转图像
【发布时间】:2021-12-01 15:28:59
【问题描述】:

我构建了这个示例来快速将图像旋转 90 度,但我总是在侧面切掉图像。经过多次测试,不幸的是我仍然不明白问题的原因。

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;
}   

【问题讨论】:

  • 旋转矩形具有更大的 AABB,因为您将目标位图设置为与逻辑上无法容纳的源相同大小并且它的剪切。您必须将目标位图大小设置为正方形,大小等于原始位图外接圆的直径(对角线大小),所以a = sqrt(width^2 + height^2)
  • 谢谢,我也尝试过这个建议,但是:对于 400x3000 像素的图像,如果我设置它,会夸大:DestBitmap-> Width = 6000;目标位图-> 高度 = 6000;我得到一张 6000x6000 像素的图像,但图像的“有用”区域变为 3500x3000 像素。在实践中,图像的宽度被压缩了 500 像素,图像看起来被压扁了。
  • “我总是在侧面剪掉图像” 这很难理解。你可以用一张图片来证明这个问题。你没有改变宽度/高度,所以除了图像会被裁剪。
  • 旋转后:link
  • 旋转前:link 旋转后:link

标签: c++ windows c++builder


【解决方案1】:

如果旋转整个图像,目标图像的宽度和高度应该翻转:

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

变换例程根据原始宽度/高度使图像居中。我们想调整 x/y 位置以将 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
【解决方案2】:

曾经我遇到过类似的问题。 我想围绕一个共同的旋转点旋转两个图像。但是我不能用标准函数来做,因为它不允许旋转点分散到中心。 尽管如此,我当时已经对标准功能做了笔记。也许他们会帮助你。 我记得目标图像的大小正确很重要!如果纵向图像变成横向图像,图像会变宽,因此 BitBlt 函数还必须指定目标图像的大小。

这是我对标准函数的注释。 填充 xForm 参数对我来说和在你的代码 sn-p 中不太一样。


这就是我用来绕任何中心旋转的功能。

【讨论】:

  • 请将代码和数据添加为文本 (using code formatting),而不是图像。图片:A)不允许我们复制粘贴代码/错误/数据进行测试; B) 不允许根据代码/错误/数据内容进行搜索;和many more reasons。除了代码格式的文本之外,只有在图像添加了一些重要的东西,而不仅仅是文本代码/错误/数据传达的内容时,才应该使用图像。
  • 请参阅stackoverflow.com/a/44299929/2521214,这与您的答案或多或少相同,并检查格式化是如何完成的...您可以在编辑历史记录中看到降价代码...代码由 4 个空格和或者通过选择它并点击编辑器中的代码按钮,您可以通过在代码块之前添加<!-- language: cpp --> 来指定语法高亮。图片是前面带有! 的链接引用,例如![image name](https://i.stack.imgur.com/L3VWh.png)
  • 我试过你的方法,但是太慢了。 5 秒旋转 4000x3000 像素的图像。使用 windows API 代替,如我的代码所示,在最好的情况下,它甚至可以达到 80 毫秒来旋转相同的图像。
  • @David 使用 Pixels[x][y] 比直接像素访问慢 1000-100000 倍尝试使用 ScanLine[y] 代替(如果使用得当,您将获得很大的速度)请参阅我之前评论中的链接答案
  • @Spektre 我也试过 Scanline,但旋转图像至少需要 1 秒。
猜你喜欢
  • 2012-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多