image - verzerren - html bildgröße dynamisch anpassen




HTML5 Größe der Bilder vor dem Hochladen anpassen (6)

Änderung der Antwort von Justin , die für mich funktioniert:

  1. Img.onload hinzugefügt
  2. Erweitern Sie die POST-Anfrage mit einem realen Beispiel

function handleFiles()
{
    var dataurl = null;
    var filesToUpload = document.getElementById('photo').files;
    var file = filesToUpload[0];

    // Create an image
    var img = document.createElement("img");
    // Create a file reader
    var reader = new FileReader();
    // Set the image once loaded into file reader
    reader.onload = function(e)
    {
        img.src = e.target.result;

        img.onload = function () {
            var canvas = document.createElement("canvas");
            var ctx = canvas.getContext("2d");
            ctx.drawImage(img, 0, 0);

            var MAX_WIDTH = 800;
            var MAX_HEIGHT = 600;
            var width = img.width;
            var height = img.height;

            if (width > height) {
              if (width > MAX_WIDTH) {
                height *= MAX_WIDTH / width;
                width = MAX_WIDTH;
              }
            } else {
              if (height > MAX_HEIGHT) {
                width *= MAX_HEIGHT / height;
                height = MAX_HEIGHT;
              }
            }
            canvas.width = width;
            canvas.height = height;
            var ctx = canvas.getContext("2d");
            ctx.drawImage(img, 0, 0, width, height);

            dataurl = canvas.toDataURL("image/jpeg");

            // Post the data
            var fd = new FormData();
            fd.append("name", "some_filename.jpg");
            fd.append("image", dataurl);
            fd.append("info", "lah_de_dah");
            $.ajax({
                url: '/ajax_photo',
                data: fd,
                cache: false,
                contentType: false,
                processData: false,
                type: 'POST',
                success: function(data){
                    $('#form_photo')[0].reset();
                    location.reload();
                }
            });
        } // img.onload
    }
    // Load files into file reader
    reader.readAsDataURL(file);
}

Hier ist ein Nudel-Scratcher.

Bedenkt, wir haben HTML5 lokalen Speicher und xhr v2 und was nicht. Ich habe mich gefragt, ob jemand ein funktionierendes Beispiel finden könnte oder mir einfach ein Ja oder Nein für diese Frage geben könnte:

Ist es möglich, ein Bild mit dem neuen lokalen Speicher (oder was auch immer) zu skalieren, so dass ein Benutzer, der keine Ahnung von der Größe eines Bildes hat, sein 10mb-Bild auf meine Website ziehen kann, Größe mit dem neuen lokalen Speicher ändern und Dann laden Sie es auf die kleinere Größe hoch.

Ich weiß ganz genau, Sie können es mit Flash, Java-Applets, ActiveX ... machen. Die Frage ist, ob Sie mit Javascript + Html5 tun können.

Ich freue mich auf die Antwort zu diesem Thema.

Ta für jetzt.


Das Ändern der Größe von Bildern in einem Canvas-Element ist im Allgemeinen eine schlechte Idee, da es die billigste Box-Interpolation verwendet. Das resultierende Bild verschlechtert sich merklich in der Qualität. Ich würde empfehlen, http://nodeca.github.io/pica/demo/ verwenden, das stattdessen eine Lanczos-Transformation durchführen kann. Die obige Demo-Seite zeigt den Unterschied zwischen Canvas- und Lanczos-Ansätzen.

Es verwendet auch Web-Worker für die Größenänderung von Bildern parallel. Es gibt auch WEBGL-Implementierung.

Es gibt einige Online-Bildgrößenanpassungen, die Pica verwenden, wie https://myimageresizer.com


Ich habe dieses Problem vor ein paar Jahren angepackt und meine Lösung als https://github.com/rossturner/HTML5-ImageUploader auf github hochgeladen

robertcs Antwort verwendet die Lösung, die im Mozilla Hacks Blogpost vorgeschlagen wurde, aber ich fand, dass dies eine wirklich schlechte Bildqualität ergab, wenn die Größe auf einen Maßstab geändert wurde, der nicht 2: 1 (oder ein Vielfaches davon) war. Ich fing an, mit verschiedenen Algorithmen zur Bildgrößenanpassung zu experimentieren, obwohl die meisten am Ende ziemlich langsam waren oder auch keine gute Qualität hatten.

Schließlich habe ich eine Lösung gefunden, die meiner Meinung nach schnell ausgeführt wird und auch eine recht gute Leistung bietet - da die Mozilla-Lösung von 1 Canvas auf einen anderen schnell und ohne Verlust der Bildqualität im Verhältnis 2: 1 bei einem Ziel von x arbeitet Pixel breit und y Pixel hoch, verwende ich diese Canvas-Methode zur Größenänderung, bis das Bild zwischen x und 2 x und y und 2 y ist . An diesem Punkt wende ich mich dann der algorithmischen Bildgrößenanpassung für den letzten "Schritt" der Größenanpassung auf die Zielgröße zu. Nachdem ich mehrere verschiedene Algorithmen ausprobiert hatte, entschied ich mich für die bilineare Interpolation, die von einem Blog stammt, der nicht mehr online ist, aber über das Internet Archive zugänglich ist , was gute Ergebnisse liefert, hier ist der anwendbare Code:

ImageUploader.prototype.scaleImage = function(img, completionCallback) {
    var canvas = document.createElement('canvas');
    canvas.width = img.width;
    canvas.height = img.height;
    canvas.getContext('2d').drawImage(img, 0, 0, canvas.width, canvas.height);

    while (canvas.width >= (2 * this.config.maxWidth)) {
        canvas = this.getHalfScaleCanvas(canvas);
    }

    if (canvas.width > this.config.maxWidth) {
        canvas = this.scaleCanvasWithAlgorithm(canvas);
    }

    var imageData = canvas.toDataURL('image/jpeg', this.config.quality);
    this.performUpload(imageData, completionCallback);
};

ImageUploader.prototype.scaleCanvasWithAlgorithm = function(canvas) {
    var scaledCanvas = document.createElement('canvas');

    var scale = this.config.maxWidth / canvas.width;

    scaledCanvas.width = canvas.width * scale;
    scaledCanvas.height = canvas.height * scale;

    var srcImgData = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
    var destImgData = scaledCanvas.getContext('2d').createImageData(scaledCanvas.width, scaledCanvas.height);

    this.applyBilinearInterpolation(srcImgData, destImgData, scale);

    scaledCanvas.getContext('2d').putImageData(destImgData, 0, 0);

    return scaledCanvas;
};

ImageUploader.prototype.getHalfScaleCanvas = function(canvas) {
    var halfCanvas = document.createElement('canvas');
    halfCanvas.width = canvas.width / 2;
    halfCanvas.height = canvas.height / 2;

    halfCanvas.getContext('2d').drawImage(canvas, 0, 0, halfCanvas.width, halfCanvas.height);

    return halfCanvas;
};

ImageUploader.prototype.applyBilinearInterpolation = function(srcCanvasData, destCanvasData, scale) {
    function inner(f00, f10, f01, f11, x, y) {
        var un_x = 1.0 - x;
        var un_y = 1.0 - y;
        return (f00 * un_x * un_y + f10 * x * un_y + f01 * un_x * y + f11 * x * y);
    }
    var i, j;
    var iyv, iy0, iy1, ixv, ix0, ix1;
    var idxD, idxS00, idxS10, idxS01, idxS11;
    var dx, dy;
    var r, g, b, a;
    for (i = 0; i < destCanvasData.height; ++i) {
        iyv = i / scale;
        iy0 = Math.floor(iyv);
        // Math.ceil can go over bounds
        iy1 = (Math.ceil(iyv) > (srcCanvasData.height - 1) ? (srcCanvasData.height - 1) : Math.ceil(iyv));
        for (j = 0; j < destCanvasData.width; ++j) {
            ixv = j / scale;
            ix0 = Math.floor(ixv);
            // Math.ceil can go over bounds
            ix1 = (Math.ceil(ixv) > (srcCanvasData.width - 1) ? (srcCanvasData.width - 1) : Math.ceil(ixv));
            idxD = (j + destCanvasData.width * i) * 4;
            // matrix to vector indices
            idxS00 = (ix0 + srcCanvasData.width * iy0) * 4;
            idxS10 = (ix1 + srcCanvasData.width * iy0) * 4;
            idxS01 = (ix0 + srcCanvasData.width * iy1) * 4;
            idxS11 = (ix1 + srcCanvasData.width * iy1) * 4;
            // overall coordinates to unit square
            dx = ixv - ix0;
            dy = iyv - iy0;
            // I let the r, g, b, a on purpose for debugging
            r = inner(srcCanvasData.data[idxS00], srcCanvasData.data[idxS10], srcCanvasData.data[idxS01], srcCanvasData.data[idxS11], dx, dy);
            destCanvasData.data[idxD] = r;

            g = inner(srcCanvasData.data[idxS00 + 1], srcCanvasData.data[idxS10 + 1], srcCanvasData.data[idxS01 + 1], srcCanvasData.data[idxS11 + 1], dx, dy);
            destCanvasData.data[idxD + 1] = g;

            b = inner(srcCanvasData.data[idxS00 + 2], srcCanvasData.data[idxS10 + 2], srcCanvasData.data[idxS01 + 2], srcCanvasData.data[idxS11 + 2], dx, dy);
            destCanvasData.data[idxD + 2] = b;

            a = inner(srcCanvasData.data[idxS00 + 3], srcCanvasData.data[idxS10 + 3], srcCanvasData.data[idxS01 + 3], srcCanvasData.data[idxS11 + 3], dx, dy);
            destCanvasData.data[idxD + 3] = a;
        }
    }
};

Dies skaliert ein Bild bis zu einer Breite von config.maxWidth unter Beibehaltung des ursprünglichen Seitenverhältnisses. Zum Zeitpunkt der Entwicklung funktionierte das auf dem iPad / iPhone Safari zusätzlich zu den großen Desktop-Browsern (IE9 +, Firefox, Chrome). Ich gehe daher davon aus, dass es angesichts der breiteren Nutzung von HTML5 noch kompatibel sein wird. Beachten Sie, dass der canvas.toDataURL () - Aufruf einen Mime-Typ und eine Bildqualität verwendet, mit der Sie die Qualität und das Ausgabeformat der Datei steuern können (möglicherweise abweichend von der Eingabe, wenn Sie möchten).

Der einzige Punkt, der hier nicht behandelt wird, ist das Beibehalten der Orientierungsinformationen. Ohne Kenntnis dieser Metadaten wird das Bild in der Größe verändert und gespeichert, wobei alle Metadaten innerhalb des Bildes zur Orientierung verloren gehen, was bedeutet, dass Bilder auf einem Tablet-Gerät "auf dem Kopf" waren so gerendert, obwohl sie im Kamerasucher des Gerätes umgedreht worden wären. Wenn dies ein Problem ist, hat dieser Blogbeitrag eine gute Anleitung und Codebeispiele, um dies zu erreichen, die ich sicher in den obigen Code integrieren könnte.


Ja, verwenden Sie die Datei-API , dann können Sie die Bilder mit dem Canvas-Element verarbeiten .

Dieser Blogeintrag von Mozilla Hacks führt Sie durch den Großteil des Prozesses. Als Referenz hier ist der zusammengesetzte Quellcode aus dem Blogpost:

// from an input element
var filesToUpload = input.files;
var file = filesToUpload[0];

var img = document.createElement("img");
var reader = new FileReader();  
reader.onload = function(e) {img.src = e.target.result}
reader.readAsDataURL(file);

var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);

var MAX_WIDTH = 800;
var MAX_HEIGHT = 600;
var width = img.width;
var height = img.height;

if (width > height) {
  if (width > MAX_WIDTH) {
    height *= MAX_WIDTH / width;
    width = MAX_WIDTH;
  }
} else {
  if (height > MAX_HEIGHT) {
    width *= MAX_HEIGHT / height;
    height = MAX_HEIGHT;
  }
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);

var dataurl = canvas.toDataURL("image/png");

//Post dataurl to the server with AJAX

Sie können dropzone.js verwenden, wenn Sie einen einfachen Upload-Manager mit Größenanpassung vor den Upload-Funktionen verwenden möchten.

Es hat eingebaute Größenänderungsfunktionen, aber Sie können Ihre eigenen zur Verfügung stellen, wenn Sie möchten.


Wenn Sie das Rad nicht neu erfinden wollen, können Sie plupload.com ausprobieren





local-storage