Start · Sprachen · JavaScript · Referenz · ImageData

ImageData

Schnittstelle

Enthält die rohen RGBA-Pixeldaten eines rechteckigen Bereichs, z. B. eines <code>&lt;canvas&gt;</code>-Elements, als <code>Uint8ClampedArray</code>.

seit JavaScript Baseline: alle Browser (Konstruktor seit ca. 2016; Kategorie: webapi

Signatur

interface ImageData

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

Typ
ImageData
Beschreibung
Ein neues 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);
256 100 102400

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)})`);
});
rgba(200, 50, 120, 1.00)

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" + passender Access-Control-Allow-Origin-Header) ins Canvas gezeichnet, ist das Canvas „tainted“. getImageData() wirft dann einen SecurityError.
  • 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, globalAlpha oder globalCompositeOperation, sondern ersetzt die Pixel direkt. Zum Überblenden zeichnest du besser über ein ImageBitmap oder ein zweites Canvas mit drawImage().
  • Leistung: Häufige getImageData()-Aufrufe sind teuer, weil die Daten aus der GPU gelesen werden müssen. Setze in dem Fall { willReadFrequently: true } beim getContext()-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 zu width/height passt. Sehr große Maße können einen RangeError auslö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 du devicePixelRatio einrechnen.
  • Kompatibilität: ImageData selbst wird überall unterstützt, auch in Workern und mit OffscreenCanvas. colorSpace und 'display-p3' gibt es erst in neueren Chromium- und Safari-Versionen, in Firefox eingeschränkt.