@embedpdf/engines 1.0.6 → 1.0.7

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/pdfium.js CHANGED
@@ -1,4 +1,4 @@
1
- import { NoopLogger, PdfTaskHelper, PdfErrorCode, Task, Rotation, PdfAnnotationSubtype, stripPdfUnwantedMarkers, PdfPageObjectType, PdfAnnotationObjectStatus, quadToRect, PDF_FORM_FIELD_TYPE, toIntRect, transformRect, toIntSize, transformSize, PdfActionType, PdfZoomMode, AppearanceMode, MatchFlag } from '@embedpdf/models';
1
+ import { NoopLogger, PdfTaskHelper, PdfErrorCode, Task, Rotation, PdfAnnotationSubtype, stripPdfUnwantedMarkers, dateToPdfDate, PdfPageObjectType, pdfAlphaColorToWebAlphaColor, webAlphaColorToPdfAlphaColor, AppearanceMode, quadToRect, pdfDateToDate, PDF_FORM_FIELD_TYPE, toIntRect, transformRect, toIntSize, transformSize, PdfActionType, PdfZoomMode, MatchFlag, rectToQuad } from '@embedpdf/models';
2
2
  import { init } from '@embedpdf/pdfium';
3
3
 
4
4
  /**
@@ -915,6 +915,12 @@ class PdfiumEngine {
915
915
  case PdfAnnotationSubtype.STAMP:
916
916
  isSucceed = this.addStampContent(ctx.docPtr, page, pageCtx.pagePtr, annotationPtr, annotation.rect, annotation.contents);
917
917
  break;
918
+ case PdfAnnotationSubtype.UNDERLINE:
919
+ case PdfAnnotationSubtype.STRIKEOUT:
920
+ case PdfAnnotationSubtype.SQUIGGLY:
921
+ case PdfAnnotationSubtype.HIGHLIGHT:
922
+ isSucceed = this.addTextMarkupContent(page, annotationPtr, annotation);
923
+ break;
918
924
  }
919
925
  if (!isSucceed) {
920
926
  this.pdfiumModule.FPDFPage_RemoveAnnot(pageCtx.pagePtr, annotationPtr);
@@ -926,10 +932,101 @@ class PdfiumEngine {
926
932
  });
927
933
  }
928
934
  this.pdfiumModule.FPDFPage_GenerateContent(pageCtx.pagePtr);
935
+ const annotId = this.pdfiumModule.FPDFPage_GetAnnotIndex(pageCtx.pagePtr, annotationPtr);
929
936
  this.pdfiumModule.FPDFPage_CloseAnnot(annotationPtr);
930
937
  pageCtx.release();
931
938
  this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, `CreatePageAnnotation`, 'End', `${doc.id}-${page.index}`);
932
- return PdfTaskHelper.resolve(true);
939
+ return annotId >= 0
940
+ ? PdfTaskHelper.resolve(annotId)
941
+ : PdfTaskHelper.reject({
942
+ code: PdfErrorCode.CantCreateAnnot,
943
+ message: 'annotation created but index could not be determined',
944
+ });
945
+ }
946
+ /**
947
+ * Update an existing page annotation in-place
948
+ *
949
+ * • Locates the annot by page-local index (`annotation.id`)
950
+ * • Re-writes its /Rect and type-specific payload
951
+ * • Calls FPDFPage_GenerateContent so the new appearance is rendered
952
+ *
953
+ * @returns PdfTask<boolean> – true on success
954
+ */
955
+ updatePageAnnotation(doc, page, annotation) {
956
+ this.logger.debug(LOG_SOURCE$1, LOG_CATEGORY$1, 'updatePageAnnotation', doc, page, annotation);
957
+ this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'UpdatePageAnnotation', 'Begin', `${doc.id}-${page.index}`);
958
+ const ctx = this.cache.getContext(doc.id);
959
+ if (!ctx) {
960
+ this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'UpdatePageAnnotation', 'End', `${doc.id}-${page.index}`);
961
+ return PdfTaskHelper.reject({
962
+ code: PdfErrorCode.DocNotOpen,
963
+ message: 'document does not open',
964
+ });
965
+ }
966
+ const pageCtx = ctx.acquirePage(page.index);
967
+ const annotPtr = this.pdfiumModule.FPDFPage_GetAnnot(pageCtx.pagePtr, annotation.id);
968
+ if (!annotPtr) {
969
+ pageCtx.release();
970
+ this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'UpdatePageAnnotation', 'End', `${doc.id}-${page.index}`);
971
+ return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: 'annotation not found' });
972
+ }
973
+ /* 1 ── (re)set bounding-box ────────────────────────────────────────────── */
974
+ if (!this.setPageAnnoRect(page, pageCtx.pagePtr, annotPtr, annotation.rect)) {
975
+ this.pdfiumModule.FPDFPage_CloseAnnot(annotPtr);
976
+ pageCtx.release();
977
+ this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'UpdatePageAnnotation', 'End', `${doc.id}-${page.index}`);
978
+ return PdfTaskHelper.reject({
979
+ code: PdfErrorCode.CantSetAnnotRect,
980
+ message: 'failed to move annotation',
981
+ });
982
+ }
983
+ /* 2 ── wipe previous payload and rebuild fresh one ─────────────────────── */
984
+ let ok = false;
985
+ switch (annotation.type) {
986
+ /* ── Ink ─────────────────────────────────────────────────────────────── */
987
+ case PdfAnnotationSubtype.INK: {
988
+ /* clear every existing stroke first */
989
+ if (!this.pdfiumModule.FPDFAnnot_RemoveInkList(annotPtr))
990
+ break;
991
+ ok = this.addInkStroke(page, pageCtx.pagePtr, annotPtr, annotation.inkList);
992
+ break;
993
+ }
994
+ /* ── Stamp ───────────────────────────────────────────────────────────── */
995
+ case PdfAnnotationSubtype.STAMP: {
996
+ /* drop every page-object inside the annot */
997
+ for (let i = this.pdfiumModule.FPDFAnnot_GetObjectCount(annotPtr) - 1; i >= 0; i--) {
998
+ this.pdfiumModule.FPDFAnnot_RemoveObject(annotPtr, i);
999
+ }
1000
+ ok = this.addStampContent(ctx.docPtr, page, pageCtx.pagePtr, annotPtr, annotation.rect, annotation.contents);
1001
+ break;
1002
+ }
1003
+ /* ── Text-markup family ──────────────────────────────────────────────── */
1004
+ case PdfAnnotationSubtype.HIGHLIGHT:
1005
+ case PdfAnnotationSubtype.UNDERLINE:
1006
+ case PdfAnnotationSubtype.STRIKEOUT:
1007
+ case PdfAnnotationSubtype.SQUIGGLY: {
1008
+ /* replace quad-points / colour / strings in one go */
1009
+ ok = this.addTextMarkupContent(page, annotPtr, annotation, true);
1010
+ break;
1011
+ }
1012
+ /* ── Unsupported edits – fall through to error ───────────────────────── */
1013
+ default:
1014
+ ok = false;
1015
+ }
1016
+ /* 3 ── regenerate appearance if payload was changed ───────────────────── */
1017
+ if (ok) {
1018
+ this.pdfiumModule.FPDFPage_GenerateContent(pageCtx.pagePtr);
1019
+ }
1020
+ /* 4 ── tidy-up native handles ──────────────────────────────────────────── */
1021
+ this.pdfiumModule.FPDFPage_CloseAnnot(annotPtr);
1022
+ pageCtx.release();
1023
+ this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'UpdatePageAnnotation', 'End', `${doc.id}-${page.index}`);
1024
+ return ok
1025
+ ? PdfTaskHelper.resolve(true)
1026
+ : PdfTaskHelper.reject({
1027
+ code: PdfErrorCode.CantSetAnnotContent,
1028
+ message: 'failed to update annotation',
1029
+ });
933
1030
  }
934
1031
  /**
935
1032
  * {@inheritDoc @embedpdf/models!PdfEngine.transformPageAnnotation}
@@ -1648,6 +1745,36 @@ class PdfiumEngine {
1648
1745
  }
1649
1746
  return true;
1650
1747
  }
1748
+ /**
1749
+ * Add highlight content to annotation
1750
+ * @param page - page info
1751
+ * @param annotationPtr - pointer to highlight annotation
1752
+ * @param annotation - highlight annotation
1753
+ * @returns whether highlight content is added to annotation
1754
+ *
1755
+ * @private
1756
+ */
1757
+ addTextMarkupContent(page, annotationPtr, annotation, shouldClearAP = false) {
1758
+ if (!this.syncQuadPointsAnno(page, annotationPtr, annotation.segmentRects)) {
1759
+ return false;
1760
+ }
1761
+ if (!this.setAnnotString(annotationPtr, 'Contents', annotation.contents ?? '')) {
1762
+ return false;
1763
+ }
1764
+ if (!this.setAnnotString(annotationPtr, 'T', annotation.author || '')) {
1765
+ return false;
1766
+ }
1767
+ if (!this.setAnnotString(annotationPtr, 'M', dateToPdfDate(annotation.modified))) {
1768
+ return false;
1769
+ }
1770
+ if (!this.setAnnotationColor(annotationPtr, {
1771
+ color: annotation.color ?? '#FFFF00',
1772
+ opacity: annotation.opacity ?? 1,
1773
+ }, shouldClearAP, 0)) {
1774
+ return false;
1775
+ }
1776
+ return true;
1777
+ }
1651
1778
  /**
1652
1779
  * Add contents to stamp annotation
1653
1780
  * @param docPtr - pointer to pdf document object
@@ -2270,8 +2397,6 @@ class PdfiumEngine {
2270
2397
  annotation = this.readPdfCaretAnno(page, pageCtx.pagePtr, annotationPtr, index);
2271
2398
  }
2272
2399
  break;
2273
- case PdfAnnotationSubtype.POPUP:
2274
- break;
2275
2400
  default:
2276
2401
  {
2277
2402
  annotation = this.readPdfAnno(page, pageCtx.pagePtr, subType, annotationPtr, index);
@@ -2418,15 +2543,35 @@ class PdfiumEngine {
2418
2543
  *
2419
2544
  * @param annotationPtr - pointer to an `FPDF_ANNOTATION`
2420
2545
  * @param fallback - colour to use when the PDF stores no tint at all
2421
- * @returns Guaranteed RGBA tuple (never `undefined`)
2546
+ * @returns WebAlphaColor with hex color and opacity (0-1)
2422
2547
  *
2423
2548
  * @private
2424
2549
  */
2425
2550
  resolveAnnotationColor(annotationPtr, fallback = { red: 255, green: 245, blue: 155, alpha: 255 }) {
2426
- return (this.readAnnotationColor(annotationPtr) ?? // 1 – /C entry
2551
+ const pdfColor = this.readAnnotationColor(annotationPtr) ?? // 1 – /C entry
2427
2552
  this.colorFromAppearance(annotationPtr) ?? // 2 – AP stream walk
2428
- fallback // 3 – default
2429
- );
2553
+ fallback; // 3 – default
2554
+ return pdfAlphaColorToWebAlphaColor(pdfColor);
2555
+ }
2556
+ /**
2557
+ * Set the fill/stroke colour for a **Highlight / Underline / StrikeOut / Squiggly** markup annotation.
2558
+ *
2559
+ * @param annotationPtr - pointer to the annotation whose colour is being set
2560
+ * @param webAlphaColor - WebAlphaColor with hex color and opacity (0-1)
2561
+ * @param shouldClearAP - whether to clear the /AP entry
2562
+ * @param which - which colour to set (0 = fill, 1 = stroke)
2563
+ * @returns `true` if the operation was successful
2564
+ *
2565
+ * @private
2566
+ */
2567
+ setAnnotationColor(annotationPtr, webAlphaColor, shouldClearAP = false, which = 0) {
2568
+ const pdfAlphaColor = webAlphaColorToPdfAlphaColor(webAlphaColor);
2569
+ if (shouldClearAP) {
2570
+ // NULL wide-string → remove the /AP entry
2571
+ this.pdfiumModule.FPDFAnnot_SetAP(annotationPtr, AppearanceMode.Normal,
2572
+ /* FPDF_WIDESTRING = */ 0);
2573
+ }
2574
+ return this.pdfiumModule.FPDFAnnot_SetColor(annotationPtr, which, pdfAlphaColor.red & 0xff, pdfAlphaColor.green & 0xff, pdfAlphaColor.blue & 0xff, (pdfAlphaColor.alpha ?? 255) & 0xff);
2430
2575
  }
2431
2576
  /**
2432
2577
  * Read `/QuadPoints` from any annotation and convert each quadrilateral to
@@ -2439,11 +2584,11 @@ class PdfiumEngine {
2439
2584
  *
2440
2585
  * @param page - logical page info object (`PdfPageObject`)
2441
2586
  * @param annotationPtr - pointer to the annotation whose quads are needed
2442
- * @returns Array of `Quad` objects (`[]` if the annotation has no quads)
2587
+ * @returns Array of `Rect` objects (`[]` if the annotation has no quads)
2443
2588
  *
2444
2589
  * @private
2445
2590
  */
2446
- readAnnotationQuads(page, annotationPtr) {
2591
+ getQuadPointsAnno(page, annotationPtr) {
2447
2592
  const quadCount = this.pdfiumModule.FPDFAnnot_CountAttachmentPoints(annotationPtr);
2448
2593
  if (quadCount === 0)
2449
2594
  return [];
@@ -2470,7 +2615,60 @@ class PdfiumEngine {
2470
2615
  }
2471
2616
  this.free(quadPtr);
2472
2617
  }
2473
- return quads;
2618
+ return quads.map(quadToRect);
2619
+ }
2620
+ /**
2621
+ * Set the quadrilaterals for a **Highlight / Underline / StrikeOut / Squiggly** markup annotation.
2622
+ *
2623
+ * @param page - logical page info object (`PdfPageObject`)
2624
+ * @param annotationPtr - pointer to the annotation whose quads are needed
2625
+ * @param rects - array of `Rect` objects (`[]` if the annotation has no quads)
2626
+ * @returns `true` if the operation was successful
2627
+ *
2628
+ * @private
2629
+ */
2630
+ syncQuadPointsAnno(page, annotPtr, rects) {
2631
+ const FS_QUADPOINTSF_SIZE = 8 * 4; // eight floats, 32 bytes
2632
+ const pdf = this.pdfiumModule.pdfium;
2633
+ const count = this.pdfiumModule.FPDFAnnot_CountAttachmentPoints(annotPtr);
2634
+ const buf = this.malloc(FS_QUADPOINTSF_SIZE);
2635
+ /** write one quad into `buf` in annotation space */
2636
+ const writeQuad = (r) => {
2637
+ const q = rectToQuad(r); // TL, TR, BR, BL
2638
+ const p1 = this.convertDevicePointToPagePoint(page, q.p1);
2639
+ const p2 = this.convertDevicePointToPagePoint(page, q.p2);
2640
+ const p3 = this.convertDevicePointToPagePoint(page, q.p3); // BR
2641
+ const p4 = this.convertDevicePointToPagePoint(page, q.p4); // BL
2642
+ // PDF QuadPoints order: BL, BR, TL, TR (bottom-left, bottom-right, top-left, top-right)
2643
+ pdf.setValue(buf + 0, p1.x, 'float'); // BL (bottom-left)
2644
+ pdf.setValue(buf + 4, p1.y, 'float');
2645
+ pdf.setValue(buf + 8, p2.x, 'float'); // BR (bottom-right)
2646
+ pdf.setValue(buf + 12, p2.y, 'float');
2647
+ pdf.setValue(buf + 16, p4.x, 'float'); // TL (top-left)
2648
+ pdf.setValue(buf + 20, p4.y, 'float');
2649
+ pdf.setValue(buf + 24, p3.x, 'float'); // TR (top-right)
2650
+ pdf.setValue(buf + 28, p3.y, 'float');
2651
+ };
2652
+ /* ----------------------------------------------------------------------- */
2653
+ /* 1. overwrite the quads that already exist */
2654
+ const min = Math.min(count, rects.length);
2655
+ for (let i = 0; i < min; i++) {
2656
+ writeQuad(rects[i]);
2657
+ if (!this.pdfiumModule.FPDFAnnot_SetAttachmentPoints(annotPtr, i, buf)) {
2658
+ this.free(buf);
2659
+ return false;
2660
+ }
2661
+ }
2662
+ /* 2. append new quads if rects.length > count */
2663
+ for (let i = count; i < rects.length; i++) {
2664
+ writeQuad(rects[i]);
2665
+ if (!this.pdfiumModule.FPDFAnnot_AppendAttachmentPoints(annotPtr, buf)) {
2666
+ this.free(buf);
2667
+ return false;
2668
+ }
2669
+ }
2670
+ this.free(buf);
2671
+ return true;
2474
2672
  }
2475
2673
  /**
2476
2674
  * Read pdf text annotation
@@ -2483,30 +2681,23 @@ class PdfiumEngine {
2483
2681
  * @private
2484
2682
  */
2485
2683
  readPdfTextAnno(page, pagePtr, annotationPtr, index) {
2486
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
2487
2684
  const annoRect = this.readPageAnnoRect(annotationPtr);
2488
2685
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, annoRect);
2489
2686
  const author = this.getAnnotString(annotationPtr, 'T');
2490
2687
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2491
- const modified = this.toIsoDate(modifiedRaw);
2688
+ const modified = pdfDateToDate(modifiedRaw);
2492
2689
  const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
2493
2690
  const state = this.getAnnotString(annotationPtr, 'State');
2494
2691
  const stateModel = this.getAnnotString(annotationPtr, 'StateModel');
2495
- const color = this.resolveAnnotationColor(annotationPtr);
2692
+ const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
2496
2693
  const inReplyToId = this.getInReplyToId(pagePtr, annotationPtr);
2497
- const popup = !inReplyToId
2498
- ? this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index)
2499
- : undefined;
2500
2694
  return {
2501
- status: PdfAnnotationObjectStatus.Committed,
2502
2695
  pageIndex: page.index,
2503
2696
  id: index,
2504
2697
  type: PdfAnnotationSubtype.TEXT,
2505
2698
  contents,
2506
- color,
2699
+ ...webAlphaColor,
2507
2700
  rect,
2508
- popup,
2509
- appearances,
2510
2701
  inReplyToId,
2511
2702
  author,
2512
2703
  modified,
@@ -2525,16 +2716,13 @@ class PdfiumEngine {
2525
2716
  * @private
2526
2717
  */
2527
2718
  readPdfFreeTextAnno(page, pagePtr, annotationPtr, index) {
2528
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
2529
2719
  const annoRect = this.readPageAnnoRect(annotationPtr);
2530
2720
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, annoRect);
2531
2721
  const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
2532
2722
  const author = this.getAnnotString(annotationPtr, 'T');
2533
2723
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2534
- const modified = this.toIsoDate(modifiedRaw);
2535
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
2724
+ const modified = pdfDateToDate(modifiedRaw);
2536
2725
  return {
2537
- status: PdfAnnotationObjectStatus.Committed,
2538
2726
  pageIndex: page.index,
2539
2727
  id: index,
2540
2728
  type: PdfAnnotationSubtype.FREETEXT,
@@ -2542,8 +2730,6 @@ class PdfiumEngine {
2542
2730
  author,
2543
2731
  modified,
2544
2732
  rect,
2545
- popup,
2546
- appearances,
2547
2733
  };
2548
2734
  }
2549
2735
  /**
@@ -2563,13 +2749,12 @@ class PdfiumEngine {
2563
2749
  if (!linkPtr) {
2564
2750
  return;
2565
2751
  }
2566
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
2567
2752
  const annoRect = this.readPageAnnoRect(annotationPtr);
2568
2753
  const { left, top, right, bottom } = annoRect;
2569
2754
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, annoRect);
2570
2755
  const author = this.getAnnotString(annotationPtr, 'T');
2571
2756
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2572
- const modified = this.toIsoDate(modifiedRaw);
2757
+ const modified = pdfDateToDate(modifiedRaw);
2573
2758
  const utf16Length = this.pdfiumModule.FPDFText_GetBoundedText(textPagePtr, left, top, right, bottom, 0, 0);
2574
2759
  const bytesCount = (utf16Length + 1) * 2; // include NIL
2575
2760
  const textBufferPtr = this.malloc(bytesCount);
@@ -2581,17 +2766,13 @@ class PdfiumEngine {
2581
2766
  }, () => {
2582
2767
  return this.pdfiumModule.FPDFLink_GetDest(docPtr, linkPtr);
2583
2768
  });
2584
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
2585
2769
  return {
2586
- status: PdfAnnotationObjectStatus.Committed,
2587
2770
  pageIndex: page.index,
2588
2771
  id: index,
2589
2772
  type: PdfAnnotationSubtype.LINK,
2590
2773
  text,
2591
2774
  target,
2592
2775
  rect,
2593
- popup,
2594
- appearances,
2595
2776
  author,
2596
2777
  modified,
2597
2778
  };
@@ -2608,23 +2789,18 @@ class PdfiumEngine {
2608
2789
  * @private
2609
2790
  */
2610
2791
  readPdfWidgetAnno(page, pagePtr, annotationPtr, formHandle, index) {
2611
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
2612
2792
  const pageRect = this.readPageAnnoRect(annotationPtr);
2613
2793
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
2614
2794
  const author = this.getAnnotString(annotationPtr, 'T');
2615
2795
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2616
- const modified = this.toIsoDate(modifiedRaw);
2617
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
2796
+ const modified = pdfDateToDate(modifiedRaw);
2618
2797
  const field = this.readPdfWidgetAnnoField(formHandle, annotationPtr);
2619
2798
  return {
2620
- status: PdfAnnotationObjectStatus.Committed,
2621
2799
  pageIndex: page.index,
2622
2800
  id: index,
2623
2801
  type: PdfAnnotationSubtype.WIDGET,
2624
2802
  rect,
2625
2803
  field,
2626
- popup,
2627
- appearances,
2628
2804
  author,
2629
2805
  modified,
2630
2806
  };
@@ -2640,21 +2816,16 @@ class PdfiumEngine {
2640
2816
  * @private
2641
2817
  */
2642
2818
  readPdfFileAttachmentAnno(page, pagePtr, annotationPtr, index) {
2643
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
2644
2819
  const pageRect = this.readPageAnnoRect(annotationPtr);
2645
2820
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
2646
2821
  const author = this.getAnnotString(annotationPtr, 'T');
2647
2822
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2648
- const modified = this.toIsoDate(modifiedRaw);
2649
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
2823
+ const modified = pdfDateToDate(modifiedRaw);
2650
2824
  return {
2651
- status: PdfAnnotationObjectStatus.Committed,
2652
2825
  pageIndex: page.index,
2653
2826
  id: index,
2654
2827
  type: PdfAnnotationSubtype.FILEATTACHMENT,
2655
2828
  rect,
2656
- popup,
2657
- appearances,
2658
2829
  author,
2659
2830
  modified,
2660
2831
  };
@@ -2670,13 +2841,11 @@ class PdfiumEngine {
2670
2841
  * @private
2671
2842
  */
2672
2843
  readPdfInkAnno(page, pagePtr, annotationPtr, index) {
2673
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
2674
2844
  const pageRect = this.readPageAnnoRect(annotationPtr);
2675
2845
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
2676
2846
  const author = this.getAnnotString(annotationPtr, 'T');
2677
2847
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2678
- const modified = this.toIsoDate(modifiedRaw);
2679
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
2848
+ const modified = pdfDateToDate(modifiedRaw);
2680
2849
  const inkList = [];
2681
2850
  const count = this.pdfiumModule.FPDFAnnot_GetInkListCount(annotationPtr);
2682
2851
  for (let i = 0; i < count; i++) {
@@ -2700,14 +2869,11 @@ class PdfiumEngine {
2700
2869
  inkList.push({ points });
2701
2870
  }
2702
2871
  return {
2703
- status: PdfAnnotationObjectStatus.Committed,
2704
2872
  pageIndex: page.index,
2705
2873
  id: index,
2706
2874
  type: PdfAnnotationSubtype.INK,
2707
2875
  rect,
2708
- popup,
2709
2876
  inkList,
2710
- appearances,
2711
2877
  author,
2712
2878
  modified,
2713
2879
  };
@@ -2723,23 +2889,18 @@ class PdfiumEngine {
2723
2889
  * @private
2724
2890
  */
2725
2891
  readPdfPolygonAnno(page, pagePtr, annotationPtr, index) {
2726
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
2727
2892
  const pageRect = this.readPageAnnoRect(annotationPtr);
2728
2893
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
2729
2894
  const author = this.getAnnotString(annotationPtr, 'T');
2730
2895
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2731
- const modified = this.toIsoDate(modifiedRaw);
2732
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
2896
+ const modified = pdfDateToDate(modifiedRaw);
2733
2897
  const vertices = this.readPdfAnnoVertices(page, pagePtr, annotationPtr);
2734
2898
  return {
2735
- status: PdfAnnotationObjectStatus.Committed,
2736
2899
  pageIndex: page.index,
2737
2900
  id: index,
2738
2901
  type: PdfAnnotationSubtype.POLYGON,
2739
2902
  rect,
2740
- popup,
2741
2903
  vertices,
2742
- appearances,
2743
2904
  author,
2744
2905
  modified,
2745
2906
  };
@@ -2755,23 +2916,18 @@ class PdfiumEngine {
2755
2916
  * @private
2756
2917
  */
2757
2918
  readPdfPolylineAnno(page, pagePtr, annotationPtr, index) {
2758
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
2759
2919
  const pageRect = this.readPageAnnoRect(annotationPtr);
2760
2920
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
2761
2921
  const author = this.getAnnotString(annotationPtr, 'T');
2762
2922
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2763
- const modified = this.toIsoDate(modifiedRaw);
2764
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
2923
+ const modified = pdfDateToDate(modifiedRaw);
2765
2924
  const vertices = this.readPdfAnnoVertices(page, pagePtr, annotationPtr);
2766
2925
  return {
2767
- status: PdfAnnotationObjectStatus.Committed,
2768
2926
  pageIndex: page.index,
2769
2927
  id: index,
2770
2928
  type: PdfAnnotationSubtype.POLYLINE,
2771
2929
  rect,
2772
- popup,
2773
2930
  vertices,
2774
- appearances,
2775
2931
  author,
2776
2932
  modified,
2777
2933
  };
@@ -2787,13 +2943,11 @@ class PdfiumEngine {
2787
2943
  * @private
2788
2944
  */
2789
2945
  readPdfLineAnno(page, pagePtr, annotationPtr, index) {
2790
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
2791
2946
  const pageRect = this.readPageAnnoRect(annotationPtr);
2792
2947
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
2793
2948
  const author = this.getAnnotString(annotationPtr, 'T');
2794
2949
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2795
- const modified = this.toIsoDate(modifiedRaw);
2796
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
2950
+ const modified = pdfDateToDate(modifiedRaw);
2797
2951
  const startPointPtr = this.malloc(8);
2798
2952
  const endPointPtr = this.malloc(8);
2799
2953
  this.pdfiumModule.FPDFAnnot_GetLine(annotationPtr, startPointPtr, endPointPtr);
@@ -2812,15 +2966,12 @@ class PdfiumEngine {
2812
2966
  this.free(startPointPtr);
2813
2967
  this.free(endPointPtr);
2814
2968
  return {
2815
- status: PdfAnnotationObjectStatus.Committed,
2816
2969
  pageIndex: page.index,
2817
2970
  id: index,
2818
2971
  type: PdfAnnotationSubtype.LINE,
2819
2972
  rect,
2820
- popup,
2821
2973
  startPoint,
2822
2974
  endPoint,
2823
- appearances,
2824
2975
  author,
2825
2976
  modified,
2826
2977
  };
@@ -2836,25 +2987,22 @@ class PdfiumEngine {
2836
2987
  * @private
2837
2988
  */
2838
2989
  readPdfHighlightAnno(page, pagePtr, annotationPtr, index) {
2839
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
2840
2990
  const pageRect = this.readPageAnnoRect(annotationPtr);
2841
2991
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
2842
- const quads = this.readAnnotationQuads(page, annotationPtr);
2843
- const color = this.resolveAnnotationColor(annotationPtr);
2844
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
2992
+ const segmentRects = this.getQuadPointsAnno(page, annotationPtr);
2993
+ const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
2845
2994
  const author = this.getAnnotString(annotationPtr, 'T');
2846
2995
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2847
- const modified = this.toIsoDate(modifiedRaw);
2996
+ const modified = pdfDateToDate(modifiedRaw);
2997
+ const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
2848
2998
  return {
2849
- status: PdfAnnotationObjectStatus.Committed,
2850
2999
  pageIndex: page.index,
2851
3000
  id: index,
2852
3001
  type: PdfAnnotationSubtype.HIGHLIGHT,
2853
3002
  rect,
2854
- popup,
2855
- appearances,
2856
- segmentRects: quads.map(quadToRect),
2857
- color,
3003
+ contents,
3004
+ segmentRects,
3005
+ ...webAlphaColor,
2858
3006
  author,
2859
3007
  modified,
2860
3008
  };
@@ -2870,21 +3018,22 @@ class PdfiumEngine {
2870
3018
  * @private
2871
3019
  */
2872
3020
  readPdfUnderlineAnno(page, pagePtr, annotationPtr, index) {
2873
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
2874
3021
  const pageRect = this.readPageAnnoRect(annotationPtr);
2875
3022
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
2876
3023
  const author = this.getAnnotString(annotationPtr, 'T');
2877
3024
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2878
- const modified = this.toIsoDate(modifiedRaw);
2879
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
3025
+ const modified = pdfDateToDate(modifiedRaw);
3026
+ const segmentRects = this.getQuadPointsAnno(page, annotationPtr);
3027
+ const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
3028
+ const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
2880
3029
  return {
2881
- status: PdfAnnotationObjectStatus.Committed,
2882
3030
  pageIndex: page.index,
2883
3031
  id: index,
2884
3032
  type: PdfAnnotationSubtype.UNDERLINE,
2885
3033
  rect,
2886
- popup,
2887
- appearances,
3034
+ contents,
3035
+ segmentRects,
3036
+ ...webAlphaColor,
2888
3037
  author,
2889
3038
  modified,
2890
3039
  };
@@ -2900,21 +3049,22 @@ class PdfiumEngine {
2900
3049
  * @private
2901
3050
  */
2902
3051
  readPdfStrikeOutAnno(page, pagePtr, annotationPtr, index) {
2903
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
2904
3052
  const pageRect = this.readPageAnnoRect(annotationPtr);
2905
3053
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
2906
3054
  const author = this.getAnnotString(annotationPtr, 'T');
2907
3055
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2908
- const modified = this.toIsoDate(modifiedRaw);
2909
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
3056
+ const modified = pdfDateToDate(modifiedRaw);
3057
+ const segmentRects = this.getQuadPointsAnno(page, annotationPtr);
3058
+ const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
3059
+ const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
2910
3060
  return {
2911
- status: PdfAnnotationObjectStatus.Committed,
2912
3061
  pageIndex: page.index,
2913
3062
  id: index,
2914
3063
  type: PdfAnnotationSubtype.STRIKEOUT,
2915
3064
  rect,
2916
- popup,
2917
- appearances,
3065
+ contents,
3066
+ segmentRects,
3067
+ ...webAlphaColor,
2918
3068
  author,
2919
3069
  modified,
2920
3070
  };
@@ -2930,21 +3080,22 @@ class PdfiumEngine {
2930
3080
  * @private
2931
3081
  */
2932
3082
  readPdfSquigglyAnno(page, pagePtr, annotationPtr, index) {
2933
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
2934
3083
  const pageRect = this.readPageAnnoRect(annotationPtr);
2935
3084
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
2936
3085
  const author = this.getAnnotString(annotationPtr, 'T');
2937
3086
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2938
- const modified = this.toIsoDate(modifiedRaw);
2939
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
3087
+ const modified = pdfDateToDate(modifiedRaw);
3088
+ const segmentRects = this.getQuadPointsAnno(page, annotationPtr);
3089
+ const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
3090
+ const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
2940
3091
  return {
2941
- status: PdfAnnotationObjectStatus.Committed,
2942
3092
  pageIndex: page.index,
2943
3093
  id: index,
2944
3094
  type: PdfAnnotationSubtype.SQUIGGLY,
2945
3095
  rect,
2946
- popup,
2947
- appearances,
3096
+ contents,
3097
+ segmentRects,
3098
+ ...webAlphaColor,
2948
3099
  author,
2949
3100
  modified,
2950
3101
  };
@@ -2960,21 +3111,16 @@ class PdfiumEngine {
2960
3111
  * @private
2961
3112
  */
2962
3113
  readPdfCaretAnno(page, pagePtr, annotationPtr, index) {
2963
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
2964
3114
  const pageRect = this.readPageAnnoRect(annotationPtr);
2965
3115
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
2966
3116
  const author = this.getAnnotString(annotationPtr, 'T');
2967
3117
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2968
- const modified = this.toIsoDate(modifiedRaw);
2969
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
3118
+ const modified = pdfDateToDate(modifiedRaw);
2970
3119
  return {
2971
- status: PdfAnnotationObjectStatus.Committed,
2972
3120
  pageIndex: page.index,
2973
3121
  id: index,
2974
3122
  type: PdfAnnotationSubtype.CARET,
2975
3123
  rect,
2976
- popup,
2977
- appearances,
2978
3124
  author,
2979
3125
  modified,
2980
3126
  };
@@ -2991,13 +3137,11 @@ class PdfiumEngine {
2991
3137
  * @private
2992
3138
  */
2993
3139
  readPdfStampAnno(docPtr, page, pagePtr, annotationPtr, index) {
2994
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
2995
3140
  const pageRect = this.readPageAnnoRect(annotationPtr);
2996
3141
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
2997
3142
  const author = this.getAnnotString(annotationPtr, 'T');
2998
3143
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
2999
- const modified = this.toIsoDate(modifiedRaw);
3000
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
3144
+ const modified = pdfDateToDate(modifiedRaw);
3001
3145
  const contents = [];
3002
3146
  const objectCount = this.pdfiumModule.FPDFAnnot_GetObjectCount(annotationPtr);
3003
3147
  for (let i = 0; i < objectCount; i++) {
@@ -3008,14 +3152,11 @@ class PdfiumEngine {
3008
3152
  }
3009
3153
  }
3010
3154
  return {
3011
- status: PdfAnnotationObjectStatus.Committed,
3012
3155
  pageIndex: page.index,
3013
3156
  id: index,
3014
3157
  type: PdfAnnotationSubtype.STAMP,
3015
3158
  rect,
3016
- popup,
3017
3159
  contents,
3018
- appearances,
3019
3160
  author,
3020
3161
  modified,
3021
3162
  };
@@ -3195,21 +3336,16 @@ class PdfiumEngine {
3195
3336
  * @private
3196
3337
  */
3197
3338
  readPdfCircleAnno(page, pagePtr, annotationPtr, index) {
3198
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
3199
3339
  const pageRect = this.readPageAnnoRect(annotationPtr);
3200
3340
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
3201
3341
  const author = this.getAnnotString(annotationPtr, 'T');
3202
3342
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
3203
- const modified = this.toIsoDate(modifiedRaw);
3204
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
3343
+ const modified = pdfDateToDate(modifiedRaw);
3205
3344
  return {
3206
- status: PdfAnnotationObjectStatus.Committed,
3207
3345
  pageIndex: page.index,
3208
3346
  id: index,
3209
3347
  type: PdfAnnotationSubtype.CIRCLE,
3210
3348
  rect,
3211
- popup,
3212
- appearances,
3213
3349
  author,
3214
3350
  modified,
3215
3351
  };
@@ -3225,21 +3361,16 @@ class PdfiumEngine {
3225
3361
  * @private
3226
3362
  */
3227
3363
  readPdfSquareAnno(page, pagePtr, annotationPtr, index) {
3228
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
3229
3364
  const pageRect = this.readPageAnnoRect(annotationPtr);
3230
3365
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
3231
3366
  const author = this.getAnnotString(annotationPtr, 'T');
3232
3367
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
3233
- const modified = this.toIsoDate(modifiedRaw);
3234
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
3368
+ const modified = pdfDateToDate(modifiedRaw);
3235
3369
  return {
3236
- status: PdfAnnotationObjectStatus.Committed,
3237
3370
  pageIndex: page.index,
3238
3371
  id: index,
3239
3372
  type: PdfAnnotationSubtype.SQUARE,
3240
3373
  rect,
3241
- popup,
3242
- appearances,
3243
3374
  author,
3244
3375
  modified,
3245
3376
  };
@@ -3256,21 +3387,16 @@ class PdfiumEngine {
3256
3387
  * @private
3257
3388
  */
3258
3389
  readPdfAnno(page, pagePtr, type, annotationPtr, index) {
3259
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
3260
3390
  const pageRect = this.readPageAnnoRect(annotationPtr);
3261
3391
  const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
3262
3392
  const author = this.getAnnotString(annotationPtr, 'T');
3263
3393
  const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
3264
- const modified = this.toIsoDate(modifiedRaw);
3265
- const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
3394
+ const modified = pdfDateToDate(modifiedRaw);
3266
3395
  return {
3267
- status: PdfAnnotationObjectStatus.Committed,
3268
3396
  pageIndex: page.index,
3269
3397
  id: index,
3270
3398
  type,
3271
3399
  rect,
3272
- popup,
3273
- appearances,
3274
3400
  author,
3275
3401
  modified,
3276
3402
  };
@@ -3292,25 +3418,6 @@ class PdfiumEngine {
3292
3418
  const idx = this.pdfiumModule.FPDFPage_GetAnnotIndex(pagePtr, parentPtr);
3293
3419
  return idx >= 0 ? idx : undefined;
3294
3420
  }
3295
- /**
3296
- * Parse a PDF date string **D:YYYYMMDDHHmmSSOHH'mm'** to ISO-8601.
3297
- *
3298
- * Returns `undefined` if the input is malformed.
3299
- *
3300
- * @private
3301
- */
3302
- toIsoDate(pdfDate) {
3303
- if (!pdfDate?.startsWith('D:'))
3304
- return;
3305
- // Minimal parse – ignore timezone for brevity
3306
- const y = pdfDate.substring(2, 6);
3307
- const m = pdfDate.substring(6, 8) || '01';
3308
- const d = pdfDate.substring(8, 10) || '01';
3309
- const H = pdfDate.substring(10, 12) || '00';
3310
- const M = pdfDate.substring(12, 14) || '00';
3311
- const S = pdfDate.substring(14, 16) || '00';
3312
- return `${y}-${m}-${d}T${H}:${M}:${S}`;
3313
- }
3314
3421
  /**
3315
3422
  * Fetch a string value (`/T`, `/M`, `/State`, …) from an annotation.
3316
3423
  *
@@ -3330,41 +3437,19 @@ class PdfiumEngine {
3330
3437
  return value || undefined;
3331
3438
  }
3332
3439
  /**
3333
- * Read linked popup of pdf annotation
3334
- * @param page - pdf page infor
3335
- * @param pagePtr - pointer to pdf page object
3336
- * @param annotationPtr - pointer to pdf annotation
3337
- * @param index - index of annotation in the pdf page
3338
- * @returns pdf popup linked to annotation
3440
+ * Set a string value (`/T`, `/M`, `/State`, …) to an annotation.
3441
+ *
3442
+ * @returns `true` if the operation was successful
3339
3443
  *
3340
3444
  * @private
3341
3445
  */
3342
- readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index) {
3343
- const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
3344
- const popupAnnotationPtr = this.pdfiumModule.FPDFAnnot_GetLinkedAnnot(annotationPtr, 'Popup');
3345
- if (!popupAnnotationPtr) {
3346
- return;
3347
- }
3348
- const pageRect = this.readPageAnnoRect(popupAnnotationPtr);
3349
- const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
3350
- const author = this.getAnnotString(annotationPtr, 'T');
3351
- const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
3352
- const modified = this.toIsoDate(modifiedRaw);
3353
- const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
3354
- const open = this.getAnnotString(annotationPtr, 'Open') || 'false';
3355
- this.pdfiumModule.FPDFPage_CloseAnnot(popupAnnotationPtr);
3356
- return {
3357
- status: PdfAnnotationObjectStatus.Committed,
3358
- pageIndex: page.index,
3359
- id: index,
3360
- type: PdfAnnotationSubtype.POPUP,
3361
- rect,
3362
- contents,
3363
- open: open === 'true',
3364
- appearances,
3365
- author,
3366
- modified,
3367
- };
3446
+ setAnnotString(annotationPtr, key, value) {
3447
+ const bytes = 2 * (value.length + 1);
3448
+ const ptr = this.malloc(bytes);
3449
+ this.pdfiumModule.pdfium.stringToUTF16(value, ptr, bytes);
3450
+ const ok = this.pdfiumModule.FPDFAnnot_SetStringValue(annotationPtr, key, ptr);
3451
+ this.free(ptr);
3452
+ return ok;
3368
3453
  }
3369
3454
  /**
3370
3455
  * Read vertices of pdf annotation
@@ -3805,6 +3890,69 @@ class PdfiumEngine {
3805
3890
  this.free(bufferPtr);
3806
3891
  return ap;
3807
3892
  }
3893
+ /**
3894
+ * Change the visible colour (and opacity) of an existing annotation.
3895
+ *
3896
+ * For markup annotations (highlight / underline / strikeout / squiggly) we
3897
+ * first clear the AP dictionary entry, otherwise the stored appearance stream
3898
+ * will override the new tint. For all other sub-types we keep the existing
3899
+ * AP so custom artwork isn't lost.
3900
+ *
3901
+ * @param doc logical document object
3902
+ * @param page logical page object
3903
+ * @param annotation the annotation we want to recolour
3904
+ * @param colour RGBA tuple (0-255 per channel)
3905
+ * @param which 0 = stroke/fill colour (PDFium's "colourType" param)
3906
+ *
3907
+ * @returns `true` when the operation succeeded
3908
+ */
3909
+ updateAnnotationColor(doc, page, annotation, color, which = 0) {
3910
+ this.logger.debug(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor', doc, page, annotation, color, which);
3911
+ this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor', 'Begin', doc.id);
3912
+ const task = PdfTaskHelper.create();
3913
+ try {
3914
+ /* 1 ── sanity & native handles ────────────────────────────────────────── */
3915
+ const ctx = this.cache.getContext(doc.id);
3916
+ if (!ctx) {
3917
+ this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor', 'End', doc.id);
3918
+ this.logger.warn(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor: doc closed');
3919
+ task.resolve(false);
3920
+ return task;
3921
+ }
3922
+ const pageCtx = ctx.acquirePage(page.index);
3923
+ const annotPtr = this.pdfiumModule.FPDFPage_GetAnnot(pageCtx.pagePtr, annotation.id);
3924
+ if (!annotPtr) {
3925
+ this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor', 'End', doc.id);
3926
+ this.logger.warn(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor: annot not found');
3927
+ pageCtx.release();
3928
+ task.resolve(false);
3929
+ return task;
3930
+ }
3931
+ /* 2 ── wipe AP if it's a simple markup annotation ─────────────────────── */
3932
+ const shouldClearAP = annotation.type === PdfAnnotationSubtype.HIGHLIGHT ||
3933
+ annotation.type === PdfAnnotationSubtype.UNDERLINE ||
3934
+ annotation.type === PdfAnnotationSubtype.STRIKEOUT ||
3935
+ annotation.type === PdfAnnotationSubtype.SQUIGGLY;
3936
+ const ok = this.setAnnotationColor(annotPtr, color, shouldClearAP, which);
3937
+ /* 4 ── regenerate appearance & clean-up ───────────────────────────────── */
3938
+ if (ok) {
3939
+ this.pdfiumModule.FPDFPage_GenerateContent(pageCtx.pagePtr);
3940
+ }
3941
+ this.pdfiumModule.FPDFPage_CloseAnnot(annotPtr);
3942
+ pageCtx.release();
3943
+ this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor', 'End', doc.id);
3944
+ task.resolve(!!ok);
3945
+ }
3946
+ catch (error) {
3947
+ this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor', 'End', doc.id);
3948
+ this.logger.error(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor: error', error);
3949
+ task.reject({
3950
+ code: PdfErrorCode.Unknown,
3951
+ message: `Failed to set annotation color: ${error instanceof Error ? error.message : String(error)}`,
3952
+ });
3953
+ }
3954
+ return task;
3955
+ }
3808
3956
  /**
3809
3957
  * Set the rect of specified annotation
3810
3958
  * @param page - page info that the annotation is belonged to
@@ -4140,7 +4288,7 @@ class EngineRunner {
4140
4288
  type: 'reject',
4141
4289
  reason: {
4142
4290
  code: PdfErrorCode.NotSupport,
4143
- message: 'engine method has not supported yet',
4291
+ message: `engine method ${name} is not supported yet`,
4144
4292
  },
4145
4293
  };
4146
4294
  const response = {
@@ -4207,12 +4355,18 @@ class EngineRunner {
4207
4355
  case 'createPageAnnotation':
4208
4356
  task = this.engine[name](...args);
4209
4357
  break;
4358
+ case 'updatePageAnnotation':
4359
+ task = this.engine[name](...args);
4360
+ break;
4210
4361
  case 'transformPageAnnotation':
4211
4362
  task = this.engine[name](...args);
4212
4363
  break;
4213
4364
  case 'removePageAnnotation':
4214
4365
  task = this.engine[name](...args);
4215
4366
  break;
4367
+ case 'updateAnnotationColor':
4368
+ task = this.engine[name](...args);
4369
+ break;
4216
4370
  case 'getPageTextRects':
4217
4371
  task = this.engine[name](...args);
4218
4372
  break;