Signatur
Beschreibung
copyExternalImageToTexture() ist in WebGPU der bequemste Weg, Bilddaten aus dem Browser in eine Textur zu übertragen. Im Gegensatz zu GPUQueue.writeTexture() muss man die Pixel nicht selbst als ArrayBuffer dekodieren. Der Browser übernimmt Dekodierung, Umrechnung des Farbraums, optional die Vormultiplikation des Alphakanals und das vertikale Spiegeln.
Als Quelle sind ImageBitmap, ImageData, HTMLImageElement, HTMLVideoElement, VideoFrame, HTMLCanvasElement und OffscreenCanvas erlaubt. Kopiert wird immer der aktuelle Zustand der Quelle. Bei Videos ist das das gerade angezeigte Bild. Für laufende Videos muss man die Methode deshalb in jedem Frame erneut aufrufen. Alternativ kann man mit GPUDevice.importExternalTexture() ohne Kopie arbeiten.
Der Aufruf wird wie alle Queue-Operationen in die Warteschlange der GPU eingereiht und kehrt sofort zurück. Validierungsfehler, etwa ein falsches Texturformat oder fehlende Usage-Flags, landen im Fehlermechanismus von WebGPU (pushErrorScope() bzw. das Event uncapturederror). Nur Fehler an der Quelle selbst werden synchron als Ausnahme geworfen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $source Pflicht | GPUCopyExternalImageSourceInfo | Objekt mit der Quelle:
|
|
| $destination Pflicht | GPUCopyExternalImageDestInfo | Ziel der Kopie:
|
|
| $copySize Pflicht | GPUExtent3D | Größe des kopierten Bereichs, als Array [width, height, depthOrArrayLayers] oder als Objekt { width, height, depthOrArrayLayers }. depthOrArrayLayers muss 1 sein. |
Rückgabewert
Beispiele
Bild laden und in eine Textur kopieren
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const response = await fetch('/img/stein.png');
const bitmap = await createImageBitmap(await response.blob(), {
colorSpaceConversion: 'none'
});
const texture = device.createTexture({
size: [bitmap.width, bitmap.height],
format: 'rgba8unorm',
// COPY_DST und RENDER_ATTACHMENT sind Pflicht
usage: GPUTextureUsage.TEXTURE_BINDING |
GPUTextureUsage.COPY_DST |
GPUTextureUsage.RENDER_ATTACHMENT
});
device.queue.copyExternalImageToTexture(
{ source: bitmap, flipY: false },
{ texture },
[bitmap.width, bitmap.height]
);
bitmap.close(); // Speicher der Bitmap freigeben
console.log('Textur:', texture.width, 'x', texture.height);
Jedes Videobild in eine Textur übertragen
const video = document.querySelector('video');
await video.play();
const videoTexture = device.createTexture({
size: [video.videoWidth, video.videoHeight],
format: 'rgba8unorm',
usage: GPUTextureUsage.TEXTURE_BINDING |
GPUTextureUsage.COPY_DST |
GPUTextureUsage.RENDER_ATTACHMENT
});
const onFrame = () => {
// Schnappschuss des aktuellen Videobilds
device.queue.copyExternalImageToTexture(
{ source: video },
{ texture: videoTexture },
[video.videoWidth, video.videoHeight]
);
// ... hier rendern ...
video.requestVideoFrameCallback(onFrame);
};
video.requestVideoFrameCallback(onFrame);
Ausschnitt eines Canvas mit Fehlerbehandlung kopieren
const canvas = new OffscreenCanvas(256, 256);
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
ctx.fillRect(0, 0, 256, 256);
const atlas = device.createTexture({
size: [1024, 1024],
format: 'rgba8unorm',
usage: GPUTextureUsage.TEXTURE_BINDING |
GPUTextureUsage.COPY_DST |
GPUTextureUsage.RENDER_ATTACHMENT
});
device.pushErrorScope('validation');
try {
device.queue.copyExternalImageToTexture(
{ source: canvas, origin: { x: 64, y: 64 } },
{ texture: atlas, origin: { x: 512, y: 0 }, premultipliedAlpha: true },
{ width: 128, height: 128 }
);
} catch (err) {
// z. B. SecurityError bei Cross-Origin-Quelle
console.error(err.name, err.message);
}
const gpuError = await device.popErrorScope();
console.log(gpuError ? gpuError.message : 'Kopie erfolgreich');