mozilla/pdf.js · error · FormatError

Reading gray scale from a color image: ${numComps}

Error message

Reading gray scale from a color image: ${numComps}

What it means

Thrown by PDFImage.fillGrayBuffer when the image has more than one color component (numComps !== 1). fillGrayBuffer is meant to extract a grayscale channel; calling it on an RGB/CMYK image is a logic error because there is no single gray channel to copy.

Source

Thrown at src/core/image.js:1019

    buffer,
    {
      destWidth,
      destHeight,
      invertOutput,
      maxRows,
      offset = 0,
      stride = 1,
    } = {}
  ) {
    if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
      assert(
        buffer instanceof Uint8ClampedArray,
        'PDFImage.fillGrayBuffer: Unsupported "buffer" type.'
      );
    }
    const numComps = this.numComps;
    if (numComps !== 1) {
      throw new FormatError(
        `Reading gray scale from a color image: ${numComps}`
      );
    }

    const srcWidth = this.width;
    const srcHeight = this.height;
    const bpc = this.bpc;

    // rows start at byte boundary
    const rowBytes = (srcWidth * numComps * bpc + 7) >> 3;
    const imgArray = await this.getImageBytes(srcHeight * rowBytes, {
      internal: true,
    });
    const comps = this.getComponents(imgArray);

    const resolvedDestWidth = destWidth ?? srcWidth;
    const resolvedDestHeight = destHeight ?? srcHeight;
    const needsResampling =

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Report the PDF to pdf.js maintainers; this is normally an internal dispatch mismatch.
  2. Ensure the source PDF's /SMask and /Mask reference single-channel (gray) images as the spec requires.
  3. Catch FormatError and fall back to full RGBA compositing without the gray fast-path.
  4. Regenerate the PDF so soft masks use 1-component images.
Defensive patterns

Strategy: validation

Validate before calling

// Before calling fillGrayBuffer, ensure the image is single-channel:
function canFillGray(image) {
  return image?.numComps === 1;
}

Type guard

function isSingleComponentImage(image) {
  return image != null && image.numComps === 1;
}

Try / catch

try { await page.render({ canvasContext }).promise; }
catch (err) {
  if (/Reading gray scale from a color image/.test(err?.message || '')) {
    console.warn('Gray fill requested on multi-component image; skipping.');
  } else throw err;
}

Prevention

When it happens

Trigger: fillGrayBuffer is invoked on a multi-component image, typically as a sub-step of compositing a single-channel mask or smask whose underlying image was mistakenly treated as gray. Reached during alpha/mask fill operations.

Common situations: Usually an internal dispatch bug (a mask image resolved to a multi-component PDFImage) rather than a user config issue; can be triggered by PDFs whose SMask/Mask references point at a color image instead of a gray one.

Related errors


AI-assisted analysis of mozilla/pdf.js@5903d58d58 (2026-08-13). Data as JSON: /api/errors/aab92b2e3daa62a1. Report an issue: GitHub.