decodePdfImagePixels function
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);
}