Ich versuche, einige Bilder mit Canvas zu verkleinern, aber ich weiß nicht, wie ich sie glätten soll ... Auf Photoshop, Browsern usw. gibt es ein paar Algorithmen (zB bikubisch, bilinear), aber ich weiß es nicht ob diese in die Leinwand integriert sind oder nicht.
Hier ist meine Geige: 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);
Der erste ist ein normaler Tag, dessen Größe geändert wurde, und der zweite ist Canvas. Beachten Sie, dass die Leinwand nicht so glatt ist. Wie kann ich 'Glätte' erreichen?
Sie können das Herunterschalten verwenden, um bessere Ergebnisse zu erzielen. Die meisten Browser scheinen eine lineare Interpolation zu verwenden, anstatt bi-kubische , wenn Sie die Bildgröße ändern.
(Update Den Spezifikationen wurde eine Qualitätseigenschaft hinzugefügt: imageSmoothingQuality
, die derzeit nur in Chrome verfügbar ist.)
Wenn Sie keine Glättung oder den nächsten Nachbarn wählen, interpoliert der Browser das Bild immer nach dem Verkleinern, da diese Funktion als Tiefpassfilter dient, um Aliasing zu vermeiden.
Bi-linear verwendet 2x2 Pixel für die Interpolation, während bi-cubic 4x4 verwendet. Wenn Sie also schrittweise vorgehen, können Sie sich dem bi-kubischen Ergebnis annähern.
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 = "//i.imgur.com/SHo6Fub.jpg";
<img src="//i.imgur.com/SHo6Fub.jpg" width="300" height="234">
<canvas id="canvas" width=300></canvas>
Je nachdem, wie drastisch Ihre Größe geändert wird, können Sie Schritt 2 überspringen, wenn der Unterschied geringer ist.
In der Demo sehen Sie, dass das neue Ergebnis jetzt dem Bildelement sehr ähnlich ist.
Ich habe einen wiederverwendbaren Angular-Dienst erstellt, um die Bildqualität/Bildqualität für alle, die daran interessiert sind, in hoher Qualität zu bearbeiten: https://Gist.github.com/transitive-bullshit/37bac5e741eaec60e983
Der Service umfasst zwei Lösungen, da beide über eigene Vor- und Nachteile verfügen. Der lanczos-Faltungsansatz ist von höherer Qualität, kostet aber langsamer, während der schrittweise Herunterskalierungsansatz angemessen antialiasierte Ergebnisse liefert und deutlich schneller ist.
Verwendungsbeispiel:
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
})
})
Da Trung Le Nguyen Nhats Geige ist überhaupt nicht richtig
Ich habe meine eigene Geige mit Leistungsvergleich geschrieben:
Im Grunde ist es:
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);
}
Ich habe eine Bibliothek erstellt, in der Sie jeden Prozentsatz herunterfahren können, während alle Farbdaten erhalten bleiben.
https://github.com/danschumann/limby-resize/blob/master/lib/canvas_resize.js
Diese Datei können Sie in den Browser aufnehmen. Die Ergebnisse sehen wie Photoshop oder Image Magick aus, wobei alle Farbdaten erhalten bleiben, die Pixel gemittelt werden, anstatt nahegelegene zu nehmen und andere zu löschen. Es verwendet keine Formel, um die Durchschnittswerte zu erraten, sondern den genauen Durchschnittswert.
Ich habe ein kleines js-Utility geschrieben, um das Bild am Frontend zu beschneiden und dessen Größe zu ändern. Hier ist link auf dem GitHub-Projekt. Sie können auch Blob vom endgültigen Bild erhalten, um es zu senden.
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;
Basierend auf der K3N-Antwort schreibe ich Code generell für jeden, der will
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);
UPDATE JSFIDDLE DEMO
Hier ist meine ONLINE DEMO
Einige dieser Code-Snippets sind zwar kurz und funktionieren, sie sind jedoch nicht trivial zu verstehen und zu verstehen.
Da ich kein Fan von "copy-paste" von stack-overflow bin, möchte ich, dass Entwickler den Code verstehen, in dem sie sich befinden.
DEMO: Ändern der Größe von Bildern mit JS und HTML Canvas Demo-Fiddler.
Es gibt 3 verschiedene Methoden, um diese Größe zu ändern. So können Sie besser verstehen, wie der Code funktioniert und warum.
https://jsfiddle.net/1b68eLdr/93089/
Den vollständigen Code der Demo- und TypeScript-Methode, die Sie möglicherweise in Ihrem Code verwenden möchten, finden Sie im GitHub-Projekt.
https://github.com/eyalc4/ts-image-resizer
Dies ist der endgültige Code:
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
}
};
}}