Signatur
Beschreibung
putImageData() ist das Gegenstück zu getImageData(): Es überträgt rohe RGBA-Pixeldaten aus einem ImageData-Objekt 1:1 in den Bitmap-Speicher des Canvas. So lassen sich Pixelmanipulationen wie Graustufen-Filter, Invertierung, Schwellwerte, prozedurale Texturen oder Partikel-Effekte umsetzen, bei denen jeder Pixel einzeln berechnet wird.
Wichtig: Die Methode arbeitet am Zeichenzustand vorbei. Transformationen (translate, scale, rotate), globalAlpha, globalCompositeOperation, Schatten, Filter und Clipping-Pfade werden ignoriert. Die Pixel werden nicht mit dem vorhandenen Inhalt gemischt, sondern ersetzen ihn – auch transparente Pixel überschreiben also das Darunterliegende.
Mit den optionalen Parametern dirtyX, dirtyY, dirtyWidth und dirtyHeight kann man nur einen Ausschnitt des ImageData schreiben. Das ist nützlich, wenn sich in einem großen Puffer nur ein kleiner Bereich geändert hat. Die Dirty-Koordinaten beziehen sich auf das ImageData, nicht auf den Canvas; der Ausschnitt landet an Position dx + dirtyX, dy + dirtyY.
Wer Bilddaten mit Transformation oder Alpha-Blending zeichnen möchte, sollte stattdessen ein ImageBitmap (via createImageBitmap()) oder einen Offscreen-Canvas erzeugen und diesen mit drawImage() zeichnen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $imageData Pflicht | ImageData | Das ImageData-Objekt mit den RGBA-Pixelwerten (je 4 Bytes pro Pixel in einem Uint8ClampedArray). |
|
| $dx Pflicht | number | Horizontale Zielposition (in Gerätepixeln) auf dem Canvas, an der die linke obere Ecke des ImageData platziert wird. |
|
| $dy Pflicht | number | Vertikale Zielposition auf dem Canvas. | |
| $dirtyX | number | 0 | X-Koordinate des zu schreibenden Ausschnitts innerhalb des ImageData. |
| $dirtyY | number | 0 | Y-Koordinate des zu schreibenden Ausschnitts innerhalb des ImageData. |
| $dirtyWidth | number | imageData.width | Breite des Ausschnitts. Negative Werte sind erlaubt und spiegeln das Rechteck in Richtung Ursprung. |
| $dirtyHeight | number | imageData.height | Höhe des Ausschnitts. Negative Werte sind erlaubt. |
Beispiele
Graustufen-Filter auf ein gezeichnetes Bild anwenden
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });
const img = new Image();
img.src = 'foto.jpg'; // muss same-origin oder CORS-freigegeben sein
await img.decode();
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const { data } = imageData;
for (let i = 0; i < data.length; i += 4) {
// Luminanz nach ITU-R BT.709
const grau = 0.2126 * data[i] + 0.7152 * data[i + 1] + 0.0722 * data[i + 2];
data[i] = data[i + 1] = data[i + 2] = grau;
// data[i + 3] (Alpha) bleibt unverändert
}
ctx.putImageData(imageData, 0, 0);
Prozeduralen Farbverlauf Pixel für Pixel erzeugen
const ctx = document.querySelector('canvas').getContext('2d');
const breite = 256;
const hoehe = 256;
const imageData = ctx.createImageData(breite, hoehe);
for (let y = 0; y < hoehe; y++) {
for (let x = 0; x < breite; x++) {
const i = (y * breite + x) * 4;
imageData.data[i] = x; // Rot steigt nach rechts
imageData.data[i + 1] = y; // Grün steigt nach unten
imageData.data[i + 2] = 128; // konstantes Blau
imageData.data[i + 3] = 255; // voll deckend
}
}
ctx.putImageData(imageData, 20, 20);
console.log(ctx.getImageData(20, 20, 1, 1).data);
Nur einen Teilbereich schreiben (Dirty Rectangle)
const ctx = document.querySelector('canvas').getContext('2d');
const puffer = ctx.createImageData(200, 200);
// Gesamten Puffer rot füllen
for (let i = 0; i < puffer.data.length; i += 4) {
puffer.data.set([255, 0, 0, 255], i);
}
// Nur den Ausschnitt (50,50)-(100,100) des Puffers schreiben.
// Er landet auf dem Canvas bei (10 + 50, 10 + 50) = (60, 60).
ctx.putImageData(puffer, 10, 10, 50, 50, 50, 50);
console.log(ctx.getImageData(60, 60, 1, 1).data); // rot
console.log(ctx.getImageData(10, 10, 1, 1).data); // unberührt
Transformationen werden ignoriert – Workaround mit ImageBitmap
const ctx = document.querySelector('canvas').getContext('2d');
const imageData = ctx.createImageData(50, 50);
imageData.data.fill(255); // weiße, deckende Pixel
ctx.translate(100, 100);
ctx.rotate(Math.PI / 4);
// Landet trotz Transformation unrotiert bei (0, 0):
ctx.putImageData(imageData, 0, 0);
// Mit Transformation zeichnen: erst in ImageBitmap umwandeln
const bitmap = await createImageBitmap(imageData);
ctx.drawImage(bitmap, -25, -25); // rotiert um (100, 100)
// Wichtig · Fallstricke
- Kein Zeichenzustand: Transformationsmatrix,
globalAlpha,globalCompositeOperation,filter, Schatten und Clipping haben keinen Einfluss. Pixel werden ersetzt, nicht überblendet – für BlendingdrawImage()mit einemImageBitmapverwenden. - Koordinaten in Gerätepixeln: Bei HiDPI-Canvas (z. B.
canvas.width = cssBreite * devicePixelRatioplusctx.scale()) wirkt die Skalierung nicht aufputImageData(). Positionen müssen selbst umgerechnet werden. - Premultiplied Alpha: Browser speichern intern oft vormultiplizierte Alphawerte. Ein Rundlauf
putImageData()→getImageData()liefert bei halbtransparenten Pixeln daher nicht zwingend exakt dieselben RGB-Werte. - Fehler: Ein
TypeErrorwird geworfen, wennimageDatakeinImageDataist; einInvalidStateError, wenn dessen Daten-Puffer abgekoppelt (detached) wurde, z. B. nach Übertragung an einen Worker. - Performance: Häufige Aufrufe mit großen Puffern sind teuer (GPU↔CPU-Synchronisation). Bei vielen Lesezugriffen
getContext('2d', { willReadFrequently: true })setzen und nach Möglichkeit Dirty Rectangles nutzen. Für schwere PixelarbeitOffscreenCanvasim Worker oder WebGL in Betracht ziehen. - Sicherheit:
putImageData()selbst ist unkritisch, das vorherigegetImageData()wirft aber einenSecurityError, wenn der Canvas durch fremde Bilder ohne CORS-Freigabe „verunreinigt“ (tainted) ist. - Seit jeher in allen Browsern verfügbar; ebenso auf
OffscreenCanvasRenderingContext2D.