【问题标题】:How to flip an image with the HTML5 canvas without scaling如何在不缩放的情况下使用 HTML5 画布翻转图像
【发布时间】:2015-05-28 00:57:43
【问题描述】:

我使用 HTML5 画布元素在 Web 应用程序中显示图像,我想水平翻转图像而不对画布应用缩放变换。这意味着我不想为此使用CanvasRenderingContext2D.scale(),因为我不想翻转其他任何东西。

// I don't want this, because it breaks the rest of the application. I have
// implemented zooming and landmark placement functionality, which no longer
// work properly after scaling.
ctx.save();
ctx.scale(-1, 1);
ctx.drawImage(image, -image.width, 0, image.width, image.height);
ctx.restore();

在我看来,我应该能够使用 CanvasRenderingContext2D.drawImage() 方法来做到这一点,因为该页面显示:

sWidth:要绘制到目标上下文中的源图像的子矩形的宽度。如果未指定,则使用从 sx 和 sy 指定的坐标到图像右下角的整个矩形。 如果指定负值,则在绘制时图像会水平翻转。

这就是我绘制图像的方式:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var image = document.getElementById('source');
ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, image.width, image.height);

这里的工作示例:https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage#Using_the_drawImage_method

但如果我尝试按照描述翻转图像,我会在 Firefox 中收到以下错误:

ctx.drawImage(image, 0, 0, -image.width, image.height, 0, 0, image.width, image.height);

IndexSizeError:索引或大小为负数或大于允许的值 金额

我不明白我在这里做错了什么。如何在不缩放画布的情况下水平翻转图像?

【问题讨论】:

  • 我第一次使用scale()restore() 测试时犯了一个错误。这实际上工作正常。
  • 我更新了 drawImage() 的 Mozilla 页面,因为规范中没有提到使用负值翻转图像。

标签: html canvas drawimage


【解决方案1】:

一个相当简单的解决方案是使用第二个画布,在那里只绘制一次翻转的图像,然后将另一个画布的那部分绘制到您的主画布上。这将成功地创建图像的翻转版本,缓存,您可以在任何您想要的地方绘制它。

【讨论】:

  • 支持好答案。为了清楚起见……您的第二个画布可以作为主画布的图像源——无需转换为图像。 mainContext.drawImage( flippingCanvas,125,50).
  • 感谢您的快速回答,埃里克!您的方法有效,但它在我的特定应用程序中带来了其他复杂性(不是您的错;仍然放弃投票)。 Ken 的第一个方法最容易实现,并且在我的应用程序中没有副作用。
  • 代码示例?我想看看这两个画布是如何实现的。至少,以你会做的方式。
【解决方案2】:

似乎不支持负区域(还没有?),或this line may affect how the implementation is done, ref. step 4

图像数据必须按原方向处理,即使 给定的尺寸是负数。

无论如何,我们对此无能为力,只能寻找替代方法 -

这给你留下了一些选择 - 我假设你想避免使用保存/恢复,你可以 -

重置转换

这是最快的方法,但您需要注意它会重置任何转换。在大多数情况下这可能没问题,所以:

ctx.scale(-1, 1);
ctx.drawImage(image, -image.width, 0);
ctx.setTransform(1, 0, 0, 1, 0, 0);

最后一次调用是使用单位矩阵重置变换矩阵。

反转上次的转换操作

如果您依赖于其他转换,您可以简单地反转最后一次转换操作。这是第二快的选项(它需要在内部进行矩阵乘法):

ctx.scale(-1, 1);
ctx.drawImage(image, -image.width, 0);
ctx.scale(-1, 1);   // revert scale only

使用保存/恢复

正如您已经知道的那样......但速度很慢,因为它保存和恢复画布的整个状态,而不仅仅是转换。

手动翻转

如果出于某种原因要求根本不使用转换,您可以随时逐个扫描线翻转它。这是效率第二低的方法,但允许您在不进行转换的情况下工作,并且确实允许您执行其他操作,例如置换:

for(var x = 0; x < width; x++)
    ctx.drawImage(img, x, 0, 1, height, width - x, 0, 1, height);

(宽度和高度是图像的宽度和高度)。

像素操作

最后,只是为了记录,当然是获取像素数据并循环,切换位置等。这是最慢的方法,它取决于CORS要求,不推荐这样做。

【讨论】:

  • 感谢您的详尽回答,肯!我选择了你的第一种方法。事实证明,缩放毕竟可以正常工作,只要您事后重置转换(我第一次使用scale()restore() 测试时犯了一个错误)。看来您对负面区域的看法是正确的;在现行的 HTML 标准中没有提到它。该 Mozilla 页面需要更新。
猜你喜欢
  • 2016-04-12
  • 1970-01-01
  • 1970-01-01
  • 2022-12-05
  • 1970-01-01
  • 2021-09-02
  • 2010-10-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多