Signatur
Beschreibung
ImageData ist ein Container für Pixeldaten: Er speichert Breite (width), Höhe (height), den Farbraum (colorSpace) und ein eindimensionales Uint8ClampedArray (data). Darin stehen die Pixel zeilenweise von links oben nach rechts unten, pro Pixel vier Bytes in der Reihenfolge R, G, B, A mit Werten von 0 bis 255. Das Array ist also genau width * height * 4 Elemente lang.
Ein ImageData-Objekt bekommst du meist über CanvasRenderingContext2D.getImageData() (Pixel aus dem Canvas auslesen) oder createImageData() (leeres Pixelraster). Du kannst es auch direkt mit new ImageData(...) erzeugen. Mit putImageData() schreibst du die geänderten Pixel zurück ins Canvas.
Typische Einsatzgebiete sind Bildfilter (Graustufen, Invertieren, Helligkeit), Pixelanalysen (Farbe unter dem Mauszeiger, Histogramme), prozedurale Grafik (Rauschen, Fraktale) und der Datenaustausch mit Web Workern oder WebAssembly. Weil ImageData übertragbar ist und auch in Workern zur Verfügung steht, kannst du rechenintensive Pixelarbeit aus dem Hauptthread auslagern.
Der Index eines Pixels an Position (x, y) ist (y * width + x) * 4. Weil Uint8ClampedArray Werte automatisch auf 0–255 begrenzt und rundet, brauchst du beim Schreiben kein eigenes Clamping.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $width Pflicht | number | Breite in Pixeln (vorzeichenlose Ganzzahl > 0). Konstruktorform new ImageData(width, height[, settings]). |
|
| $height Pflicht | number | Höhe in Pixeln (> 0). Wenn dataArray übergeben wird, ist sie optional und wird dann aus der Array-Länge berechnet. |
|
| $dataArray | Uint8ClampedArray | Vorhandene Pixeldaten für die Form new ImageData(dataArray, width[, height[, settings]]). Die Länge muss ein Vielfaches von 4 * width sein. Das Array wird nicht kopiert, sondern direkt verwendet. |
|
| $settings | { colorSpace?: 'srgb' | 'display-p3' } | { colorSpace: 'srgb' } | Optionales Objekt, das den Farbraum der Pixeldaten festlegt. |
Rückgabewert
ImageData-Objekt mit den schreibgeschützten Eigenschaften width, height, colorSpace und data (Uint8ClampedArray). Die Eigenschaft ist schreibgeschützt, der Inhalt des Arrays lässt sich aber ändern. Ohne dataArray sind alle Pixel transparentes Schwarz (0, 0, 0, 0).Beispiele
ImageData erzeugen und einen Farbverlauf zeichnen
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const width = 256;
const height = 100;
const img = new ImageData(width, height);
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const i = (y * width + x) * 4;
img.data[i] = x; // Rot steigt von links nach rechts
img.data[i + 1] = 0; // Grün
img.data[i + 2] = 255 - x; // Blau fällt
img.data[i + 3] = 255; // voll deckend
}
}
ctx.putImageData(img, 0, 0);
console.log(img.width, img.height, img.data.length);
Graustufen-Filter auf ein geladenes Bild
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });
const bild = new Image();
bild.src = 'foto.jpg'; // gleiche Herkunft oder CORS-freigegeben
await bild.decode();
canvas.width = bild.naturalWidth;
canvas.height = bild.naturalHeight;
ctx.drawImage(bild, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const { data } = imageData;
for (let i = 0; i < data.length; i += 4) {
// Gewichtete Luminanz nach ITU-R BT.601
const grau = 0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2];
data[i] = data[i + 1] = data[i + 2] = grau;
}
ctx.putImageData(imageData, 0, 0);
Farbe unter dem Mauszeiger auslesen
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });
ctx.fillStyle = 'rgb(200, 50, 120)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
canvas.addEventListener('click', (event) => {
const rect = canvas.getBoundingClientRect();
const x = Math.floor(event.clientX - rect.left);
const y = Math.floor(event.clientY - rect.top);
const [r, g, b, a] = ctx.getImageData(x, y, 1, 1).data;
console.log(`rgba(${r}, ${g}, ${b}, ${(a / 255).toFixed(2)})`);
});
Pixelarbeit in einen Web Worker auslagern
// main.js
const ctx = document.querySelector('canvas').getContext('2d');
const worker = new Worker('invert-worker.js');
const imageData = ctx.getImageData(0, 0, 300, 150);
worker.onmessage = ({ data }) => ctx.putImageData(data, 0, 0);
// Puffer übertragen statt kopieren (imageData ist danach im Hauptthread unbrauchbar)
worker.postMessage(imageData, [imageData.data.buffer]);
// invert-worker.js
self.onmessage = ({ data: img }) => {
const d = img.data;
for (let i = 0; i < d.length; i += 4) {
d[i] = 255 - d[i];
d[i + 1] = 255 - d[i + 1];
d[i + 2] = 255 - d[i + 2];
}
self.postMessage(img, [img.data.buffer]);
};
// Wichtig · Fallstricke
- Cross-Origin-Sperre: Wurde ein Bild aus fremder Quelle ohne CORS-Freigabe (
crossOrigin="anonymous"+ passenderAccess-Control-Allow-Origin-Header) ins Canvas gezeichnet, ist das Canvas „tainted“.getImageData()wirft dann einenSecurityError. - Vormultipliziertes Alpha: Canvas speichert intern oft mit vormultipliziertem Alpha. Schreibst du halbtransparente Pixel mit
putImageData()und liest sie danach wieder aus, weichen die RGB-Werte durch Rundung leicht ab. putImageData()beachtet keine Transformationen, Clipping-Bereiche,globalAlphaoderglobalCompositeOperation, sondern ersetzt die Pixel direkt. Zum Überblenden zeichnest du besser über einImageBitmapoder ein zweites Canvas mitdrawImage().- Leistung: Häufige
getImageData()-Aufrufe sind teuer, weil die Daten aus der GPU gelesen werden müssen. Setze in dem Fall{ willReadFrequently: true }beimgetContext()-Aufruf. Lies außerdem einmal einen großen Bereich statt vieler 1×1-Bereiche. - Der Konstruktor wirft einen
IndexSizeError, wenn Breite oder Höhe 0 sind oder die Array-Länge nicht zuwidth/heightpasst. Sehr große Maße können einenRangeErrorauslösen. - Die Koordinaten und Maße beziehen sich auf die Canvas-Pixel (
canvas.width/height), nicht auf die CSS-Größe. Auf HiDPI-Displays solltest dudevicePixelRatioeinrechnen. - Kompatibilität:
ImageDataselbst wird überall unterstützt, auch in Workern und mitOffscreenCanvas.colorSpaceund'display-p3'gibt es erst in neueren Chromium- und Safari-Versionen, in Firefox eingeschränkt.