몇 년 전에이 문제를 해결하고 https://github.com/rossturner/HTML5-ImageUploader 로 솔루션을 github에 업로드했습니다.
robertc의 답변은 Mozilla Hacks 블로그 게시물 에서 제안한 솔루션을 사용 하지만 2 : 1 (또는 그 배수)이 아닌 스케일로 크기를 조정할 때 이미지 품질이 실제로 좋지 않은 것으로 나타났습니다. 다른 이미지 크기 조정 알고리즘을 실험하기 시작했지만 대부분 속도가 느리거나 품질이 좋지 않았습니다.
마지막으로 x를 목표로 2 : 1 비율로 이미지 품질을 잃지 않고 1 캔버스에서 다른 캔버스로 복사하는 Mozilla 솔루션이 신속하게 작동하기 때문에 신속하게 실행되고 성능이 매우 좋은 솔루션을 생각해 냈습니다. 너비와 너비가 y 픽셀 인 경우 이미지가 x 와 2 x 사이 , y 와 2 y 사이가 될 때까지이 캔버스 크기 조정 방법을 사용합니다 . 이 시점에서 목표 크기로 크기를 조정하는 최종 "단계"에 대한 알고리즘 이미지 크기 조정으로 돌아갑니다. 몇 가지 다른 알고리즘을 시도한 후 더 이상 온라인이 아니지만 인터넷 아카이브를 통해 액세스 할 수 있는 블로그에서 가져온 이중 선형 보간에 정착했습니다.좋은 결과를 제공합니다. 적용 가능한 코드는 다음과 같습니다.
ImageUploader.prototype.scaleImage = function(img, completionCallback) {
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0, canvas.width, canvas.height);
while (canvas.width >= (2 * this.config.maxWidth)) {
canvas = this.getHalfScaleCanvas(canvas);
}
if (canvas.width > this.config.maxWidth) {
canvas = this.scaleCanvasWithAlgorithm(canvas);
}
var imageData = canvas.toDataURL('image/jpeg', this.config.quality);
this.performUpload(imageData, completionCallback);
};
ImageUploader.prototype.scaleCanvasWithAlgorithm = function(canvas) {
var scaledCanvas = document.createElement('canvas');
var scale = this.config.maxWidth / canvas.width;
scaledCanvas.width = canvas.width * scale;
scaledCanvas.height = canvas.height * scale;
var srcImgData = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
var destImgData = scaledCanvas.getContext('2d').createImageData(scaledCanvas.width, scaledCanvas.height);
this.applyBilinearInterpolation(srcImgData, destImgData, scale);
scaledCanvas.getContext('2d').putImageData(destImgData, 0, 0);
return scaledCanvas;
};
ImageUploader.prototype.getHalfScaleCanvas = function(canvas) {
var halfCanvas = document.createElement('canvas');
halfCanvas.width = canvas.width / 2;
halfCanvas.height = canvas.height / 2;
halfCanvas.getContext('2d').drawImage(canvas, 0, 0, halfCanvas.width, halfCanvas.height);
return halfCanvas;
};
ImageUploader.prototype.applyBilinearInterpolation = function(srcCanvasData, destCanvasData, scale) {
function inner(f00, f10, f01, f11, x, y) {
var un_x = 1.0 - x;
var un_y = 1.0 - y;
return (f00 * un_x * un_y + f10 * x * un_y + f01 * un_x * y + f11 * x * y);
}
var i, j;
var iyv, iy0, iy1, ixv, ix0, ix1;
var idxD, idxS00, idxS10, idxS01, idxS11;
var dx, dy;
var r, g, b, a;
for (i = 0; i < destCanvasData.height; ++i) {
iyv = i / scale;
iy0 = Math.floor(iyv);
// Math.ceil can go over bounds
iy1 = (Math.ceil(iyv) > (srcCanvasData.height - 1) ? (srcCanvasData.height - 1) : Math.ceil(iyv));
for (j = 0; j < destCanvasData.width; ++j) {
ixv = j / scale;
ix0 = Math.floor(ixv);
// Math.ceil can go over bounds
ix1 = (Math.ceil(ixv) > (srcCanvasData.width - 1) ? (srcCanvasData.width - 1) : Math.ceil(ixv));
idxD = (j + destCanvasData.width * i) * 4;
// matrix to vector indices
idxS00 = (ix0 + srcCanvasData.width * iy0) * 4;
idxS10 = (ix1 + srcCanvasData.width * iy0) * 4;
idxS01 = (ix0 + srcCanvasData.width * iy1) * 4;
idxS11 = (ix1 + srcCanvasData.width * iy1) * 4;
// overall coordinates to unit square
dx = ixv - ix0;
dy = iyv - iy0;
// I let the r, g, b, a on purpose for debugging
r = inner(srcCanvasData.data[idxS00], srcCanvasData.data[idxS10], srcCanvasData.data[idxS01], srcCanvasData.data[idxS11], dx, dy);
destCanvasData.data[idxD] = r;
g = inner(srcCanvasData.data[idxS00 + 1], srcCanvasData.data[idxS10 + 1], srcCanvasData.data[idxS01 + 1], srcCanvasData.data[idxS11 + 1], dx, dy);
destCanvasData.data[idxD + 1] = g;
b = inner(srcCanvasData.data[idxS00 + 2], srcCanvasData.data[idxS10 + 2], srcCanvasData.data[idxS01 + 2], srcCanvasData.data[idxS11 + 2], dx, dy);
destCanvasData.data[idxD + 2] = b;
a = inner(srcCanvasData.data[idxS00 + 3], srcCanvasData.data[idxS10 + 3], srcCanvasData.data[idxS01 + 3], srcCanvasData.data[idxS11 + 3], dx, dy);
destCanvasData.data[idxD + 3] = a;
}
}
};
config.maxWidth
원래의 종횡비를 유지하면서 이미지를 너비로 축소합니다 . 개발 당시 이것은 주요 데스크탑 브라우저 (IE9 +, Firefox, Chrome) 외에도 iPad / iPhone Safari에서 작동 했으므로 오늘날 HTML5가 더 광범위하게 채택되면 여전히 호환 될 것으로 기대합니다. canvas.toDataURL () 호출은 MIME 유형과 이미지 품질을 사용하므로 품질 및 출력 파일 형식을 제어 할 수 있습니다 (원하는 경우 입력과 다를 수 있음).
여기서 다루지 않는 유일한 점은이 메타 데이터에 대한 지식이 없어도 방향 정보를 유지하는 것입니다. 이미지의 크기는 그대로있는 그대로 저장되며 방향에 대한 이미지 내 메타 데이터는 손실됩니다. 즉, 태블릿 장치에서 "거꾸로"찍은 이미지는 장치의 카메라 뷰 파인더에서 뒤집어 졌을지라도 렌더링됩니다. 이것이 우려되는 경우이 블로그 게시물 에는이를 수행하는 방법에 대한 좋은 가이드와 코드 예제가 있으며 위 코드에 통합 될 수 있습니다.