我使用HTML5 canvas元素在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);
但是如果我尝试按照描述翻转图像,我在Firefox中会出现以下错误:
ctx.drawImage(image, 0, 0, -image.width, image.height, 0, 0, image.width, image.height);
IndexSizeError:索引或大小为负数或大于允许值 量
我不明白我在这里做错了什么。如何在不缩放画布的情况下水平翻转图像?
答案 0 :(得分:4)
一个相当简单的解决方案是使用第二个画布,将图像仅翻转一次,然后将另一个画布的那部分绘制到主画布上。这将成功创建图像的翻转版本,缓存,您可以在任何地方绘制它。
答案 1 :(得分:3)
似乎不支持负区域(还是?),或 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要求,不建议用于此。