Vous pouvez utiliser la descente pour obtenir de meilleurs résultats. La plupart des navigateurs semblent utiliser l'interpolation linéaire plutôt que bi-cubique lors du redimensionnement des images.
( Mise à jour Une propriété de qualité a été ajoutée aux spécifications, imageSmoothingQuality
qui n'est actuellement disponible que dans Chrome.)
À moins que l'on ne choisisse pas de lissage ou de voisin le plus proche, le navigateur interpolera toujours l'image après l'avoir réduite comme cette fonction comme un filtre passe-bas pour éviter l'aliasing.
Le bi-linéaire utilise 2x2 pixels pour faire l'interpolation tandis que le bi-cubique utilise le 4x4 donc en le faisant par étapes, vous pouvez vous rapprocher du résultat bi-cubique tout en utilisant l'interpolation bi-linéaire comme on le voit dans les images résultantes.
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>
En fonction de la rigueur de votre redimensionnement, vous pouvez sauter l'étape 2 si la différence est moindre.
Dans la démo, vous pouvez voir que le nouveau résultat est maintenant très similaire à l'élément image.
Puisque le violon de Trung Le Nguyen Nhat n'est pas du tout correct (il utilise juste l'image originale dans la dernière étape)
j'ai écrit mon propre violon général avec comparaison des performances:
VIOLON
En gros, c'est:
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); }
la source
J'ai créé un service Angular réutilisable pour gérer le redimensionnement de haute qualité des images / toiles pour tous ceux qui sont intéressés: https://gist.github.com/transitive-bullshit/37bac5e741eaec60e983
Le service comprend deux solutions car elles ont toutes les deux leurs propres avantages / inconvénients. L'approche de convolution lanczos est de meilleure qualité au prix d'être plus lente, tandis que l'approche de réduction d'échelle par étapes produit des résultats raisonnablement anticrénelés et est nettement plus rapide.
Exemple d'utilisation:
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 }) })
la source
Bien que certains de ces extraits de code soient courts et efficaces, ils ne sont pas simples à suivre et à comprendre.
Comme je ne suis pas fan du "copier-coller" de stack-overflow, j'aimerais que les développeurs comprennent le code qu'ils introduisent dans leur logiciel, j'espère que vous trouverez ce qui suit utile.
DEMO : Redimensionner des images avec JS et HTML Canvas Demo Fiddler.
Vous pouvez trouver 3 méthodes différentes pour effectuer ce redimensionnement, qui vous aideront à comprendre comment le code fonctionne et pourquoi.
https://jsfiddle.net/1b68eLdr/93089/
Le code complet de la démo et de la méthode TypeScript que vous pouvez utiliser dans votre code se trouve dans le projet GitHub.
https://github.com/eyalc4/ts-image-resizer
Voici le code final:
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 } }; }}
la source
J'ai créé une bibliothèque qui vous permet d'abaisser n'importe quel pourcentage tout en conservant toutes les données de couleur.
https://github.com/danschumann/limby-resize/blob/master/lib/canvas_resize.js
Ce fichier que vous pouvez inclure dans le navigateur. Les résultats ressembleront à Photoshop ou à la magie de l'image, préservant toutes les données de couleur, calculant la moyenne des pixels, plutôt que de prendre ceux qui se trouvent à proximité et d'en laisser tomber d'autres. Il n'utilise pas de formule pour deviner les moyennes, il prend la moyenne exacte.
la source
Sur la base de la réponse K3N, je réécris le code généralement pour quiconque veut
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);
MISE À JOUR DE LA DÉMO JSFIDDLE
Voici ma DEMO EN LIGNE
la source
Je ne comprends pas pourquoi personne ne suggère
createImageBitmap
.createImageBitmap( document.getElementById('image'), { resizeWidth: 300, resizeHeight: 234, resizeQuality: 'high' } ) .then(imageBitmap => document.getElementById('canvas').getContext('2d').drawImage(imageBitmap, 0, 0) );
fonctionne à merveille (en supposant que vous définissez des identifiants pour l'image et le canevas).
la source
J'ai écrit un petit utilitaire js pour recadrer et redimensionner l'image sur le front-end. Voici le lien sur le projet GitHub. Vous pouvez également obtenir le blob de l'image finale pour l'envoyer.
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;
la source