【问题标题】:Why do images lose quality after the context has been rotated?为什么旋转上下文后图像质量会下降?
【发布时间】:2012-07-06 08:05:03
【问题描述】:

我正在制作一个自上而下的射击游戏,它依赖于始终旋转指向鼠标光标的头像。我实现了这样的旋转:

//Rendering.
context.save(); //Save the context state, we're about to change it a lot.

context.translate(position[0] + picture.width/2, position[1] + picture.height/2); //Translate the context to the center of the image.
context.rotate(phi); //Rotate the context by the object's phi.
context.drawImage(picture.image, -picture.width/2, -picture.height/2); //Draw the image at the appropriate position (center of the image = [0, 0]).

context.restore(); //Get the state back.

phi 为零时,图像以其正常质量呈现,具有锐利的边缘和可检测的像素。但是,当我将phi 设置为非零值时(实际上,当它不是0Pi/2PiPi+Pi/22Pi)时,图像会失去它的清晰度,并且单个像素可以再也看不到了,因为它们已经模糊了。

这是一个屏幕截图(很抱歉屏幕截图的质量很差,但我认为差异非常明显):

这有点不可接受。我不能让图像总是模糊不清! 为什么会发生这种情况,我可以解决吗?

【问题讨论】:

  • 想想原始像素需要如何与图像的旋转版本对齐..它们与像素网格不匹配 - 那么应该发生什么..?
  • 为什么非 HTML5 游戏不会出​​现这种情况?今天晚些时候我在玩Dragon Fly,旋转小龙没有问题!
  • 我相信它是用 Java 编写的,但是是的,谢谢你提醒我,@Daedalus,这在 Flash 游戏中也不会发生。所以我猜它一定是特定于 HTML5 的东西。如果其他游戏可以适合我显示器的像素网格,而且看起来不模糊,那可能是软件问题。
  • 您确定它是正在旋转的单个图像吗?一种方法是绘制多张图像并在正确的时间使用它们 - 这样您就可以直接控制任何抗锯齿。
  • 在缩放或旋转时减少质量损失的一个选项是使用矢量图形 - 参考这个问题:stackoverflow.com/questions/4340040/…

标签: javascript image canvas browser


【解决方案1】:

(picture.width/2, picture.height/2) 点并不总是有效。

(Math.floor(picture.width/2) + 0.5, Math.floor(picture.height/2) + 0.5) 应该会有所帮助。

【讨论】:

  • 这仅适用于线条,对于图像则完全相反 - 始终使用整数。
【解决方案2】:

你可以试试

context.imageSmoothingEnabled = false;

docs:

context.imageSmoothingEnabled [ = value ]

返回是否填充图案,并且 drawImage() 方法将在必须重新缩放图像时尝试平滑图像(而不是仅使用“大像素”渲染图像)。

可以设置,改变图像是否平滑(true)或不平滑(false)。

如果您想要一个真正的像素艺术复古风格效果,您需要手动创建多个角度的旋转精灵图像,为phi 的当前值查找适当的精灵,然后在不旋转的情况下绘制它。这显然需要大量的艺术作品!

【讨论】:

  • +1 用于手动创建。对于游戏的主要元素来说,这几乎是不可避免的。
【解决方案3】:

如果您要围绕中心点旋转图像,请确保图像本身具有偶数像素。一旦你最终得到奇坐标,就需要为目标画布插入图像数据。苹果有一些不错的documentation on translating and rotating the canvas

因此,对于任何图像,如上所述,使用舍入捕捉到完整像素。

context.translate(Math.floor(img.width/2), Math.floor(img.height/2));

这样,图像的每个源像素将始终精确地绘制到画布内的像素中,并且不会发生模糊。然而,这只适用于 90 度的倍数。

似乎所有浏览器在某种程度上都会在图像绘制中进行抗锯齿处理,因此您可能必须提供旋转图像作为精灵。

根据Chromium bug report,如果他们还没有修复它,你可能会很幸运。通读一遍,您会发现 Ian Hickson 可能反对将抗锯齿图像绘制设为可选。

【讨论】:

  • 但这仅适用于 90 度的倍数。 是的,这是一个大问题......
  • 是的,这似乎是一个众所周知的问题,Chromium 团队自 2009 年以来一直在讨论。我已经相应地更新了我的答案。
  • 您的 Apple 链接似乎已损坏。
【解决方案4】:

嗯,实际上这是你无法绕过的事情

如果您将图像旋转 90 度的倍数,您的库应该足够智能,不会应用插值。

但是,一旦您将图像旋转了一个不同于 90 度的倍数的角度,您就需要进行插值。结果,你得到了平滑。如果你对理论感兴趣,可以找一本关于计算机图形学或图像处理的书。

对于图像旋转的具体情况,你可以看看这篇论文, http://bigwww.epfl.ch/publications/unser9502.html

【讨论】:

  • 我很确定你可以绕过它。也许不使用画布,而是使用 C++,但这绝对是可能的。即,不要应用任何插值,只是把所有东西都画得有点粗糙。也许这些的混合是最好的......另外,如果你提供一些指向上述文献的链接,那就太好了。
  • @Bane 把所有东西画得粗糙怎么能成为解决方案?结果会遗漏您放入原始图像的所有小像素细节。此外,如果您将粗略的绘图与插值混合,结果仍然是模糊的(和粗略的)。我还没有找到将 c++ 集成到 javascript 中的方法,但当然可以将 c++ 代码转换为 javascript 代码。仍然没有真正的方法可以在不丢失 C++ 中的像素的情况下旋转任意光栅图像。使用基于矢量的图像会容易得多。
  • 好吧,我说你不能绕过它,因为旋转时你需要插值。这些是插值伪影。它与特定的编程语言无关。这是数学
猜你喜欢
  • 2021-02-07
  • 2017-05-06
  • 1970-01-01
  • 1970-01-01
  • 2019-08-04
  • 1970-01-01
  • 2015-07-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多