decodePdfImagePixels function

PdfDecodedPixels? decodePdfImagePixels(
  1. CosDocument cos,
  2. CosStream stream
)

Decodes an image XObject stream to premultiplied, codec-ready RGBA purely (no dart:ui), or returns null when the platform JPEG codec is needed - a non-CMYK DCTDecode base, or any image paired with a DCTDecode- encoded /SMask - or the image can't be decoded. On null the caller falls back to the dart:ui decode path (decodePdfImageBase + the codec).

Implementation

PdfDecodedPixels? decodePdfImagePixels(CosDocument cos, CosStream stream) {
  final dict = stream.dictionary;
  final isStencil = cos.resolve(dict['ImageMask']) == const CosBoolean(true);

  // Bail before decoding the base, not after: a DCTDecode /SMask sends the
  // image to the `dart:ui` path whatever the base holds, and that path decodes
  // the base itself ([decodePdfImageBase]), so a base decoded here is thrown
  // away and paid for twice. A stencil ignores the soft mask, so it stays.
  if (!isStencil && _softMaskIsDct(cos, dict)) return null;

  final base = decodePdfImageBase(cos, stream);
  if (base == null) return null;

  if (isStencil) {
    // A stencil's alpha is already in base.rgba; no soft mask applies.
    return _finish(base.rgba, base.width, base.height, hasAlpha: true);
  }
  final mask = pdfImageSoftMask(cos, dict) ?? pdfImageStencilMask(cos, dict);
  if (mask == null) {
    return _finish(base.rgba, base.width, base.height, hasAlpha: !base.opaque);
  }
  final m = pdfApplyImageAlpha(base.rgba, base.width, base.height, mask);
  return _finish(m.$1, m.$2, m.$3, hasAlpha: true);
}