Вы можете использовать пошаговое снижение для достижения лучших результатов. Большинство браузеров, кажется, используют линейную интерполяцию, а не бикубическую при изменении размера изображений.
( Обновление. В спецификации добавлено свойство качества, imageSmoothingQuality
которое в настоящее время доступно только в Chrome.)
Если не выбрано сглаживание или ближайший сосед, браузер всегда будет интерполировать изображение после его уменьшения, поскольку эта функция работает как фильтр нижних частот, чтобы избежать сглаживания.
Билинейный использует 2x2 пикселя для интерполяции, в то время как бикубический использует 4x4, поэтому, выполняя его поэтапно, вы можете приблизиться к билинейному результату, используя билинейную интерполяцию, как видно на результирующих изображениях.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var img = new Image();
img.onload = function () {
canvas.height = canvas.width * (img.height / img.width);
var oc = document.createElement('canvas'),
octx = oc.getContext('2d');
oc.width = img.width * 0.5;
oc.height = img.height * 0.5;
octx.drawImage(img, 0, 0, oc.width, oc.height);
octx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5);
ctx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5,
0, 0, canvas.width, canvas.height);
}
img.src = "//i.imgur.com/SHo6Fub.jpg";
<img src="//i.imgur.com/SHo6Fub.jpg" width="300" height="234">
<canvas id="canvas" width=300></canvas>
В зависимости от того, насколько сильно вы изменили размер, вы можете пропустить шаг 2, если разница меньше.
В демонстрации вы можете увидеть, что новый результат теперь очень похож на элемент изображения.
Поскольку скрипка Trung Le Nguyen Nhat совсем не правильная (она просто использует исходное изображение на последнем шаге),
я написал свою собственную общую скрипку со сравнением производительности:
FIDDLE
В основном это:
img.onload = function() { var canvas = document.createElement('canvas'), ctx = canvas.getContext("2d"), oc = document.createElement('canvas'), octx = oc.getContext('2d'); canvas.width = width; // destination canvas size canvas.height = canvas.width * img.height / img.width; var cur = { width: Math.floor(img.width * 0.5), height: Math.floor(img.height * 0.5) } oc.width = cur.width; oc.height = cur.height; octx.drawImage(img, 0, 0, cur.width, cur.height); while (cur.width * 0.5 > width) { cur = { width: Math.floor(cur.width * 0.5), height: Math.floor(cur.height * 0.5) }; octx.drawImage(oc, 0, 0, cur.width * 2, cur.height * 2, 0, 0, cur.width, cur.height); } ctx.drawImage(oc, 0, 0, cur.width, cur.height, 0, 0, canvas.width, canvas.height); }
источник
Я создал многоразовую службу Angular для обработки высококачественного изменения размеров изображений / холстов для всех, кто заинтересован: https://gist.github.com/transitive-bullshit/37bac5e741eaec60e983
Сервис включает в себя два решения, потому что у обоих есть свои плюсы и минусы. Подход свертки Ланцоша обеспечивает более высокое качество за счет более медленной работы, тогда как подход пошагового масштабирования дает достаточно сглаженные результаты и работает значительно быстрее.
Пример использования:
angular.module('demo').controller('ExampleCtrl', function (imageService) { // EXAMPLE USAGE // NOTE: it's bad practice to access the DOM inside a controller, // but this is just to show the example usage. // resize by lanczos-sinc filter imageService.resize($('#myimg')[0], 256, 256) .then(function (resizedImage) { // do something with resized image }) // resize by stepping down image size in increments of 2x imageService.resizeStep($('#myimg')[0], 256, 256) .then(function (resizedImage) { // do something with resized image }) })
источник
Хотя некоторые из этих фрагментов кода короткие и работают, их нетривиально понять и понять.
Поскольку я не являюсь поклонником «копипаста» из переполнения стека, я хотел бы, чтобы разработчики понимали код, который они вставляют в свое программное обеспечение, надеюсь, вы найдете нижеприведенное.
ДЕМО : изменение размера изображений с помощью JS и HTML Canvas Demo fiddler.
Вы можете найти 3 различных метода изменения размера, которые помогут вам понять, как работает код и почему.
https://jsfiddle.net/1b68eLdr/93089/
Полный код демонстрации и метода TypeScript, который вы, возможно, захотите использовать в своем коде, можно найти в проекте GitHub.
https://github.com/eyalc4/ts-image-resizer
Это последний код:
export class ImageTools { base64ResizedImage: string = null; constructor() { } ResizeImage(base64image: string, width: number = 1080, height: number = 1080) { let img = new Image(); img.src = base64image; img.onload = () => { // Check if the image require resize at all if(img.height <= height && img.width <= width) { this.base64ResizedImage = base64image; // TODO: Call method to do something with the resize image } else { // Make sure the width and height preserve the original aspect ratio and adjust if needed if(img.height > img.width) { width = Math.floor(height * (img.width / img.height)); } else { height = Math.floor(width * (img.height / img.width)); } let resizingCanvas: HTMLCanvasElement = document.createElement('canvas'); let resizingCanvasContext = resizingCanvas.getContext("2d"); // Start with original image size resizingCanvas.width = img.width; resizingCanvas.height = img.height; // Draw the original image on the (temp) resizing canvas resizingCanvasContext.drawImage(img, 0, 0, resizingCanvas.width, resizingCanvas.height); let curImageDimensions = { width: Math.floor(img.width), height: Math.floor(img.height) }; let halfImageDimensions = { width: null, height: null }; // Quickly reduce the dize by 50% each time in few iterations until the size is less then // 2x time the target size - the motivation for it, is to reduce the aliasing that would have been // created with direct reduction of very big image to small image while (curImageDimensions.width * 0.5 > width) { // Reduce the resizing canvas by half and refresh the image halfImageDimensions.width = Math.floor(curImageDimensions.width * 0.5); halfImageDimensions.height = Math.floor(curImageDimensions.height * 0.5); resizingCanvasContext.drawImage(resizingCanvas, 0, 0, curImageDimensions.width, curImageDimensions.height, 0, 0, halfImageDimensions.width, halfImageDimensions.height); curImageDimensions.width = halfImageDimensions.width; curImageDimensions.height = halfImageDimensions.height; } // Now do final resize for the resizingCanvas to meet the dimension requirments // directly to the output canvas, that will output the final image let outputCanvas: HTMLCanvasElement = document.createElement('canvas'); let outputCanvasContext = outputCanvas.getContext("2d"); outputCanvas.width = width; outputCanvas.height = height; outputCanvasContext.drawImage(resizingCanvas, 0, 0, curImageDimensions.width, curImageDimensions.height, 0, 0, width, height); // output the canvas pixels as an image. params: format, quality this.base64ResizedImage = outputCanvas.toDataURL('image/jpeg', 0.85); // TODO: Call method to do something with the resize image } }; }}
источник
Я создал библиотеку, которая позволяет вам уменьшить любой процент, сохраняя при этом все данные о цвете.
https://github.com/danschumann/limby-resize/blob/master/lib/canvas_resize.js
Этот файл вы можете включить в браузер. Результаты будут выглядеть как фотошоп или магия изображений, сохраняя все данные о цвете, усредняя пиксели, вместо того, чтобы брать соседние и отбрасывать другие. Он не использует формулу для вычисления средних значений, он берет точное среднее значение.
источник
Основываясь на ответе K3N, я обычно переписываю код для всех, кто хочет
var oc = document.createElement('canvas'), octx = oc.getContext('2d'); oc.width = img.width; oc.height = img.height; octx.drawImage(img, 0, 0); while (oc.width * 0.5 > width) { oc.width *= 0.5; oc.height *= 0.5; octx.drawImage(oc, 0, 0, oc.width, oc.height); } oc.width = width; oc.height = oc.width * img.height / img.width; octx.drawImage(img, 0, 0, oc.width, oc.height);
ОБНОВИТЬ ДЕМО JSFIDDLE
Вот моя ОНЛАЙН ДЕМО
источник
Я не понимаю, почему никто не предлагает
createImageBitmap
.createImageBitmap( document.getElementById('image'), { resizeWidth: 300, resizeHeight: 234, resizeQuality: 'high' } ) .then(imageBitmap => document.getElementById('canvas').getContext('2d').drawImage(imageBitmap, 0, 0) );
прекрасно работает (при условии, что вы установили идентификаторы для изображения и холста).
источник
Я написал небольшую js-утилиту для обрезки и изменения размера изображения на интерфейсе. Вот ссылка на проект GitHub. Также вы можете получить blob из конечного изображения, чтобы отправить его.
import imageSqResizer from './image-square-resizer.js' let resizer = new imageSqResizer( 'image-input', 300, (dataUrl) => document.getElementById('image-output').src = dataUrl; ); //Get blob let formData = new FormData(); formData.append('files[0]', resizer.blob); //get dataUrl document.getElementById('image-output').src = resizer.dataUrl;
источник