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