我遇到使用画布在iOS7中压缩图像的问题。我发现以下帖子似乎正朝着正确的方向发展:
HTML5 Canvas drawImage ratio bug iOS
然而,我不仅仅是绘制图像的简单情况,我还在绘制图像之前旋转和缩放上下文(对于带有EXIF方向数据的缩略图)。代码运行,但我的缩略图中没有图像数据。我猜这与画布旋转和缩放有关。但是,我很难理解为什么当我的挤压系数为1(在没有错误的iOS设备上)缩略图无法正确创建时。
这是我的完整“onload()”代码:
reader.onloadend = function(evt) {
console.log('read file data!');
var tempImg = new Image();
console.log('created new Image');
tempImg.src = evt.target.result;
console.log('set canvas to file');
// alert(this);
tempImg.onload = function() {
console.log('loaded tempImg');
var MAX_WIDTH = 450;
var MAX_HEIGHT = 450;
var tempW = tempImg.width;
var tempH = tempImg.height;
if (tempW > tempH) {
if (tempW > MAX_WIDTH) {
tempH *= MAX_WIDTH / tempW;
tempW = MAX_WIDTH;
}
} else {
if (tempH > MAX_HEIGHT) {
tempW *= MAX_HEIGHT / tempH;
tempH = MAX_HEIGHT;
}
}
var canvas = document.createElement('canvas');
canvas.width = tempW;
canvas.height = tempH;
var ctx = canvas.getContext("2d");
// save the current co-ordinate system
// before we screw with it
ctx.save();
// move to the middle of where we want to draw our image
ctx.translate(tempW/2, tempH/2);
if (exifTags.hasOwnProperty('Orientation')) {
// EXIF FORMAT: 0x0112 Orientation int16u IFD0
// 1 = Horizontal (normal)
// 2 = Mirror horizontal
// 3 = Rotate 180
// 4 = Mirror vertical
// 5 = Mirror horizontal and rotate 270 CW
// 6 = Rotate 90 CW
// 7 = Mirror horizontal and rotate 90 CW
// 8 = Rotate 270 CW
// Working. See: http://creativejs.com/2012/01/day-10-drawing-rotated-images-into-canvas/
if (exifTags.Orientation == 2) {
console.log('orientation: 2 = Mirror horizontal')
// flip context horizontally
// ctx.translate
ctx.scale(-1, 1);
} else if (exifTags.Orientation == 3) {
console.log('orientation: 3 = Rotate 180')
ctx.rotate(180*Math.PI/180);
} else if (exifTags.Orientation == 4) {
console.log('orientation: 4 = Mirror vertical')
// flip context vertically
ctx.scale(1, -1);
} else if (exifTags.Orientation == 5) {
console.log('orientation: Mirror horizontal and rotate 270 CW')
// flip context horizontally
ctx.rotate(270*Math.PI/180);
ctx.scale(-1, 1);
} else if (exifTags.Orientation == 6) {
console.log('orientation: Rotate 90 CW')
ctx.rotate(90*Math.PI/180);
} else if (exifTags.Orientation == 7) {
console.log('orientation: Mirror horizontal and rotate 90 CW')
// flip context horizontally
ctx.rotate(90*Math.PI/180);
ctx.scale(-1, 1);
} else if (exifTags.Orientation == 8) {
console.log('orientation: Rotate 270 CW')
ctx.rotate(270*Math.PI/180);
} else {
console.log('unknown orientation: ' + exifTags.Orientation);
}
}
var myImage = this;
if ($scope.platform == "iOS") {
/* 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);
console.log('ratio: ' + vertSquashRatio);
// 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 );
}
console.log('image to unsquish', myImage);
// draw it up and to the left by half the width
// and height of the image
drawImageIOSFix(ctx, myImage, -tempW/2, -tempH/2, tempW, tempH);
} else {
// draw it up and to the left by half the width
// and height of the image
ctx.drawImage(myImage, -tempW/2, -tempH/2, tempW, tempH);
}
// and restore the co-ords to how they were when we began
ctx.restore();
var dataURL = canvas.toDataURL();
// alert('created image!');
var fileName = undefined;
if ($scope.platform == "iOS") {
// Store only the name for iOS, hard paths are unreliable
var timestamp = new Date().getTime();
fileName = timestamp.toString().concat('t.jpg');
var thumbPath = fileSystem.root.toURL() + "/STL/" + fileName;
var thumbName = "/STL/" + fileName;
} else {
var name = file.name
var position = name.length-4
fileName = name.substr(0, position) + 't.jpg';
var thumbPath = fileSystem.root.toURL() + "/.STL/" + thumbName;
var thumbName = fileName;
}
$scope.mediaCollection.thumbNames.push(thumbName);
$scope.mediaCollection.thumbPaths.push(thumbPath);
$scope.mediaCollection.exifData.push(exifTags);
$scope.mediaCollection.Orientation.push(exifTags.Orientation);
canvas.toBlob(function(blob){
console.log(blob.size + ':' + blob.type);
function newFile(fileEntry){
console.log('created new fileEntry');
fileEntry.createWriter(gotFileWriter, fail);
}
function gotFileWriter(writer) {
console.log('got fileWriter');
writer.seek(0);
// window.location = blobUrl;
writer.write(blob);
console.log('wrote blob!');
writeIfReady();
}
console.log('about to get Directory');
console.log('fileSystem root: ', fileSystem.root, $scope.iOS_FS);
console.log('platform: ', $scope.platform);
// can replace if/else with single request using $scope.STL_dir
if ($scope.platform = "iOS") {
// May need maintenance...
fileSystem.root.getDirectory('STL', {create: true}, function(dirEntry) {
console.log('got directory, about to create thumbnail file: ' + fileName);
dirEntry.getFile(fileName, {create: true, exclusive: true}, newFile, fail);
}, fail);
} else {
fileSystem.root.getDirectory('.STL', {create: true}, function(dirEntry) {
dirEntry.getFile(fileName, {create: true, exclusive: true}, newFile, fail);
}, fail);
}
}, "image/jpg");
}
}