2012-08-13 184 views
52

我想用HTML5 Canvas调整客户端iOS摄像头的图像大小,但我一直运行在这个奇怪的错误,其中图像的错误比率大于〜1.5mbHTML5 Canvas drawImage ratio bug iOS

它可以在桌面上运行,但不能在带媒体上传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); 
}); 
+0

我试过1.2M的照片在我的代码和问题是一样的。你可以查看http://orientation.gokercebeci.com – 2012-09-28 12:13:02

+0

我刚刚打过。你相信吗!?! – zaf 2013-05-20 17:05:22

+7

这是在iPhone4下固定在iOS 7下,但有趣的是,这个问题在iOS 7下并没有固定在iPhone5C上,实际上比之前更糟糕。 – 2013-10-09 14:10:25

回答

30

有一个JavaScript画布大小调整库,它围绕遇到iOS装置绘制画布缩放的图像时,子采样和垂直壁球问题的工作原理: http://github.com/stomita/ios-imagefile-megapixel

有调节具有alpha通道图像时侧的问题(因为它使用Alpha通道进行问题检测),并尝试调整现有画布元素的大小时,但是这是我发现的第一个解决方案,实际上可以解决问题。

stomita也是StackOverflow的用户,并张贴在这里他的解决方案: https://stackoverflow.com/a/12615436/644048

+0

创建了我刚刚写的另一个文件上传小部件的在线演示。它可以检测到iOS渲染问题。如果图像看起来没有被正确渲染,则应用修复将重新渲染图像。将高度缩小两倍,似乎也可以解决这个问题... http://sandbox.juurlink.org/html5imageuploader/ – 2013-02-13 20:04:17

+0

我试过stomita的解决方案,它的工作原理。但是,一旦我运行他的库并显示图片,如何访问该画布上下文以进一步对其执行图像处理? – Chaz 2013-05-10 15:56:29

+0

信用和链接+1,gj。 – Xyon 2013-06-24 14:14:49

6

看起来这是一个iOS 6的错误。没有理由让你的代码失控。我有同样的问题,这只是在iOS 6中引入的。似乎他们的二次采样例程给出了错误的高度。我向苹果提交了一个错误报告,你也应该这样做。他们得到的错误报告越多越好。

+1

我向苹果发送了一个错误报告来解决这个壁球问题。 – 2012-10-02 07:37:12

+0

请链接bug。 – 2013-04-23 22:36:46

+1

以下是我提交给苹果的示例:http://evsjupiter.com/canvas.htm – Torchify 2013-04-24 20:12:05

51

如果您仍然需要使用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的伟大工作,你应该在他的工作中信任他。

+1

上述解决方案修复了iOS 7中的垂直压扁问题。我应该注意,此代码基于的megapixel-image.js由于某些原因不起作用与iOS 7,但是这样做。现在,如果我可以找到解决方案问题,我将被设置。 – 2013-10-11 15:26:07

+1

真棒修复。我做了一个函数,将这个修补程序应用于特定的画布实例,以便您可以使用所有现有的canvas 2d上下文drawImage调用。也许这对其他人有用? http://jsfiddle.net/gWY2a/24/ – L0LN1NJ4 2013-11-27 13:30:51

+0

@ L0LN1NJ4我看到你正在重写drawimage函数与你的实现。感谢分享 – 2013-11-27 17:08:17

-1

上述代码的修改版本。

编辑:看到L0LN1NJ4的代码在http://jsfiddle.net/gWY2a/24/ ..想,一个人的好一点......

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 
} 
} 
+0

这不是一个答案,它应该是一个评论。请不要像论坛帖子那样对待答案!阅读StackOverflow规则。 – Soviut 2013-11-28 18:39:07

+0

你说得对。我添加了一些代码。 – Agamemnus 2014-08-10 16:51:41