HTML5 Canvasを使用して、クライアント側の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);
});
JavaScriptキャンバスサイズ変更ライブラリがあり、iOSデバイスでキャンバス上にスケーリングされた画像を描画するときに発生するサブサンプリングと垂直スカッシュの問題を回避します。 http://github.com/stomita/ios-imagefile-megapixel
(問題検出にアルファチャネルを使用するため)アルファチャネルを使用して画像をスケーリングする場合、および既存のキャンバス要素のサイズを変更しようとする場合、副次的な問題がありますが、実際に当面の問題で動作することがわかった最初のソリューションです。
stomitaはStackOverflowユーザーでもあり、彼のソリューションをここに投稿しました: https://stackoverflow.com/a/12615436/644048
まだ長いバージョンのdrawImage関数を使用する必要がある場合は、これを変更できます。
context.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh);
これに:
drawImageIOSFix(context, img, sx, sy, sw, sh, dx, dy, dw, dh);
これらの2つの関数をどこかに含める必要があります。
/**
* 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 6のバグのようです。アスペクトがコードから強打から抜け出す理由はありません。 iOS 6でのみ導入された同じ問題があります。サブサンプリングルーチンの高さが間違っているようです。バグレポートをアップルに提出しましたが、同じことをする必要があります。バグレポートが多いほど、より良い結果が得られます。
同じ問題が発生しました。これはiOSの制限のようです。2メガピクセルを超えるjpgはサブサンプリングされます。
IPhoneでのSafariの互換性のあるWebコンテンツの作成 を参照してください