Signatur
Beschreibung
ImageData.data liefert die Rohdaten eines Bildausschnitts als eindimensionales typisiertes Array. Jedes Pixel belegt vier aufeinanderfolgende Einträge in der Reihenfolge Rot, Grün, Blau, Alpha (RGBA). Die Zeilen liegen von oben nach unten und innerhalb einer Zeile von links nach rechts hintereinander. Die Länge des Arrays ist daher immer width * height * 4.
Standardmäßig ist das Array ein Uint8ClampedArray mit Werten von 0 bis 255. Werte außerhalb dieses Bereichs werden beim Schreiben automatisch begrenzt (z. B. wird aus 300 der Wert 255 und aus -20 der Wert 0), Nachkommastellen werden gerundet. Wird das ImageData-Objekt mit pixelFormat: "rgba-float16" erzeugt, ist data stattdessen ein Float16Array mit Gleitkommawerten (typischerweise 0.0 bis 1.0), etwa für HDR-Inhalte.
Die Eigenschaft selbst ist schreibgeschützt: Man kann ihr kein neues Array zuweisen. Der Inhalt des Arrays lässt sich jedoch beliebig verändern. Das ist die Grundlage für pixelgenaue Bildbearbeitung im Browser, etwa Filter (Graustufen, Invertieren, Helligkeit), Farbanalysen, Histogramme oder die Erzeugung prozeduraler Grafiken. Änderungen werden erst sichtbar, wenn das Objekt per CanvasRenderingContext2D.putImageData() zurück in den Canvas geschrieben wird.
Der Index eines Pixels an Position (x, y) berechnet sich als (y * width + x) * 4; die Farbkanäle liegen dann an diesem Index sowie den drei folgenden.
Rückgabewert
width * height * 4 mit den RGBA-Werten aller Pixel. Bei Uint8ClampedArray liegen die Werte im Bereich 0–255; bei Float16Array (Pixelformat "rgba-float16") sind es Gleitkommawerte.Beispiele
Graustufen-Filter auf einen Canvas anwenden
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const { data } = imageData;
for (let i = 0; i < data.length; i += 4) {
// Gewichtete Helligkeit nach ITU-R BT.601
const gray = 0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2];
data[i] = data[i + 1] = data[i + 2] = gray;
// data[i + 3] (Alpha) bleibt unverändert
}
ctx.putImageData(imageData, 0, 0);
Farbe eines einzelnen Pixels auslesen
const canvas = document.createElement('canvas');
canvas.width = 10;
canvas.height = 10;
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgb(255, 128, 0)';
ctx.fillRect(0, 0, 10, 10);
const imageData = ctx.getImageData(0, 0, 10, 10);
const getPixel = (img, x, y) => {
const i = (y * img.width + x) * 4;
const [r, g, b, a] = img.data.slice(i, i + 4);
return { r, g, b, a };
};
console.log(getPixel(imageData, 3, 7));
console.log(imageData.data.length);
Farbverlauf direkt aus Pixeldaten erzeugen
const width = 256;
const height = 100;
const imageData = new ImageData(width, height);
const { data } = imageData;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const i = (y * width + x) * 4;
data[i] = x; // Rot steigt von links nach rechts
data[i + 1] = 0;
data[i + 2] = 255 - x; // Blau fällt
data[i + 3] = 255; // voll deckend
}
}
const ctx = document.querySelector('canvas').getContext('2d');
ctx.putImageData(imageData, 0, 0);
Automatisches Begrenzen der Werte (Clamping)
const img = new ImageData(1, 1);
img.data[0] = 300; // wird zu 255
img.data[1] = -50; // wird zu 0
img.data[2] = 127.5; // wird gerundet
console.log(Array.from(img.data));
// Die Eigenschaft selbst ist schreibgeschützt:
img.data = new Uint8ClampedArray(4); // wird ignoriert (TypeError im Strict Mode)
console.log(img.data[0]);
// Wichtig · Fallstricke
- Änderungen nicht automatisch sichtbar: Das Bearbeiten von
dataverändert den Canvas nicht. Erstctx.putImageData(imageData, x, y)schreibt die Pixel zurück. - Vormultipliziertes Alpha: Canvas speichert intern oft vormultiplizierte Farben. Halbtransparente Pixel können daher nach
putImageData()und erneutemgetImageData()leicht abweichende RGB-Werte haben (Rundungsverluste). - CORS / „tainted canvas“: Wurde ein Bild einer fremden Herkunft ohne CORS-Freigabe (
crossOrigin="anonymous"plus passender Server-Header) gezeichnet, wirftgetImageData()einenSecurityError– an die Daten kommt man dann gar nicht heran. - Performance: Bei großen Bildern ist eine einfache
for-Schleife meist deutlich schneller alsforEachodermap. Für häufiges Auslesen den Kontext mitgetContext('2d', { willReadFrequently: true })anlegen. Für aufwendige Filter lohnen sich Web Worker (mitOffscreenCanvas) oder WebGL. - Schnellere 32-Bit-Zugriffe: Über
new Uint32Array(imageData.data.buffer)lässt sich ein ganzes Pixel auf einmal lesen/schreiben – die Byte-Reihenfolge hängt aber von der Endianness der Plattform ab (meist Little Endian, also ABGR). - Datenschutz: Manche Browser (z. B. Firefox mit Fingerprinting-Schutz, Brave) verfälschen ausgelesene Pixeldaten leicht, um Canvas-Fingerprinting zu erschweren.
- Kompatibilität: Die
Uint8ClampedArray-Variante wird von allen Browsern unterstützt. Das Pixelformat"rgba-float16"mitFloat16Arrayist sehr neu und nur in wenigen Browsern verfügbar – vorher per Feature-Erkennung prüfen.