HTML5 Canvas drawImage 比例bug iOS
Posted
技术标签:
【中文标题】HTML5 Canvas drawImage 比例bug iOS【英文标题】:HTML5 Canvas drawImage ratio bug iOS 【发布时间】:2012-08-09 09:00:13 【问题描述】:我想使用 html5 Canvas 调整从客户端的 ios 相机拍摄的图像的大小,但我一直在这个奇怪的错误中运行,如果图像大于 ~1.5mb,则图像的比例错误
它适用于桌面,但不适用于带有媒体上传 API 的最新 iOS 版本。
您可以在此处查看示例:http://jsbin.com/ekuros/1
知道如何解决这个问题吗?这是内存问题吗?
$('#file').on('change', function (e)
var file = e.currentTarget.files[0];
var reader = new FileReader();
reader.onload = function (e)
var image = $('<img/>');
image.on('load', function ()
var square = 320;
var canvas = document.createElement('canvas');
canvas.width = square;
canvas.height = square;
var context = canvas.getContext('2d');
context.clearRect(0, 0, square, square);
var imageWidth;
var imageHeight;
var offsetX = 0;
var offsetY = 0;
if (this.width > this.height)
imageWidth = Math.round(square * this.width / this.height);
imageHeight = square;
offsetX = - Math.round((imageWidth - square) / 2);
else
imageHeight = Math.round(square * this.height / this.width);
imageWidth = square;
offsetY = - Math.round((imageHeight - square) / 2);
context.drawImage(this, offsetX, offsetY, imageWidth, imageHeight);
var data = canvas.toDataURL('image/jpeg');
var thumb = $('<img/>');
thumb.attr('src', data);
$('body').append(thumb);
);
image.attr('src', e.target.result);
;
reader.readAsDataURL(file);
);
【问题讨论】:
我已经在我的代码上尝试了 120 万张照片,但问题是一样的。你可以在orientation.gokercebeci.com查看它 我刚刚打了这个。你能相信吗!?! 这在 iOS 7 下的 iPhone4 上已修复,但有趣的是,该问题在 iOS 7 下的 iPhone5C 上并未修复,实际上比以前更糟。 有谁知道这个bug是否在iOS8中仍然存在? 直到今天仍然如此吗? 【参考方案1】:上述代码的修改版本。
编辑:在http://jsfiddle.net/gWY2a/24/ 看到 L0LN1NJ4 的代码 .. 猜猜那个更好一点...
function drawImageIOSFix (ctx, img)
var vertSquashRatio = detectVerticalSquash (img)
var arg_count = arguments.length
switch (arg_count)
case 4 : ctx.drawImage (img, arguments[2], arguments[3] / vertSquashRatio); break
case 6 : ctx.drawImage (img, arguments[2], arguments[3], arguments[4], arguments[5] / vertSquashRatio); break
case 8 : ctx.drawImage (img, arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7] / vertSquashRatio); break
case 10 : ctx.drawImage (img, arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9] / vertSquashRatio); break
// Detects vertical squash in loaded image.
// Fixes a bug which squash image vertically while drawing into canvas for some images.
// This is a bug in iOS6 (and IOS7) devices. This function from https://github.com/stomita/ios-imagefile-megapixel
function detectVerticalSquash (img)
var iw = img.naturalWidth, ih = img.naturalHeight
var canvas = document.createElement ("canvas")
canvas.width = 1
canvas.height = ih
var ctx = canvas.getContext('2d')
ctx.drawImage (img, 0, 0)
var data = ctx.getImageData(0, 0, 1, ih).data
// search image edge pixel position in case it is squashed vertically.
var sy = 0, ey = ih, py = ih
while (py > sy)
var alpha = data[(py - 1) * 4 + 3]
if (alpha === 0) ey = py else sy = py
py = (ey + sy) >> 1
var ratio = (py / ih)
return (ratio === 0) ? 1 : ratio
【讨论】:
这不是答案,应该是评论。请不要将答案视为论坛帖子!阅读 *** 规则。【参考方案2】:如果你还需要使用drawImage函数的长版本,你可以改变这个:
context.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh);
到这里:
drawImageIOSFix(context, img, sx, sy, sw, sh, dx, dy, dw, dh);
你只需要在某处包含这两个函数:
/**
* Detecting vertical squash in loaded image.
* Fixes a bug which squash image vertically while drawing into canvas for some images.
* This is a bug in iOS6 devices. This function from https://github.com/stomita/ios-imagefile-megapixel
*
*/
function detectVerticalSquash(img)
var iw = img.naturalWidth, ih = img.naturalHeight;
var canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = ih;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
var data = ctx.getImageData(0, 0, 1, ih).data;
// search image edge pixel position in case it is squashed vertically.
var sy = 0;
var ey = ih;
var py = ih;
while (py > sy)
var alpha = data[(py - 1) * 4 + 3];
if (alpha === 0)
ey = py;
else
sy = py;
py = (ey + sy) >> 1;
var ratio = (py / ih);
return (ratio===0)?1:ratio;
/**
* A replacement for context.drawImage
* (args are for source and destination).
*/
function drawImageIOSFix(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh)
var vertSquashRatio = detectVerticalSquash(img);
// Works only if whole image is displayed:
// ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio);
// The following works correct also when only a part of the image is displayed:
ctx.drawImage(img, sx * vertSquashRatio, sy * vertSquashRatio,
sw * vertSquashRatio, sh * vertSquashRatio,
dx, dy, dw, dh );
无论是在 iOS 还是其他平台上运行,都可以正常工作。
这是基于stomita 的出色工作,您应该感谢他的工作。
【讨论】:
上述解决方案修复了 iOS 7 中的垂直挤压问题。我应该注意,此代码所基于的 megapixel-image.js 出于某种原因不适用于 iOS 7,但确实如此。现在,如果我能找到方向问题的解决方案,我将被设置。 很棒的修复。我制作了一个函数,将此修复应用于特定的画布实例,您可以使用所有现有的画布 2d 上下文 drawImage 调用。也许它对其他人有用? jsfiddle.net/gWY2a/24 @L0LN1NJ4 我看到你正在用你的实现覆盖 drawimage 函数。感谢分享 不幸的是,该修复不适用于绘制远程图像,因为这会引发 getImageData 调用的安全错误 搞砸了 android 4.x :/【参考方案3】:有一个 javascript 画布调整大小库,可以解决在 iOS 设备上的画布上绘制缩放图像时遇到的二次采样和垂直挤压问题: http://github.com/stomita/ios-imagefile-megapixel
使用 alpha 通道缩放图像(因为它使用 alpha 通道进行问题检测)以及尝试调整现有画布元素的大小时存在一些副作用,但这是我发现的第一个实际适用于该问题的解决方案手。
stomita 也是 *** 用户,并在此处发布了他的解决方案: https://***.com/a/12615436/644048
【讨论】:
创建了我刚刚编写的另一个文件上传小部件的在线演示。它可以检测 iOS 渲染问题。如果图像似乎未正确渲染,则应用修复程序重新渲染图像。将高度比例加倍似乎也可以解决它...sandbox.juurlink.org/html5imageuploader 我尝试了 stomita 的解决方案,它有效。但是,一旦我运行他的库并显示图片,我如何访问该画布上下文以进一步对其进行图像处理? 我刚刚在运行 iOS 7 的新 iPhone 5C 上测试了 megapix-image.js,但无法转换图像。它似乎与 iPhone 5 和/或 iOS 7 不兼容。【参考方案4】:看起来这是一个 iOS 6 错误。方面没有理由从您的代码中脱离出来。我有同样的问题,它只在 iOS 6 中引入。似乎他们的子采样例程给出了错误的高度。我向 Apple 提交了错误报告,您也应该这样做。他们为此获得的错误报告越多越好。
【讨论】:
我就这个壁球问题向 Apple 发送了错误报告。【参考方案5】:我也遇到过同样的问题。看来这是 iOS 的限制,超过 2 兆像素的 jpg 会被二次采样。
见Creating Compatible Web Content for Safari on IPhone
【讨论】:
以上是关于HTML5 Canvas drawImage 比例bug iOS的主要内容,如果未能解决你的问题,请参考以下文章
[js高手之路] html5 canvas系列教程 - 图片操作(drawImage,clip,createPattern)
为啥HTML5canvas中drawImage()第一次加载只出现最后一个图,刷新就出现问题?
来自视频的 HTML5 Canvas drawImage 在第一次绘制时未显示
HTML5 Canvas DrawImage Safari 12.0 错误(在 iOS 12.1/Mac OS Mojave 上测试)