@embedpdf/engines 1.0.7 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -912,7 +912,7 @@ class PdfiumEngine {
912
912
  let isSucceed = false;
913
913
  switch (annotation.type) {
914
914
  case models.PdfAnnotationSubtype.INK:
915
- isSucceed = this.addInkStroke(page, pageCtx.pagePtr, annotationPtr, annotation.inkList);
915
+ isSucceed = this.addInkStroke(page, pageCtx.pagePtr, annotationPtr, annotation);
916
916
  break;
917
917
  case models.PdfAnnotationSubtype.STAMP:
918
918
  isSucceed = this.addStampContent(ctx.docPtr, page, pageCtx.pagePtr, annotationPtr, annotation.rect, annotation.contents);
@@ -921,7 +921,7 @@ class PdfiumEngine {
921
921
  case models.PdfAnnotationSubtype.STRIKEOUT:
922
922
  case models.PdfAnnotationSubtype.SQUIGGLY:
923
923
  case models.PdfAnnotationSubtype.HIGHLIGHT:
924
- isSucceed = this.addTextMarkupContent(page, annotationPtr, annotation);
924
+ isSucceed = this.addTextMarkupContent(page, pageCtx.pagePtr, annotationPtr, annotation);
925
925
  break;
926
926
  }
927
927
  if (!isSucceed) {
@@ -933,6 +933,7 @@ class PdfiumEngine {
933
933
  message: 'can not add content of the annotation',
934
934
  });
935
935
  }
936
+ this.pdfiumModule.EPDFAnnot_GenerateAppearance(annotationPtr);
936
937
  this.pdfiumModule.FPDFPage_GenerateContent(pageCtx.pagePtr);
937
938
  const annotId = this.pdfiumModule.FPDFPage_GetAnnotIndex(pageCtx.pagePtr, annotationPtr);
938
939
  this.pdfiumModule.FPDFPage_CloseAnnot(annotationPtr);
@@ -990,7 +991,7 @@ class PdfiumEngine {
990
991
  /* clear every existing stroke first */
991
992
  if (!this.pdfiumModule.FPDFAnnot_RemoveInkList(annotPtr))
992
993
  break;
993
- ok = this.addInkStroke(page, pageCtx.pagePtr, annotPtr, annotation.inkList);
994
+ ok = this.addInkStroke(page, pageCtx.pagePtr, annotPtr, annotation);
994
995
  break;
995
996
  }
996
997
  /* ── Stamp ───────────────────────────────────────────────────────────── */
@@ -1008,7 +1009,7 @@ class PdfiumEngine {
1008
1009
  case models.PdfAnnotationSubtype.STRIKEOUT:
1009
1010
  case models.PdfAnnotationSubtype.SQUIGGLY: {
1010
1011
  /* replace quad-points / colour / strings in one go */
1011
- ok = this.addTextMarkupContent(page, annotPtr, annotation, true);
1012
+ ok = this.addTextMarkupContent(page, pageCtx.pagePtr, annotPtr, annotation);
1012
1013
  break;
1013
1014
  }
1014
1015
  /* ── Unsupported edits – fall through to error ───────────────────────── */
@@ -1017,6 +1018,7 @@ class PdfiumEngine {
1017
1018
  }
1018
1019
  /* 3 ── regenerate appearance if payload was changed ───────────────────── */
1019
1020
  if (ok) {
1021
+ this.pdfiumModule.EPDFAnnot_GenerateAppearance(annotPtr);
1020
1022
  this.pdfiumModule.FPDFPage_GenerateContent(pageCtx.pagePtr);
1021
1023
  }
1022
1024
  /* 4 ── tidy-up native handles ──────────────────────────────────────────── */
@@ -1030,85 +1032,6 @@ class PdfiumEngine {
1030
1032
  message: 'failed to update annotation',
1031
1033
  });
1032
1034
  }
1033
- /**
1034
- * {@inheritDoc @embedpdf/models!PdfEngine.transformPageAnnotation}
1035
- *
1036
- * @public
1037
- */
1038
- transformPageAnnotation(doc, page, annotation, transformation) {
1039
- this.logger.debug(LOG_SOURCE$2, LOG_CATEGORY$2, 'transformPageAnnotation', doc, page, annotation, transformation);
1040
- this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, `TransformPageAnnotation`, 'Begin', `${doc.id}-${page.index}`);
1041
- const ctx = this.cache.getContext(doc.id);
1042
- if (!ctx) {
1043
- this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, `TransformPageAnnotation`, 'End', `${doc.id}-${page.index}`);
1044
- return models.PdfTaskHelper.reject({
1045
- code: models.PdfErrorCode.DocNotOpen,
1046
- message: 'document does not open',
1047
- });
1048
- }
1049
- const pageCtx = ctx.acquirePage(page.index);
1050
- const annotationPtr = this.pdfiumModule.FPDFPage_GetAnnot(pageCtx.pagePtr, annotation.id);
1051
- const rect = {
1052
- origin: {
1053
- x: annotation.rect.origin.x + transformation.offset.x,
1054
- y: annotation.rect.origin.y + transformation.offset.y,
1055
- },
1056
- size: {
1057
- width: annotation.rect.size.width * transformation.scale.width,
1058
- height: annotation.rect.size.height * transformation.scale.height,
1059
- },
1060
- };
1061
- if (!this.setPageAnnoRect(page, pageCtx.pagePtr, annotationPtr, rect)) {
1062
- this.pdfiumModule.FPDFPage_CloseAnnot(annotationPtr);
1063
- pageCtx.release();
1064
- this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, `TransformPageAnnotation`, 'End', `${doc.id}-${page.index}`);
1065
- return models.PdfTaskHelper.reject({
1066
- code: models.PdfErrorCode.CantSetAnnotRect,
1067
- message: 'can not set the rect of the annotation',
1068
- });
1069
- }
1070
- switch (annotation.type) {
1071
- case models.PdfAnnotationSubtype.INK:
1072
- {
1073
- if (!this.pdfiumModule.FPDFAnnot_RemoveInkList(annotationPtr)) {
1074
- this.pdfiumModule.FPDFPage_CloseAnnot(annotationPtr);
1075
- pageCtx.release();
1076
- this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, `TransformPageAnnotation`, 'End', `${doc.id}-${page.index}`);
1077
- return models.PdfTaskHelper.reject({
1078
- code: models.PdfErrorCode.CantRemoveInkList,
1079
- message: 'can not set the rect of the annotation',
1080
- });
1081
- }
1082
- const inkList = annotation.inkList.map((inkStroke) => {
1083
- return {
1084
- points: inkStroke.points.map((point) => {
1085
- return {
1086
- x: rect.origin.x +
1087
- (point.x - annotation.rect.origin.x) * transformation.scale.width,
1088
- y: rect.origin.y +
1089
- (point.y - annotation.rect.origin.y) * transformation.scale.height,
1090
- };
1091
- }),
1092
- };
1093
- });
1094
- if (!this.addInkStroke(page, pageCtx.pagePtr, annotationPtr, inkList)) {
1095
- this.pdfiumModule.FPDFPage_CloseAnnot(annotationPtr);
1096
- pageCtx.release();
1097
- this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, `TransformPageAnnotation`, 'End', `${doc.id}-${page.index}`);
1098
- return models.PdfTaskHelper.reject({
1099
- code: models.PdfErrorCode.CantAddInkStoke,
1100
- message: 'can not add stroke to the ink list of annotation',
1101
- });
1102
- }
1103
- }
1104
- break;
1105
- }
1106
- this.pdfiumModule.FPDFPage_GenerateContent(pageCtx.pagePtr);
1107
- this.pdfiumModule.FPDFPage_CloseAnnot(annotationPtr);
1108
- pageCtx.release();
1109
- this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, `TransformPageAnnotation`, 'End', `${doc.id}-${page.index}`);
1110
- return models.PdfTaskHelper.resolve(true);
1111
- }
1112
1035
  /**
1113
1036
  * {@inheritDoc @embedpdf/models!PdfEngine.removePageAnnotation}
1114
1037
  *
@@ -1729,21 +1652,27 @@ class PdfiumEngine {
1729
1652
  *
1730
1653
  * @private
1731
1654
  */
1732
- addInkStroke(page, pagePtr, annotationPtr, inkList) {
1733
- for (const inkStroke of inkList) {
1734
- const inkPointsCount = inkStroke.points.length;
1735
- const inkPointsPtr = this.malloc(inkPointsCount * 8);
1736
- for (let i = 0; i < inkPointsCount; i++) {
1737
- const point = inkStroke.points[i];
1738
- const { x, y } = this.convertDevicePointToPagePoint(page, point);
1739
- this.pdfiumModule.pdfium.setValue(inkPointsPtr + i * 8, x, 'float');
1740
- this.pdfiumModule.pdfium.setValue(inkPointsPtr + i * 8 + 4, y, 'float');
1741
- }
1742
- if (this.pdfiumModule.FPDFAnnot_AddInkStroke(annotationPtr, inkPointsPtr, inkPointsCount) === -1) {
1743
- this.free(inkPointsPtr);
1744
- return false;
1745
- }
1746
- this.free(inkPointsPtr);
1655
+ addInkStroke(page, pagePtr, annotationPtr, annotation) {
1656
+ if (!this.setBorderStyle(annotationPtr, models.PdfAnnotationBorderStyle.SOLID, annotation.strokeWidth)) {
1657
+ return false;
1658
+ }
1659
+ if (!this.setPageAnnoRect(page, pagePtr, annotationPtr, annotation.rect)) {
1660
+ return false;
1661
+ }
1662
+ if (!this.setInkList(page, annotationPtr, annotation.inkList)) {
1663
+ return false;
1664
+ }
1665
+ if (!this.setAnnotString(annotationPtr, 'T', annotation.author || '')) {
1666
+ return false;
1667
+ }
1668
+ if (!this.setAnnotString(annotationPtr, 'M', models.dateToPdfDate(annotation.modified))) {
1669
+ return false;
1670
+ }
1671
+ if (!this.setAnnotationColor(annotationPtr, {
1672
+ color: annotation.color ?? '#FFFF00',
1673
+ opacity: annotation.opacity ?? 1,
1674
+ }, models.PdfAnnotationColorType.Color)) {
1675
+ return false;
1747
1676
  }
1748
1677
  return true;
1749
1678
  }
@@ -1756,7 +1685,10 @@ class PdfiumEngine {
1756
1685
  *
1757
1686
  * @private
1758
1687
  */
1759
- addTextMarkupContent(page, annotationPtr, annotation, shouldClearAP = false) {
1688
+ addTextMarkupContent(page, pagePtr, annotationPtr, annotation) {
1689
+ if (!this.setPageAnnoRect(page, pagePtr, annotationPtr, annotation.rect)) {
1690
+ return false;
1691
+ }
1760
1692
  if (!this.syncQuadPointsAnno(page, annotationPtr, annotation.segmentRects)) {
1761
1693
  return false;
1762
1694
  }
@@ -1772,7 +1704,7 @@ class PdfiumEngine {
1772
1704
  if (!this.setAnnotationColor(annotationPtr, {
1773
1705
  color: annotation.color ?? '#FFFF00',
1774
1706
  opacity: annotation.opacity ?? 1,
1775
- }, shouldClearAP, 0)) {
1707
+ }, models.PdfAnnotationColorType.Color)) {
1776
1708
  return false;
1777
1709
  }
1778
1710
  return true;
@@ -2419,14 +2351,13 @@ class PdfiumEngine {
2419
2351
  *
2420
2352
  * @private
2421
2353
  */
2422
- readAnnotationColor(annotationPtr) {
2354
+ readAnnotationColor(annotationPtr, colorType = models.PdfAnnotationColorType.Color) {
2423
2355
  const rPtr = this.malloc(4);
2424
2356
  const gPtr = this.malloc(4);
2425
2357
  const bPtr = this.malloc(4);
2426
2358
  const aPtr = this.malloc(4);
2427
2359
  // colourType 0 = "colour" (stroke/fill); other types are interior/border
2428
- const ok = this.pdfiumModule.FPDFAnnot_GetColor(annotationPtr,
2429
- /* colorType = */ 0, rPtr, gPtr, bPtr, aPtr);
2360
+ const ok = this.pdfiumModule.EPDFAnnot_GetColor(annotationPtr, colorType, rPtr, gPtr, bPtr, aPtr);
2430
2361
  let colour;
2431
2362
  if (ok) {
2432
2363
  colour = {
@@ -2443,97 +2374,6 @@ class PdfiumEngine {
2443
2374
  return colour;
2444
2375
  }
2445
2376
  /* --------------------------------------------------------------------------- */
2446
- /**
2447
- * Extract the fill (or, if absent, the stroke) colour from a **path object**
2448
- * inside an appearance stream.
2449
- *
2450
- * Works for simple highlights produced by Chrome, Preview, etc. that paint a
2451
- * single filled rectangle with the desired tint.
2452
- *
2453
- * @param pathPtr - pointer to a `FPDF_PAGEOBJECT` of type **PATH**
2454
- * @returns RGBA tuple or `undefined` when no colour is set on the path
2455
- *
2456
- * @private
2457
- */
2458
- getColorFromPath(pathPtr) {
2459
- const r = this.malloc(4), g = this.malloc(4), b = this.malloc(4), a = this.malloc(4);
2460
- const fillOk = this.pdfiumModule.FPDFPageObj_GetFillColor(pathPtr, r, g, b, a);
2461
- const strokeOk = !fillOk && // try stroke only if fill failed
2462
- this.pdfiumModule.FPDFPageObj_GetStrokeColor(pathPtr, r, g, b, a);
2463
- const ok = fillOk || strokeOk;
2464
- let c;
2465
- if (ok) {
2466
- c = {
2467
- red: this.pdfiumModule.pdfium.getValue(r, 'i32') & 0xff,
2468
- green: this.pdfiumModule.pdfium.getValue(g, 'i32') & 0xff,
2469
- blue: this.pdfiumModule.pdfium.getValue(b, 'i32') & 0xff,
2470
- alpha: this.pdfiumModule.pdfium.getValue(a, 'i32') & 0xff,
2471
- };
2472
- }
2473
- this.free(r);
2474
- this.free(g);
2475
- this.free(b);
2476
- this.free(a);
2477
- return c;
2478
- }
2479
- /* --------------------------------------------------------------------------- */
2480
- /**
2481
- * Recursively walk a page-object tree (PATHs and nested FORM XObjects) until
2482
- * a colour can be extracted.
2483
- *
2484
- * Acrobat often wraps its highlight rectangle in a Form XObject referenced by
2485
- * the "Do" operator, so this function drills down unlimited depth.
2486
- *
2487
- * @param objPtr - pointer to a `FPDF_PAGEOBJECT`
2488
- * @returns First RGBA tint found, or `undefined` if none of the descendants
2489
- * carry an explicit fill/stroke colour
2490
- *
2491
- * @private
2492
- */
2493
- walkPageObjTree(objPtr) {
2494
- const type = this.pdfiumModule.FPDFPageObj_GetType(objPtr);
2495
- if (type === models.PdfPageObjectType.PATH)
2496
- return this.getColorFromPath(objPtr);
2497
- if (type !== models.PdfPageObjectType.FORM)
2498
- return undefined;
2499
- const cnt = this.pdfiumModule.FPDFFormObj_CountObjects(objPtr);
2500
- for (let i = 0; i < cnt; i++) {
2501
- const child = this.pdfiumModule.FPDFFormObj_GetObject(objPtr, i);
2502
- if (!child)
2503
- continue;
2504
- const c = this.walkPageObjTree(child);
2505
- if (c)
2506
- return c;
2507
- }
2508
- return undefined;
2509
- }
2510
- /* --------------------------------------------------------------------------- */
2511
- /**
2512
- * Iterate over every top-level object in the annotation's **appearance stream**
2513
- * and invoke {@link walkPageObjTree} to locate a usable tint.
2514
- *
2515
- * Catches:
2516
- * • Simple filled path (Preview, Chrome)
2517
- * • Form XObject containing the path (Acrobat)
2518
- *
2519
- * @param annotPtr - pointer to an `FPDF_ANNOTATION`
2520
- * @returns RGBA tuple or `undefined` when no colour can be resolved from AP
2521
- *
2522
- * @private
2523
- */
2524
- colorFromAppearance(annotPtr) {
2525
- const n = this.pdfiumModule.FPDFAnnot_GetObjectCount(annotPtr);
2526
- for (let i = 0; i < n; i++) {
2527
- const obj = this.pdfiumModule.FPDFAnnot_GetObject(annotPtr, i);
2528
- if (!obj)
2529
- continue;
2530
- const c = this.walkPageObjTree(obj);
2531
- if (c)
2532
- return c;
2533
- }
2534
- return undefined;
2535
- }
2536
- /* --------------------------------------------------------------------------- */
2537
2377
  /**
2538
2378
  * Resolve the visible fill colour for **Highlight / Underline / StrikeOut /
2539
2379
  * Squiggly** markup annotations.
@@ -2549,10 +2389,8 @@ class PdfiumEngine {
2549
2389
  *
2550
2390
  * @private
2551
2391
  */
2552
- resolveAnnotationColor(annotationPtr, fallback = { red: 255, green: 245, blue: 155, alpha: 255 }) {
2553
- const pdfColor = this.readAnnotationColor(annotationPtr) ?? // 1 – /C entry
2554
- this.colorFromAppearance(annotationPtr) ?? // 2 – AP stream walk
2555
- fallback; // 3 – default
2392
+ resolveAnnotationColor(annotationPtr, colorType = models.PdfAnnotationColorType.Color, fallback = { red: 255, green: 245, blue: 155, alpha: 255 }) {
2393
+ const pdfColor = this.readAnnotationColor(annotationPtr, colorType) ?? fallback;
2556
2394
  return models.pdfAlphaColorToWebAlphaColor(pdfColor);
2557
2395
  }
2558
2396
  /**
@@ -2566,14 +2404,115 @@ class PdfiumEngine {
2566
2404
  *
2567
2405
  * @private
2568
2406
  */
2569
- setAnnotationColor(annotationPtr, webAlphaColor, shouldClearAP = false, which = 0) {
2407
+ setAnnotationColor(annotationPtr, webAlphaColor, colorType = models.PdfAnnotationColorType.Color) {
2570
2408
  const pdfAlphaColor = models.webAlphaColorToPdfAlphaColor(webAlphaColor);
2571
- if (shouldClearAP) {
2572
- // NULL wide-string → remove the /AP entry
2573
- this.pdfiumModule.FPDFAnnot_SetAP(annotationPtr, models.AppearanceMode.Normal,
2574
- /* FPDF_WIDESTRING = */ 0);
2409
+ return this.pdfiumModule.EPDFAnnot_SetColor(annotationPtr, colorType, pdfAlphaColor.red & 0xff, pdfAlphaColor.green & 0xff, pdfAlphaColor.blue & 0xff, (pdfAlphaColor.alpha ?? 255) & 0xff);
2410
+ }
2411
+ /**
2412
+ * Border‐style + width helper
2413
+ *
2414
+ * Tries the new PDFium helper `EPDFAnnot_GetBorderStyle()` (patch series
2415
+ * 9 July 2025).
2416
+ *
2417
+ * @param annotationPtr pointer to an `FPDF_ANNOTATION`
2418
+ * @returns `{ ok, style, width }`
2419
+ * • `ok` – `true` when the call succeeded
2420
+ * • `style` – `PdfAnnotationBorderStyle` enum
2421
+ * • `width` – stroke-width in points (defaults to 0 pt)
2422
+ */
2423
+ getBorderStyle(annotationPtr) {
2424
+ /* 1 ── allocate tmp storage for the returned width ─────────────── */
2425
+ const widthPtr = this.malloc(4);
2426
+ let width = 0;
2427
+ let style = models.PdfAnnotationBorderStyle.UNKNOWN;
2428
+ let ok = false;
2429
+ style = this.pdfiumModule.EPDFAnnot_GetBorderStyle(annotationPtr, widthPtr);
2430
+ width = this.pdfiumModule.pdfium.getValue(widthPtr, 'float');
2431
+ ok = style !== models.PdfAnnotationBorderStyle.UNKNOWN;
2432
+ this.free(widthPtr);
2433
+ return { ok, style, width };
2434
+ }
2435
+ setBorderStyle(annotationPtr, style, width) {
2436
+ return this.pdfiumModule.EPDFAnnot_SetBorderStyle(annotationPtr, style, width);
2437
+ }
2438
+ /**
2439
+ * Border-effect (“cloudy”) helper
2440
+ *
2441
+ * Calls the new PDFium function `EPDFAnnot_GetBorderEffect()` (July 2025).
2442
+ *
2443
+ * @param annotationPtr pointer to an `FPDF_ANNOTATION`
2444
+ * @returns `{ ok, intensity }`
2445
+ * • `ok` – `true` when the annotation *does* have a
2446
+ * valid cloudy-border effect
2447
+ * • `intensity` – radius/intensity value (0 when `ok` is false)
2448
+ */
2449
+ getBorderEffect(annotationPtr) {
2450
+ const intensityPtr = this.malloc(4);
2451
+ const ok = !!this.pdfiumModule.EPDFAnnot_GetBorderEffect(annotationPtr, intensityPtr);
2452
+ const intensity = ok ? this.pdfiumModule.pdfium.getValue(intensityPtr, 'float') : 0;
2453
+ this.free(intensityPtr);
2454
+ return { ok, intensity };
2455
+ }
2456
+ /**
2457
+ * Rectangle-differences helper ( /RD array on Square / Circle annots )
2458
+ *
2459
+ * Calls `EPDFAnnot_GetRectangleDifferences()` introduced in July 2025.
2460
+ *
2461
+ * @param annotationPtr pointer to an `FPDF_ANNOTATION`
2462
+ * @returns `{ ok, left, top, right, bottom }`
2463
+ * • `ok` – `true` when the annotation *has* an /RD entry
2464
+ * • the four floats are 0 when `ok` is false
2465
+ */
2466
+ getRectangleDifferences(annotationPtr) {
2467
+ /* tmp storage ─────────────────────────────────────────── */
2468
+ const lPtr = this.malloc(4);
2469
+ const tPtr = this.malloc(4);
2470
+ const rPtr = this.malloc(4);
2471
+ const bPtr = this.malloc(4);
2472
+ const ok = !!this.pdfiumModule.EPDFAnnot_GetRectangleDifferences(annotationPtr, lPtr, tPtr, rPtr, bPtr);
2473
+ const pdf = this.pdfiumModule.pdfium;
2474
+ const left = pdf.getValue(lPtr, 'float');
2475
+ const top = pdf.getValue(tPtr, 'float');
2476
+ const right = pdf.getValue(rPtr, 'float');
2477
+ const bottom = pdf.getValue(bPtr, 'float');
2478
+ /* cleanup ─────────────────────────────────────────────── */
2479
+ this.free(lPtr);
2480
+ this.free(tPtr);
2481
+ this.free(rPtr);
2482
+ this.free(bPtr);
2483
+ return { ok, left, top, right, bottom };
2484
+ }
2485
+ /**
2486
+ * Dash-pattern helper ( /BS → /D array, dashed borders only )
2487
+ *
2488
+ * Uses the two new PDFium helpers:
2489
+ * • `EPDFAnnot_GetBorderDashPatternCount`
2490
+ * • `EPDFAnnot_GetBorderDashPattern`
2491
+ *
2492
+ * @param annotationPtr pointer to an `FPDF_ANNOTATION`
2493
+ * @returns `{ ok, pattern }`
2494
+ * • `ok` – `true` when the annot is dashed *and* the array
2495
+ * was retrieved successfully
2496
+ * • `pattern` – numeric array of dash/space lengths (empty when `ok` is false)
2497
+ */
2498
+ getBorderDashPattern(annotationPtr) {
2499
+ const count = this.pdfiumModule.EPDFAnnot_GetBorderDashPatternCount(annotationPtr);
2500
+ if (count === 0) {
2501
+ return { ok: false, pattern: [] };
2575
2502
  }
2576
- return this.pdfiumModule.FPDFAnnot_SetColor(annotationPtr, which, pdfAlphaColor.red & 0xff, pdfAlphaColor.green & 0xff, pdfAlphaColor.blue & 0xff, (pdfAlphaColor.alpha ?? 255) & 0xff);
2503
+ /* allocate `count` floats on the WASM heap */
2504
+ const arrPtr = this.malloc(4 * count);
2505
+ const okNative = !!this.pdfiumModule.EPDFAnnot_GetBorderDashPattern(annotationPtr, arrPtr, count);
2506
+ /* copy out */
2507
+ const pattern = [];
2508
+ if (okNative) {
2509
+ const pdf = this.pdfiumModule.pdfium;
2510
+ for (let i = 0; i < count; i++) {
2511
+ pattern.push(pdf.getValue(arrPtr + 4 * i, 'float'));
2512
+ }
2513
+ }
2514
+ this.free(arrPtr);
2515
+ return { ok: okNative, pattern };
2577
2516
  }
2578
2517
  /**
2579
2518
  * Read `/QuadPoints` from any annotation and convert each quadrilateral to
@@ -2672,6 +2611,62 @@ class PdfiumEngine {
2672
2611
  this.free(buf);
2673
2612
  return true;
2674
2613
  }
2614
+ /**
2615
+ * Read ink list from annotation
2616
+ * @param page - logical page info object (`PdfPageObject`)
2617
+ * @param annotationPtr - pointer to the annotation whose ink list is needed
2618
+ * @returns ink list
2619
+ */
2620
+ getInkList(page, annotationPtr) {
2621
+ const inkList = [];
2622
+ const count = this.pdfiumModule.FPDFAnnot_GetInkListCount(annotationPtr);
2623
+ for (let i = 0; i < count; i++) {
2624
+ const points = [];
2625
+ const pointsCount = this.pdfiumModule.FPDFAnnot_GetInkListPath(annotationPtr, i, 0, 0);
2626
+ if (pointsCount > 0) {
2627
+ const pointMemorySize = 8;
2628
+ const pointsPtr = this.malloc(pointsCount * pointMemorySize);
2629
+ this.pdfiumModule.FPDFAnnot_GetInkListPath(annotationPtr, i, pointsPtr, pointsCount);
2630
+ for (let j = 0; j < pointsCount; j++) {
2631
+ const pointX = this.pdfiumModule.pdfium.getValue(pointsPtr + j * 8, 'float');
2632
+ const pointY = this.pdfiumModule.pdfium.getValue(pointsPtr + j * 8 + 4, 'float');
2633
+ const { x, y } = this.convertPagePointToDevicePoint(page, {
2634
+ x: pointX,
2635
+ y: pointY,
2636
+ });
2637
+ points.push({ x, y });
2638
+ }
2639
+ this.free(pointsPtr);
2640
+ }
2641
+ inkList.push({ points });
2642
+ }
2643
+ return inkList;
2644
+ }
2645
+ /**
2646
+ * Add ink list to annotation
2647
+ * @param page - logical page info object (`PdfPageObject`)
2648
+ * @param annotationPtr - pointer to the annotation whose ink list is needed
2649
+ * @param annotation - annotation object (`PdfInkAnnoObject`)
2650
+ * @returns `true` if the operation was successful
2651
+ */
2652
+ setInkList(page, annotationPtr, inkList) {
2653
+ for (const inkStroke of inkList) {
2654
+ const inkPointsCount = inkStroke.points.length;
2655
+ const inkPointsPtr = this.malloc(inkPointsCount * 8);
2656
+ for (let i = 0; i < inkPointsCount; i++) {
2657
+ const point = inkStroke.points[i];
2658
+ const { x, y } = this.convertDevicePointToPagePoint(page, point);
2659
+ this.pdfiumModule.pdfium.setValue(inkPointsPtr + i * 8, x, 'float');
2660
+ this.pdfiumModule.pdfium.setValue(inkPointsPtr + i * 8 + 4, y, 'float');
2661
+ }
2662
+ if (this.pdfiumModule.FPDFAnnot_AddInkStroke(annotationPtr, inkPointsPtr, inkPointsCount) === -1) {
2663
+ this.free(inkPointsPtr);
2664
+ return false;
2665
+ }
2666
+ this.free(inkPointsPtr);
2667
+ }
2668
+ return true;
2669
+ }
2675
2670
  /**
2676
2671
  * Read pdf text annotation
2677
2672
  * @param page - pdf page infor
@@ -2848,32 +2843,15 @@ class PdfiumEngine {
2848
2843
  const author = this.getAnnotString(annotationPtr, 'T');
2849
2844
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2850
2845
  const modified = models.pdfDateToDate(modifiedRaw);
2851
- const inkList = [];
2852
- const count = this.pdfiumModule.FPDFAnnot_GetInkListCount(annotationPtr);
2853
- for (let i = 0; i < count; i++) {
2854
- const points = [];
2855
- const pointsCount = this.pdfiumModule.FPDFAnnot_GetInkListPath(annotationPtr, i, 0, 0);
2856
- if (pointsCount > 0) {
2857
- const pointMemorySize = 8;
2858
- const pointsPtr = this.malloc(pointsCount * pointMemorySize);
2859
- this.pdfiumModule.FPDFAnnot_GetInkListPath(annotationPtr, i, pointsPtr, pointsCount);
2860
- for (let j = 0; j < pointsCount; j++) {
2861
- const pointX = this.pdfiumModule.pdfium.getValue(pointsPtr + j * 8, 'float');
2862
- const pointY = this.pdfiumModule.pdfium.getValue(pointsPtr + j * 8 + 4, 'float');
2863
- const { x, y } = this.convertPagePointToDevicePoint(page, {
2864
- x: pointX,
2865
- y: pointY,
2866
- });
2867
- points.push({ x, y });
2868
- }
2869
- this.free(pointsPtr);
2870
- }
2871
- inkList.push({ points });
2872
- }
2846
+ const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
2847
+ const { width: strokeWidth } = this.getBorderStyle(annotationPtr);
2848
+ const inkList = this.getInkList(page, annotationPtr);
2873
2849
  return {
2874
2850
  pageIndex: page.index,
2875
2851
  id: index,
2876
2852
  type: models.PdfAnnotationSubtype.INK,
2853
+ ...webAlphaColor,
2854
+ strokeWidth,
2877
2855
  rect,
2878
2856
  inkList,
2879
2857
  author,
@@ -3327,6 +3305,39 @@ class PdfiumEngine {
3327
3305
  this.free(matrixPtr);
3328
3306
  return { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 };
3329
3307
  }
3308
+ /**
3309
+ * Return the stroke-width declared in the annotation’s /Border or /BS entry.
3310
+ * Falls back to 1 pt when nothing is defined.
3311
+ *
3312
+ * @param annotationPtr - pointer to pdf annotation
3313
+ * @returns stroke-width
3314
+ *
3315
+ * @private
3316
+ */
3317
+ getStrokeWidth(annotationPtr) {
3318
+ // FPDFAnnot_GetBorder(annot, &hRadius, &vRadius, &borderWidth)
3319
+ const hPtr = this.malloc(4);
3320
+ const vPtr = this.malloc(4);
3321
+ const wPtr = this.malloc(4);
3322
+ const ok = this.pdfiumModule.FPDFAnnot_GetBorder(annotationPtr, hPtr, vPtr, wPtr);
3323
+ const width = ok ? this.pdfiumModule.pdfium.getValue(wPtr, 'float') : 1; // default 1 pt
3324
+ this.free(hPtr);
3325
+ this.free(vPtr);
3326
+ this.free(wPtr);
3327
+ return width;
3328
+ }
3329
+ /**
3330
+ * Fetches the `/F` flag bit-field from an annotation.
3331
+ *
3332
+ * @param annotationPtr pointer to an `FPDF_ANNOTATION`
3333
+ * @returns `{ raw, flags }`
3334
+ * • `raw` – the 32-bit integer returned by PDFium
3335
+ * • `flags` – object with individual booleans
3336
+ */
3337
+ getAnnotationFlags(annotationPtr) {
3338
+ const rawFlags = this.pdfiumModule.FPDFAnnot_GetFlags(annotationPtr); // number
3339
+ return models.flagsToNames(rawFlags);
3340
+ }
3330
3341
  /**
3331
3342
  * Read circle annotation
3332
3343
  * @param page - pdf page infor
@@ -3338,18 +3349,51 @@ class PdfiumEngine {
3338
3349
  * @private
3339
3350
  */
3340
3351
  readPdfCircleAnno(page, pagePtr, annotationPtr, index) {
3352
+ const flags = this.getAnnotationFlags(annotationPtr);
3341
3353
  const pageRect = this.readPageAnnoRect(annotationPtr);
3342
3354
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
3343
3355
  const author = this.getAnnotString(annotationPtr, 'T');
3344
3356
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
3345
3357
  const modified = models.pdfDateToDate(modifiedRaw);
3358
+ const { color, opacity } = this.resolveAnnotationColor(annotationPtr, models.PdfAnnotationColorType.InteriorColor);
3359
+ const { color: strokeColor } = this.resolveAnnotationColor(annotationPtr);
3360
+ let { style: strokeStyle, width: strokeWidth } = this.getBorderStyle(annotationPtr);
3361
+ let cloudyBorderIntensity;
3362
+ let cloudyBorderInset;
3363
+ if (strokeStyle === models.PdfAnnotationBorderStyle.CLOUDY ||
3364
+ strokeStyle === models.PdfAnnotationBorderStyle.UNKNOWN) {
3365
+ const { ok: hasEffect, intensity } = this.getBorderEffect(annotationPtr);
3366
+ if (hasEffect) {
3367
+ cloudyBorderIntensity = intensity;
3368
+ strokeStyle = models.PdfAnnotationBorderStyle.CLOUDY;
3369
+ const { ok: hasInset, left, top, right, bottom, } = this.getRectangleDifferences(annotationPtr);
3370
+ if (hasInset)
3371
+ cloudyBorderInset = [left, top, right, bottom];
3372
+ }
3373
+ }
3374
+ let strokeDashArray;
3375
+ if (strokeStyle === models.PdfAnnotationBorderStyle.DASHED) {
3376
+ const { ok, pattern } = this.getBorderDashPattern(annotationPtr);
3377
+ if (ok) {
3378
+ strokeDashArray = pattern;
3379
+ }
3380
+ }
3346
3381
  return {
3347
3382
  pageIndex: page.index,
3348
3383
  id: index,
3349
3384
  type: models.PdfAnnotationSubtype.CIRCLE,
3385
+ flags,
3386
+ color,
3387
+ opacity,
3388
+ strokeWidth,
3389
+ strokeColor,
3390
+ strokeStyle,
3350
3391
  rect,
3351
3392
  author,
3352
3393
  modified,
3394
+ ...(cloudyBorderIntensity !== undefined && { cloudyBorderIntensity }),
3395
+ ...(cloudyBorderInset !== undefined && { cloudyBorderInset }),
3396
+ ...(strokeDashArray !== undefined && { strokeDashArray }),
3353
3397
  };
3354
3398
  }
3355
3399
  /**
@@ -3363,18 +3407,51 @@ class PdfiumEngine {
3363
3407
  * @private
3364
3408
  */
3365
3409
  readPdfSquareAnno(page, pagePtr, annotationPtr, index) {
3410
+ const flags = this.getAnnotationFlags(annotationPtr);
3366
3411
  const pageRect = this.readPageAnnoRect(annotationPtr);
3367
3412
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
3368
3413
  const author = this.getAnnotString(annotationPtr, 'T');
3369
3414
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
3370
3415
  const modified = models.pdfDateToDate(modifiedRaw);
3416
+ const { color, opacity } = this.resolveAnnotationColor(annotationPtr, models.PdfAnnotationColorType.InteriorColor);
3417
+ const { color: strokeColor } = this.resolveAnnotationColor(annotationPtr);
3418
+ let { style: strokeStyle, width: strokeWidth } = this.getBorderStyle(annotationPtr);
3419
+ let cloudyBorderIntensity;
3420
+ let cloudyBorderInset;
3421
+ if (strokeStyle === models.PdfAnnotationBorderStyle.CLOUDY ||
3422
+ strokeStyle === models.PdfAnnotationBorderStyle.UNKNOWN) {
3423
+ const { ok: hasEffect, intensity } = this.getBorderEffect(annotationPtr);
3424
+ if (hasEffect) {
3425
+ cloudyBorderIntensity = intensity;
3426
+ strokeStyle = models.PdfAnnotationBorderStyle.CLOUDY;
3427
+ const { ok: hasInset, left, top, right, bottom, } = this.getRectangleDifferences(annotationPtr);
3428
+ if (hasInset)
3429
+ cloudyBorderInset = [left, top, right, bottom];
3430
+ }
3431
+ }
3432
+ let strokeDashArray;
3433
+ if (strokeStyle === models.PdfAnnotationBorderStyle.DASHED) {
3434
+ const { ok, pattern } = this.getBorderDashPattern(annotationPtr);
3435
+ if (ok) {
3436
+ strokeDashArray = pattern;
3437
+ }
3438
+ }
3371
3439
  return {
3372
3440
  pageIndex: page.index,
3373
3441
  id: index,
3374
3442
  type: models.PdfAnnotationSubtype.SQUARE,
3443
+ flags,
3444
+ color,
3445
+ opacity,
3446
+ strokeColor,
3447
+ strokeWidth,
3448
+ strokeStyle,
3375
3449
  rect,
3376
3450
  author,
3377
3451
  modified,
3452
+ ...(cloudyBorderIntensity !== undefined && { cloudyBorderIntensity }),
3453
+ ...(cloudyBorderInset !== undefined && { cloudyBorderInset }),
3454
+ ...(strokeDashArray !== undefined && { strokeDashArray }),
3378
3455
  };
3379
3456
  }
3380
3457
  /**
@@ -3560,6 +3637,81 @@ class PdfiumEngine {
3560
3637
  options,
3561
3638
  };
3562
3639
  }
3640
+ /**
3641
+ * {@inheritDoc @embedpdf/models!PdfEngine.renderAnnotation}
3642
+ *
3643
+ * @public
3644
+ */
3645
+ renderAnnotation(doc, page, annotation, scaleFactor, rotation, dpr = 1, // device-pixel-ratio (canvas)
3646
+ mode = models.AppearanceMode.Normal, imageType = 'image/webp') {
3647
+ this.logger.debug(LOG_SOURCE$2, LOG_CATEGORY$2, 'renderAnnotation', doc, page, annotation, scaleFactor, rotation, dpr, mode, imageType);
3648
+ this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, `RenderAnnotation`, 'Begin', `${doc.id}-${page.index}-${annotation.id}`);
3649
+ const task = new models.Task();
3650
+ const ctx = this.cache.getContext(doc.id);
3651
+ if (!ctx) {
3652
+ this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, `RenderAnnotation`, 'End', `${doc.id}-${page.index}-${annotation.id}`);
3653
+ return models.PdfTaskHelper.reject({
3654
+ code: models.PdfErrorCode.DocNotOpen,
3655
+ message: 'document does not open',
3656
+ });
3657
+ }
3658
+ /* ── 1. grab native handles ───────────────────────────────────────── */
3659
+ const pageCtx = ctx.acquirePage(page.index);
3660
+ const annotPtr = this.pdfiumModule.FPDFPage_GetAnnot(pageCtx.pagePtr, annotation.id);
3661
+ if (!annotPtr) {
3662
+ pageCtx.release();
3663
+ this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, `RenderAnnotation`, 'End', `${doc.id}-${page.index}-${annotation.id}`);
3664
+ return models.PdfTaskHelper.reject({
3665
+ code: models.PdfErrorCode.NotFound,
3666
+ message: 'annotation not found',
3667
+ });
3668
+ }
3669
+ const finalScale = scaleFactor * dpr;
3670
+ /* ── 2. decide bitmap size (integer pixels) ──────────────────────── */
3671
+ const annotRect = annotation.rect;
3672
+ const bitmapRect = models.toIntRect(models.transformRect(page.size, annotRect, rotation, finalScale));
3673
+ const format = exports.BitmapFormat.Bitmap_BGRA;
3674
+ const bytesPerPixel = 4;
3675
+ const bitmapHeapLength = bitmapRect.size.width * bitmapRect.size.height * bytesPerPixel;
3676
+ const bitmapHeapPtr = this.malloc(bitmapHeapLength);
3677
+ const bitmapPtr = this.pdfiumModule.FPDFBitmap_CreateEx(bitmapRect.size.width, bitmapRect.size.height, format, bitmapHeapPtr, bitmapRect.size.width * bytesPerPixel);
3678
+ this.pdfiumModule.FPDFBitmap_FillRect(bitmapPtr, 0, 0, bitmapRect.size.width, bitmapRect.size.height, 0x00000000);
3679
+ const matrix = models.makeMatrix(annotation.rect, rotation, finalScale);
3680
+ // Allocate memory for the matrix on the wasm heap and write to it
3681
+ const matrixSize = 6 * 4;
3682
+ const matrixPtr = this.malloc(matrixSize);
3683
+ const matrixView = new Float32Array(this.pdfiumModule.pdfium.HEAPF32.buffer, matrixPtr, 6);
3684
+ matrixView.set([matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f]);
3685
+ /* ── 5. call the native helper with the new matrix ───────────────── */
3686
+ const FLAGS = exports.RenderFlag.REVERSE_BYTE_ORDER;
3687
+ const ok = !!this.pdfiumModule.EPDF_RenderAnnotBitmap(bitmapPtr, pageCtx.pagePtr, annotPtr, mode, matrixPtr, FLAGS);
3688
+ /* ── 6. tear down native resources ───────────────────────────────── */
3689
+ this.free(matrixPtr); // Free the matrix memory
3690
+ this.pdfiumModule.FPDFBitmap_Destroy(bitmapPtr);
3691
+ this.pdfiumModule.FPDFPage_CloseAnnot(annotPtr);
3692
+ pageCtx.release();
3693
+ if (!ok) {
3694
+ this.free(bitmapHeapPtr);
3695
+ this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, `RenderAnnotation`, 'End', `${doc.id}-${page.index}-${annotation.id}`);
3696
+ return models.PdfTaskHelper.reject({
3697
+ code: models.PdfErrorCode.Unknown,
3698
+ message: 'EPDF_RenderAnnotBitmap failed',
3699
+ });
3700
+ }
3701
+ /* ── 6. copy out + convert to Blob (reuse existing converter) ─────── */
3702
+ const data = this.pdfiumModule.pdfium.HEAPU8.subarray(bitmapHeapPtr, bitmapHeapPtr + bitmapHeapLength);
3703
+ const imageData = {
3704
+ data: new Uint8ClampedArray(data),
3705
+ width: bitmapRect.size.width,
3706
+ height: bitmapRect.size.height,
3707
+ };
3708
+ this.free(bitmapHeapPtr);
3709
+ this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, `RenderAnnotation`, 'End', `${doc.id}-${page.index}-${annotation.id}`);
3710
+ this.imageDataConverter(imageData, imageType)
3711
+ .then((blob) => task.resolve(blob))
3712
+ .catch((err) => task.reject({ code: models.PdfErrorCode.Unknown, message: String(err) }));
3713
+ return task;
3714
+ }
3563
3715
  /**
3564
3716
  * render rectangle of pdf page to image
3565
3717
  * @param docPtr - pointer to pdf document object
@@ -3930,12 +4082,7 @@ class PdfiumEngine {
3930
4082
  task.resolve(false);
3931
4083
  return task;
3932
4084
  }
3933
- /* 2 ── wipe AP if it's a simple markup annotation ─────────────────────── */
3934
- const shouldClearAP = annotation.type === models.PdfAnnotationSubtype.HIGHLIGHT ||
3935
- annotation.type === models.PdfAnnotationSubtype.UNDERLINE ||
3936
- annotation.type === models.PdfAnnotationSubtype.STRIKEOUT ||
3937
- annotation.type === models.PdfAnnotationSubtype.SQUIGGLY;
3938
- const ok = this.setAnnotationColor(annotPtr, color, shouldClearAP, which);
4085
+ const ok = this.setAnnotationColor(annotPtr, color, which);
3939
4086
  /* 4 ── regenerate appearance & clean-up ───────────────────────────────── */
3940
4087
  if (ok) {
3941
4088
  this.pdfiumModule.FPDFPage_GenerateContent(pageCtx.pagePtr);
@@ -4345,6 +4492,9 @@ class EngineRunner {
4345
4492
  case 'renderPageRect':
4346
4493
  task = this.engine[name](...args);
4347
4494
  break;
4495
+ case 'renderAnnotation':
4496
+ task = this.engine[name](...args);
4497
+ break;
4348
4498
  case 'renderThumbnail':
4349
4499
  task = this.engine[name](...args);
4350
4500
  break;
@@ -4360,9 +4510,6 @@ class EngineRunner {
4360
4510
  case 'updatePageAnnotation':
4361
4511
  task = this.engine[name](...args);
4362
4512
  break;
4363
- case 'transformPageAnnotation':
4364
- task = this.engine[name](...args);
4365
- break;
4366
4513
  case 'removePageAnnotation':
4367
4514
  task = this.engine[name](...args);
4368
4515
  break;
@@ -4877,6 +5024,26 @@ class WebWorkerEngine {
4877
5024
  this.proxy(task, request);
4878
5025
  return task;
4879
5026
  }
5027
+ /**
5028
+ * {@inheritDoc @embedpdf/models!PdfEngine.renderAnnotation}
5029
+ *
5030
+ * @public
5031
+ */
5032
+ renderAnnotation(doc, page, annotation, scaleFactor, rotation, dpr, mode, imageType) {
5033
+ this.logger.debug(LOG_SOURCE, LOG_CATEGORY, 'renderAnnotation', doc, page, annotation, scaleFactor, rotation, dpr, mode, imageType);
5034
+ const requestId = this.generateRequestId(doc.id);
5035
+ const task = new WorkerTask(this.worker, requestId);
5036
+ const request = {
5037
+ id: requestId,
5038
+ type: 'ExecuteRequest',
5039
+ data: {
5040
+ name: 'renderAnnotation',
5041
+ args: [doc, page, annotation, scaleFactor, rotation, dpr, mode, imageType],
5042
+ },
5043
+ };
5044
+ this.proxy(task, request);
5045
+ return task;
5046
+ }
4880
5047
  /**
4881
5048
  * {@inheritDoc @embedpdf/models!PdfEngine.getAllAnnotations}
4882
5049
  *
@@ -4952,26 +5119,6 @@ class WebWorkerEngine {
4952
5119
  this.proxy(task, request);
4953
5120
  return task;
4954
5121
  }
4955
- /**
4956
- * {@inheritDoc @embedpdf/models!PdfEngine.transformPageAnnotation}
4957
- *
4958
- * @public
4959
- */
4960
- transformPageAnnotation(doc, page, annotation, transformation) {
4961
- this.logger.debug(LOG_SOURCE, LOG_CATEGORY, 'transformPageAnnotation', doc, page, annotation, transformation);
4962
- const requestId = this.generateRequestId(doc.id);
4963
- const task = new WorkerTask(this.worker, requestId);
4964
- const request = {
4965
- id: requestId,
4966
- type: 'ExecuteRequest',
4967
- data: {
4968
- name: 'transformPageAnnotation',
4969
- args: [doc, page, annotation, transformation],
4970
- },
4971
- };
4972
- this.proxy(task, request);
4973
- return task;
4974
- }
4975
5122
  /**
4976
5123
  * {@inheritDoc @embedpdf/models!PdfEngine.removePageAnnotation}
4977
5124
  *
@@ -5496,6 +5643,9 @@ function createMockPdfEngine(partialEngine) {
5496
5643
  const blob = new Blob([realBuffer], { type: 'image/png' });
5497
5644
  return models.PdfTaskHelper.resolve(blob);
5498
5645
  }),
5646
+ renderAnnotation: jest.fn((doc, page, annotation, scaleFactor, rotation, dpr, mode, imageType) => {
5647
+ return models.PdfTaskHelper.resolve(new Blob([], { type: 'image/png' }));
5648
+ }),
5499
5649
  getAllAnnotations: jest.fn((doc) => {
5500
5650
  return models.PdfTaskHelper.resolve({});
5501
5651
  }),
@@ -5533,9 +5683,6 @@ function createMockPdfEngine(partialEngine) {
5533
5683
  updatePageAnnotation: jest.fn(() => {
5534
5684
  return models.PdfTaskHelper.resolve(true);
5535
5685
  }),
5536
- transformPageAnnotation: () => {
5537
- return models.PdfTaskHelper.resolve(true);
5538
- },
5539
5686
  removePageAnnotation: jest.fn(() => {
5540
5687
  return models.PdfTaskHelper.resolve(true);
5541
5688
  }),