logo hsb.horse
← Zur Blog-Übersicht

Blog

Bildverarbeitung mit OffscreenCanvas und Web Worker umsetzen

Wie man mit Web Worker und OffscreenCanvas Bildverarbeitung umsetzt, ohne den Main Thread zu blockieren. Der Artikel fasst ein konkretes Beispiel für eine WebP-Konvertierung zusammen.

Veröffentlicht:

Durch die Kombination von OffscreenCanvas und Web Worker lässt sich Bildverarbeitung umsetzen, ohne den Main Thread zu blockieren.

Verwendete Technologien

  • Web Worker
  • Offscreen Canvas
  • Blob
  • Bitmap

Interface

export interface WorkerRequestBody {
buffer: ArrayBuffer;
type: string;
size: {
height: number;
width: number;
};
}
export interface WorkerResponseBody {
buffer: ArrayBuffer;
contentType: string;
}

Ein Bild im Web Worker verarbeiten

async function imageProcessing(
data: WorkerRequestBody
): Promise<WorkerResponseBody> {
const { buffer, type, size } = data;
// ArrayBuffer zurück in ein Blob umwandeln
const blob = new Blob([buffer], { type });
// OffscreenCanvas erzeugen
const canvas = new OffscreenCanvas(size.width, size.height);
// Aus dem Blob ein Bitmap erzeugen
const bitmap = await createImageBitmap(blob);
// CanvasRenderingContext2D holen
const ctx = canvas.getContext("2d");
if (!ctx) throw new Error("Context2D is not defined");
// Bild auf das Canvas zeichnen
ctx.drawImage(bitmap, 0, 0);
// In WebP umwandeln
const webp = await canvas.convertToBlob({
type: "image/webp",
quality: 0.85,
});
// WebP-Blob in ArrayBuffer umwandeln
const buf = await webp.arrayBuffer();
return {
buffer: buf,
contentType: "image/webp",
};
}
self.addEventListener("message", async (e: MessageEvent<WorkerRequestBody>) => {
const output = await imageProcessing(e.data);
// Zweites Argument angeben, um den Besitz des ArrayBuffer an den UI-Thread zu übertragen
self.postMessage(output, [output.buffer]);
});

Ein Bild an den Worker senden und das konvertierte Bild empfangen

import MyWorker from "./worker.ts";
const worker = new MyWorker();
const fileInput = document.querySelector<HTMLInputElement>("#js-file-input");
worker.addEventListener("message", (e: MessageEvent<WorkerResponseBody>) => {
const { buffer, contentType } = e.data;
const blob = new Blob([buffer], { type: contentType });
// do something
});
fileInput.addEventListener("change", async (e) => {
const [file] = Array.from(fileInput.files);
if (!file) return;
const buffer = await file.arrayBuffer();
const type = file.type;
const size = { height: 1080, width: 1980 }; // Bildgröße ermitteln
// An den Web Worker senden und Besitz übertragen
worker.postMessage(
{
buffer,
type,
size
},
[buffer]
);
});

Wichtige Punkte

  1. OffscreenCanvas: eine Canvas-API, die im Web Worker verwendet werden kann
  2. ArrayBuffer-Transfer: Daten werden effizient übergeben, indem der Besitz übertragen wird
  3. convertToBlob: mit OffscreenCanvas in Formate wie WebP konvertieren

Zusammenfassung

Mit OffscreenCanvas und Web Worker lässt sich Bildverarbeitung ausführen, ohne den Main Thread zu blockieren.

Wenn viele Bilder verarbeitet oder teure Konvertierungen ausgeführt werden müssen, bleibt die UI reaktionsfähig und die Nutzererfahrung verbessert sich.