addImagePage method

Future<int?> addImagePage(
  1. Uint8List encoded, {
  2. Size? size,
  3. double margin = 0,
})

Implementation

Future<int?> addImagePage(Uint8List encoded, {Size? size, double margin = 0}) async {
  final UPdfRaster? raster = await UPdfEdit.rasterizeImage(encoded, maxSize: 4096);
  if (raster == null || raster.isEmpty) return null;
  final double pageWidth = size?.width ?? raster.width.toDouble();
  final double pageHeight = size?.height ?? raster.height.toDouble();
  final int pixels = raster.width * raster.height;
  final Uint8List colour = Uint8List(pixels * 3);
  final Uint8List alpha = Uint8List(pixels);
  bool transparent = false;
  for (int i = 0; i < pixels; i++) {
    colour[i * 3] = raster.rgba[i * 4];
    colour[i * 3 + 1] = raster.rgba[i * 4 + 1];
    colour[i * 3 + 2] = raster.rgba[i * 4 + 2];
    alpha[i] = raster.rgba[i * 4 + 3];
    if (alpha[i] != 255) transparent = true;
  }
  int? maskNumber;
  if (transparent) {
    maskNumber = allocate();
    _objects[maskNumber] = _stream(
      alpha,
      extra: <String, Object?>{
        "Type": const UPdfName("XObject"),
        "Subtype": const UPdfName("Image"),
        "Width": raster.width,
        "Height": raster.height,
        "ColorSpace": const UPdfName("DeviceGray"),
        "BitsPerComponent": 8,
      },
    );
  }
  final int imageNumber = allocate();
  _objects[imageNumber] = _stream(
    colour,
    extra: <String, Object?>{
      "Type": const UPdfName("XObject"),
      "Subtype": const UPdfName("Image"),
      "Width": raster.width,
      "Height": raster.height,
      "ColorSpace": const UPdfName("DeviceRGB"),
      "BitsPerComponent": 8,
      if (maskNumber != null) "SMask": UPdfRef(maskNumber, 0),
    },
  );
  final double drawWidth = pageWidth - margin * 2;
  final double drawHeight = pageHeight - margin * 2;
  final double scale = min(drawWidth / raster.width, drawHeight / raster.height);
  final double placedWidth = raster.width * scale;
  final double placedHeight = raster.height * scale;
  final double offsetX = (pageWidth - placedWidth) / 2;
  final double offsetY = (pageHeight - placedHeight) / 2;
  final int contents = allocate();
  _objects[contents] = _stream(
    Uint8List.fromList(
      utf8.encode("q ${UPdfSerializer.number(placedWidth)} 0 0 ${UPdfSerializer.number(placedHeight)} ${UPdfSerializer.number(offsetX)} ${UPdfSerializer.number(offsetY)} cm /Im0 Do Q"),
    ),
  );
  final int number = allocate();
  _objects[number] = UPdfDict(<String, Object?>{
    "Type": const UPdfName("Page"),
    "MediaBox": <Object?>[0, 0, pageWidth, pageHeight],
    "Resources": UPdfDict(<String, Object?>{
      "XObject": UPdfDict(<String, Object?>{"Im0": UPdfRef(imageNumber, 0)}),
    }),
    "Contents": UPdfRef(contents, 0),
  });
  _pages.add(number);
  return number;
}