2012-08-13 77 views
52

HTML5 Canvasを使用してクライアント側のiOSカメラから取得した画像のサイズを変更したいのですが、画像サイズが〜1.5mbより大きい場合、この奇妙なバグで実行し続けるHTML5 Canvas drawImage ratioバグiOS

デスクトップ上では動作しますが、最新のiOSバージョンではメディアアップロードAPIで動作しません。

あなたはここでは例を見ることができます: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でそれをチェックすることができます –

+0

私はこれをヒットしました。信じられますか!?! – zaf

+7

これはiOS 7のiPhone4で修正されていますが、興味深いことに、問題はiOS 7のiPhone5Cでは修正されておらず、実際には以前よりもはるかに悪いです。 –

答えて

30

JavaScriptのキャンバスは、サブサンプリングおよびiOSデバイス上のキャンバスにスケーリングされた画像を描画するときに遭遇した垂直スカッシュの問題を回避しますライブラリのサイズを変更あり: http://github.com/stomita/ios-imagefile-megapixel

(それとして、アルファチャンネルで画像を拡大縮小するとき側の問題があります。問題の検出にアルファチャネルを使用します)、既存のキャンバス要素のサイズを変更しようとしているときは、実際に問題が発生している最初の解決策です。

stomitaもStackOverflowのユーザーであり、ここで彼の解決策を掲載:あなたはまだのdrawImage機能の長いバージョンを使用する必要がある場合 https://stackoverflow.com/a/12615436/644048

+0

作成した別のファイルアップロードウィジェットのオンラインデモを作成しました。 iOSのレンダリングの問題を検出できます。イメージが正しくレンダリングされていないように見える場合、イメージは修正が適用された状態で再レンダリングされます。高さスケールを2倍にするとそれも修正されるようです... http://sandbox.juurlink.org/html5imageuploader/ –

+0

私はstomitaのソリューションを試してみました。しかし、ライブラリを実行して画像が表示されたら、画像処理をさらに実行するためにそのキャンバスコンテキストにアクセスするにはどうすればよいですか? – Chaz

+0

クレジットとリンクの場合は+1、gj。 – Xyon

2

私は同じ問題を経験しました。これはiOSの制限だと思われますが、2メガピクセルを超えるjpgがサブサンプリングされています。

が、これはiOSの6のバグであるように見えますCreating Compatible Web Content for Safari on IPhone

6

を参照してください。アスペクトがコードから逃げる理由はありません。私はiOS 6でのみ導入された同じ問題を抱えています。彼らのサブサンプリングルーチンが間違った高さを与えているようです。私はAppleにバグレポートを提出しました。あなたは同じことをする必要があります。より多くのバグ報告が得られます。

+1

このスカッシュ問題のためにAppleにバグ報告を送った。 –

+0

バグにリンクしてください。 –

+1

アップルに提出した例です:http://evsjupiter.com/canvas.htm – Torchify

51

あなたはこれを変更することができます。これに

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でもそうです。今私がオリエンテーションの問題の解決策を見つけることができれば、私は設定されます。 –

+1

素晴らしい修正。私は、この修正を特定のキャンバスインスタンスに適用する関数を作成しました。既存のキャンバス2DコンテキストのdrawImage呼び出しをすべて使用できるようにしました。おそらく、それは他の人にとって役に立つでしょうか? http://jsfiddle.net/gWY2a/24/ – L0LN1NJ4

+0

@ L0LN1NJ4私はあなたの実装でdrawimage関数をオーバーライドしているのを見ています。おかげで残念ながら –

-1

上記のコードの変更されたバージョン。

編集: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 
} 
} 
+0

これは答えではなく、コメントであったはずです。フォーラム投稿のような回答は扱わないでください! StackOverflowルールを読んでください。 – Soviut

+0

あなたは正しいです。代わりにコードを追加しました。 – Agamemnus