@embedpdf/engines 1.0.6 → 1.0.8
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 +709 -378
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +162 -66
- package/dist/index.js +710 -379
- package/dist/index.js.map +1 -1
- package/dist/pdfium-direct-engine.cjs +653 -358
- package/dist/pdfium-direct-engine.cjs.map +1 -1
- package/dist/pdfium-direct-engine.d.ts +153 -59
- package/dist/pdfium-direct-engine.js +654 -359
- package/dist/pdfium-direct-engine.js.map +1 -1
- package/dist/pdfium-worker-engine.cjs +40 -10
- package/dist/pdfium-worker-engine.cjs.map +1 -1
- package/dist/pdfium-worker-engine.d.ts +10 -8
- package/dist/pdfium-worker-engine.js +40 -10
- package/dist/pdfium-worker-engine.js.map +1 -1
- package/dist/pdfium.cjs +661 -360
- package/dist/pdfium.cjs.map +1 -1
- package/dist/pdfium.d.ts +153 -59
- package/dist/pdfium.js +662 -361
- package/dist/pdfium.js.map +1 -1
- package/dist/preact.cjs +4 -3
- package/dist/preact.cjs.map +1 -1
- package/dist/preact.d.ts +4 -3
- package/dist/preact.js +4 -3
- package/dist/preact.js.map +1 -1
- package/dist/react.cjs +4 -3
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +4 -3
- package/dist/react.js +4 -3
- package/dist/react.js.map +1 -1
- package/dist/worker.cjs +39 -9
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.ts +10 -8
- package/dist/worker.js +39 -9
- package/dist/worker.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -912,11 +912,17 @@ 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
|
|
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);
|
|
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, pageCtx.pagePtr, annotationPtr, annotation);
|
|
925
|
+
break;
|
|
920
926
|
}
|
|
921
927
|
if (!isSucceed) {
|
|
922
928
|
this.pdfiumModule.FPDFPage_RemoveAnnot(pageCtx.pagePtr, annotationPtr);
|
|
@@ -927,90 +933,104 @@ class PdfiumEngine {
|
|
|
927
933
|
message: 'can not add content of the annotation',
|
|
928
934
|
});
|
|
929
935
|
}
|
|
936
|
+
this.pdfiumModule.EPDFAnnot_GenerateAppearance(annotationPtr);
|
|
930
937
|
this.pdfiumModule.FPDFPage_GenerateContent(pageCtx.pagePtr);
|
|
938
|
+
const annotId = this.pdfiumModule.FPDFPage_GetAnnotIndex(pageCtx.pagePtr, annotationPtr);
|
|
931
939
|
this.pdfiumModule.FPDFPage_CloseAnnot(annotationPtr);
|
|
932
940
|
pageCtx.release();
|
|
933
941
|
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, `CreatePageAnnotation`, 'End', `${doc.id}-${page.index}`);
|
|
934
|
-
return
|
|
942
|
+
return annotId >= 0
|
|
943
|
+
? models.PdfTaskHelper.resolve(annotId)
|
|
944
|
+
: models.PdfTaskHelper.reject({
|
|
945
|
+
code: models.PdfErrorCode.CantCreateAnnot,
|
|
946
|
+
message: 'annotation created but index could not be determined',
|
|
947
|
+
});
|
|
935
948
|
}
|
|
936
949
|
/**
|
|
937
|
-
*
|
|
950
|
+
* Update an existing page annotation in-place
|
|
938
951
|
*
|
|
939
|
-
*
|
|
952
|
+
* • Locates the annot by page-local index (`annotation.id`)
|
|
953
|
+
* • Re-writes its /Rect and type-specific payload
|
|
954
|
+
* • Calls FPDFPage_GenerateContent so the new appearance is rendered
|
|
955
|
+
*
|
|
956
|
+
* @returns PdfTask<boolean> – true on success
|
|
940
957
|
*/
|
|
941
|
-
|
|
942
|
-
this.logger.debug(LOG_SOURCE$2, LOG_CATEGORY$2, '
|
|
943
|
-
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2,
|
|
958
|
+
updatePageAnnotation(doc, page, annotation) {
|
|
959
|
+
this.logger.debug(LOG_SOURCE$2, LOG_CATEGORY$2, 'updatePageAnnotation', doc, page, annotation);
|
|
960
|
+
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, 'UpdatePageAnnotation', 'Begin', `${doc.id}-${page.index}`);
|
|
944
961
|
const ctx = this.cache.getContext(doc.id);
|
|
945
962
|
if (!ctx) {
|
|
946
|
-
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2,
|
|
963
|
+
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, 'UpdatePageAnnotation', 'End', `${doc.id}-${page.index}`);
|
|
947
964
|
return models.PdfTaskHelper.reject({
|
|
948
965
|
code: models.PdfErrorCode.DocNotOpen,
|
|
949
966
|
message: 'document does not open',
|
|
950
967
|
});
|
|
951
968
|
}
|
|
952
969
|
const pageCtx = ctx.acquirePage(page.index);
|
|
953
|
-
const
|
|
954
|
-
|
|
955
|
-
origin: {
|
|
956
|
-
x: annotation.rect.origin.x + transformation.offset.x,
|
|
957
|
-
y: annotation.rect.origin.y + transformation.offset.y,
|
|
958
|
-
},
|
|
959
|
-
size: {
|
|
960
|
-
width: annotation.rect.size.width * transformation.scale.width,
|
|
961
|
-
height: annotation.rect.size.height * transformation.scale.height,
|
|
962
|
-
},
|
|
963
|
-
};
|
|
964
|
-
if (!this.setPageAnnoRect(page, pageCtx.pagePtr, annotationPtr, rect)) {
|
|
965
|
-
this.pdfiumModule.FPDFPage_CloseAnnot(annotationPtr);
|
|
970
|
+
const annotPtr = this.pdfiumModule.FPDFPage_GetAnnot(pageCtx.pagePtr, annotation.id);
|
|
971
|
+
if (!annotPtr) {
|
|
966
972
|
pageCtx.release();
|
|
967
|
-
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2,
|
|
973
|
+
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, 'UpdatePageAnnotation', 'End', `${doc.id}-${page.index}`);
|
|
974
|
+
return models.PdfTaskHelper.reject({ code: models.PdfErrorCode.NotFound, message: 'annotation not found' });
|
|
975
|
+
}
|
|
976
|
+
/* 1 ── (re)set bounding-box ────────────────────────────────────────────── */
|
|
977
|
+
if (!this.setPageAnnoRect(page, pageCtx.pagePtr, annotPtr, annotation.rect)) {
|
|
978
|
+
this.pdfiumModule.FPDFPage_CloseAnnot(annotPtr);
|
|
979
|
+
pageCtx.release();
|
|
980
|
+
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, 'UpdatePageAnnotation', 'End', `${doc.id}-${page.index}`);
|
|
968
981
|
return models.PdfTaskHelper.reject({
|
|
969
982
|
code: models.PdfErrorCode.CantSetAnnotRect,
|
|
970
|
-
message: '
|
|
983
|
+
message: 'failed to move annotation',
|
|
971
984
|
});
|
|
972
985
|
}
|
|
986
|
+
/* 2 ── wipe previous payload and rebuild fresh one ─────────────────────── */
|
|
987
|
+
let ok = false;
|
|
973
988
|
switch (annotation.type) {
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
points: inkStroke.points.map((point) => {
|
|
988
|
-
return {
|
|
989
|
-
x: rect.origin.x +
|
|
990
|
-
(point.x - annotation.rect.origin.x) * transformation.scale.width,
|
|
991
|
-
y: rect.origin.y +
|
|
992
|
-
(point.y - annotation.rect.origin.y) * transformation.scale.height,
|
|
993
|
-
};
|
|
994
|
-
}),
|
|
995
|
-
};
|
|
996
|
-
});
|
|
997
|
-
if (!this.addInkStroke(page, pageCtx.pagePtr, annotationPtr, inkList)) {
|
|
998
|
-
this.pdfiumModule.FPDFPage_CloseAnnot(annotationPtr);
|
|
999
|
-
pageCtx.release();
|
|
1000
|
-
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, `TransformPageAnnotation`, 'End', `${doc.id}-${page.index}`);
|
|
1001
|
-
return models.PdfTaskHelper.reject({
|
|
1002
|
-
code: models.PdfErrorCode.CantAddInkStoke,
|
|
1003
|
-
message: 'can not add stroke to the ink list of annotation',
|
|
1004
|
-
});
|
|
1005
|
-
}
|
|
989
|
+
/* ── Ink ─────────────────────────────────────────────────────────────── */
|
|
990
|
+
case models.PdfAnnotationSubtype.INK: {
|
|
991
|
+
/* clear every existing stroke first */
|
|
992
|
+
if (!this.pdfiumModule.FPDFAnnot_RemoveInkList(annotPtr))
|
|
993
|
+
break;
|
|
994
|
+
ok = this.addInkStroke(page, pageCtx.pagePtr, annotPtr, annotation);
|
|
995
|
+
break;
|
|
996
|
+
}
|
|
997
|
+
/* ── Stamp ───────────────────────────────────────────────────────────── */
|
|
998
|
+
case models.PdfAnnotationSubtype.STAMP: {
|
|
999
|
+
/* drop every page-object inside the annot */
|
|
1000
|
+
for (let i = this.pdfiumModule.FPDFAnnot_GetObjectCount(annotPtr) - 1; i >= 0; i--) {
|
|
1001
|
+
this.pdfiumModule.FPDFAnnot_RemoveObject(annotPtr, i);
|
|
1006
1002
|
}
|
|
1003
|
+
ok = this.addStampContent(ctx.docPtr, page, pageCtx.pagePtr, annotPtr, annotation.rect, annotation.contents);
|
|
1004
|
+
break;
|
|
1005
|
+
}
|
|
1006
|
+
/* ── Text-markup family ──────────────────────────────────────────────── */
|
|
1007
|
+
case models.PdfAnnotationSubtype.HIGHLIGHT:
|
|
1008
|
+
case models.PdfAnnotationSubtype.UNDERLINE:
|
|
1009
|
+
case models.PdfAnnotationSubtype.STRIKEOUT:
|
|
1010
|
+
case models.PdfAnnotationSubtype.SQUIGGLY: {
|
|
1011
|
+
/* replace quad-points / colour / strings in one go */
|
|
1012
|
+
ok = this.addTextMarkupContent(page, pageCtx.pagePtr, annotPtr, annotation);
|
|
1007
1013
|
break;
|
|
1014
|
+
}
|
|
1015
|
+
/* ── Unsupported edits – fall through to error ───────────────────────── */
|
|
1016
|
+
default:
|
|
1017
|
+
ok = false;
|
|
1008
1018
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1019
|
+
/* 3 ── regenerate appearance if payload was changed ───────────────────── */
|
|
1020
|
+
if (ok) {
|
|
1021
|
+
this.pdfiumModule.EPDFAnnot_GenerateAppearance(annotPtr);
|
|
1022
|
+
this.pdfiumModule.FPDFPage_GenerateContent(pageCtx.pagePtr);
|
|
1023
|
+
}
|
|
1024
|
+
/* 4 ── tidy-up native handles ──────────────────────────────────────────── */
|
|
1025
|
+
this.pdfiumModule.FPDFPage_CloseAnnot(annotPtr);
|
|
1011
1026
|
pageCtx.release();
|
|
1012
|
-
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2,
|
|
1013
|
-
return
|
|
1027
|
+
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, 'UpdatePageAnnotation', 'End', `${doc.id}-${page.index}`);
|
|
1028
|
+
return ok
|
|
1029
|
+
? models.PdfTaskHelper.resolve(true)
|
|
1030
|
+
: models.PdfTaskHelper.reject({
|
|
1031
|
+
code: models.PdfErrorCode.CantSetAnnotContent,
|
|
1032
|
+
message: 'failed to update annotation',
|
|
1033
|
+
});
|
|
1014
1034
|
}
|
|
1015
1035
|
/**
|
|
1016
1036
|
* {@inheritDoc @embedpdf/models!PdfEngine.removePageAnnotation}
|
|
@@ -1632,21 +1652,60 @@ class PdfiumEngine {
|
|
|
1632
1652
|
*
|
|
1633
1653
|
* @private
|
|
1634
1654
|
*/
|
|
1635
|
-
addInkStroke(page, pagePtr, annotationPtr,
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
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;
|
|
1676
|
+
}
|
|
1677
|
+
return true;
|
|
1678
|
+
}
|
|
1679
|
+
/**
|
|
1680
|
+
* Add highlight content to annotation
|
|
1681
|
+
* @param page - page info
|
|
1682
|
+
* @param annotationPtr - pointer to highlight annotation
|
|
1683
|
+
* @param annotation - highlight annotation
|
|
1684
|
+
* @returns whether highlight content is added to annotation
|
|
1685
|
+
*
|
|
1686
|
+
* @private
|
|
1687
|
+
*/
|
|
1688
|
+
addTextMarkupContent(page, pagePtr, annotationPtr, annotation) {
|
|
1689
|
+
if (!this.setPageAnnoRect(page, pagePtr, annotationPtr, annotation.rect)) {
|
|
1690
|
+
return false;
|
|
1691
|
+
}
|
|
1692
|
+
if (!this.syncQuadPointsAnno(page, annotationPtr, annotation.segmentRects)) {
|
|
1693
|
+
return false;
|
|
1694
|
+
}
|
|
1695
|
+
if (!this.setAnnotString(annotationPtr, 'Contents', annotation.contents ?? '')) {
|
|
1696
|
+
return false;
|
|
1697
|
+
}
|
|
1698
|
+
if (!this.setAnnotString(annotationPtr, 'T', annotation.author || '')) {
|
|
1699
|
+
return false;
|
|
1700
|
+
}
|
|
1701
|
+
if (!this.setAnnotString(annotationPtr, 'M', models.dateToPdfDate(annotation.modified))) {
|
|
1702
|
+
return false;
|
|
1703
|
+
}
|
|
1704
|
+
if (!this.setAnnotationColor(annotationPtr, {
|
|
1705
|
+
color: annotation.color ?? '#FFFF00',
|
|
1706
|
+
opacity: annotation.opacity ?? 1,
|
|
1707
|
+
}, models.PdfAnnotationColorType.Color)) {
|
|
1708
|
+
return false;
|
|
1650
1709
|
}
|
|
1651
1710
|
return true;
|
|
1652
1711
|
}
|
|
@@ -2272,8 +2331,6 @@ class PdfiumEngine {
|
|
|
2272
2331
|
annotation = this.readPdfCaretAnno(page, pageCtx.pagePtr, annotationPtr, index);
|
|
2273
2332
|
}
|
|
2274
2333
|
break;
|
|
2275
|
-
case models.PdfAnnotationSubtype.POPUP:
|
|
2276
|
-
break;
|
|
2277
2334
|
default:
|
|
2278
2335
|
{
|
|
2279
2336
|
annotation = this.readPdfAnno(page, pageCtx.pagePtr, subType, annotationPtr, index);
|
|
@@ -2294,14 +2351,13 @@ class PdfiumEngine {
|
|
|
2294
2351
|
*
|
|
2295
2352
|
* @private
|
|
2296
2353
|
*/
|
|
2297
|
-
readAnnotationColor(annotationPtr) {
|
|
2354
|
+
readAnnotationColor(annotationPtr, colorType = models.PdfAnnotationColorType.Color) {
|
|
2298
2355
|
const rPtr = this.malloc(4);
|
|
2299
2356
|
const gPtr = this.malloc(4);
|
|
2300
2357
|
const bPtr = this.malloc(4);
|
|
2301
2358
|
const aPtr = this.malloc(4);
|
|
2302
2359
|
// colourType 0 = "colour" (stroke/fill); other types are interior/border
|
|
2303
|
-
const ok = this.pdfiumModule.
|
|
2304
|
-
/* colorType = */ 0, rPtr, gPtr, bPtr, aPtr);
|
|
2360
|
+
const ok = this.pdfiumModule.EPDFAnnot_GetColor(annotationPtr, colorType, rPtr, gPtr, bPtr, aPtr);
|
|
2305
2361
|
let colour;
|
|
2306
2362
|
if (ok) {
|
|
2307
2363
|
colour = {
|
|
@@ -2319,116 +2375,144 @@ class PdfiumEngine {
|
|
|
2319
2375
|
}
|
|
2320
2376
|
/* --------------------------------------------------------------------------- */
|
|
2321
2377
|
/**
|
|
2322
|
-
*
|
|
2323
|
-
*
|
|
2378
|
+
* Resolve the visible fill colour for **Highlight / Underline / StrikeOut /
|
|
2379
|
+
* Squiggly** markup annotations.
|
|
2324
2380
|
*
|
|
2325
|
-
*
|
|
2326
|
-
*
|
|
2381
|
+
* Resolution order (first non-`undefined` wins):
|
|
2382
|
+
* 1. `/C` dictionary entry – fast, present in Acrobat / Office PDFs
|
|
2383
|
+
* 2. Appearance-stream objects – drills into paths & nested forms
|
|
2384
|
+
* 3. Hard-coded fallback (Acrobat-style opaque yellow)
|
|
2327
2385
|
*
|
|
2328
|
-
* @param
|
|
2329
|
-
* @
|
|
2386
|
+
* @param annotationPtr - pointer to an `FPDF_ANNOTATION`
|
|
2387
|
+
* @param fallback - colour to use when the PDF stores no tint at all
|
|
2388
|
+
* @returns WebAlphaColor with hex color and opacity (0-1)
|
|
2330
2389
|
*
|
|
2331
2390
|
* @private
|
|
2332
2391
|
*/
|
|
2333
|
-
|
|
2334
|
-
const
|
|
2335
|
-
|
|
2336
|
-
const strokeOk = !fillOk && // try stroke only if fill failed
|
|
2337
|
-
this.pdfiumModule.FPDFPageObj_GetStrokeColor(pathPtr, r, g, b, a);
|
|
2338
|
-
const ok = fillOk || strokeOk;
|
|
2339
|
-
let c;
|
|
2340
|
-
if (ok) {
|
|
2341
|
-
c = {
|
|
2342
|
-
red: this.pdfiumModule.pdfium.getValue(r, 'i32') & 0xff,
|
|
2343
|
-
green: this.pdfiumModule.pdfium.getValue(g, 'i32') & 0xff,
|
|
2344
|
-
blue: this.pdfiumModule.pdfium.getValue(b, 'i32') & 0xff,
|
|
2345
|
-
alpha: this.pdfiumModule.pdfium.getValue(a, 'i32') & 0xff,
|
|
2346
|
-
};
|
|
2347
|
-
}
|
|
2348
|
-
this.free(r);
|
|
2349
|
-
this.free(g);
|
|
2350
|
-
this.free(b);
|
|
2351
|
-
this.free(a);
|
|
2352
|
-
return c;
|
|
2392
|
+
resolveAnnotationColor(annotationPtr, colorType = models.PdfAnnotationColorType.Color, fallback = { red: 255, green: 245, blue: 155, alpha: 255 }) {
|
|
2393
|
+
const pdfColor = this.readAnnotationColor(annotationPtr, colorType) ?? fallback;
|
|
2394
|
+
return models.pdfAlphaColorToWebAlphaColor(pdfColor);
|
|
2353
2395
|
}
|
|
2354
|
-
/* --------------------------------------------------------------------------- */
|
|
2355
2396
|
/**
|
|
2356
|
-
*
|
|
2357
|
-
* a colour can be extracted.
|
|
2358
|
-
*
|
|
2359
|
-
* Acrobat often wraps its highlight rectangle in a Form XObject referenced by
|
|
2360
|
-
* the "Do" operator, so this function drills down unlimited depth.
|
|
2397
|
+
* Set the fill/stroke colour for a **Highlight / Underline / StrikeOut / Squiggly** markup annotation.
|
|
2361
2398
|
*
|
|
2362
|
-
* @param
|
|
2363
|
-
* @
|
|
2364
|
-
*
|
|
2399
|
+
* @param annotationPtr - pointer to the annotation whose colour is being set
|
|
2400
|
+
* @param webAlphaColor - WebAlphaColor with hex color and opacity (0-1)
|
|
2401
|
+
* @param shouldClearAP - whether to clear the /AP entry
|
|
2402
|
+
* @param which - which colour to set (0 = fill, 1 = stroke)
|
|
2403
|
+
* @returns `true` if the operation was successful
|
|
2365
2404
|
*
|
|
2366
2405
|
* @private
|
|
2367
2406
|
*/
|
|
2368
|
-
|
|
2369
|
-
const
|
|
2370
|
-
|
|
2371
|
-
return this.getColorFromPath(objPtr);
|
|
2372
|
-
if (type !== models.PdfPageObjectType.FORM)
|
|
2373
|
-
return undefined;
|
|
2374
|
-
const cnt = this.pdfiumModule.FPDFFormObj_CountObjects(objPtr);
|
|
2375
|
-
for (let i = 0; i < cnt; i++) {
|
|
2376
|
-
const child = this.pdfiumModule.FPDFFormObj_GetObject(objPtr, i);
|
|
2377
|
-
if (!child)
|
|
2378
|
-
continue;
|
|
2379
|
-
const c = this.walkPageObjTree(child);
|
|
2380
|
-
if (c)
|
|
2381
|
-
return c;
|
|
2382
|
-
}
|
|
2383
|
-
return undefined;
|
|
2407
|
+
setAnnotationColor(annotationPtr, webAlphaColor, colorType = models.PdfAnnotationColorType.Color) {
|
|
2408
|
+
const pdfAlphaColor = models.webAlphaColorToPdfAlphaColor(webAlphaColor);
|
|
2409
|
+
return this.pdfiumModule.EPDFAnnot_SetColor(annotationPtr, colorType, pdfAlphaColor.red & 0xff, pdfAlphaColor.green & 0xff, pdfAlphaColor.blue & 0xff, (pdfAlphaColor.alpha ?? 255) & 0xff);
|
|
2384
2410
|
}
|
|
2385
|
-
/* --------------------------------------------------------------------------- */
|
|
2386
2411
|
/**
|
|
2387
|
-
*
|
|
2388
|
-
*
|
|
2412
|
+
* Border‐style + width helper
|
|
2413
|
+
*
|
|
2414
|
+
* Tries the new PDFium helper `EPDFAnnot_GetBorderStyle()` (patch series
|
|
2415
|
+
* 9 July 2025).
|
|
2389
2416
|
*
|
|
2390
|
-
*
|
|
2391
|
-
*
|
|
2392
|
-
*
|
|
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
|
|
2393
2440
|
*
|
|
2394
|
-
*
|
|
2395
|
-
* @returns RGBA tuple or `undefined` when no colour can be resolved from AP
|
|
2441
|
+
* Calls the new PDFium function `EPDFAnnot_GetBorderEffect()` (July 2025).
|
|
2396
2442
|
*
|
|
2397
|
-
* @
|
|
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)
|
|
2398
2448
|
*/
|
|
2399
|
-
|
|
2400
|
-
const
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
const c = this.walkPageObjTree(obj);
|
|
2406
|
-
if (c)
|
|
2407
|
-
return c;
|
|
2408
|
-
}
|
|
2409
|
-
return undefined;
|
|
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 };
|
|
2410
2455
|
}
|
|
2411
|
-
/* --------------------------------------------------------------------------- */
|
|
2412
2456
|
/**
|
|
2413
|
-
*
|
|
2414
|
-
* Squiggly** markup annotations.
|
|
2457
|
+
* Rectangle-differences helper ( /RD array on Square / Circle annots )
|
|
2415
2458
|
*
|
|
2416
|
-
*
|
|
2417
|
-
* 1. `/C` dictionary entry – fast, present in Acrobat / Office PDFs
|
|
2418
|
-
* 2. Appearance-stream objects – drills into paths & nested forms
|
|
2419
|
-
* 3. Hard-coded fallback (Acrobat-style opaque yellow)
|
|
2459
|
+
* Calls `EPDFAnnot_GetRectangleDifferences()` introduced in July 2025.
|
|
2420
2460
|
*
|
|
2421
|
-
* @param
|
|
2422
|
-
* @
|
|
2423
|
-
*
|
|
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 )
|
|
2424
2487
|
*
|
|
2425
|
-
*
|
|
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)
|
|
2426
2497
|
*/
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2498
|
+
getBorderDashPattern(annotationPtr) {
|
|
2499
|
+
const count = this.pdfiumModule.EPDFAnnot_GetBorderDashPatternCount(annotationPtr);
|
|
2500
|
+
if (count === 0) {
|
|
2501
|
+
return { ok: false, pattern: [] };
|
|
2502
|
+
}
|
|
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 };
|
|
2432
2516
|
}
|
|
2433
2517
|
/**
|
|
2434
2518
|
* Read `/QuadPoints` from any annotation and convert each quadrilateral to
|
|
@@ -2441,11 +2525,11 @@ class PdfiumEngine {
|
|
|
2441
2525
|
*
|
|
2442
2526
|
* @param page - logical page info object (`PdfPageObject`)
|
|
2443
2527
|
* @param annotationPtr - pointer to the annotation whose quads are needed
|
|
2444
|
-
* @returns Array of `
|
|
2528
|
+
* @returns Array of `Rect` objects (`[]` if the annotation has no quads)
|
|
2445
2529
|
*
|
|
2446
2530
|
* @private
|
|
2447
2531
|
*/
|
|
2448
|
-
|
|
2532
|
+
getQuadPointsAnno(page, annotationPtr) {
|
|
2449
2533
|
const quadCount = this.pdfiumModule.FPDFAnnot_CountAttachmentPoints(annotationPtr);
|
|
2450
2534
|
if (quadCount === 0)
|
|
2451
2535
|
return [];
|
|
@@ -2472,7 +2556,116 @@ class PdfiumEngine {
|
|
|
2472
2556
|
}
|
|
2473
2557
|
this.free(quadPtr);
|
|
2474
2558
|
}
|
|
2475
|
-
return quads;
|
|
2559
|
+
return quads.map(models.quadToRect);
|
|
2560
|
+
}
|
|
2561
|
+
/**
|
|
2562
|
+
* Set the quadrilaterals for a **Highlight / Underline / StrikeOut / Squiggly** markup annotation.
|
|
2563
|
+
*
|
|
2564
|
+
* @param page - logical page info object (`PdfPageObject`)
|
|
2565
|
+
* @param annotationPtr - pointer to the annotation whose quads are needed
|
|
2566
|
+
* @param rects - array of `Rect` objects (`[]` if the annotation has no quads)
|
|
2567
|
+
* @returns `true` if the operation was successful
|
|
2568
|
+
*
|
|
2569
|
+
* @private
|
|
2570
|
+
*/
|
|
2571
|
+
syncQuadPointsAnno(page, annotPtr, rects) {
|
|
2572
|
+
const FS_QUADPOINTSF_SIZE = 8 * 4; // eight floats, 32 bytes
|
|
2573
|
+
const pdf = this.pdfiumModule.pdfium;
|
|
2574
|
+
const count = this.pdfiumModule.FPDFAnnot_CountAttachmentPoints(annotPtr);
|
|
2575
|
+
const buf = this.malloc(FS_QUADPOINTSF_SIZE);
|
|
2576
|
+
/** write one quad into `buf` in annotation space */
|
|
2577
|
+
const writeQuad = (r) => {
|
|
2578
|
+
const q = models.rectToQuad(r); // TL, TR, BR, BL
|
|
2579
|
+
const p1 = this.convertDevicePointToPagePoint(page, q.p1);
|
|
2580
|
+
const p2 = this.convertDevicePointToPagePoint(page, q.p2);
|
|
2581
|
+
const p3 = this.convertDevicePointToPagePoint(page, q.p3); // BR
|
|
2582
|
+
const p4 = this.convertDevicePointToPagePoint(page, q.p4); // BL
|
|
2583
|
+
// PDF QuadPoints order: BL, BR, TL, TR (bottom-left, bottom-right, top-left, top-right)
|
|
2584
|
+
pdf.setValue(buf + 0, p1.x, 'float'); // BL (bottom-left)
|
|
2585
|
+
pdf.setValue(buf + 4, p1.y, 'float');
|
|
2586
|
+
pdf.setValue(buf + 8, p2.x, 'float'); // BR (bottom-right)
|
|
2587
|
+
pdf.setValue(buf + 12, p2.y, 'float');
|
|
2588
|
+
pdf.setValue(buf + 16, p4.x, 'float'); // TL (top-left)
|
|
2589
|
+
pdf.setValue(buf + 20, p4.y, 'float');
|
|
2590
|
+
pdf.setValue(buf + 24, p3.x, 'float'); // TR (top-right)
|
|
2591
|
+
pdf.setValue(buf + 28, p3.y, 'float');
|
|
2592
|
+
};
|
|
2593
|
+
/* ----------------------------------------------------------------------- */
|
|
2594
|
+
/* 1. overwrite the quads that already exist */
|
|
2595
|
+
const min = Math.min(count, rects.length);
|
|
2596
|
+
for (let i = 0; i < min; i++) {
|
|
2597
|
+
writeQuad(rects[i]);
|
|
2598
|
+
if (!this.pdfiumModule.FPDFAnnot_SetAttachmentPoints(annotPtr, i, buf)) {
|
|
2599
|
+
this.free(buf);
|
|
2600
|
+
return false;
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
/* 2. append new quads if rects.length > count */
|
|
2604
|
+
for (let i = count; i < rects.length; i++) {
|
|
2605
|
+
writeQuad(rects[i]);
|
|
2606
|
+
if (!this.pdfiumModule.FPDFAnnot_AppendAttachmentPoints(annotPtr, buf)) {
|
|
2607
|
+
this.free(buf);
|
|
2608
|
+
return false;
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
this.free(buf);
|
|
2612
|
+
return true;
|
|
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;
|
|
2476
2669
|
}
|
|
2477
2670
|
/**
|
|
2478
2671
|
* Read pdf text annotation
|
|
@@ -2485,30 +2678,23 @@ class PdfiumEngine {
|
|
|
2485
2678
|
* @private
|
|
2486
2679
|
*/
|
|
2487
2680
|
readPdfTextAnno(page, pagePtr, annotationPtr, index) {
|
|
2488
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2489
2681
|
const annoRect = this.readPageAnnoRect(annotationPtr);
|
|
2490
2682
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, annoRect);
|
|
2491
2683
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2492
2684
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2493
|
-
const modified =
|
|
2685
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
2494
2686
|
const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
|
|
2495
2687
|
const state = this.getAnnotString(annotationPtr, 'State');
|
|
2496
2688
|
const stateModel = this.getAnnotString(annotationPtr, 'StateModel');
|
|
2497
|
-
const
|
|
2689
|
+
const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
|
|
2498
2690
|
const inReplyToId = this.getInReplyToId(pagePtr, annotationPtr);
|
|
2499
|
-
const popup = !inReplyToId
|
|
2500
|
-
? this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index)
|
|
2501
|
-
: undefined;
|
|
2502
2691
|
return {
|
|
2503
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
2504
2692
|
pageIndex: page.index,
|
|
2505
2693
|
id: index,
|
|
2506
2694
|
type: models.PdfAnnotationSubtype.TEXT,
|
|
2507
2695
|
contents,
|
|
2508
|
-
|
|
2696
|
+
...webAlphaColor,
|
|
2509
2697
|
rect,
|
|
2510
|
-
popup,
|
|
2511
|
-
appearances,
|
|
2512
2698
|
inReplyToId,
|
|
2513
2699
|
author,
|
|
2514
2700
|
modified,
|
|
@@ -2527,16 +2713,13 @@ class PdfiumEngine {
|
|
|
2527
2713
|
* @private
|
|
2528
2714
|
*/
|
|
2529
2715
|
readPdfFreeTextAnno(page, pagePtr, annotationPtr, index) {
|
|
2530
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2531
2716
|
const annoRect = this.readPageAnnoRect(annotationPtr);
|
|
2532
2717
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, annoRect);
|
|
2533
2718
|
const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
|
|
2534
2719
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2535
2720
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2536
|
-
const modified =
|
|
2537
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2721
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
2538
2722
|
return {
|
|
2539
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
2540
2723
|
pageIndex: page.index,
|
|
2541
2724
|
id: index,
|
|
2542
2725
|
type: models.PdfAnnotationSubtype.FREETEXT,
|
|
@@ -2544,8 +2727,6 @@ class PdfiumEngine {
|
|
|
2544
2727
|
author,
|
|
2545
2728
|
modified,
|
|
2546
2729
|
rect,
|
|
2547
|
-
popup,
|
|
2548
|
-
appearances,
|
|
2549
2730
|
};
|
|
2550
2731
|
}
|
|
2551
2732
|
/**
|
|
@@ -2565,13 +2746,12 @@ class PdfiumEngine {
|
|
|
2565
2746
|
if (!linkPtr) {
|
|
2566
2747
|
return;
|
|
2567
2748
|
}
|
|
2568
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2569
2749
|
const annoRect = this.readPageAnnoRect(annotationPtr);
|
|
2570
2750
|
const { left, top, right, bottom } = annoRect;
|
|
2571
2751
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, annoRect);
|
|
2572
2752
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2573
2753
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2574
|
-
const modified =
|
|
2754
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
2575
2755
|
const utf16Length = this.pdfiumModule.FPDFText_GetBoundedText(textPagePtr, left, top, right, bottom, 0, 0);
|
|
2576
2756
|
const bytesCount = (utf16Length + 1) * 2; // include NIL
|
|
2577
2757
|
const textBufferPtr = this.malloc(bytesCount);
|
|
@@ -2583,17 +2763,13 @@ class PdfiumEngine {
|
|
|
2583
2763
|
}, () => {
|
|
2584
2764
|
return this.pdfiumModule.FPDFLink_GetDest(docPtr, linkPtr);
|
|
2585
2765
|
});
|
|
2586
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2587
2766
|
return {
|
|
2588
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
2589
2767
|
pageIndex: page.index,
|
|
2590
2768
|
id: index,
|
|
2591
2769
|
type: models.PdfAnnotationSubtype.LINK,
|
|
2592
2770
|
text,
|
|
2593
2771
|
target,
|
|
2594
2772
|
rect,
|
|
2595
|
-
popup,
|
|
2596
|
-
appearances,
|
|
2597
2773
|
author,
|
|
2598
2774
|
modified,
|
|
2599
2775
|
};
|
|
@@ -2610,23 +2786,18 @@ class PdfiumEngine {
|
|
|
2610
2786
|
* @private
|
|
2611
2787
|
*/
|
|
2612
2788
|
readPdfWidgetAnno(page, pagePtr, annotationPtr, formHandle, index) {
|
|
2613
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2614
2789
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2615
2790
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2616
2791
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2617
2792
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2618
|
-
const modified =
|
|
2619
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2793
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
2620
2794
|
const field = this.readPdfWidgetAnnoField(formHandle, annotationPtr);
|
|
2621
2795
|
return {
|
|
2622
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
2623
2796
|
pageIndex: page.index,
|
|
2624
2797
|
id: index,
|
|
2625
2798
|
type: models.PdfAnnotationSubtype.WIDGET,
|
|
2626
2799
|
rect,
|
|
2627
2800
|
field,
|
|
2628
|
-
popup,
|
|
2629
|
-
appearances,
|
|
2630
2801
|
author,
|
|
2631
2802
|
modified,
|
|
2632
2803
|
};
|
|
@@ -2642,21 +2813,16 @@ class PdfiumEngine {
|
|
|
2642
2813
|
* @private
|
|
2643
2814
|
*/
|
|
2644
2815
|
readPdfFileAttachmentAnno(page, pagePtr, annotationPtr, index) {
|
|
2645
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2646
2816
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2647
2817
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2648
2818
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2649
2819
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2650
|
-
const modified =
|
|
2651
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2820
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
2652
2821
|
return {
|
|
2653
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
2654
2822
|
pageIndex: page.index,
|
|
2655
2823
|
id: index,
|
|
2656
2824
|
type: models.PdfAnnotationSubtype.FILEATTACHMENT,
|
|
2657
2825
|
rect,
|
|
2658
|
-
popup,
|
|
2659
|
-
appearances,
|
|
2660
2826
|
author,
|
|
2661
2827
|
modified,
|
|
2662
2828
|
};
|
|
@@ -2672,44 +2838,22 @@ class PdfiumEngine {
|
|
|
2672
2838
|
* @private
|
|
2673
2839
|
*/
|
|
2674
2840
|
readPdfInkAnno(page, pagePtr, annotationPtr, index) {
|
|
2675
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2676
2841
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2677
2842
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2678
2843
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2679
2844
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2680
|
-
const modified =
|
|
2681
|
-
const
|
|
2682
|
-
const
|
|
2683
|
-
const
|
|
2684
|
-
for (let i = 0; i < count; i++) {
|
|
2685
|
-
const points = [];
|
|
2686
|
-
const pointsCount = this.pdfiumModule.FPDFAnnot_GetInkListPath(annotationPtr, i, 0, 0);
|
|
2687
|
-
if (pointsCount > 0) {
|
|
2688
|
-
const pointMemorySize = 8;
|
|
2689
|
-
const pointsPtr = this.malloc(pointsCount * pointMemorySize);
|
|
2690
|
-
this.pdfiumModule.FPDFAnnot_GetInkListPath(annotationPtr, i, pointsPtr, pointsCount);
|
|
2691
|
-
for (let j = 0; j < pointsCount; j++) {
|
|
2692
|
-
const pointX = this.pdfiumModule.pdfium.getValue(pointsPtr + j * 8, 'float');
|
|
2693
|
-
const pointY = this.pdfiumModule.pdfium.getValue(pointsPtr + j * 8 + 4, 'float');
|
|
2694
|
-
const { x, y } = this.convertPagePointToDevicePoint(page, {
|
|
2695
|
-
x: pointX,
|
|
2696
|
-
y: pointY,
|
|
2697
|
-
});
|
|
2698
|
-
points.push({ x, y });
|
|
2699
|
-
}
|
|
2700
|
-
this.free(pointsPtr);
|
|
2701
|
-
}
|
|
2702
|
-
inkList.push({ points });
|
|
2703
|
-
}
|
|
2845
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
2846
|
+
const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
|
|
2847
|
+
const { width: strokeWidth } = this.getBorderStyle(annotationPtr);
|
|
2848
|
+
const inkList = this.getInkList(page, annotationPtr);
|
|
2704
2849
|
return {
|
|
2705
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
2706
2850
|
pageIndex: page.index,
|
|
2707
2851
|
id: index,
|
|
2708
2852
|
type: models.PdfAnnotationSubtype.INK,
|
|
2853
|
+
...webAlphaColor,
|
|
2854
|
+
strokeWidth,
|
|
2709
2855
|
rect,
|
|
2710
|
-
popup,
|
|
2711
2856
|
inkList,
|
|
2712
|
-
appearances,
|
|
2713
2857
|
author,
|
|
2714
2858
|
modified,
|
|
2715
2859
|
};
|
|
@@ -2725,23 +2869,18 @@ class PdfiumEngine {
|
|
|
2725
2869
|
* @private
|
|
2726
2870
|
*/
|
|
2727
2871
|
readPdfPolygonAnno(page, pagePtr, annotationPtr, index) {
|
|
2728
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2729
2872
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2730
2873
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2731
2874
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2732
2875
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2733
|
-
const modified =
|
|
2734
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2876
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
2735
2877
|
const vertices = this.readPdfAnnoVertices(page, pagePtr, annotationPtr);
|
|
2736
2878
|
return {
|
|
2737
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
2738
2879
|
pageIndex: page.index,
|
|
2739
2880
|
id: index,
|
|
2740
2881
|
type: models.PdfAnnotationSubtype.POLYGON,
|
|
2741
2882
|
rect,
|
|
2742
|
-
popup,
|
|
2743
2883
|
vertices,
|
|
2744
|
-
appearances,
|
|
2745
2884
|
author,
|
|
2746
2885
|
modified,
|
|
2747
2886
|
};
|
|
@@ -2757,23 +2896,18 @@ class PdfiumEngine {
|
|
|
2757
2896
|
* @private
|
|
2758
2897
|
*/
|
|
2759
2898
|
readPdfPolylineAnno(page, pagePtr, annotationPtr, index) {
|
|
2760
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2761
2899
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2762
2900
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2763
2901
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2764
2902
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2765
|
-
const modified =
|
|
2766
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2903
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
2767
2904
|
const vertices = this.readPdfAnnoVertices(page, pagePtr, annotationPtr);
|
|
2768
2905
|
return {
|
|
2769
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
2770
2906
|
pageIndex: page.index,
|
|
2771
2907
|
id: index,
|
|
2772
2908
|
type: models.PdfAnnotationSubtype.POLYLINE,
|
|
2773
2909
|
rect,
|
|
2774
|
-
popup,
|
|
2775
2910
|
vertices,
|
|
2776
|
-
appearances,
|
|
2777
2911
|
author,
|
|
2778
2912
|
modified,
|
|
2779
2913
|
};
|
|
@@ -2789,13 +2923,11 @@ class PdfiumEngine {
|
|
|
2789
2923
|
* @private
|
|
2790
2924
|
*/
|
|
2791
2925
|
readPdfLineAnno(page, pagePtr, annotationPtr, index) {
|
|
2792
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2793
2926
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2794
2927
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2795
2928
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2796
2929
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2797
|
-
const modified =
|
|
2798
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2930
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
2799
2931
|
const startPointPtr = this.malloc(8);
|
|
2800
2932
|
const endPointPtr = this.malloc(8);
|
|
2801
2933
|
this.pdfiumModule.FPDFAnnot_GetLine(annotationPtr, startPointPtr, endPointPtr);
|
|
@@ -2814,15 +2946,12 @@ class PdfiumEngine {
|
|
|
2814
2946
|
this.free(startPointPtr);
|
|
2815
2947
|
this.free(endPointPtr);
|
|
2816
2948
|
return {
|
|
2817
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
2818
2949
|
pageIndex: page.index,
|
|
2819
2950
|
id: index,
|
|
2820
2951
|
type: models.PdfAnnotationSubtype.LINE,
|
|
2821
2952
|
rect,
|
|
2822
|
-
popup,
|
|
2823
2953
|
startPoint,
|
|
2824
2954
|
endPoint,
|
|
2825
|
-
appearances,
|
|
2826
2955
|
author,
|
|
2827
2956
|
modified,
|
|
2828
2957
|
};
|
|
@@ -2838,25 +2967,22 @@ class PdfiumEngine {
|
|
|
2838
2967
|
* @private
|
|
2839
2968
|
*/
|
|
2840
2969
|
readPdfHighlightAnno(page, pagePtr, annotationPtr, index) {
|
|
2841
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2842
2970
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2843
2971
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2844
|
-
const
|
|
2845
|
-
const
|
|
2846
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2972
|
+
const segmentRects = this.getQuadPointsAnno(page, annotationPtr);
|
|
2973
|
+
const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
|
|
2847
2974
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2848
2975
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2849
|
-
const modified =
|
|
2976
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
2977
|
+
const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
|
|
2850
2978
|
return {
|
|
2851
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
2852
2979
|
pageIndex: page.index,
|
|
2853
2980
|
id: index,
|
|
2854
2981
|
type: models.PdfAnnotationSubtype.HIGHLIGHT,
|
|
2855
2982
|
rect,
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
color,
|
|
2983
|
+
contents,
|
|
2984
|
+
segmentRects,
|
|
2985
|
+
...webAlphaColor,
|
|
2860
2986
|
author,
|
|
2861
2987
|
modified,
|
|
2862
2988
|
};
|
|
@@ -2872,21 +2998,22 @@ class PdfiumEngine {
|
|
|
2872
2998
|
* @private
|
|
2873
2999
|
*/
|
|
2874
3000
|
readPdfUnderlineAnno(page, pagePtr, annotationPtr, index) {
|
|
2875
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2876
3001
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2877
3002
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2878
3003
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2879
3004
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2880
|
-
const modified =
|
|
2881
|
-
const
|
|
3005
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
3006
|
+
const segmentRects = this.getQuadPointsAnno(page, annotationPtr);
|
|
3007
|
+
const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
|
|
3008
|
+
const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
|
|
2882
3009
|
return {
|
|
2883
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
2884
3010
|
pageIndex: page.index,
|
|
2885
3011
|
id: index,
|
|
2886
3012
|
type: models.PdfAnnotationSubtype.UNDERLINE,
|
|
2887
3013
|
rect,
|
|
2888
|
-
|
|
2889
|
-
|
|
3014
|
+
contents,
|
|
3015
|
+
segmentRects,
|
|
3016
|
+
...webAlphaColor,
|
|
2890
3017
|
author,
|
|
2891
3018
|
modified,
|
|
2892
3019
|
};
|
|
@@ -2902,21 +3029,22 @@ class PdfiumEngine {
|
|
|
2902
3029
|
* @private
|
|
2903
3030
|
*/
|
|
2904
3031
|
readPdfStrikeOutAnno(page, pagePtr, annotationPtr, index) {
|
|
2905
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2906
3032
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2907
3033
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2908
3034
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2909
3035
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2910
|
-
const modified =
|
|
2911
|
-
const
|
|
3036
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
3037
|
+
const segmentRects = this.getQuadPointsAnno(page, annotationPtr);
|
|
3038
|
+
const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
|
|
3039
|
+
const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
|
|
2912
3040
|
return {
|
|
2913
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
2914
3041
|
pageIndex: page.index,
|
|
2915
3042
|
id: index,
|
|
2916
3043
|
type: models.PdfAnnotationSubtype.STRIKEOUT,
|
|
2917
3044
|
rect,
|
|
2918
|
-
|
|
2919
|
-
|
|
3045
|
+
contents,
|
|
3046
|
+
segmentRects,
|
|
3047
|
+
...webAlphaColor,
|
|
2920
3048
|
author,
|
|
2921
3049
|
modified,
|
|
2922
3050
|
};
|
|
@@ -2932,21 +3060,22 @@ class PdfiumEngine {
|
|
|
2932
3060
|
* @private
|
|
2933
3061
|
*/
|
|
2934
3062
|
readPdfSquigglyAnno(page, pagePtr, annotationPtr, index) {
|
|
2935
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2936
3063
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2937
3064
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2938
3065
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2939
3066
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2940
|
-
const modified =
|
|
2941
|
-
const
|
|
3067
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
3068
|
+
const segmentRects = this.getQuadPointsAnno(page, annotationPtr);
|
|
3069
|
+
const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
|
|
3070
|
+
const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
|
|
2942
3071
|
return {
|
|
2943
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
2944
3072
|
pageIndex: page.index,
|
|
2945
3073
|
id: index,
|
|
2946
3074
|
type: models.PdfAnnotationSubtype.SQUIGGLY,
|
|
2947
3075
|
rect,
|
|
2948
|
-
|
|
2949
|
-
|
|
3076
|
+
contents,
|
|
3077
|
+
segmentRects,
|
|
3078
|
+
...webAlphaColor,
|
|
2950
3079
|
author,
|
|
2951
3080
|
modified,
|
|
2952
3081
|
};
|
|
@@ -2962,21 +3091,16 @@ class PdfiumEngine {
|
|
|
2962
3091
|
* @private
|
|
2963
3092
|
*/
|
|
2964
3093
|
readPdfCaretAnno(page, pagePtr, annotationPtr, index) {
|
|
2965
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2966
3094
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2967
3095
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2968
3096
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2969
3097
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2970
|
-
const modified =
|
|
2971
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
3098
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
2972
3099
|
return {
|
|
2973
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
2974
3100
|
pageIndex: page.index,
|
|
2975
3101
|
id: index,
|
|
2976
3102
|
type: models.PdfAnnotationSubtype.CARET,
|
|
2977
3103
|
rect,
|
|
2978
|
-
popup,
|
|
2979
|
-
appearances,
|
|
2980
3104
|
author,
|
|
2981
3105
|
modified,
|
|
2982
3106
|
};
|
|
@@ -2993,13 +3117,11 @@ class PdfiumEngine {
|
|
|
2993
3117
|
* @private
|
|
2994
3118
|
*/
|
|
2995
3119
|
readPdfStampAnno(docPtr, page, pagePtr, annotationPtr, index) {
|
|
2996
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2997
3120
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2998
3121
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2999
3122
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
3000
3123
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
3001
|
-
const modified =
|
|
3002
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
3124
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
3003
3125
|
const contents = [];
|
|
3004
3126
|
const objectCount = this.pdfiumModule.FPDFAnnot_GetObjectCount(annotationPtr);
|
|
3005
3127
|
for (let i = 0; i < objectCount; i++) {
|
|
@@ -3010,14 +3132,11 @@ class PdfiumEngine {
|
|
|
3010
3132
|
}
|
|
3011
3133
|
}
|
|
3012
3134
|
return {
|
|
3013
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
3014
3135
|
pageIndex: page.index,
|
|
3015
3136
|
id: index,
|
|
3016
3137
|
type: models.PdfAnnotationSubtype.STAMP,
|
|
3017
3138
|
rect,
|
|
3018
|
-
popup,
|
|
3019
3139
|
contents,
|
|
3020
|
-
appearances,
|
|
3021
3140
|
author,
|
|
3022
3141
|
modified,
|
|
3023
3142
|
};
|
|
@@ -3186,6 +3305,39 @@ class PdfiumEngine {
|
|
|
3186
3305
|
this.free(matrixPtr);
|
|
3187
3306
|
return { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 };
|
|
3188
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
|
+
}
|
|
3189
3341
|
/**
|
|
3190
3342
|
* Read circle annotation
|
|
3191
3343
|
* @param page - pdf page infor
|
|
@@ -3197,23 +3349,51 @@ class PdfiumEngine {
|
|
|
3197
3349
|
* @private
|
|
3198
3350
|
*/
|
|
3199
3351
|
readPdfCircleAnno(page, pagePtr, annotationPtr, index) {
|
|
3200
|
-
const
|
|
3352
|
+
const flags = this.getAnnotationFlags(annotationPtr);
|
|
3201
3353
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
3202
3354
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
3203
3355
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
3204
3356
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
3205
|
-
const modified =
|
|
3206
|
-
const
|
|
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
|
+
}
|
|
3207
3381
|
return {
|
|
3208
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
3209
3382
|
pageIndex: page.index,
|
|
3210
3383
|
id: index,
|
|
3211
3384
|
type: models.PdfAnnotationSubtype.CIRCLE,
|
|
3385
|
+
flags,
|
|
3386
|
+
color,
|
|
3387
|
+
opacity,
|
|
3388
|
+
strokeWidth,
|
|
3389
|
+
strokeColor,
|
|
3390
|
+
strokeStyle,
|
|
3212
3391
|
rect,
|
|
3213
|
-
popup,
|
|
3214
|
-
appearances,
|
|
3215
3392
|
author,
|
|
3216
3393
|
modified,
|
|
3394
|
+
...(cloudyBorderIntensity !== undefined && { cloudyBorderIntensity }),
|
|
3395
|
+
...(cloudyBorderInset !== undefined && { cloudyBorderInset }),
|
|
3396
|
+
...(strokeDashArray !== undefined && { strokeDashArray }),
|
|
3217
3397
|
};
|
|
3218
3398
|
}
|
|
3219
3399
|
/**
|
|
@@ -3227,23 +3407,51 @@ class PdfiumEngine {
|
|
|
3227
3407
|
* @private
|
|
3228
3408
|
*/
|
|
3229
3409
|
readPdfSquareAnno(page, pagePtr, annotationPtr, index) {
|
|
3230
|
-
const
|
|
3410
|
+
const flags = this.getAnnotationFlags(annotationPtr);
|
|
3231
3411
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
3232
3412
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
3233
3413
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
3234
3414
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
3235
|
-
const modified =
|
|
3236
|
-
const
|
|
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
|
+
}
|
|
3237
3439
|
return {
|
|
3238
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
3239
3440
|
pageIndex: page.index,
|
|
3240
3441
|
id: index,
|
|
3241
3442
|
type: models.PdfAnnotationSubtype.SQUARE,
|
|
3443
|
+
flags,
|
|
3444
|
+
color,
|
|
3445
|
+
opacity,
|
|
3446
|
+
strokeColor,
|
|
3447
|
+
strokeWidth,
|
|
3448
|
+
strokeStyle,
|
|
3242
3449
|
rect,
|
|
3243
|
-
popup,
|
|
3244
|
-
appearances,
|
|
3245
3450
|
author,
|
|
3246
3451
|
modified,
|
|
3452
|
+
...(cloudyBorderIntensity !== undefined && { cloudyBorderIntensity }),
|
|
3453
|
+
...(cloudyBorderInset !== undefined && { cloudyBorderInset }),
|
|
3454
|
+
...(strokeDashArray !== undefined && { strokeDashArray }),
|
|
3247
3455
|
};
|
|
3248
3456
|
}
|
|
3249
3457
|
/**
|
|
@@ -3258,21 +3466,16 @@ class PdfiumEngine {
|
|
|
3258
3466
|
* @private
|
|
3259
3467
|
*/
|
|
3260
3468
|
readPdfAnno(page, pagePtr, type, annotationPtr, index) {
|
|
3261
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
3262
3469
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
3263
3470
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
3264
3471
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
3265
3472
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
3266
|
-
const modified =
|
|
3267
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
3473
|
+
const modified = models.pdfDateToDate(modifiedRaw);
|
|
3268
3474
|
return {
|
|
3269
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
3270
3475
|
pageIndex: page.index,
|
|
3271
3476
|
id: index,
|
|
3272
3477
|
type,
|
|
3273
3478
|
rect,
|
|
3274
|
-
popup,
|
|
3275
|
-
appearances,
|
|
3276
3479
|
author,
|
|
3277
3480
|
modified,
|
|
3278
3481
|
};
|
|
@@ -3294,25 +3497,6 @@ class PdfiumEngine {
|
|
|
3294
3497
|
const idx = this.pdfiumModule.FPDFPage_GetAnnotIndex(pagePtr, parentPtr);
|
|
3295
3498
|
return idx >= 0 ? idx : undefined;
|
|
3296
3499
|
}
|
|
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
3500
|
/**
|
|
3317
3501
|
* Fetch a string value (`/T`, `/M`, `/State`, …) from an annotation.
|
|
3318
3502
|
*
|
|
@@ -3332,41 +3516,19 @@ class PdfiumEngine {
|
|
|
3332
3516
|
return value || undefined;
|
|
3333
3517
|
}
|
|
3334
3518
|
/**
|
|
3335
|
-
*
|
|
3336
|
-
*
|
|
3337
|
-
* @
|
|
3338
|
-
* @param annotationPtr - pointer to pdf annotation
|
|
3339
|
-
* @param index - index of annotation in the pdf page
|
|
3340
|
-
* @returns pdf popup linked to annotation
|
|
3519
|
+
* Set a string value (`/T`, `/M`, `/State`, …) to an annotation.
|
|
3520
|
+
*
|
|
3521
|
+
* @returns `true` if the operation was successful
|
|
3341
3522
|
*
|
|
3342
3523
|
* @private
|
|
3343
3524
|
*/
|
|
3344
|
-
|
|
3345
|
-
const
|
|
3346
|
-
const
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
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
|
-
};
|
|
3525
|
+
setAnnotString(annotationPtr, key, value) {
|
|
3526
|
+
const bytes = 2 * (value.length + 1);
|
|
3527
|
+
const ptr = this.malloc(bytes);
|
|
3528
|
+
this.pdfiumModule.pdfium.stringToUTF16(value, ptr, bytes);
|
|
3529
|
+
const ok = this.pdfiumModule.FPDFAnnot_SetStringValue(annotationPtr, key, ptr);
|
|
3530
|
+
this.free(ptr);
|
|
3531
|
+
return ok;
|
|
3370
3532
|
}
|
|
3371
3533
|
/**
|
|
3372
3534
|
* Read vertices of pdf annotation
|
|
@@ -3475,6 +3637,81 @@ class PdfiumEngine {
|
|
|
3475
3637
|
options,
|
|
3476
3638
|
};
|
|
3477
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
|
+
}
|
|
3478
3715
|
/**
|
|
3479
3716
|
* render rectangle of pdf page to image
|
|
3480
3717
|
* @param docPtr - pointer to pdf document object
|
|
@@ -3807,6 +4044,64 @@ class PdfiumEngine {
|
|
|
3807
4044
|
this.free(bufferPtr);
|
|
3808
4045
|
return ap;
|
|
3809
4046
|
}
|
|
4047
|
+
/**
|
|
4048
|
+
* Change the visible colour (and opacity) of an existing annotation.
|
|
4049
|
+
*
|
|
4050
|
+
* For markup annotations (highlight / underline / strikeout / squiggly) we
|
|
4051
|
+
* first clear the AP dictionary entry, otherwise the stored appearance stream
|
|
4052
|
+
* will override the new tint. For all other sub-types we keep the existing
|
|
4053
|
+
* AP so custom artwork isn't lost.
|
|
4054
|
+
*
|
|
4055
|
+
* @param doc logical document object
|
|
4056
|
+
* @param page logical page object
|
|
4057
|
+
* @param annotation the annotation we want to recolour
|
|
4058
|
+
* @param colour RGBA tuple (0-255 per channel)
|
|
4059
|
+
* @param which 0 = stroke/fill colour (PDFium's "colourType" param)
|
|
4060
|
+
*
|
|
4061
|
+
* @returns `true` when the operation succeeded
|
|
4062
|
+
*/
|
|
4063
|
+
updateAnnotationColor(doc, page, annotation, color, which = 0) {
|
|
4064
|
+
this.logger.debug(LOG_SOURCE$2, LOG_CATEGORY$2, 'setAnnotationColor', doc, page, annotation, color, which);
|
|
4065
|
+
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, 'setAnnotationColor', 'Begin', doc.id);
|
|
4066
|
+
const task = models.PdfTaskHelper.create();
|
|
4067
|
+
try {
|
|
4068
|
+
/* 1 ── sanity & native handles ────────────────────────────────────────── */
|
|
4069
|
+
const ctx = this.cache.getContext(doc.id);
|
|
4070
|
+
if (!ctx) {
|
|
4071
|
+
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, 'setAnnotationColor', 'End', doc.id);
|
|
4072
|
+
this.logger.warn(LOG_SOURCE$2, LOG_CATEGORY$2, 'setAnnotationColor: doc closed');
|
|
4073
|
+
task.resolve(false);
|
|
4074
|
+
return task;
|
|
4075
|
+
}
|
|
4076
|
+
const pageCtx = ctx.acquirePage(page.index);
|
|
4077
|
+
const annotPtr = this.pdfiumModule.FPDFPage_GetAnnot(pageCtx.pagePtr, annotation.id);
|
|
4078
|
+
if (!annotPtr) {
|
|
4079
|
+
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, 'setAnnotationColor', 'End', doc.id);
|
|
4080
|
+
this.logger.warn(LOG_SOURCE$2, LOG_CATEGORY$2, 'setAnnotationColor: annot not found');
|
|
4081
|
+
pageCtx.release();
|
|
4082
|
+
task.resolve(false);
|
|
4083
|
+
return task;
|
|
4084
|
+
}
|
|
4085
|
+
const ok = this.setAnnotationColor(annotPtr, color, which);
|
|
4086
|
+
/* 4 ── regenerate appearance & clean-up ───────────────────────────────── */
|
|
4087
|
+
if (ok) {
|
|
4088
|
+
this.pdfiumModule.FPDFPage_GenerateContent(pageCtx.pagePtr);
|
|
4089
|
+
}
|
|
4090
|
+
this.pdfiumModule.FPDFPage_CloseAnnot(annotPtr);
|
|
4091
|
+
pageCtx.release();
|
|
4092
|
+
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, 'setAnnotationColor', 'End', doc.id);
|
|
4093
|
+
task.resolve(!!ok);
|
|
4094
|
+
}
|
|
4095
|
+
catch (error) {
|
|
4096
|
+
this.logger.perf(LOG_SOURCE$2, LOG_CATEGORY$2, 'setAnnotationColor', 'End', doc.id);
|
|
4097
|
+
this.logger.error(LOG_SOURCE$2, LOG_CATEGORY$2, 'setAnnotationColor: error', error);
|
|
4098
|
+
task.reject({
|
|
4099
|
+
code: models.PdfErrorCode.Unknown,
|
|
4100
|
+
message: `Failed to set annotation color: ${error instanceof Error ? error.message : String(error)}`,
|
|
4101
|
+
});
|
|
4102
|
+
}
|
|
4103
|
+
return task;
|
|
4104
|
+
}
|
|
3810
4105
|
/**
|
|
3811
4106
|
* Set the rect of specified annotation
|
|
3812
4107
|
* @param page - page info that the annotation is belonged to
|
|
@@ -4142,7 +4437,7 @@ class EngineRunner {
|
|
|
4142
4437
|
type: 'reject',
|
|
4143
4438
|
reason: {
|
|
4144
4439
|
code: models.PdfErrorCode.NotSupport,
|
|
4145
|
-
message:
|
|
4440
|
+
message: `engine method ${name} is not supported yet`,
|
|
4146
4441
|
},
|
|
4147
4442
|
};
|
|
4148
4443
|
const response = {
|
|
@@ -4197,6 +4492,9 @@ class EngineRunner {
|
|
|
4197
4492
|
case 'renderPageRect':
|
|
4198
4493
|
task = this.engine[name](...args);
|
|
4199
4494
|
break;
|
|
4495
|
+
case 'renderAnnotation':
|
|
4496
|
+
task = this.engine[name](...args);
|
|
4497
|
+
break;
|
|
4200
4498
|
case 'renderThumbnail':
|
|
4201
4499
|
task = this.engine[name](...args);
|
|
4202
4500
|
break;
|
|
@@ -4209,12 +4507,15 @@ class EngineRunner {
|
|
|
4209
4507
|
case 'createPageAnnotation':
|
|
4210
4508
|
task = this.engine[name](...args);
|
|
4211
4509
|
break;
|
|
4212
|
-
case '
|
|
4510
|
+
case 'updatePageAnnotation':
|
|
4213
4511
|
task = this.engine[name](...args);
|
|
4214
4512
|
break;
|
|
4215
4513
|
case 'removePageAnnotation':
|
|
4216
4514
|
task = this.engine[name](...args);
|
|
4217
4515
|
break;
|
|
4516
|
+
case 'updateAnnotationColor':
|
|
4517
|
+
task = this.engine[name](...args);
|
|
4518
|
+
break;
|
|
4218
4519
|
case 'getPageTextRects':
|
|
4219
4520
|
task = this.engine[name](...args);
|
|
4220
4521
|
break;
|
|
@@ -4588,6 +4889,21 @@ class WebWorkerEngine {
|
|
|
4588
4889
|
this.proxy(task, request);
|
|
4589
4890
|
return task;
|
|
4590
4891
|
}
|
|
4892
|
+
updateAnnotationColor(doc, page, annotation, color, which = 0) {
|
|
4893
|
+
this.logger.debug(LOG_SOURCE, LOG_CATEGORY, 'setAnnotationColor', doc, page, annotation, color);
|
|
4894
|
+
const requestId = this.generateRequestId(doc.id);
|
|
4895
|
+
const task = new WorkerTask(this.worker, requestId);
|
|
4896
|
+
const request = {
|
|
4897
|
+
id: requestId,
|
|
4898
|
+
type: 'ExecuteRequest',
|
|
4899
|
+
data: {
|
|
4900
|
+
name: 'updateAnnotationColor',
|
|
4901
|
+
args: [doc, page, annotation, color, which],
|
|
4902
|
+
},
|
|
4903
|
+
};
|
|
4904
|
+
this.proxy(task, request);
|
|
4905
|
+
return task;
|
|
4906
|
+
}
|
|
4591
4907
|
/**
|
|
4592
4908
|
* {@inheritDoc @embedpdf/models!PdfEngine.getDocPermissions}
|
|
4593
4909
|
*
|
|
@@ -4708,6 +5024,26 @@ class WebWorkerEngine {
|
|
|
4708
5024
|
this.proxy(task, request);
|
|
4709
5025
|
return task;
|
|
4710
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
|
+
}
|
|
4711
5047
|
/**
|
|
4712
5048
|
* {@inheritDoc @embedpdf/models!PdfEngine.getAllAnnotations}
|
|
4713
5049
|
*
|
|
@@ -4768,21 +5104,16 @@ class WebWorkerEngine {
|
|
|
4768
5104
|
this.proxy(task, request);
|
|
4769
5105
|
return task;
|
|
4770
5106
|
}
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
*
|
|
4774
|
-
* @public
|
|
4775
|
-
*/
|
|
4776
|
-
transformPageAnnotation(doc, page, annotation, transformation) {
|
|
4777
|
-
this.logger.debug(LOG_SOURCE, LOG_CATEGORY, 'transformPageAnnotation', doc, page, annotation, transformation);
|
|
5107
|
+
updatePageAnnotation(doc, page, annotation) {
|
|
5108
|
+
this.logger.debug(LOG_SOURCE, LOG_CATEGORY, 'updatePageAnnotation', doc, page, annotation);
|
|
4778
5109
|
const requestId = this.generateRequestId(doc.id);
|
|
4779
5110
|
const task = new WorkerTask(this.worker, requestId);
|
|
4780
5111
|
const request = {
|
|
4781
5112
|
id: requestId,
|
|
4782
5113
|
type: 'ExecuteRequest',
|
|
4783
5114
|
data: {
|
|
4784
|
-
name: '
|
|
4785
|
-
args: [doc, page, annotation
|
|
5115
|
+
name: 'updatePageAnnotation',
|
|
5116
|
+
args: [doc, page, annotation],
|
|
4786
5117
|
},
|
|
4787
5118
|
};
|
|
4788
5119
|
this.proxy(task, request);
|
|
@@ -5200,6 +5531,9 @@ function createMockPdfEngine(partialEngine) {
|
|
|
5200
5531
|
const signatures = [];
|
|
5201
5532
|
return models.PdfTaskHelper.resolve(signatures);
|
|
5202
5533
|
},
|
|
5534
|
+
updateAnnotationColor: (doc, page, annotation, color, which = 0) => {
|
|
5535
|
+
return models.PdfTaskHelper.resolve(true);
|
|
5536
|
+
},
|
|
5203
5537
|
getBookmarks: (doc) => {
|
|
5204
5538
|
const bookmarks = [];
|
|
5205
5539
|
bookmarks.push({
|
|
@@ -5309,12 +5643,14 @@ function createMockPdfEngine(partialEngine) {
|
|
|
5309
5643
|
const blob = new Blob([realBuffer], { type: 'image/png' });
|
|
5310
5644
|
return models.PdfTaskHelper.resolve(blob);
|
|
5311
5645
|
}),
|
|
5646
|
+
renderAnnotation: jest.fn((doc, page, annotation, scaleFactor, rotation, dpr, mode, imageType) => {
|
|
5647
|
+
return models.PdfTaskHelper.resolve(new Blob([], { type: 'image/png' }));
|
|
5648
|
+
}),
|
|
5312
5649
|
getAllAnnotations: jest.fn((doc) => {
|
|
5313
5650
|
return models.PdfTaskHelper.resolve({});
|
|
5314
5651
|
}),
|
|
5315
5652
|
getPageAnnotations: jest.fn((doc, page) => {
|
|
5316
5653
|
const link = {
|
|
5317
|
-
status: models.PdfAnnotationObjectStatus.Committed,
|
|
5318
5654
|
pageIndex: page.index,
|
|
5319
5655
|
id: page.index + 1,
|
|
5320
5656
|
type: models.PdfAnnotationSubtype.LINK,
|
|
@@ -5336,22 +5672,17 @@ function createMockPdfEngine(partialEngine) {
|
|
|
5336
5672
|
height: 100,
|
|
5337
5673
|
},
|
|
5338
5674
|
},
|
|
5339
|
-
appearances: {
|
|
5340
|
-
normal: '',
|
|
5341
|
-
rollover: '',
|
|
5342
|
-
down: '',
|
|
5343
|
-
},
|
|
5344
5675
|
};
|
|
5345
5676
|
const annotations = [];
|
|
5346
5677
|
annotations.push(link);
|
|
5347
5678
|
return models.PdfTaskHelper.resolve(annotations);
|
|
5348
5679
|
}),
|
|
5349
5680
|
createPageAnnotation: jest.fn(() => {
|
|
5350
|
-
return models.PdfTaskHelper.resolve(
|
|
5681
|
+
return models.PdfTaskHelper.resolve(1);
|
|
5351
5682
|
}),
|
|
5352
|
-
|
|
5683
|
+
updatePageAnnotation: jest.fn(() => {
|
|
5353
5684
|
return models.PdfTaskHelper.resolve(true);
|
|
5354
|
-
},
|
|
5685
|
+
}),
|
|
5355
5686
|
removePageAnnotation: jest.fn(() => {
|
|
5356
5687
|
return models.PdfTaskHelper.resolve(true);
|
|
5357
5688
|
}),
|