Ridimensiona l’immagine con canvas javascript (senza intoppi)

Sto cercando di ridimensionare alcune immagini con la canvas ma non ho idea di come renderle più morbide. Su Photoshop, browser ecc. Ci sono alcuni algoritmi che usano (es. Bicubico, bilineare) ma non so se questi sono incorporati nella canvas o no.

Ecco il mio violino: http://jsfiddle.net/EWupT/

var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); canvas.width=300 canvas.height=234 ctx.drawImage(img, 0, 0, 300, 234); document.body.appendChild(canvas); 

Il primo è un normale tag immagine ridimensionato e il secondo è canvas. Nota come la canvas non è così liscia. Come posso ottenere “scorrevolezza”?

Puoi usare down-stepping per ottenere risultati migliori. La maggior parte dei browser sembra utilizzare l’interpolazione lineare anziché bi-cubica durante il ridimensionamento delle immagini.

( Aggiornamento È stata aggiunta una proprietà di qualità alle specifiche, imageSmoothingQuality che è attualmente disponibile solo in Chrome.)

A meno che non si scelga la levigatura o il vicino più vicino, il browser interpola sempre l’immagine dopo averla ridimensionata come questa come un filtro passa-basso per evitare l’aliasing.

Bi-lineare usa 2×2 pixel per eseguire l’interpolazione mentre bi-cubic usa 4×4 quindi, eseguendolo in step, è ansible avvicinarsi al risultato bi-cubico mentre si utilizza l’interpolazione bi-lineare come si vede nelle immagini risultanti.

 var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); var img = new Image(); img.onload = function () { // set size proportional to image canvas.height = canvas.width * (img.height / img.width); // step 1 - resize to 50% 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); // step 2 octx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5); // step 3, resize to final size ctx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5, 0, 0, canvas.width, canvas.height); } img.src = "http://sofit.miximages.com/javascript/SHo6Fub.jpg"; 
   

Ho creato un servizio angular riutilizzabile per gestire il ridimensionamento di immagini / tele di alta qualità per chiunque sia interessato: https://gist.github.com/transitive-bullshit/37bac5e741eaec60e983

Il servizio include due soluzioni perché entrambi hanno i loro pro / contro. L’approccio alla convoluzione di lanczos è di qualità superiore al costo di essere più lento, mentre l’approccio di downscaling graduale produce risultati ragionevolmente antialias ed è significativamente più veloce.

Esempio di utilizzo:

 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 }) }) 

Dal momento che il violino di Trung Le Nguyen Nhat non è corretto (usa solo l’immagine originale nell’ultimo passaggio)
Ho scritto il mio violino generale con il confronto delle prestazioni:

VIOLINO

Fondamentalmente è:

 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); } 

Ho creato una libreria che ti consente di scaricare qualsiasi percentuale mantenendo tutti i dati del colore.

https://github.com/danschumann/limby-resize/blob/master/lib/canvas_resize.js

Quel file che puoi includere nel browser. I risultati saranno simili a photoshop o image magick, conservando tutti i dati relativi ai colors, facendo la media dei pixel, invece di prendere quelli vicini e far cadere altri. Non usa una formula per indovinare le medie, ci vuole la media esatta.

In base alla risposta K3N, ho riscritto il codice in generale per chiunque lo desideri

 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); 

AGGIORNA DEMO JSFIDDLE

Ecco la mia DEMO ONLINE

Ho scritto piccola js-utility per ritagliare e ridimensionare l’immagine sul front-end. Ecco il link sul progetto GitHub. Inoltre puoi ottenere blob dall’immagine finale per inviarlo.

 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;