it-swarm.com.de

Bildgröße mit Javascript-Leinwand (glatt) ändern

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?

64
steve

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.

102
user1693593

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

Da Trung Le Nguyen Nhats Geige ist überhaupt nicht richtig
Ich habe meine eigene Geige mit Leistungsvergleich geschrieben:

GEIGE

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);
}
8
Sebastian Ott

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.

4
Funkodebat

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;
1
Diyaz Yakubov

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
        }
    };
}}
0
Eyal c