я столкнулся эта проблема несколько лет назад и загрузила мое решение в github как https://github.com/rossturner/HTML5-ImageUploader
Ответ robertc использует решение, предложенное в Mozilla Hacks blog post, однако я обнаружил, что при изменении размера до шкалы, которая не была 2: 1 (или несколько ее), это дало очень низкое качество изображения. Я начал экспериментировать с различными алгоритмами изменения размера изображения, хотя большинство из них оказались довольно медленными, а также не отличались высоким качеством.
Наконец-то я придумал решение, которое, как я считаю, выполняется быстро и имеет довольно хорошую производительность - поскольку решение для копирования Mozilla с одного холста на другое работает быстро и без потери качества изображения при соотношении 2: 1, данный мишенью х пикселей в ширину и у пикселей в высоту, я использую этот метод изменения размера холста до тех пор, пока изображение не находится между х и 2 х и у и 2 у. Затем я перехожу к алгоритмическому изменению размера изображения для окончательного «шага» изменения размера до целевого размера. После попытки несколько различных алгоритмов я остановился на билинейной интерполяции, взятой из блога, который не находится в сети больше, но accessible via the Internet Archive, что дает хорошие результаты, вот применимый код:
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
, сохраняя исходное соотношение сторон. На момент разработки это работало на iPad/iPhone Safari в дополнение к основным настольным браузерам (IE9 +, Firefox, Chrome), поэтому я ожидаю, что он будет по-прежнему совместим, учитывая более широкое восприятие HTML5 сегодня. Обратите внимание, что холст.toDataURL() принимает тип mime и качество изображения, что позволит вам контролировать качество и формат выходного файла (потенциально отличающийся от ввода, если хотите).
Единственное, что не охватывает, это сохранение информации о ориентации, без знания этих метаданных, размер изображения изменяется и сохраняется как есть, теряя любые метаданные в изображении для ориентации, что означает, что изображения, сделанные на планшетном устройстве " вверх ногами ", были показаны как таковые, хотя они были бы перевернуты в видоискателе камеры устройства. Если это вызывает беспокойство, у this blog post есть хороший пример руководства и кода о том, как это сделать, что, я уверен, можно было бы интегрировать с вышеуказанным кодом.
Почему спасибо сударь. Сегодня вечером у меня будет игра ... С файлом api, который есть. Я получил загрузку перетаскивания на работу, и я понял, что это тоже будет очень хорошая функция для включения. Yippee. – Jimmyt1988
Спасибо, сэр! На мой взгляд, эти две строки не нужны: var ctx = canvas.getContext ("2d"); ctx.drawImage (img, 0, 0); ---- как вы уже получили контекст и drawImage в конце ... – Qlimax
Не нужно использовать этот mycanvas.toDataURL («image/jpeg», 0.5), чтобы убедиться, что качество приведено для уменьшения размер файла. Я наткнулся на этот комментарий на сообщение в блоге mozilla и увидел здесь ошибку. Https://bugzilla.mozilla.org/show_bug.cgi?id=564388 – sbose