@embedpdf/engines 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +471 -193
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +84 -21
- package/dist/index.js +472 -194
- package/dist/index.js.map +1 -1
- package/dist/pdfium-direct-engine.cjs +405 -189
- package/dist/pdfium-direct-engine.cjs.map +1 -1
- package/dist/pdfium-direct-engine.d.ts +76 -21
- package/dist/pdfium-direct-engine.js +405 -189
- package/dist/pdfium-direct-engine.js.map +1 -1
- package/dist/pdfium-worker-engine.cjs +54 -3
- package/dist/pdfium-worker-engine.cjs.map +1 -1
- package/dist/pdfium-worker-engine.d.ts +11 -3
- package/dist/pdfium-worker-engine.js +54 -3
- package/dist/pdfium-worker-engine.js.map +1 -1
- package/dist/pdfium.cjs +412 -187
- package/dist/pdfium.cjs.map +1 -1
- package/dist/pdfium.d.ts +75 -20
- package/dist/pdfium.js +413 -188
- package/dist/pdfium.js.map +1 -1
- package/dist/worker.cjs +50 -0
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.ts +10 -2
- package/dist/worker.js +50 -0
- package/dist/worker.js.map +1 -1
- package/package.json +3 -3
package/dist/pdfium.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NoopLogger, PdfTaskHelper, PdfErrorCode, Task, Rotation, PdfAnnotationSubtype, PdfPageObjectType,
|
|
1
|
+
import { NoopLogger, PdfTaskHelper, PdfErrorCode, Task, Rotation, PdfAnnotationSubtype, stripPdfUnwantedMarkers, dateToPdfDate, PdfPageObjectType, pdfAlphaColorToWebAlphaColor, webAlphaColorToPdfAlphaColor, AppearanceMode, quadToRect, pdfDateToDate, PDF_FORM_FIELD_TYPE, toIntRect, transformRect, toIntSize, transformSize, PdfActionType, PdfZoomMode, MatchFlag, rectToQuad } from '@embedpdf/models';
|
|
2
2
|
import { init } from '@embedpdf/pdfium';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -915,6 +915,12 @@ class PdfiumEngine {
|
|
|
915
915
|
case PdfAnnotationSubtype.STAMP:
|
|
916
916
|
isSucceed = this.addStampContent(ctx.docPtr, page, pageCtx.pagePtr, annotationPtr, annotation.rect, annotation.contents);
|
|
917
917
|
break;
|
|
918
|
+
case PdfAnnotationSubtype.UNDERLINE:
|
|
919
|
+
case PdfAnnotationSubtype.STRIKEOUT:
|
|
920
|
+
case PdfAnnotationSubtype.SQUIGGLY:
|
|
921
|
+
case PdfAnnotationSubtype.HIGHLIGHT:
|
|
922
|
+
isSucceed = this.addTextMarkupContent(page, annotationPtr, annotation);
|
|
923
|
+
break;
|
|
918
924
|
}
|
|
919
925
|
if (!isSucceed) {
|
|
920
926
|
this.pdfiumModule.FPDFPage_RemoveAnnot(pageCtx.pagePtr, annotationPtr);
|
|
@@ -926,10 +932,101 @@ class PdfiumEngine {
|
|
|
926
932
|
});
|
|
927
933
|
}
|
|
928
934
|
this.pdfiumModule.FPDFPage_GenerateContent(pageCtx.pagePtr);
|
|
935
|
+
const annotId = this.pdfiumModule.FPDFPage_GetAnnotIndex(pageCtx.pagePtr, annotationPtr);
|
|
929
936
|
this.pdfiumModule.FPDFPage_CloseAnnot(annotationPtr);
|
|
930
937
|
pageCtx.release();
|
|
931
938
|
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, `CreatePageAnnotation`, 'End', `${doc.id}-${page.index}`);
|
|
932
|
-
return
|
|
939
|
+
return annotId >= 0
|
|
940
|
+
? PdfTaskHelper.resolve(annotId)
|
|
941
|
+
: PdfTaskHelper.reject({
|
|
942
|
+
code: PdfErrorCode.CantCreateAnnot,
|
|
943
|
+
message: 'annotation created but index could not be determined',
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
/**
|
|
947
|
+
* Update an existing page annotation in-place
|
|
948
|
+
*
|
|
949
|
+
* • Locates the annot by page-local index (`annotation.id`)
|
|
950
|
+
* • Re-writes its /Rect and type-specific payload
|
|
951
|
+
* • Calls FPDFPage_GenerateContent so the new appearance is rendered
|
|
952
|
+
*
|
|
953
|
+
* @returns PdfTask<boolean> – true on success
|
|
954
|
+
*/
|
|
955
|
+
updatePageAnnotation(doc, page, annotation) {
|
|
956
|
+
this.logger.debug(LOG_SOURCE$1, LOG_CATEGORY$1, 'updatePageAnnotation', doc, page, annotation);
|
|
957
|
+
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'UpdatePageAnnotation', 'Begin', `${doc.id}-${page.index}`);
|
|
958
|
+
const ctx = this.cache.getContext(doc.id);
|
|
959
|
+
if (!ctx) {
|
|
960
|
+
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'UpdatePageAnnotation', 'End', `${doc.id}-${page.index}`);
|
|
961
|
+
return PdfTaskHelper.reject({
|
|
962
|
+
code: PdfErrorCode.DocNotOpen,
|
|
963
|
+
message: 'document does not open',
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
const pageCtx = ctx.acquirePage(page.index);
|
|
967
|
+
const annotPtr = this.pdfiumModule.FPDFPage_GetAnnot(pageCtx.pagePtr, annotation.id);
|
|
968
|
+
if (!annotPtr) {
|
|
969
|
+
pageCtx.release();
|
|
970
|
+
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'UpdatePageAnnotation', 'End', `${doc.id}-${page.index}`);
|
|
971
|
+
return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: 'annotation not found' });
|
|
972
|
+
}
|
|
973
|
+
/* 1 ── (re)set bounding-box ────────────────────────────────────────────── */
|
|
974
|
+
if (!this.setPageAnnoRect(page, pageCtx.pagePtr, annotPtr, annotation.rect)) {
|
|
975
|
+
this.pdfiumModule.FPDFPage_CloseAnnot(annotPtr);
|
|
976
|
+
pageCtx.release();
|
|
977
|
+
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'UpdatePageAnnotation', 'End', `${doc.id}-${page.index}`);
|
|
978
|
+
return PdfTaskHelper.reject({
|
|
979
|
+
code: PdfErrorCode.CantSetAnnotRect,
|
|
980
|
+
message: 'failed to move annotation',
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
/* 2 ── wipe previous payload and rebuild fresh one ─────────────────────── */
|
|
984
|
+
let ok = false;
|
|
985
|
+
switch (annotation.type) {
|
|
986
|
+
/* ── Ink ─────────────────────────────────────────────────────────────── */
|
|
987
|
+
case PdfAnnotationSubtype.INK: {
|
|
988
|
+
/* clear every existing stroke first */
|
|
989
|
+
if (!this.pdfiumModule.FPDFAnnot_RemoveInkList(annotPtr))
|
|
990
|
+
break;
|
|
991
|
+
ok = this.addInkStroke(page, pageCtx.pagePtr, annotPtr, annotation.inkList);
|
|
992
|
+
break;
|
|
993
|
+
}
|
|
994
|
+
/* ── Stamp ───────────────────────────────────────────────────────────── */
|
|
995
|
+
case PdfAnnotationSubtype.STAMP: {
|
|
996
|
+
/* drop every page-object inside the annot */
|
|
997
|
+
for (let i = this.pdfiumModule.FPDFAnnot_GetObjectCount(annotPtr) - 1; i >= 0; i--) {
|
|
998
|
+
this.pdfiumModule.FPDFAnnot_RemoveObject(annotPtr, i);
|
|
999
|
+
}
|
|
1000
|
+
ok = this.addStampContent(ctx.docPtr, page, pageCtx.pagePtr, annotPtr, annotation.rect, annotation.contents);
|
|
1001
|
+
break;
|
|
1002
|
+
}
|
|
1003
|
+
/* ── Text-markup family ──────────────────────────────────────────────── */
|
|
1004
|
+
case PdfAnnotationSubtype.HIGHLIGHT:
|
|
1005
|
+
case PdfAnnotationSubtype.UNDERLINE:
|
|
1006
|
+
case PdfAnnotationSubtype.STRIKEOUT:
|
|
1007
|
+
case PdfAnnotationSubtype.SQUIGGLY: {
|
|
1008
|
+
/* replace quad-points / colour / strings in one go */
|
|
1009
|
+
ok = this.addTextMarkupContent(page, annotPtr, annotation, true);
|
|
1010
|
+
break;
|
|
1011
|
+
}
|
|
1012
|
+
/* ── Unsupported edits – fall through to error ───────────────────────── */
|
|
1013
|
+
default:
|
|
1014
|
+
ok = false;
|
|
1015
|
+
}
|
|
1016
|
+
/* 3 ── regenerate appearance if payload was changed ───────────────────── */
|
|
1017
|
+
if (ok) {
|
|
1018
|
+
this.pdfiumModule.FPDFPage_GenerateContent(pageCtx.pagePtr);
|
|
1019
|
+
}
|
|
1020
|
+
/* 4 ── tidy-up native handles ──────────────────────────────────────────── */
|
|
1021
|
+
this.pdfiumModule.FPDFPage_CloseAnnot(annotPtr);
|
|
1022
|
+
pageCtx.release();
|
|
1023
|
+
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'UpdatePageAnnotation', 'End', `${doc.id}-${page.index}`);
|
|
1024
|
+
return ok
|
|
1025
|
+
? PdfTaskHelper.resolve(true)
|
|
1026
|
+
: PdfTaskHelper.reject({
|
|
1027
|
+
code: PdfErrorCode.CantSetAnnotContent,
|
|
1028
|
+
message: 'failed to update annotation',
|
|
1029
|
+
});
|
|
933
1030
|
}
|
|
934
1031
|
/**
|
|
935
1032
|
* {@inheritDoc @embedpdf/models!PdfEngine.transformPageAnnotation}
|
|
@@ -1362,6 +1459,62 @@ class PdfiumEngine {
|
|
|
1362
1459
|
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, `ExtractText`, 'End', doc.id);
|
|
1363
1460
|
return PdfTaskHelper.resolve(text);
|
|
1364
1461
|
}
|
|
1462
|
+
/**
|
|
1463
|
+
* {@inheritDoc @embedpdf/models!PdfEngine.getTextSlices}
|
|
1464
|
+
*
|
|
1465
|
+
* @public
|
|
1466
|
+
*/
|
|
1467
|
+
getTextSlices(doc, slices) {
|
|
1468
|
+
this.logger.debug(LOG_SOURCE$1, LOG_CATEGORY$1, 'getTextSlices', doc, slices);
|
|
1469
|
+
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'GetTextSlices', 'Begin', doc.id);
|
|
1470
|
+
/* ⚠︎ 1 — trivial case */
|
|
1471
|
+
if (slices.length === 0) {
|
|
1472
|
+
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'GetTextSlices', 'End', doc.id);
|
|
1473
|
+
return PdfTaskHelper.resolve([]);
|
|
1474
|
+
}
|
|
1475
|
+
/* ⚠︎ 2 — document must be open */
|
|
1476
|
+
const ctx = this.cache.getContext(doc.id);
|
|
1477
|
+
if (!ctx) {
|
|
1478
|
+
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'GetTextSlices', 'End', doc.id);
|
|
1479
|
+
return PdfTaskHelper.reject({
|
|
1480
|
+
code: PdfErrorCode.DocNotOpen,
|
|
1481
|
+
message: 'document does not open',
|
|
1482
|
+
});
|
|
1483
|
+
}
|
|
1484
|
+
try {
|
|
1485
|
+
/* keep caller order */
|
|
1486
|
+
const out = new Array(slices.length);
|
|
1487
|
+
/* group → open each page once */
|
|
1488
|
+
const byPage = new Map();
|
|
1489
|
+
slices.forEach((s, i) => {
|
|
1490
|
+
(byPage.get(s.pageIndex) ?? byPage.set(s.pageIndex, []).get(s.pageIndex)).push({
|
|
1491
|
+
slice: s,
|
|
1492
|
+
pos: i,
|
|
1493
|
+
});
|
|
1494
|
+
});
|
|
1495
|
+
for (const [pageIdx, list] of byPage) {
|
|
1496
|
+
const pageCtx = ctx.acquirePage(pageIdx);
|
|
1497
|
+
const textPagePtr = pageCtx.getTextPage();
|
|
1498
|
+
for (const { slice, pos } of list) {
|
|
1499
|
+
const bufPtr = this.malloc(2 * (slice.charCount + 1)); // UTF-16 + NIL
|
|
1500
|
+
this.pdfiumModule.FPDFText_GetText(textPagePtr, slice.charIndex, slice.charCount, bufPtr);
|
|
1501
|
+
out[pos] = stripPdfUnwantedMarkers(this.pdfiumModule.pdfium.UTF16ToString(bufPtr));
|
|
1502
|
+
this.free(bufPtr);
|
|
1503
|
+
}
|
|
1504
|
+
pageCtx.release();
|
|
1505
|
+
}
|
|
1506
|
+
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'GetTextSlices', 'End', doc.id);
|
|
1507
|
+
return PdfTaskHelper.resolve(out);
|
|
1508
|
+
}
|
|
1509
|
+
catch (e) {
|
|
1510
|
+
this.logger.error(LOG_SOURCE$1, LOG_CATEGORY$1, 'getTextSlices error', e);
|
|
1511
|
+
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'GetTextSlices', 'End', doc.id);
|
|
1512
|
+
return PdfTaskHelper.reject({
|
|
1513
|
+
code: PdfErrorCode.Unknown,
|
|
1514
|
+
message: String(e),
|
|
1515
|
+
});
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1365
1518
|
/**
|
|
1366
1519
|
* {@inheritDoc @embedpdf/models!PdfEngine.merge}
|
|
1367
1520
|
*
|
|
@@ -1592,6 +1745,36 @@ class PdfiumEngine {
|
|
|
1592
1745
|
}
|
|
1593
1746
|
return true;
|
|
1594
1747
|
}
|
|
1748
|
+
/**
|
|
1749
|
+
* Add highlight content to annotation
|
|
1750
|
+
* @param page - page info
|
|
1751
|
+
* @param annotationPtr - pointer to highlight annotation
|
|
1752
|
+
* @param annotation - highlight annotation
|
|
1753
|
+
* @returns whether highlight content is added to annotation
|
|
1754
|
+
*
|
|
1755
|
+
* @private
|
|
1756
|
+
*/
|
|
1757
|
+
addTextMarkupContent(page, annotationPtr, annotation, shouldClearAP = false) {
|
|
1758
|
+
if (!this.syncQuadPointsAnno(page, annotationPtr, annotation.segmentRects)) {
|
|
1759
|
+
return false;
|
|
1760
|
+
}
|
|
1761
|
+
if (!this.setAnnotString(annotationPtr, 'Contents', annotation.contents ?? '')) {
|
|
1762
|
+
return false;
|
|
1763
|
+
}
|
|
1764
|
+
if (!this.setAnnotString(annotationPtr, 'T', annotation.author || '')) {
|
|
1765
|
+
return false;
|
|
1766
|
+
}
|
|
1767
|
+
if (!this.setAnnotString(annotationPtr, 'M', dateToPdfDate(annotation.modified))) {
|
|
1768
|
+
return false;
|
|
1769
|
+
}
|
|
1770
|
+
if (!this.setAnnotationColor(annotationPtr, {
|
|
1771
|
+
color: annotation.color ?? '#FFFF00',
|
|
1772
|
+
opacity: annotation.opacity ?? 1,
|
|
1773
|
+
}, shouldClearAP, 0)) {
|
|
1774
|
+
return false;
|
|
1775
|
+
}
|
|
1776
|
+
return true;
|
|
1777
|
+
}
|
|
1595
1778
|
/**
|
|
1596
1779
|
* Add contents to stamp annotation
|
|
1597
1780
|
* @param docPtr - pointer to pdf document object
|
|
@@ -1891,14 +2074,12 @@ class PdfiumEngine {
|
|
|
1891
2074
|
const runs = [];
|
|
1892
2075
|
let current = null;
|
|
1893
2076
|
let curObjPtr = null;
|
|
2077
|
+
let bounds = null;
|
|
1894
2078
|
/** ── main loop ──────────────────────────────────────────── */
|
|
1895
2079
|
for (let i = 0; i < glyphs.length; i++) {
|
|
1896
2080
|
const g = glyphs[i];
|
|
1897
2081
|
/* 1 — find the CPDF_TextObject this glyph belongs to */
|
|
1898
2082
|
const objPtr = this.pdfiumModule.FPDFText_GetTextObject(textPagePtr, i);
|
|
1899
|
-
if (g.isEmpty) {
|
|
1900
|
-
continue;
|
|
1901
|
-
}
|
|
1902
2083
|
/* 2 — start a new run when the text object changes */
|
|
1903
2084
|
if (objPtr !== curObjPtr) {
|
|
1904
2085
|
curObjPtr = objPtr;
|
|
@@ -1912,6 +2093,12 @@ class PdfiumEngine {
|
|
|
1912
2093
|
charStart: i,
|
|
1913
2094
|
glyphs: [],
|
|
1914
2095
|
};
|
|
2096
|
+
bounds = {
|
|
2097
|
+
minX: g.origin.x,
|
|
2098
|
+
minY: g.origin.y,
|
|
2099
|
+
maxX: g.origin.x + g.size.width,
|
|
2100
|
+
maxY: g.origin.y + g.size.height,
|
|
2101
|
+
};
|
|
1915
2102
|
runs.push(current);
|
|
1916
2103
|
}
|
|
1917
2104
|
/* 3 — append the slim glyph record */
|
|
@@ -1920,16 +2107,24 @@ class PdfiumEngine {
|
|
|
1920
2107
|
y: g.origin.y,
|
|
1921
2108
|
width: g.size.width,
|
|
1922
2109
|
height: g.size.height,
|
|
1923
|
-
flags: g.isSpace ? 1 : 0,
|
|
2110
|
+
flags: g.isEmpty ? 2 : g.isSpace ? 1 : 0,
|
|
1924
2111
|
});
|
|
1925
2112
|
/* 4 — expand the run's bounding rect */
|
|
2113
|
+
if (g.isEmpty) {
|
|
2114
|
+
continue;
|
|
2115
|
+
}
|
|
1926
2116
|
const right = g.origin.x + g.size.width;
|
|
1927
2117
|
const bottom = g.origin.y + g.size.height;
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
2118
|
+
// Update bounds
|
|
2119
|
+
bounds.minX = Math.min(bounds.minX, g.origin.x);
|
|
2120
|
+
bounds.minY = Math.min(bounds.minY, g.origin.y);
|
|
2121
|
+
bounds.maxX = Math.max(bounds.maxX, right);
|
|
2122
|
+
bounds.maxY = Math.max(bounds.maxY, bottom);
|
|
2123
|
+
// Calculate final rect from bounds
|
|
2124
|
+
current.rect.x = bounds.minX;
|
|
2125
|
+
current.rect.y = bounds.minY;
|
|
2126
|
+
current.rect.width = bounds.maxX - bounds.minX;
|
|
2127
|
+
current.rect.height = bounds.maxY - bounds.minY;
|
|
1933
2128
|
}
|
|
1934
2129
|
return runs;
|
|
1935
2130
|
}
|
|
@@ -2202,8 +2397,6 @@ class PdfiumEngine {
|
|
|
2202
2397
|
annotation = this.readPdfCaretAnno(page, pageCtx.pagePtr, annotationPtr, index);
|
|
2203
2398
|
}
|
|
2204
2399
|
break;
|
|
2205
|
-
case PdfAnnotationSubtype.POPUP:
|
|
2206
|
-
break;
|
|
2207
2400
|
default:
|
|
2208
2401
|
{
|
|
2209
2402
|
annotation = this.readPdfAnno(page, pageCtx.pagePtr, subType, annotationPtr, index);
|
|
@@ -2350,15 +2543,35 @@ class PdfiumEngine {
|
|
|
2350
2543
|
*
|
|
2351
2544
|
* @param annotationPtr - pointer to an `FPDF_ANNOTATION`
|
|
2352
2545
|
* @param fallback - colour to use when the PDF stores no tint at all
|
|
2353
|
-
* @returns
|
|
2546
|
+
* @returns WebAlphaColor with hex color and opacity (0-1)
|
|
2354
2547
|
*
|
|
2355
2548
|
* @private
|
|
2356
2549
|
*/
|
|
2357
2550
|
resolveAnnotationColor(annotationPtr, fallback = { red: 255, green: 245, blue: 155, alpha: 255 }) {
|
|
2358
|
-
|
|
2551
|
+
const pdfColor = this.readAnnotationColor(annotationPtr) ?? // 1 – /C entry
|
|
2359
2552
|
this.colorFromAppearance(annotationPtr) ?? // 2 – AP stream walk
|
|
2360
|
-
fallback // 3 – default
|
|
2361
|
-
);
|
|
2553
|
+
fallback; // 3 – default
|
|
2554
|
+
return pdfAlphaColorToWebAlphaColor(pdfColor);
|
|
2555
|
+
}
|
|
2556
|
+
/**
|
|
2557
|
+
* Set the fill/stroke colour for a **Highlight / Underline / StrikeOut / Squiggly** markup annotation.
|
|
2558
|
+
*
|
|
2559
|
+
* @param annotationPtr - pointer to the annotation whose colour is being set
|
|
2560
|
+
* @param webAlphaColor - WebAlphaColor with hex color and opacity (0-1)
|
|
2561
|
+
* @param shouldClearAP - whether to clear the /AP entry
|
|
2562
|
+
* @param which - which colour to set (0 = fill, 1 = stroke)
|
|
2563
|
+
* @returns `true` if the operation was successful
|
|
2564
|
+
*
|
|
2565
|
+
* @private
|
|
2566
|
+
*/
|
|
2567
|
+
setAnnotationColor(annotationPtr, webAlphaColor, shouldClearAP = false, which = 0) {
|
|
2568
|
+
const pdfAlphaColor = webAlphaColorToPdfAlphaColor(webAlphaColor);
|
|
2569
|
+
if (shouldClearAP) {
|
|
2570
|
+
// NULL wide-string → remove the /AP entry
|
|
2571
|
+
this.pdfiumModule.FPDFAnnot_SetAP(annotationPtr, AppearanceMode.Normal,
|
|
2572
|
+
/* FPDF_WIDESTRING = */ 0);
|
|
2573
|
+
}
|
|
2574
|
+
return this.pdfiumModule.FPDFAnnot_SetColor(annotationPtr, which, pdfAlphaColor.red & 0xff, pdfAlphaColor.green & 0xff, pdfAlphaColor.blue & 0xff, (pdfAlphaColor.alpha ?? 255) & 0xff);
|
|
2362
2575
|
}
|
|
2363
2576
|
/**
|
|
2364
2577
|
* Read `/QuadPoints` from any annotation and convert each quadrilateral to
|
|
@@ -2371,11 +2584,11 @@ class PdfiumEngine {
|
|
|
2371
2584
|
*
|
|
2372
2585
|
* @param page - logical page info object (`PdfPageObject`)
|
|
2373
2586
|
* @param annotationPtr - pointer to the annotation whose quads are needed
|
|
2374
|
-
* @returns Array of `
|
|
2587
|
+
* @returns Array of `Rect` objects (`[]` if the annotation has no quads)
|
|
2375
2588
|
*
|
|
2376
2589
|
* @private
|
|
2377
2590
|
*/
|
|
2378
|
-
|
|
2591
|
+
getQuadPointsAnno(page, annotationPtr) {
|
|
2379
2592
|
const quadCount = this.pdfiumModule.FPDFAnnot_CountAttachmentPoints(annotationPtr);
|
|
2380
2593
|
if (quadCount === 0)
|
|
2381
2594
|
return [];
|
|
@@ -2402,7 +2615,60 @@ class PdfiumEngine {
|
|
|
2402
2615
|
}
|
|
2403
2616
|
this.free(quadPtr);
|
|
2404
2617
|
}
|
|
2405
|
-
return quads;
|
|
2618
|
+
return quads.map(quadToRect);
|
|
2619
|
+
}
|
|
2620
|
+
/**
|
|
2621
|
+
* Set the quadrilaterals for a **Highlight / Underline / StrikeOut / Squiggly** markup annotation.
|
|
2622
|
+
*
|
|
2623
|
+
* @param page - logical page info object (`PdfPageObject`)
|
|
2624
|
+
* @param annotationPtr - pointer to the annotation whose quads are needed
|
|
2625
|
+
* @param rects - array of `Rect` objects (`[]` if the annotation has no quads)
|
|
2626
|
+
* @returns `true` if the operation was successful
|
|
2627
|
+
*
|
|
2628
|
+
* @private
|
|
2629
|
+
*/
|
|
2630
|
+
syncQuadPointsAnno(page, annotPtr, rects) {
|
|
2631
|
+
const FS_QUADPOINTSF_SIZE = 8 * 4; // eight floats, 32 bytes
|
|
2632
|
+
const pdf = this.pdfiumModule.pdfium;
|
|
2633
|
+
const count = this.pdfiumModule.FPDFAnnot_CountAttachmentPoints(annotPtr);
|
|
2634
|
+
const buf = this.malloc(FS_QUADPOINTSF_SIZE);
|
|
2635
|
+
/** write one quad into `buf` in annotation space */
|
|
2636
|
+
const writeQuad = (r) => {
|
|
2637
|
+
const q = rectToQuad(r); // TL, TR, BR, BL
|
|
2638
|
+
const p1 = this.convertDevicePointToPagePoint(page, q.p1);
|
|
2639
|
+
const p2 = this.convertDevicePointToPagePoint(page, q.p2);
|
|
2640
|
+
const p3 = this.convertDevicePointToPagePoint(page, q.p3); // BR
|
|
2641
|
+
const p4 = this.convertDevicePointToPagePoint(page, q.p4); // BL
|
|
2642
|
+
// PDF QuadPoints order: BL, BR, TL, TR (bottom-left, bottom-right, top-left, top-right)
|
|
2643
|
+
pdf.setValue(buf + 0, p1.x, 'float'); // BL (bottom-left)
|
|
2644
|
+
pdf.setValue(buf + 4, p1.y, 'float');
|
|
2645
|
+
pdf.setValue(buf + 8, p2.x, 'float'); // BR (bottom-right)
|
|
2646
|
+
pdf.setValue(buf + 12, p2.y, 'float');
|
|
2647
|
+
pdf.setValue(buf + 16, p4.x, 'float'); // TL (top-left)
|
|
2648
|
+
pdf.setValue(buf + 20, p4.y, 'float');
|
|
2649
|
+
pdf.setValue(buf + 24, p3.x, 'float'); // TR (top-right)
|
|
2650
|
+
pdf.setValue(buf + 28, p3.y, 'float');
|
|
2651
|
+
};
|
|
2652
|
+
/* ----------------------------------------------------------------------- */
|
|
2653
|
+
/* 1. overwrite the quads that already exist */
|
|
2654
|
+
const min = Math.min(count, rects.length);
|
|
2655
|
+
for (let i = 0; i < min; i++) {
|
|
2656
|
+
writeQuad(rects[i]);
|
|
2657
|
+
if (!this.pdfiumModule.FPDFAnnot_SetAttachmentPoints(annotPtr, i, buf)) {
|
|
2658
|
+
this.free(buf);
|
|
2659
|
+
return false;
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
/* 2. append new quads if rects.length > count */
|
|
2663
|
+
for (let i = count; i < rects.length; i++) {
|
|
2664
|
+
writeQuad(rects[i]);
|
|
2665
|
+
if (!this.pdfiumModule.FPDFAnnot_AppendAttachmentPoints(annotPtr, buf)) {
|
|
2666
|
+
this.free(buf);
|
|
2667
|
+
return false;
|
|
2668
|
+
}
|
|
2669
|
+
}
|
|
2670
|
+
this.free(buf);
|
|
2671
|
+
return true;
|
|
2406
2672
|
}
|
|
2407
2673
|
/**
|
|
2408
2674
|
* Read pdf text annotation
|
|
@@ -2415,30 +2681,23 @@ class PdfiumEngine {
|
|
|
2415
2681
|
* @private
|
|
2416
2682
|
*/
|
|
2417
2683
|
readPdfTextAnno(page, pagePtr, annotationPtr, index) {
|
|
2418
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2419
2684
|
const annoRect = this.readPageAnnoRect(annotationPtr);
|
|
2420
2685
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, annoRect);
|
|
2421
2686
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2422
2687
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2423
|
-
const modified =
|
|
2688
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
2424
2689
|
const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
|
|
2425
2690
|
const state = this.getAnnotString(annotationPtr, 'State');
|
|
2426
2691
|
const stateModel = this.getAnnotString(annotationPtr, 'StateModel');
|
|
2427
|
-
const
|
|
2692
|
+
const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
|
|
2428
2693
|
const inReplyToId = this.getInReplyToId(pagePtr, annotationPtr);
|
|
2429
|
-
const popup = !inReplyToId
|
|
2430
|
-
? this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index)
|
|
2431
|
-
: undefined;
|
|
2432
2694
|
return {
|
|
2433
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
2434
2695
|
pageIndex: page.index,
|
|
2435
2696
|
id: index,
|
|
2436
2697
|
type: PdfAnnotationSubtype.TEXT,
|
|
2437
2698
|
contents,
|
|
2438
|
-
|
|
2699
|
+
...webAlphaColor,
|
|
2439
2700
|
rect,
|
|
2440
|
-
popup,
|
|
2441
|
-
appearances,
|
|
2442
2701
|
inReplyToId,
|
|
2443
2702
|
author,
|
|
2444
2703
|
modified,
|
|
@@ -2457,16 +2716,13 @@ class PdfiumEngine {
|
|
|
2457
2716
|
* @private
|
|
2458
2717
|
*/
|
|
2459
2718
|
readPdfFreeTextAnno(page, pagePtr, annotationPtr, index) {
|
|
2460
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2461
2719
|
const annoRect = this.readPageAnnoRect(annotationPtr);
|
|
2462
2720
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, annoRect);
|
|
2463
2721
|
const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
|
|
2464
2722
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2465
2723
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2466
|
-
const modified =
|
|
2467
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2724
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
2468
2725
|
return {
|
|
2469
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
2470
2726
|
pageIndex: page.index,
|
|
2471
2727
|
id: index,
|
|
2472
2728
|
type: PdfAnnotationSubtype.FREETEXT,
|
|
@@ -2474,8 +2730,6 @@ class PdfiumEngine {
|
|
|
2474
2730
|
author,
|
|
2475
2731
|
modified,
|
|
2476
2732
|
rect,
|
|
2477
|
-
popup,
|
|
2478
|
-
appearances,
|
|
2479
2733
|
};
|
|
2480
2734
|
}
|
|
2481
2735
|
/**
|
|
@@ -2495,13 +2749,12 @@ class PdfiumEngine {
|
|
|
2495
2749
|
if (!linkPtr) {
|
|
2496
2750
|
return;
|
|
2497
2751
|
}
|
|
2498
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2499
2752
|
const annoRect = this.readPageAnnoRect(annotationPtr);
|
|
2500
2753
|
const { left, top, right, bottom } = annoRect;
|
|
2501
2754
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, annoRect);
|
|
2502
2755
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2503
2756
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2504
|
-
const modified =
|
|
2757
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
2505
2758
|
const utf16Length = this.pdfiumModule.FPDFText_GetBoundedText(textPagePtr, left, top, right, bottom, 0, 0);
|
|
2506
2759
|
const bytesCount = (utf16Length + 1) * 2; // include NIL
|
|
2507
2760
|
const textBufferPtr = this.malloc(bytesCount);
|
|
@@ -2513,17 +2766,13 @@ class PdfiumEngine {
|
|
|
2513
2766
|
}, () => {
|
|
2514
2767
|
return this.pdfiumModule.FPDFLink_GetDest(docPtr, linkPtr);
|
|
2515
2768
|
});
|
|
2516
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2517
2769
|
return {
|
|
2518
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
2519
2770
|
pageIndex: page.index,
|
|
2520
2771
|
id: index,
|
|
2521
2772
|
type: PdfAnnotationSubtype.LINK,
|
|
2522
2773
|
text,
|
|
2523
2774
|
target,
|
|
2524
2775
|
rect,
|
|
2525
|
-
popup,
|
|
2526
|
-
appearances,
|
|
2527
2776
|
author,
|
|
2528
2777
|
modified,
|
|
2529
2778
|
};
|
|
@@ -2540,23 +2789,18 @@ class PdfiumEngine {
|
|
|
2540
2789
|
* @private
|
|
2541
2790
|
*/
|
|
2542
2791
|
readPdfWidgetAnno(page, pagePtr, annotationPtr, formHandle, index) {
|
|
2543
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2544
2792
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2545
2793
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2546
2794
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2547
2795
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2548
|
-
const modified =
|
|
2549
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2796
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
2550
2797
|
const field = this.readPdfWidgetAnnoField(formHandle, annotationPtr);
|
|
2551
2798
|
return {
|
|
2552
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
2553
2799
|
pageIndex: page.index,
|
|
2554
2800
|
id: index,
|
|
2555
2801
|
type: PdfAnnotationSubtype.WIDGET,
|
|
2556
2802
|
rect,
|
|
2557
2803
|
field,
|
|
2558
|
-
popup,
|
|
2559
|
-
appearances,
|
|
2560
2804
|
author,
|
|
2561
2805
|
modified,
|
|
2562
2806
|
};
|
|
@@ -2572,21 +2816,16 @@ class PdfiumEngine {
|
|
|
2572
2816
|
* @private
|
|
2573
2817
|
*/
|
|
2574
2818
|
readPdfFileAttachmentAnno(page, pagePtr, annotationPtr, index) {
|
|
2575
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2576
2819
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2577
2820
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2578
2821
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2579
2822
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2580
|
-
const modified =
|
|
2581
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2823
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
2582
2824
|
return {
|
|
2583
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
2584
2825
|
pageIndex: page.index,
|
|
2585
2826
|
id: index,
|
|
2586
2827
|
type: PdfAnnotationSubtype.FILEATTACHMENT,
|
|
2587
2828
|
rect,
|
|
2588
|
-
popup,
|
|
2589
|
-
appearances,
|
|
2590
2829
|
author,
|
|
2591
2830
|
modified,
|
|
2592
2831
|
};
|
|
@@ -2602,13 +2841,11 @@ class PdfiumEngine {
|
|
|
2602
2841
|
* @private
|
|
2603
2842
|
*/
|
|
2604
2843
|
readPdfInkAnno(page, pagePtr, annotationPtr, index) {
|
|
2605
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2606
2844
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2607
2845
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2608
2846
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2609
2847
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2610
|
-
const modified =
|
|
2611
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2848
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
2612
2849
|
const inkList = [];
|
|
2613
2850
|
const count = this.pdfiumModule.FPDFAnnot_GetInkListCount(annotationPtr);
|
|
2614
2851
|
for (let i = 0; i < count; i++) {
|
|
@@ -2632,14 +2869,11 @@ class PdfiumEngine {
|
|
|
2632
2869
|
inkList.push({ points });
|
|
2633
2870
|
}
|
|
2634
2871
|
return {
|
|
2635
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
2636
2872
|
pageIndex: page.index,
|
|
2637
2873
|
id: index,
|
|
2638
2874
|
type: PdfAnnotationSubtype.INK,
|
|
2639
2875
|
rect,
|
|
2640
|
-
popup,
|
|
2641
2876
|
inkList,
|
|
2642
|
-
appearances,
|
|
2643
2877
|
author,
|
|
2644
2878
|
modified,
|
|
2645
2879
|
};
|
|
@@ -2655,23 +2889,18 @@ class PdfiumEngine {
|
|
|
2655
2889
|
* @private
|
|
2656
2890
|
*/
|
|
2657
2891
|
readPdfPolygonAnno(page, pagePtr, annotationPtr, index) {
|
|
2658
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2659
2892
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2660
2893
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2661
2894
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2662
2895
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2663
|
-
const modified =
|
|
2664
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2896
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
2665
2897
|
const vertices = this.readPdfAnnoVertices(page, pagePtr, annotationPtr);
|
|
2666
2898
|
return {
|
|
2667
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
2668
2899
|
pageIndex: page.index,
|
|
2669
2900
|
id: index,
|
|
2670
2901
|
type: PdfAnnotationSubtype.POLYGON,
|
|
2671
2902
|
rect,
|
|
2672
|
-
popup,
|
|
2673
2903
|
vertices,
|
|
2674
|
-
appearances,
|
|
2675
2904
|
author,
|
|
2676
2905
|
modified,
|
|
2677
2906
|
};
|
|
@@ -2687,23 +2916,18 @@ class PdfiumEngine {
|
|
|
2687
2916
|
* @private
|
|
2688
2917
|
*/
|
|
2689
2918
|
readPdfPolylineAnno(page, pagePtr, annotationPtr, index) {
|
|
2690
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2691
2919
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2692
2920
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2693
2921
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2694
2922
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2695
|
-
const modified =
|
|
2696
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2923
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
2697
2924
|
const vertices = this.readPdfAnnoVertices(page, pagePtr, annotationPtr);
|
|
2698
2925
|
return {
|
|
2699
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
2700
2926
|
pageIndex: page.index,
|
|
2701
2927
|
id: index,
|
|
2702
2928
|
type: PdfAnnotationSubtype.POLYLINE,
|
|
2703
2929
|
rect,
|
|
2704
|
-
popup,
|
|
2705
2930
|
vertices,
|
|
2706
|
-
appearances,
|
|
2707
2931
|
author,
|
|
2708
2932
|
modified,
|
|
2709
2933
|
};
|
|
@@ -2719,13 +2943,11 @@ class PdfiumEngine {
|
|
|
2719
2943
|
* @private
|
|
2720
2944
|
*/
|
|
2721
2945
|
readPdfLineAnno(page, pagePtr, annotationPtr, index) {
|
|
2722
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2723
2946
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2724
2947
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2725
2948
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2726
2949
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2727
|
-
const modified =
|
|
2728
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2950
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
2729
2951
|
const startPointPtr = this.malloc(8);
|
|
2730
2952
|
const endPointPtr = this.malloc(8);
|
|
2731
2953
|
this.pdfiumModule.FPDFAnnot_GetLine(annotationPtr, startPointPtr, endPointPtr);
|
|
@@ -2744,15 +2966,12 @@ class PdfiumEngine {
|
|
|
2744
2966
|
this.free(startPointPtr);
|
|
2745
2967
|
this.free(endPointPtr);
|
|
2746
2968
|
return {
|
|
2747
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
2748
2969
|
pageIndex: page.index,
|
|
2749
2970
|
id: index,
|
|
2750
2971
|
type: PdfAnnotationSubtype.LINE,
|
|
2751
2972
|
rect,
|
|
2752
|
-
popup,
|
|
2753
2973
|
startPoint,
|
|
2754
2974
|
endPoint,
|
|
2755
|
-
appearances,
|
|
2756
2975
|
author,
|
|
2757
2976
|
modified,
|
|
2758
2977
|
};
|
|
@@ -2768,25 +2987,22 @@ class PdfiumEngine {
|
|
|
2768
2987
|
* @private
|
|
2769
2988
|
*/
|
|
2770
2989
|
readPdfHighlightAnno(page, pagePtr, annotationPtr, index) {
|
|
2771
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2772
2990
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2773
2991
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2774
|
-
const
|
|
2775
|
-
const
|
|
2776
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
2992
|
+
const segmentRects = this.getQuadPointsAnno(page, annotationPtr);
|
|
2993
|
+
const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
|
|
2777
2994
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2778
2995
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2779
|
-
const modified =
|
|
2996
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
2997
|
+
const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
|
|
2780
2998
|
return {
|
|
2781
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
2782
2999
|
pageIndex: page.index,
|
|
2783
3000
|
id: index,
|
|
2784
3001
|
type: PdfAnnotationSubtype.HIGHLIGHT,
|
|
2785
3002
|
rect,
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
color,
|
|
3003
|
+
contents,
|
|
3004
|
+
segmentRects,
|
|
3005
|
+
...webAlphaColor,
|
|
2790
3006
|
author,
|
|
2791
3007
|
modified,
|
|
2792
3008
|
};
|
|
@@ -2802,21 +3018,22 @@ class PdfiumEngine {
|
|
|
2802
3018
|
* @private
|
|
2803
3019
|
*/
|
|
2804
3020
|
readPdfUnderlineAnno(page, pagePtr, annotationPtr, index) {
|
|
2805
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2806
3021
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2807
3022
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2808
3023
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2809
3024
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2810
|
-
const modified =
|
|
2811
|
-
const
|
|
3025
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
3026
|
+
const segmentRects = this.getQuadPointsAnno(page, annotationPtr);
|
|
3027
|
+
const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
|
|
3028
|
+
const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
|
|
2812
3029
|
return {
|
|
2813
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
2814
3030
|
pageIndex: page.index,
|
|
2815
3031
|
id: index,
|
|
2816
3032
|
type: PdfAnnotationSubtype.UNDERLINE,
|
|
2817
3033
|
rect,
|
|
2818
|
-
|
|
2819
|
-
|
|
3034
|
+
contents,
|
|
3035
|
+
segmentRects,
|
|
3036
|
+
...webAlphaColor,
|
|
2820
3037
|
author,
|
|
2821
3038
|
modified,
|
|
2822
3039
|
};
|
|
@@ -2832,21 +3049,22 @@ class PdfiumEngine {
|
|
|
2832
3049
|
* @private
|
|
2833
3050
|
*/
|
|
2834
3051
|
readPdfStrikeOutAnno(page, pagePtr, annotationPtr, index) {
|
|
2835
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2836
3052
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2837
3053
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2838
3054
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2839
3055
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2840
|
-
const modified =
|
|
2841
|
-
const
|
|
3056
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
3057
|
+
const segmentRects = this.getQuadPointsAnno(page, annotationPtr);
|
|
3058
|
+
const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
|
|
3059
|
+
const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
|
|
2842
3060
|
return {
|
|
2843
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
2844
3061
|
pageIndex: page.index,
|
|
2845
3062
|
id: index,
|
|
2846
3063
|
type: PdfAnnotationSubtype.STRIKEOUT,
|
|
2847
3064
|
rect,
|
|
2848
|
-
|
|
2849
|
-
|
|
3065
|
+
contents,
|
|
3066
|
+
segmentRects,
|
|
3067
|
+
...webAlphaColor,
|
|
2850
3068
|
author,
|
|
2851
3069
|
modified,
|
|
2852
3070
|
};
|
|
@@ -2862,21 +3080,22 @@ class PdfiumEngine {
|
|
|
2862
3080
|
* @private
|
|
2863
3081
|
*/
|
|
2864
3082
|
readPdfSquigglyAnno(page, pagePtr, annotationPtr, index) {
|
|
2865
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2866
3083
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2867
3084
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2868
3085
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2869
3086
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2870
|
-
const modified =
|
|
2871
|
-
const
|
|
3087
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
3088
|
+
const segmentRects = this.getQuadPointsAnno(page, annotationPtr);
|
|
3089
|
+
const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
|
|
3090
|
+
const webAlphaColor = this.resolveAnnotationColor(annotationPtr);
|
|
2872
3091
|
return {
|
|
2873
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
2874
3092
|
pageIndex: page.index,
|
|
2875
3093
|
id: index,
|
|
2876
3094
|
type: PdfAnnotationSubtype.SQUIGGLY,
|
|
2877
3095
|
rect,
|
|
2878
|
-
|
|
2879
|
-
|
|
3096
|
+
contents,
|
|
3097
|
+
segmentRects,
|
|
3098
|
+
...webAlphaColor,
|
|
2880
3099
|
author,
|
|
2881
3100
|
modified,
|
|
2882
3101
|
};
|
|
@@ -2892,21 +3111,16 @@ class PdfiumEngine {
|
|
|
2892
3111
|
* @private
|
|
2893
3112
|
*/
|
|
2894
3113
|
readPdfCaretAnno(page, pagePtr, annotationPtr, index) {
|
|
2895
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2896
3114
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2897
3115
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2898
3116
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2899
3117
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2900
|
-
const modified =
|
|
2901
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
3118
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
2902
3119
|
return {
|
|
2903
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
2904
3120
|
pageIndex: page.index,
|
|
2905
3121
|
id: index,
|
|
2906
3122
|
type: PdfAnnotationSubtype.CARET,
|
|
2907
3123
|
rect,
|
|
2908
|
-
popup,
|
|
2909
|
-
appearances,
|
|
2910
3124
|
author,
|
|
2911
3125
|
modified,
|
|
2912
3126
|
};
|
|
@@ -2923,13 +3137,11 @@ class PdfiumEngine {
|
|
|
2923
3137
|
* @private
|
|
2924
3138
|
*/
|
|
2925
3139
|
readPdfStampAnno(docPtr, page, pagePtr, annotationPtr, index) {
|
|
2926
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
2927
3140
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
2928
3141
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
2929
3142
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
2930
3143
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
2931
|
-
const modified =
|
|
2932
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
3144
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
2933
3145
|
const contents = [];
|
|
2934
3146
|
const objectCount = this.pdfiumModule.FPDFAnnot_GetObjectCount(annotationPtr);
|
|
2935
3147
|
for (let i = 0; i < objectCount; i++) {
|
|
@@ -2940,14 +3152,11 @@ class PdfiumEngine {
|
|
|
2940
3152
|
}
|
|
2941
3153
|
}
|
|
2942
3154
|
return {
|
|
2943
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
2944
3155
|
pageIndex: page.index,
|
|
2945
3156
|
id: index,
|
|
2946
3157
|
type: PdfAnnotationSubtype.STAMP,
|
|
2947
3158
|
rect,
|
|
2948
|
-
popup,
|
|
2949
3159
|
contents,
|
|
2950
|
-
appearances,
|
|
2951
3160
|
author,
|
|
2952
3161
|
modified,
|
|
2953
3162
|
};
|
|
@@ -3127,21 +3336,16 @@ class PdfiumEngine {
|
|
|
3127
3336
|
* @private
|
|
3128
3337
|
*/
|
|
3129
3338
|
readPdfCircleAnno(page, pagePtr, annotationPtr, index) {
|
|
3130
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
3131
3339
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
3132
3340
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
3133
3341
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
3134
3342
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
3135
|
-
const modified =
|
|
3136
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
3343
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
3137
3344
|
return {
|
|
3138
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
3139
3345
|
pageIndex: page.index,
|
|
3140
3346
|
id: index,
|
|
3141
3347
|
type: PdfAnnotationSubtype.CIRCLE,
|
|
3142
3348
|
rect,
|
|
3143
|
-
popup,
|
|
3144
|
-
appearances,
|
|
3145
3349
|
author,
|
|
3146
3350
|
modified,
|
|
3147
3351
|
};
|
|
@@ -3157,21 +3361,16 @@ class PdfiumEngine {
|
|
|
3157
3361
|
* @private
|
|
3158
3362
|
*/
|
|
3159
3363
|
readPdfSquareAnno(page, pagePtr, annotationPtr, index) {
|
|
3160
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
3161
3364
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
3162
3365
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
3163
3366
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
3164
3367
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
3165
|
-
const modified =
|
|
3166
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
3368
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
3167
3369
|
return {
|
|
3168
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
3169
3370
|
pageIndex: page.index,
|
|
3170
3371
|
id: index,
|
|
3171
3372
|
type: PdfAnnotationSubtype.SQUARE,
|
|
3172
3373
|
rect,
|
|
3173
|
-
popup,
|
|
3174
|
-
appearances,
|
|
3175
3374
|
author,
|
|
3176
3375
|
modified,
|
|
3177
3376
|
};
|
|
@@ -3188,21 +3387,16 @@ class PdfiumEngine {
|
|
|
3188
3387
|
* @private
|
|
3189
3388
|
*/
|
|
3190
3389
|
readPdfAnno(page, pagePtr, type, annotationPtr, index) {
|
|
3191
|
-
const appearances = this.readPageAnnoAppearanceStreams(annotationPtr);
|
|
3192
3390
|
const pageRect = this.readPageAnnoRect(annotationPtr);
|
|
3193
3391
|
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
3194
3392
|
const author = this.getAnnotString(annotationPtr, 'T');
|
|
3195
3393
|
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
3196
|
-
const modified =
|
|
3197
|
-
const popup = this.readPdfAnnoLinkedPopup(page, pagePtr, annotationPtr, index);
|
|
3394
|
+
const modified = pdfDateToDate(modifiedRaw);
|
|
3198
3395
|
return {
|
|
3199
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
3200
3396
|
pageIndex: page.index,
|
|
3201
3397
|
id: index,
|
|
3202
3398
|
type,
|
|
3203
3399
|
rect,
|
|
3204
|
-
popup,
|
|
3205
|
-
appearances,
|
|
3206
3400
|
author,
|
|
3207
3401
|
modified,
|
|
3208
3402
|
};
|
|
@@ -3224,25 +3418,6 @@ class PdfiumEngine {
|
|
|
3224
3418
|
const idx = this.pdfiumModule.FPDFPage_GetAnnotIndex(pagePtr, parentPtr);
|
|
3225
3419
|
return idx >= 0 ? idx : undefined;
|
|
3226
3420
|
}
|
|
3227
|
-
/**
|
|
3228
|
-
* Parse a PDF date string **D:YYYYMMDDHHmmSSOHH'mm'** to ISO-8601.
|
|
3229
|
-
*
|
|
3230
|
-
* Returns `undefined` if the input is malformed.
|
|
3231
|
-
*
|
|
3232
|
-
* @private
|
|
3233
|
-
*/
|
|
3234
|
-
toIsoDate(pdfDate) {
|
|
3235
|
-
if (!pdfDate?.startsWith('D:'))
|
|
3236
|
-
return;
|
|
3237
|
-
// Minimal parse – ignore timezone for brevity
|
|
3238
|
-
const y = pdfDate.substring(2, 6);
|
|
3239
|
-
const m = pdfDate.substring(6, 8) || '01';
|
|
3240
|
-
const d = pdfDate.substring(8, 10) || '01';
|
|
3241
|
-
const H = pdfDate.substring(10, 12) || '00';
|
|
3242
|
-
const M = pdfDate.substring(12, 14) || '00';
|
|
3243
|
-
const S = pdfDate.substring(14, 16) || '00';
|
|
3244
|
-
return `${y}-${m}-${d}T${H}:${M}:${S}`;
|
|
3245
|
-
}
|
|
3246
3421
|
/**
|
|
3247
3422
|
* Fetch a string value (`/T`, `/M`, `/State`, …) from an annotation.
|
|
3248
3423
|
*
|
|
@@ -3262,41 +3437,19 @@ class PdfiumEngine {
|
|
|
3262
3437
|
return value || undefined;
|
|
3263
3438
|
}
|
|
3264
3439
|
/**
|
|
3265
|
-
*
|
|
3266
|
-
*
|
|
3267
|
-
* @
|
|
3268
|
-
* @param annotationPtr - pointer to pdf annotation
|
|
3269
|
-
* @param index - index of annotation in the pdf page
|
|
3270
|
-
* @returns pdf popup linked to annotation
|
|
3440
|
+
* Set a string value (`/T`, `/M`, `/State`, …) to an annotation.
|
|
3441
|
+
*
|
|
3442
|
+
* @returns `true` if the operation was successful
|
|
3271
3443
|
*
|
|
3272
3444
|
* @private
|
|
3273
3445
|
*/
|
|
3274
|
-
|
|
3275
|
-
const
|
|
3276
|
-
const
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
const rect = this.convertPageRectToDeviceRect(page, pagePtr, pageRect);
|
|
3282
|
-
const author = this.getAnnotString(annotationPtr, 'T');
|
|
3283
|
-
const modifiedRaw = this.getAnnotString(annotationPtr, 'M');
|
|
3284
|
-
const modified = this.toIsoDate(modifiedRaw);
|
|
3285
|
-
const contents = this.getAnnotString(annotationPtr, 'Contents') || '';
|
|
3286
|
-
const open = this.getAnnotString(annotationPtr, 'Open') || 'false';
|
|
3287
|
-
this.pdfiumModule.FPDFPage_CloseAnnot(popupAnnotationPtr);
|
|
3288
|
-
return {
|
|
3289
|
-
status: PdfAnnotationObjectStatus.Committed,
|
|
3290
|
-
pageIndex: page.index,
|
|
3291
|
-
id: index,
|
|
3292
|
-
type: PdfAnnotationSubtype.POPUP,
|
|
3293
|
-
rect,
|
|
3294
|
-
contents,
|
|
3295
|
-
open: open === 'true',
|
|
3296
|
-
appearances,
|
|
3297
|
-
author,
|
|
3298
|
-
modified,
|
|
3299
|
-
};
|
|
3446
|
+
setAnnotString(annotationPtr, key, value) {
|
|
3447
|
+
const bytes = 2 * (value.length + 1);
|
|
3448
|
+
const ptr = this.malloc(bytes);
|
|
3449
|
+
this.pdfiumModule.pdfium.stringToUTF16(value, ptr, bytes);
|
|
3450
|
+
const ok = this.pdfiumModule.FPDFAnnot_SetStringValue(annotationPtr, key, ptr);
|
|
3451
|
+
this.free(ptr);
|
|
3452
|
+
return ok;
|
|
3300
3453
|
}
|
|
3301
3454
|
/**
|
|
3302
3455
|
* Read vertices of pdf annotation
|
|
@@ -3737,6 +3890,69 @@ class PdfiumEngine {
|
|
|
3737
3890
|
this.free(bufferPtr);
|
|
3738
3891
|
return ap;
|
|
3739
3892
|
}
|
|
3893
|
+
/**
|
|
3894
|
+
* Change the visible colour (and opacity) of an existing annotation.
|
|
3895
|
+
*
|
|
3896
|
+
* For markup annotations (highlight / underline / strikeout / squiggly) we
|
|
3897
|
+
* first clear the AP dictionary entry, otherwise the stored appearance stream
|
|
3898
|
+
* will override the new tint. For all other sub-types we keep the existing
|
|
3899
|
+
* AP so custom artwork isn't lost.
|
|
3900
|
+
*
|
|
3901
|
+
* @param doc logical document object
|
|
3902
|
+
* @param page logical page object
|
|
3903
|
+
* @param annotation the annotation we want to recolour
|
|
3904
|
+
* @param colour RGBA tuple (0-255 per channel)
|
|
3905
|
+
* @param which 0 = stroke/fill colour (PDFium's "colourType" param)
|
|
3906
|
+
*
|
|
3907
|
+
* @returns `true` when the operation succeeded
|
|
3908
|
+
*/
|
|
3909
|
+
updateAnnotationColor(doc, page, annotation, color, which = 0) {
|
|
3910
|
+
this.logger.debug(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor', doc, page, annotation, color, which);
|
|
3911
|
+
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor', 'Begin', doc.id);
|
|
3912
|
+
const task = PdfTaskHelper.create();
|
|
3913
|
+
try {
|
|
3914
|
+
/* 1 ── sanity & native handles ────────────────────────────────────────── */
|
|
3915
|
+
const ctx = this.cache.getContext(doc.id);
|
|
3916
|
+
if (!ctx) {
|
|
3917
|
+
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor', 'End', doc.id);
|
|
3918
|
+
this.logger.warn(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor: doc closed');
|
|
3919
|
+
task.resolve(false);
|
|
3920
|
+
return task;
|
|
3921
|
+
}
|
|
3922
|
+
const pageCtx = ctx.acquirePage(page.index);
|
|
3923
|
+
const annotPtr = this.pdfiumModule.FPDFPage_GetAnnot(pageCtx.pagePtr, annotation.id);
|
|
3924
|
+
if (!annotPtr) {
|
|
3925
|
+
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor', 'End', doc.id);
|
|
3926
|
+
this.logger.warn(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor: annot not found');
|
|
3927
|
+
pageCtx.release();
|
|
3928
|
+
task.resolve(false);
|
|
3929
|
+
return task;
|
|
3930
|
+
}
|
|
3931
|
+
/* 2 ── wipe AP if it's a simple markup annotation ─────────────────────── */
|
|
3932
|
+
const shouldClearAP = annotation.type === PdfAnnotationSubtype.HIGHLIGHT ||
|
|
3933
|
+
annotation.type === PdfAnnotationSubtype.UNDERLINE ||
|
|
3934
|
+
annotation.type === PdfAnnotationSubtype.STRIKEOUT ||
|
|
3935
|
+
annotation.type === PdfAnnotationSubtype.SQUIGGLY;
|
|
3936
|
+
const ok = this.setAnnotationColor(annotPtr, color, shouldClearAP, which);
|
|
3937
|
+
/* 4 ── regenerate appearance & clean-up ───────────────────────────────── */
|
|
3938
|
+
if (ok) {
|
|
3939
|
+
this.pdfiumModule.FPDFPage_GenerateContent(pageCtx.pagePtr);
|
|
3940
|
+
}
|
|
3941
|
+
this.pdfiumModule.FPDFPage_CloseAnnot(annotPtr);
|
|
3942
|
+
pageCtx.release();
|
|
3943
|
+
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor', 'End', doc.id);
|
|
3944
|
+
task.resolve(!!ok);
|
|
3945
|
+
}
|
|
3946
|
+
catch (error) {
|
|
3947
|
+
this.logger.perf(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor', 'End', doc.id);
|
|
3948
|
+
this.logger.error(LOG_SOURCE$1, LOG_CATEGORY$1, 'setAnnotationColor: error', error);
|
|
3949
|
+
task.reject({
|
|
3950
|
+
code: PdfErrorCode.Unknown,
|
|
3951
|
+
message: `Failed to set annotation color: ${error instanceof Error ? error.message : String(error)}`,
|
|
3952
|
+
});
|
|
3953
|
+
}
|
|
3954
|
+
return task;
|
|
3955
|
+
}
|
|
3740
3956
|
/**
|
|
3741
3957
|
* Set the rect of specified annotation
|
|
3742
3958
|
* @param page - page info that the annotation is belonged to
|
|
@@ -4072,7 +4288,7 @@ class EngineRunner {
|
|
|
4072
4288
|
type: 'reject',
|
|
4073
4289
|
reason: {
|
|
4074
4290
|
code: PdfErrorCode.NotSupport,
|
|
4075
|
-
message:
|
|
4291
|
+
message: `engine method ${name} is not supported yet`,
|
|
4076
4292
|
},
|
|
4077
4293
|
};
|
|
4078
4294
|
const response = {
|
|
@@ -4139,12 +4355,18 @@ class EngineRunner {
|
|
|
4139
4355
|
case 'createPageAnnotation':
|
|
4140
4356
|
task = this.engine[name](...args);
|
|
4141
4357
|
break;
|
|
4358
|
+
case 'updatePageAnnotation':
|
|
4359
|
+
task = this.engine[name](...args);
|
|
4360
|
+
break;
|
|
4142
4361
|
case 'transformPageAnnotation':
|
|
4143
4362
|
task = this.engine[name](...args);
|
|
4144
4363
|
break;
|
|
4145
4364
|
case 'removePageAnnotation':
|
|
4146
4365
|
task = this.engine[name](...args);
|
|
4147
4366
|
break;
|
|
4367
|
+
case 'updateAnnotationColor':
|
|
4368
|
+
task = this.engine[name](...args);
|
|
4369
|
+
break;
|
|
4148
4370
|
case 'getPageTextRects':
|
|
4149
4371
|
task = this.engine[name](...args);
|
|
4150
4372
|
break;
|
|
@@ -4175,6 +4397,9 @@ class EngineRunner {
|
|
|
4175
4397
|
case 'extractText':
|
|
4176
4398
|
task = this.engine[name](...args);
|
|
4177
4399
|
break;
|
|
4400
|
+
case 'getTextSlices':
|
|
4401
|
+
task = this.engine[name](...args);
|
|
4402
|
+
break;
|
|
4178
4403
|
case 'getPageGlyphs':
|
|
4179
4404
|
task = this.engine[name](...args);
|
|
4180
4405
|
break;
|