Anda dapat menggunakan langkah turun untuk mencapai hasil yang lebih baik. Sebagian besar browser tampaknya menggunakan interpolasi linier daripada bi-kubik saat mengubah ukuran gambar.
( Perbarui Ada telah menambahkan properti kualitas ke spesifikasi, imageSmoothingQuality
yang saat ini hanya tersedia di Chrome.)
Kecuali jika seseorang memilih tidak ada penghalusan atau tetangga terdekat, browser akan selalu menginterpolasi gambar setelah menurunkan ukurannya karena ini berfungsi sebagai filter akses rendah untuk menghindari aliasing.
Bi-linear menggunakan 2x2 piksel untuk melakukan interpolasi sedangkan bi-kubik menggunakan 4x4 sehingga dengan melakukan langkah-langkah Anda bisa mendekati hasil bi-kubik saat menggunakan interpolasi bi-linear seperti yang terlihat pada gambar yang dihasilkan.
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>
Bergantung pada seberapa drastis pengubahan ukuran Anda, Anda dapat melewati langkah 2 jika perbedaannya kurang.
Dalam demo Anda dapat melihat hasil baru sekarang sangat mirip dengan elemen gambar.
Karena biola Trung Le Nguyen Nhat tidak benar sama sekali (hanya menggunakan gambar asli di langkah terakhir)
saya menulis biola umum saya sendiri dengan perbandingan kinerja:
BIOLA
Pada dasarnya ini:
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); }
sumber
Saya membuat layanan Angular yang dapat digunakan kembali untuk menangani pengubahan ukuran gambar / kanvas berkualitas tinggi bagi siapa saja yang tertarik: https://gist.github.com/transitive-bullshit/37bac5e741eaec60e983
Layanan ini mencakup dua solusi karena keduanya memiliki pro / kontra sendiri. Pendekatan konvolusi lanczos berkualitas lebih tinggi dengan biaya menjadi lebih lambat, sedangkan pendekatan penurunan skala bertahap menghasilkan hasil antialiased yang wajar dan secara signifikan lebih cepat.
Contoh penggunaan:
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 }) })
sumber
Meskipun beberapa cuplikan kode tersebut pendek dan berfungsi, namun tidak mudah untuk diikuti dan dipahami.
Karena saya bukan penggemar "copy-paste" dari stack-overflow, saya ingin para pengembang memahami kode yang mereka masukkan ke dalam perangkat lunak mereka, semoga hal di bawah ini berguna.
DEMO : Mengubah ukuran gambar dengan fiddler JS dan HTML Canvas Demo.
Anda mungkin menemukan 3 metode berbeda untuk melakukan pengubahan ukuran ini, yang akan membantu Anda memahami cara kerja kode dan alasannya.
https://jsfiddle.net/1b68eLdr/93089/
Kode lengkap dari kedua demo, dan metode TypeScript yang mungkin ingin Anda gunakan dalam kode Anda, dapat ditemukan di proyek GitHub.
https://github.com/eyalc4/ts-image-resizer
Ini adalah kode terakhir:
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 } }; }}
sumber
Saya membuat perpustakaan yang memungkinkan Anda menurunkan persentase apa pun sambil menyimpan semua data warna.
https://github.com/danschumann/limby-resize/blob/master/lib/canvas_resize.js
File itu bisa Anda masukkan ke dalam browser. Hasilnya akan terlihat seperti photoshop atau image magick, mempertahankan semua data warna, rata-rata piksel, daripada mengambil yang terdekat dan menjatuhkan yang lain. Itu tidak menggunakan rumus untuk menebak rata-rata, itu mengambil rata-rata yang tepat.
sumber
Berdasarkan jawaban K3N, saya menulis ulang kode secara umum untuk siapapun yang mau
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);
PERBARUI DEMO JSFIDDLE
Ini DEMO ONLINE saya
sumber
Saya tidak mengerti mengapa tidak ada yang menyarankan
createImageBitmap
.createImageBitmap( document.getElementById('image'), { resizeWidth: 300, resizeHeight: 234, resizeQuality: 'high' } ) .then(imageBitmap => document.getElementById('canvas').getContext('2d').drawImage(imageBitmap, 0, 0) );
bekerja dengan indah (dengan asumsi Anda menetapkan id untuk gambar dan kanvas).
sumber
Saya menulis utilitas js kecil untuk memotong dan mengubah ukuran gambar di front-end. Ini tautan di proyek GitHub. Anda juga bisa mendapatkan gumpalan dari gambar akhir untuk mengirimkannya.
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;
sumber