preparePdf static method

Future<PdfExternalSigningPrepared> preparePdf({
  1. required Uint8List inputBytes,
  2. required int pageNumber,
  3. required PdfRect bounds,
  4. required String fieldName,
  5. PdfSignatureConfig? signature,
  6. List<List<int>> publicCertificates = const <List<int>>[],
  7. void drawAppearance(
    1. PdfGraphics graphics,
    2. PdfRect bounds
    )?,
  8. int contentsReserveSize = 16384,
  9. int byteRangeDigits = 10,
})

Prepares a PDF with a signature placeholder and returns ByteRange + hash.

Implementation

static Future<PdfExternalSigningPrepared> preparePdf({
  required Uint8List inputBytes,
  required int pageNumber,
  required PdfRect bounds,
  required String fieldName,
  PdfSignatureConfig? signature,
  List<List<int>> publicCertificates = const <List<int>>[],
  void Function(PdfGraphics graphics, PdfRect bounds)? drawAppearance,
  int contentsReserveSize = 16384,
  int byteRangeDigits = 10,
}) async {
  final parser = PdfDocumentParser(inputBytes);
  final document = PdfDocument.load(parser);

  final pageIndex = pageNumber - 1;
  if (pageIndex < 0 || pageIndex >= document.pdfPageList.pages.length) {
    throw RangeError.index(
        pageIndex, document.pdfPageList.pages, 'pageNumber');
  }

  final existingField = document.signatures.findByName(fieldName);
  PdfRect? fieldBounds;
  if (existingField != null && existingField.info.rect != null) {
    final rect = existingField.info.rect!;
    if (rect.length == 4) {
      fieldBounds = PdfRect(
        rect[0],
        rect[1],
        rect[2] - rect[0],
        rect[3] - rect[1],
      );
    }
  }

  final placeholder = _PdfExternalSignaturePlaceholder(
    signature: signature,
    contentsReserveSize: contentsReserveSize,
    byteRangeDigits: byteRangeDigits,
  );

  document.sign = PdfSignature(
    document,
    value: placeholder,
    flags: {PdfSigFlags.signaturesExist, PdfSigFlags.appendOnly},
  );

  if (existingField == null) {
    final page = document.pdfPageList.pages[pageIndex];
    final annot = PdfAnnotSign(rect: bounds, fieldName: fieldName);
    if (drawAppearance != null) {
      final g = annot.appearance(document, PdfAnnotAppearance.normal);
      final localBounds = PdfRect(0, 0, bounds.width, bounds.height);
      drawAppearance(g, localBounds);
    }
    PdfAnnot(page, annot);
  } else {
    final updated = PdfDict<PdfDataType>.values(
      Map<String, PdfDataType>.from(existingField.fieldDict.values),
    );
    updated[PdfNameTokens.v] = document.sign!.ref();

    if (drawAppearance != null && fieldBounds != null) {
      final appearance = PdfGraphicXObject(document, PdfNameTokens.form);
      appearance.params[PdfNameTokens.bbox] = PdfArray.fromNum(
        [0, 0, fieldBounds.width, fieldBounds.height],
      );
      final g = PdfGraphics(appearance, appearance.buf);
      drawAppearance(g, PdfRect(0, 0, fieldBounds.width, fieldBounds.height));
      updated[PdfNameTokens.ap] =
          PdfDict.values({PdfNameTokens.n: appearance.ref()});
    }

    document.signatures.updateFieldDict(existingField, updated);
  }

  final preparedBytes = await document.save(useIsolate: false);
  final byteRange = placeholder.byteRange;
  final hashBytes = placeholder.hashBytes;
  if (byteRange == null || hashBytes == null) {
    throw StateError('Falha ao preparar assinatura externa (ByteRange).');
  }

  return PdfExternalSigningPrepared(
    preparedPdfBytes: Uint8List.fromList(preparedBytes),
    byteRange: byteRange,
    hashBase64: base64.encode(hashBytes),
  );
}