Het decoderen van afbeeldingen voor gebruik met een canvas is vrij gebruikelijk, of het nu gaat om gebruikers de mogelijkheid te geven een avatar aan te passen, een afbeelding bij te snijden of gewoon in te zoomen op een foto. Het probleem met het decoderen van afbeeldingen is dat het CPU-intensief kan zijn, en dat kan soms 'jank' of 'checkerboarding' betekenen. Vanaf Chrome 50 (en in Firefox 42+) heb je nu een andere optie: createImageBitmap()
. Hiermee kunt u een afbeelding op de achtergrond decoderen en toegang krijgen tot een nieuwe ImageBitmap
primitief, die u op dezelfde manier in een canvas kunt tekenen als een <img>
-element, een ander canvas of een video.
Blobs tekenen met createImageBitmap()
Stel dat u een blob-afbeelding downloadt met fetch()
(of XHR) en deze in een canvas wilt tekenen. Zonder createImageBitmap()
zou u een afbeeldingselement en een Blob-URL moeten maken om de afbeelding in een indeling te krijgen die u zou kunnen gebruiken. Hiermee krijg je een veel directere route naar schilderen:
fetch(url)
.then(response => response.blob())
.then(blob => createImageBitmap(blob))
.then(imageBitmap => ctx.drawImage(imageBitmap, 0, 0));
Deze aanpak werkt ook met afbeeldingen die zijn opgeslagen als blobs in IndexedDB, waardoor blobs een handig tussenformaat zijn. Toevallig ondersteunt Chrome 50 ook de .toBlob()
methode op canvaselementen, wat betekent dat je bijvoorbeeld blobs kunt genereren op basis van canvaselementen.
CreateImageBitmap() gebruiken in webwerkers
Een van de leukste eigenschappen van createImageBitmap()
is dat het ook beschikbaar is inworkers, wat betekent dat je nu afbeeldingen kunt decoderen waar je maar wilt. Als u veel afbeeldingen moet decoderen die u als niet-essentieel beschouwt, kunt u de URL's ervan naar een webwerker sturen, die ze zal downloaden en decoderen zodra de tijd het toelaat. Het zou ze vervolgens terugbrengen naar de hoofddraad om op een canvas te tekenen.
De code om dit te doen kan er ongeveer zo uitzien:
// In the worker.
fetch(imageURL)
.then(response => response.blob())
.then(blob => createImageBitmap(blob))
.then(imageBitmap => {
// Transfer the imageBitmap back to main thread.
self.postMessage({ imageBitmap }, [imageBitmap]);
}, err => {
self.postMessage({ err });
});
// In the main thread.
worker.onmessage = (evt) => {
if (evt.data.err)
throw new Error(evt.data.err);
canvasContext.drawImage(evt.data.imageBitmap, 0, 0);
}
Als je vandaag createImageBitmap()
aanroept in de hoofdthread, is dat precies waar de decodering zal plaatsvinden. Het is echter de bedoeling dat Chrome de decodering automatisch in een andere thread uitvoert , waardoor de werklast van de hoofdthread laag blijft. In de tussentijd moet u er echter op letten dat u de hoofdthread decodeert, omdat dit intensief werk is dat andere essentiële taken zou kunnen blokkeren, zoals JavaScript, stijlberekeningen, lay-out, schilderen of composities maken.
Een hulpbibliotheek
Om het leven een beetje eenvoudiger te maken, heb ik een helperbibliotheek gemaakt die de decodering van een werker afhandelt, en de gedecodeerde afbeelding terugstuurt naar de hoofdthread, en deze in een canvas tekent. Je moet het natuurlijk gerust reverse-engineeren en het model op je eigen apps toepassen. Het grootste voordeel is meer controle, maar dat gaat (zoals gewoonlijk) gepaard met meer code, meer debuggen en meer randgevallen waarmee rekening moet worden gehouden dan het gebruik van een <img>
-element.
Als je meer controle nodig hebt met het decoderen van afbeeldingen, is createImageBitmap()
je nieuwe beste vriend. Bekijk het in Chrome 50 en laat ons weten hoe het met je gaat!
Het decoderen van afbeeldingen voor gebruik met een canvas is vrij gebruikelijk, of het nu gaat om gebruikers de mogelijkheid te geven een avatar aan te passen, een afbeelding bij te snijden of gewoon in te zoomen op een foto. Het probleem met het decoderen van afbeeldingen is dat het CPU-intensief kan zijn, en dat kan soms 'jank' of 'checkerboarding' betekenen. Vanaf Chrome 50 (en in Firefox 42+) heb je nu een andere optie: createImageBitmap()
. Hiermee kunt u een afbeelding op de achtergrond decoderen en toegang krijgen tot een nieuwe ImageBitmap
primitief, die u op dezelfde manier in een canvas kunt tekenen als een <img>
-element, een ander canvas of een video.
Blobs tekenen met createImageBitmap()
Stel dat u een blob-afbeelding downloadt met fetch()
(of XHR) en deze in een canvas wilt tekenen. Zonder createImageBitmap()
zou u een afbeeldingselement en een Blob-URL moeten maken om de afbeelding in een indeling te krijgen die u zou kunnen gebruiken. Hiermee krijg je een veel directere route naar schilderen:
fetch(url)
.then(response => response.blob())
.then(blob => createImageBitmap(blob))
.then(imageBitmap => ctx.drawImage(imageBitmap, 0, 0));
Deze aanpak werkt ook met afbeeldingen die zijn opgeslagen als blobs in IndexedDB, waardoor blobs een handig tussenformaat zijn. Toevallig ondersteunt Chrome 50 ook de .toBlob()
methode op canvaselementen, wat betekent dat je bijvoorbeeld blobs kunt genereren op basis van canvaselementen.
CreateImageBitmap() gebruiken in webwerkers
Een van de leukste eigenschappen van createImageBitmap()
is dat het ook beschikbaar is inworkers, wat betekent dat je nu afbeeldingen kunt decoderen waar je maar wilt. Als u veel afbeeldingen moet decoderen die u als niet-essentieel beschouwt, kunt u de URL's ervan naar een webwerker sturen, die ze zal downloaden en decoderen zodra de tijd het toelaat. Het zou ze vervolgens terugbrengen naar de hoofddraad om op een canvas te tekenen.
De code om dit te doen kan er ongeveer zo uitzien:
// In the worker.
fetch(imageURL)
.then(response => response.blob())
.then(blob => createImageBitmap(blob))
.then(imageBitmap => {
// Transfer the imageBitmap back to main thread.
self.postMessage({ imageBitmap }, [imageBitmap]);
}, err => {
self.postMessage({ err });
});
// In the main thread.
worker.onmessage = (evt) => {
if (evt.data.err)
throw new Error(evt.data.err);
canvasContext.drawImage(evt.data.imageBitmap, 0, 0);
}
Als je vandaag createImageBitmap()
aanroept in de hoofdthread, is dat precies waar de decodering zal plaatsvinden. Het is echter de bedoeling dat Chrome de decodering automatisch in een andere thread uitvoert , waardoor de werklast van de hoofdthread laag blijft. In de tussentijd moet u er echter op letten dat u de hoofdthread decodeert, omdat dit intensief werk is dat andere essentiële taken zou kunnen blokkeren, zoals JavaScript, stijlberekeningen, lay-out, schilderen of compositie.
Een hulpbibliotheek
Om het leven een beetje eenvoudiger te maken, heb ik een helperbibliotheek gemaakt die de decodering van een werker afhandelt, en de gedecodeerde afbeelding terugstuurt naar de hoofdthread, en deze in een canvas tekent. Je moet het natuurlijk gerust reverse-engineeren en het model op je eigen apps toepassen. Het grootste voordeel is meer controle, maar dat gaat (zoals gewoonlijk) gepaard met meer code, meer debuggen en meer randgevallen waarmee rekening moet worden gehouden dan het gebruik van een <img>
-element.
Als je meer controle nodig hebt met het decoderen van afbeeldingen, is createImageBitmap()
je nieuwe beste vriend. Bekijk het in Chrome 50 en laat ons weten hoe het met je gaat!