Formaat van een Base-64-afbeelding wijzigen in JavaScript zonder canvas te gebruiken

Ik heb een manier nodig om het formaat van afbeeldingen in JavaScript te wijzigen zonder een HTML-element te gebruiken.

Mijn mobiele HTML-app legt foto’s vast en converteert ze vervolgens naar base64-strings. Daarna moet ik ze verkleinen voordat ze naar de API worden verzonden om opslagruimte te besparen.

Ik ben op zoek naar een andere en meer geschikte manier om het formaat te wijzigen dan het gebruik van een canvaselement, is er een manier?


Antwoord 1, autoriteit 100%

Een manier om te voorkomen dat de belangrijkste HTML wordt beïnvloed, is door een canvas buiten het scherm te maken dat buiten de DOM-tree wordt gehouden.

Dit levert een bitmapbuffer en native gecompileerde code op om de afbeeldingsgegevens te coderen. Het is eenvoudig om te doen:

function imageToDataUri(img, width, height) {
    // create an off-screen canvas
    var canvas = document.createElement('canvas'),
        ctx = canvas.getContext('2d');
    // set its dimension to target size
    canvas.width = width;
    canvas.height = height;
    // draw source image into the off-screen canvas:
    ctx.drawImage(img, 0, 0, width, height);
    // encode image to data-uri with base64 version of compressed image
    return canvas.toDataURL();
}

Als u een ander formaat dan PNG (standaard) wilt maken, geeft u het type als volgt op:

return canvas.toDataURL('image/jpeg', quality);  // quality = [0.0, 1.0]

Het is vermeldenswaard dat CORS-beperkingen van toepassing zijn op toDataURL().

Als je app alleen base64-gecodeerde afbeeldingen geeft (ik neem aan dat het data-uri’s zijn met base64-gegevens?) dan moet je eerst de afbeelding “laden”:

var img = new Image;
img.onload = resizeImage;
img.src = originalDataUriHere;
function resizeImage() {
    var newDataUri = imageToDataUri(this, targetWidth, targetHeight);
    // continue from here...
}

Als de bron een pure base-64-tekenreeks is, voegt u er gewoon een header aan toe om er een data-uri van te maken:

function base64ToDataUri(base64) {
    return 'data:image/png;base64,' + base64;
}

Vervang gewoon het image/png-gedeelte door het type dat de base64-tekenreeks vertegenwoordigt (dwz maak er een optioneel argument van).


Antwoord 2, autoriteit 33%

Kens antwoord is het juiste antwoord, maar zijn code werkt niet. Ik heb er wat aanpassingen aan gedaan en het werkt nu perfect. Het formaat van een gegevens-URI wijzigen:

// Takes a data URI and returns the Data URI corresponding to the resized image at the wanted size.
function resizedataURL(datas, wantedWidth, wantedHeight)
    {
        // We create an image to receive the Data URI
        var img = document.createElement('img');
        // When the event "onload" is triggered we can resize the image.
        img.onload = function()
            {        
                // We create a canvas and get its context.
                var canvas = document.createElement('canvas');
                var ctx = canvas.getContext('2d');
                // We set the dimensions at the wanted size.
                canvas.width = wantedWidth;
                canvas.height = wantedHeight;
                // We resize the image with the canvas method drawImage();
                ctx.drawImage(this, 0, 0, wantedWidth, wantedHeight);
                var dataURI = canvas.toDataURL();
                /////////////////////////////////////////
                // Use and treat your Data URI here !! //
                /////////////////////////////////////////
            };
        // We put the Data URI in the image's src attribute
        img.src = datas;
    }
// Use it like that : resizedataURL('yourDataURIHere', 50, 50);

Antwoord 3, autoriteit 24%

Pierrick Martellière is verreweg het beste antwoord, ik wilde er alleen op wijzen dat je dat zou moeten implementeren met een asynchrone functie. Daarna zou je iets kunnen doen als:

var newDataUri = await resizedataURL(datas,600,600);

Hiermee wordt gewacht op het resultaat van de functie voordat u naar de volgende stap gaat. Het is een schonere manier om code te schrijven. Hier is de functie van Pierrick met de kleine bewerking:

// Takes a data URI and returns the Data URI corresponding to the resized image at the wanted size.
function resizedataURL(datas, wantedWidth, wantedHeight){
    return new Promise(async function(resolve,reject){
        // We create an image to receive the Data URI
        var img = document.createElement('img');
        // When the event "onload" is triggered we can resize the image.
        img.onload = function()
        {        
            // We create a canvas and get its context.
            var canvas = document.createElement('canvas');
            var ctx = canvas.getContext('2d');
            // We set the dimensions at the wanted size.
            canvas.width = wantedWidth;
            canvas.height = wantedHeight;
            // We resize the image with the canvas method drawImage();
            ctx.drawImage(this, 0, 0, wantedWidth, wantedHeight);
            var dataURI = canvas.toDataURL();
            // This is the return of the Promise
            resolve(dataURI);
        };
        // We put the Data URI in the image's src attribute
        img.src = datas;
    })
}// Use it like : var newDataURI = await resizedataURL('yourDataURIHere', 50, 50);

Voor meer details kun je MDN Docs raadplegen: https:/ /developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Promise


Antwoord 4, autoriteit 13%

Ja, dat kan. Deze oplossingen zijn goed voor het wijzigen van het formaat, niet alleen voor het converteren van afbeeldingen naar base64.

  1. Je kunt het js-bestand converteren naar een afbeeldingsbitmap door jpg-js.En je kunt het formaat alleen wijzigen door deze lib, maar in het geval van het wijzigen van het formaat van een zeer grote afbeelding naar een zeer kleine, zal de kwaliteit zeer slecht zijn.
  2. Je kunt afbeeldingsgegevens uit een bestand halen met jpg-js (of een afbeelding tekenen op canvas) en vervolgens het formaat van canvasImageData wijzigen door het formaat van lib pica. (goed voor afbeeldingen met hoge resolutie, zonder beperking van de canvasgrootte)
  3. Je kunt offscreen canvas gebruiken, zonder het canvas aan een body te bevestigen, en het formaat van een afbeelding wijzigen. Deze oplossing zal sneller zijn, maar zal de slechtste oplossing zijn voor afbeeldingen met een hoge resolutie, bijvoorbeeld 6000×6000 pixels. In dat geval kan het resultaatcanvas van slechte kwaliteit zijn of gewoon leeg zijn, of de browser kan vallen met een geheugenlimietuitzondering. (goed voor normale en kleine afbeeldingen)

Jpg-js en Pica zullen helemaal geen dom-elementen gebruiken. Deze bibliotheken werken alleen met afbeeldingsgegevens, zonder dom-elementen (canvas en afbeelding).

Over het canvas, groottebeperking zie deze post


Antwoord 5

U kunt een onbewerkte Base64-beeldmanipulatie gebruiken, zoals hier wordt weergegeven.

Ziet er moeilijk uit (en alleen voor png) en waarom velen ervoor kiezen om canvas te gebruiken

http://blog.calyptus.eu/seb /2009/05/png-parser-in-javascript/


Antwoord 6

Ik denk dat deze methode de beste manier is voor deze oplossing.

function base64Resize(sourceBase64, scale , callBack) {
    const _scale = scale;
    var img = document.createElement('img');
    img.setAttribute("src", sourceBase64);
    img.onload = () => {
        var canvas = document.createElement('canvas');
        canvas.width = img.width * _scale;
        canvas.height = img.height * _scale;
        var ctx = canvas.getContext("2d");
        var cw = canvas.width;
        var ch = canvas.height;
        var maxW = img.width * _scale;
        var maxH = img.height * _scale;
        var iw = img.width;
        var ih = img.height;
        var scl = Math.min((maxW / iw), (maxH / ih));
        var iwScaled = iw * scl;
        var ihScaled = ih * scl;
        canvas.width = iwScaled;
        canvas.height = ihScaled;
        ctx.drawImage(img, 0, 0, iwScaled, ihScaled);
        const newBase64 = canvas.toDataURL("image/jpeg", scl);
        callBack(newBase64);
    }
}

Belangrijk punt is dat je de gebeurtenis img.onloadmoet gebruiken.

Other episodes