pdfImageStencilMask function

PdfImageSoftMask? pdfImageStencilMask(
  1. CosDocument cos,
  2. CosDictionary dict, {
  3. int? targetWidth,
  4. int? targetHeight,
})

An explicit /Mask stencil stream (§8.9.6.3): 1-bit samples where 1 means "masked out" (transparent); /Decode 1 0 flips the polarity.

Implementation

PdfImageSoftMask? pdfImageStencilMask(
  CosDocument cos,
  CosDictionary dict, {
  int? targetWidth,
  int? targetHeight,
}) {
  final mask = cos.resolve(dict['Mask']);
  if (mask is! CosStream) return null;
  try {
    final declaredWidth = _intOf(cos.resolve(mask.dictionary['Width']));
    final declaredHeight = _intOf(cos.resolve(mask.dictionary['Height']));
    if (declaredWidth <= 0 || declaredHeight <= 0) return null;
    final declaredBits =
        _intOf(cos.resolve(mask.dictionary['BitsPerComponent']), fallback: 1);
    if (declaredBits != 1) return null;
    final decode = cos.resolve(mask.dictionary['Decode']);
    final inverted = decode is CosArray &&
        decode.length > 0 &&
        _numOf(cos.resolve(decode[0])) == 1;
    final samples = _maskSampleData(
        cos, mask, declaredWidth, declaredHeight, declaredBits);
    // A codec that hands back wider samples is not a stencil (§8.9.6.3
    // requires 1 bit per sample), whatever the dictionary declared.
    if (samples == null || samples.bits != 1) return null;
    final data = samples.data;
    final width = samples.width;
    final height = samples.height;
    final rowBytes = (width + 7) ~/ 8;
    if (data.length < rowBytes * height) return null;
    final alpha = Uint8List(width * height);
    for (var y = 0; y < height; y++) {
      for (var x = 0; x < width; x++) {
        final bit = (data[y * rowBytes + (x >> 3)] >> (7 - (x & 7))) & 1;
        final masked = inverted ? bit == 0 : bit == 1;
        alpha[y * width + x] = masked ? 0 : 255;
      }
    }
    return _targetSizedSoftMask(
      PdfImageSoftMask(alpha, width, height),
      targetWidth,
      targetHeight,
    );
  } on Exception {
    return null; // unsupported mask: leave the image opaque
  }
}