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