kviewer 0.2.0 → 0.2.2
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/README.md +47 -0
- package/dist/module.d.mts +8 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +25 -3
- package/dist/runtime/annotation/engine/canvas-resolution.d.ts +7 -0
- package/dist/runtime/annotation/engine/canvas-resolution.js +21 -0
- package/dist/runtime/annotation/engine/editor/editor.d.ts +5 -0
- package/dist/runtime/annotation/engine/editor/editor.js +14 -0
- package/dist/runtime/annotation/engine/editor/selector.d.ts +13 -1
- package/dist/runtime/annotation/engine/editor/selector.js +60 -8
- package/dist/runtime/annotation/engine/painter.d.ts +31 -0
- package/dist/runtime/annotation/engine/painter.js +88 -2
- package/dist/runtime/annotation/engine/store.js +3 -0
- package/dist/runtime/annotation/engine/tools/arrow.js +0 -1
- package/dist/runtime/annotation/engine/tools/circle.js +0 -2
- package/dist/runtime/annotation/engine/tools/free-highlight.js +0 -2
- package/dist/runtime/annotation/engine/tools/freehand.js +0 -2
- package/dist/runtime/annotation/engine/tools/rectangle.js +0 -2
- package/dist/runtime/annotation/engine/types.d.ts +5 -0
- package/dist/runtime/annotation/font-style.d.ts +15 -0
- package/dist/runtime/annotation/font-style.js +19 -0
- package/dist/runtime/annotation/parsers/extractCheckboxStyles.d.ts +8 -0
- package/dist/runtime/annotation/parsers/extractCheckboxStyles.js +24 -1
- package/dist/runtime/annotation/pdf-export/annotation-flags.d.ts +8 -0
- package/dist/runtime/annotation/pdf-export/annotation-flags.js +5 -0
- package/dist/runtime/annotation/pdf-export/export-form-fields.js +3 -1
- package/dist/runtime/annotation/pdf-export/export.js +13 -1
- package/dist/runtime/annotation/pdf-export/parse_circle.js +3 -0
- package/dist/runtime/annotation/pdf-export/parse_freetext.js +31 -19
- package/dist/runtime/annotation/pdf-export/parse_highlight.js +3 -0
- package/dist/runtime/annotation/pdf-export/parse_ink.js +5 -1
- package/dist/runtime/annotation/pdf-export/parse_line.js +5 -1
- package/dist/runtime/annotation/pdf-export/parse_polyline.js +5 -1
- package/dist/runtime/annotation/pdf-export/parse_square.js +3 -0
- package/dist/runtime/annotation/pdf-export/parse_stamp.js +4 -2
- package/dist/runtime/annotation/pdf-export/parse_strikeout.js +3 -0
- package/dist/runtime/annotation/pdf-export/parse_text.js +3 -0
- package/dist/runtime/annotation/pdf-export/parse_underline.js +3 -0
- package/dist/runtime/annotation/pdf-export/unicode-font.d.ts +5 -0
- package/dist/runtime/annotation/pdf-export/unicode-font.js +31 -0
- package/dist/runtime/annotation/pdf-export/winansi.d.ts +17 -0
- package/dist/runtime/annotation/pdf-export/winansi.js +77 -0
- package/dist/runtime/annotation/pdf-import/decode_circle.js +0 -1
- package/dist/runtime/annotation/pdf-import/decode_ink.js +0 -1
- package/dist/runtime/annotation/pdf-import/decode_line.js +0 -1
- package/dist/runtime/annotation/pdf-import/decode_square.js +0 -1
- package/dist/runtime/annotation/pdf-import/extract_stamp_appearance.d.ts +12 -0
- package/dist/runtime/annotation/pdf-import/extract_stamp_appearance.js +17 -4
- package/dist/runtime/annotation/pdf-import/types.d.ts +2 -0
- package/dist/runtime/assets/fonts/LICENSE-LiberationSans +102 -0
- package/dist/runtime/assets/fonts/LiberationSans-Regular.ttf +0 -0
- package/dist/runtime/assets/kviewer.css +1 -1
- package/dist/runtime/components/AnnotationToolbar.vue +6 -4
- package/dist/runtime/components/PdfPage.d.vue.ts +16 -0
- package/dist/runtime/components/PdfPage.vue +170 -9
- package/dist/runtime/components/PdfPage.vue.d.ts +16 -0
- package/dist/runtime/components/PerfHud.d.vue.ts +3 -0
- package/dist/runtime/components/PerfHud.vue +97 -0
- package/dist/runtime/components/PerfHud.vue.d.ts +3 -0
- package/dist/runtime/components/ToolButton.vue +4 -1
- package/dist/runtime/components/Viewer.d.vue.ts +37 -2
- package/dist/runtime/components/Viewer.vue +208 -13
- package/dist/runtime/components/Viewer.vue.d.ts +37 -2
- package/dist/runtime/components/ViewerBar.d.vue.ts +21 -1
- package/dist/runtime/components/ViewerBar.vue +183 -101
- package/dist/runtime/components/ViewerBar.vue.d.ts +21 -1
- package/dist/runtime/components/ViewerTabs.d.vue.ts +10 -2
- package/dist/runtime/components/ViewerTabs.vue +13 -2
- package/dist/runtime/components/ViewerTabs.vue.d.ts +10 -2
- package/dist/runtime/components/form-fields/FormDropdown.vue +50 -19
- package/dist/runtime/components/form-fields/FormSignatureField.vue +4 -2
- package/dist/runtime/components/form-fields/FormTextField.vue +7 -18
- package/dist/runtime/components/modals/FreeTextModal.vue +6 -4
- package/dist/runtime/components/modals/SignatureDrawModal.vue +6 -4
- package/dist/runtime/components/panels/PlacedFieldSidebar.vue +67 -50
- package/dist/runtime/components/panels/SignaturePicker.vue +6 -4
- package/dist/runtime/components/panels/StampPicker.vue +3 -1
- package/dist/runtime/components/tools/AnnotationToolButton.d.vue.ts +10 -0
- package/dist/runtime/components/tools/AnnotationToolButton.vue +33 -0
- package/dist/runtime/components/tools/AnnotationToolButton.vue.d.ts +10 -0
- package/dist/runtime/components/tools/MarqueeTool.vue +3 -1
- package/dist/runtime/components/tools/PageSettings.vue +13 -11
- package/dist/runtime/components/tools/SearchTool.vue +12 -10
- package/dist/runtime/components/tools/ToolProperties.vue +7 -5
- package/dist/runtime/components/tools/ToolbarMenu.d.vue.ts +9 -0
- package/dist/runtime/components/tools/ToolbarMenu.vue +79 -0
- package/dist/runtime/components/tools/ToolbarMenu.vue.d.ts +9 -0
- package/dist/runtime/components/tools/ZoomControls.vue +17 -9
- package/dist/runtime/composables/canvas-limits.d.ts +22 -0
- package/dist/runtime/composables/canvas-limits.js +10 -0
- package/dist/runtime/composables/useFormFields.d.ts +6 -0
- package/dist/runtime/composables/useFormFields.js +28 -0
- package/dist/runtime/composables/useInertiaPanzoom.d.ts +10 -0
- package/dist/runtime/composables/useInertiaPanzoom.js +57 -10
- package/dist/runtime/composables/useKviewerI18n.d.ts +18 -0
- package/dist/runtime/composables/useKviewerI18n.js +29 -0
- package/dist/runtime/composables/usePageVirtualization.d.ts +11 -0
- package/dist/runtime/composables/usePageVirtualization.js +40 -0
- package/dist/runtime/composables/useScriptingManager.d.ts +8 -4
- package/dist/runtime/composables/useScriptingManager.js +2 -0
- package/dist/runtime/composables/useViewerState.d.ts +4 -0
- package/dist/runtime/composables/useViewerState.js +8 -0
- package/dist/runtime/embed/bridge-client.d.ts +9 -1
- package/dist/runtime/embed/bridge-client.js +13 -0
- package/dist/runtime/embed/bridge-host.d.ts +3 -0
- package/dist/runtime/embed/bridge-host.js +30 -8
- package/dist/runtime/embed/protocol.d.ts +21 -0
- package/dist/runtime/i18n/messages.d.ts +252 -0
- package/dist/runtime/i18n/messages.js +249 -0
- package/dist/runtime/public-types.d.ts +2 -0
- package/dist/runtime/toolbar-tools.d.ts +54 -0
- package/dist/runtime/toolbar-tools.js +79 -0
- package/dist/types.d.mts +1 -1
- package/package.json +14 -31
|
@@ -22,8 +22,6 @@ export class EditorFreeHighlight extends Editor {
|
|
|
22
22
|
this.getBgLayer().add(this.currentShapeGroup.konvaGroup);
|
|
23
23
|
const pos = this.konvaStage.getRelativePointerPosition();
|
|
24
24
|
this.line = new Konva.Line({
|
|
25
|
-
// do not scale strokes
|
|
26
|
-
strokeScaleEnabled: false,
|
|
27
25
|
stroke: this.currentAnnotation.style.color,
|
|
28
26
|
strokeWidth: this.currentAnnotation.style.strokeWidth,
|
|
29
27
|
opacity: this.currentAnnotation.style.opacity,
|
|
@@ -29,8 +29,6 @@ export class EditorFreeHand extends Editor {
|
|
|
29
29
|
}
|
|
30
30
|
const pos = this.konvaStage.getRelativePointerPosition();
|
|
31
31
|
this.line = new Konva.Line({
|
|
32
|
-
// do not scale strokes
|
|
33
|
-
strokeScaleEnabled: false,
|
|
34
32
|
stroke: this.currentAnnotation.style.color,
|
|
35
33
|
// Set the line color
|
|
36
34
|
strokeWidth: this.currentAnnotation.style.strokeWidth,
|
|
@@ -34,8 +34,6 @@ export class EditorRectangle extends Editor {
|
|
|
34
34
|
y: pos.y,
|
|
35
35
|
width: 0,
|
|
36
36
|
height: 0,
|
|
37
|
-
// do not scale strokes
|
|
38
|
-
strokeScaleEnabled: false,
|
|
39
37
|
visible: false,
|
|
40
38
|
stroke: this.currentAnnotation.style.color,
|
|
41
39
|
strokeWidth: this.currentAnnotation.style.strokeWidth || 2,
|
|
@@ -192,6 +192,11 @@ export interface FormFieldDefinition {
|
|
|
192
192
|
/** Signature-only: placeholder text shown on the unsigned widget.
|
|
193
193
|
* Defaults to 'Click to sign' when unset. */
|
|
194
194
|
promptText?: string;
|
|
195
|
+
/** Signature-only: the source PDF already carries a digital signature
|
|
196
|
+
* (`/V` is a `/Sig` dict) on this widget. The widget's appearance
|
|
197
|
+
* stream is rasterized after parse and seeded as the field value so
|
|
198
|
+
* the existing stamp is shown instead of the sign prompt. */
|
|
199
|
+
signedInSource?: boolean;
|
|
195
200
|
/** Signature-only: when this signature is filled, lock other fields in
|
|
196
201
|
* the form so they can no longer be edited. Mirrors PDF spec
|
|
197
202
|
* /Lock /Action: 'all' locks every other field; 'include' locks only
|
|
@@ -20,4 +20,19 @@ export interface DecodedFontStyle {
|
|
|
20
20
|
fontWeight: 'normal' | 'bold';
|
|
21
21
|
fontStyle: 'normal' | 'italic';
|
|
22
22
|
}
|
|
23
|
+
export declare const FONT_BORDER_SIZE = 2;
|
|
24
|
+
export declare const LINE_HEIGHT_FACTOR = 1.35;
|
|
25
|
+
export declare const DEFAULT_FIELD_FONT_SIZE = 9;
|
|
26
|
+
/**
|
|
27
|
+
* Compute the rendered font size (in PDF points) for a form field, matching
|
|
28
|
+
* pdf.js's `_setTextStyle` so text never gets clipped at the top/bottom of a
|
|
29
|
+
* short field. A declared size of 0 / undefined means the widget's `/DA` had
|
|
30
|
+
* no explicit size ("auto") — we fall back to 9pt before fitting, exactly
|
|
31
|
+
* like pdf.js. Single-line fields shrink the font to fit the field height;
|
|
32
|
+
* multi-line fields fit N lines of the declared size and shrink only if the
|
|
33
|
+
* per-line height is smaller than declared.
|
|
34
|
+
*/
|
|
35
|
+
export declare function computeFieldFontSize(declaredSize: number | undefined, rectHeightPts: number, opts?: {
|
|
36
|
+
multiLine?: boolean;
|
|
37
|
+
}): number;
|
|
23
38
|
export declare function decodeFontName(fontName: string | undefined): DecodedFontStyle;
|
|
@@ -32,6 +32,25 @@ const DEFAULT_STYLE = {
|
|
|
32
32
|
fontWeight: "normal",
|
|
33
33
|
fontStyle: "normal"
|
|
34
34
|
};
|
|
35
|
+
export const FONT_BORDER_SIZE = 2;
|
|
36
|
+
export const LINE_HEIGHT_FACTOR = 1.35;
|
|
37
|
+
export const DEFAULT_FIELD_FONT_SIZE = 9;
|
|
38
|
+
export function computeFieldFontSize(declaredSize, rectHeightPts, opts) {
|
|
39
|
+
const declared = declaredSize && declaredSize > 0 ? declaredSize : DEFAULT_FIELD_FONT_SIZE;
|
|
40
|
+
const rectHeight = Math.abs(rectHeightPts - FONT_BORDER_SIZE);
|
|
41
|
+
let size;
|
|
42
|
+
if (opts?.multiLine) {
|
|
43
|
+
const numberOfLines = Math.max(
|
|
44
|
+
1,
|
|
45
|
+
Math.round(rectHeight / (LINE_HEIGHT_FACTOR * declared))
|
|
46
|
+
);
|
|
47
|
+
const lineHeight = rectHeight / numberOfLines;
|
|
48
|
+
size = Math.min(declared, lineHeight / LINE_HEIGHT_FACTOR);
|
|
49
|
+
} else {
|
|
50
|
+
size = Math.min(declared, rectHeight / LINE_HEIGHT_FACTOR);
|
|
51
|
+
}
|
|
52
|
+
return Math.round(10 * size) / 10;
|
|
53
|
+
}
|
|
35
54
|
export function decodeFontName(fontName) {
|
|
36
55
|
if (!fontName) return DEFAULT_STYLE;
|
|
37
56
|
const name = fontName.startsWith("/") ? fontName.slice(1) : fontName;
|
|
@@ -10,6 +10,14 @@ import type { CheckboxStyle } from '../engine/types.js';
|
|
|
10
10
|
* wins.
|
|
11
11
|
*/
|
|
12
12
|
export declare function extractCheckboxStyles(pdfBytes: Uint8Array | ArrayBuffer): Promise<Map<string, CheckboxStyle>>;
|
|
13
|
+
/**
|
|
14
|
+
* Walk the AcroForm and collect the fully qualified names of signature
|
|
15
|
+
* fields that are already digitally signed (`/V` holds a `/Sig` dict).
|
|
16
|
+
* pdf.js deliberately nulls a signature widget's fieldValue before
|
|
17
|
+
* shipping it to the main thread (the `/Sig` dict is non-serializable),
|
|
18
|
+
* so the signed state is only reachable through this side-channel parse.
|
|
19
|
+
*/
|
|
20
|
+
export declare function extractSignedSignatureNames(pdfBytes: Uint8Array | ArrayBuffer): Promise<Set<string>>;
|
|
13
21
|
/**
|
|
14
22
|
* Walk the AcroForm and extract push-button captions from `/MK /CA`.
|
|
15
23
|
* pdf.js exposes neither the caption nor a button label, so without this
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PDFButton, PDFCheckBox, PDFDocument, PDFDict, PDFHexString, PDFName, PDFString } from "pdf-lib";
|
|
1
|
+
import { PDFButton, PDFCheckBox, PDFDocument, PDFDict, PDFHexString, PDFName, PDFSignature, PDFString } from "pdf-lib";
|
|
2
2
|
import { captionToStyle } from "../checkbox-styles.js";
|
|
3
3
|
export async function extractCheckboxStyles(pdfBytes) {
|
|
4
4
|
const out = /* @__PURE__ */ new Map();
|
|
@@ -38,6 +38,29 @@ export async function extractCheckboxStyles(pdfBytes) {
|
|
|
38
38
|
}
|
|
39
39
|
return out;
|
|
40
40
|
}
|
|
41
|
+
export async function extractSignedSignatureNames(pdfBytes) {
|
|
42
|
+
const out = /* @__PURE__ */ new Set();
|
|
43
|
+
let doc;
|
|
44
|
+
try {
|
|
45
|
+
doc = await PDFDocument.load(pdfBytes, { ignoreEncryption: true });
|
|
46
|
+
} catch {
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
let form;
|
|
50
|
+
try {
|
|
51
|
+
form = doc.getForm();
|
|
52
|
+
} catch {
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
for (const field of form.getFields()) {
|
|
56
|
+
if (!(field instanceof PDFSignature)) continue;
|
|
57
|
+
const name = field.getName();
|
|
58
|
+
if (!name) continue;
|
|
59
|
+
const value = field.acroField.getInheritableAttribute(PDFName.of("V"));
|
|
60
|
+
if (value != null) out.add(name);
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
41
64
|
export async function extractButtonCaptions(pdfBytes) {
|
|
42
65
|
const out = /* @__PURE__ */ new Map();
|
|
43
66
|
let doc;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PDFNumber } from 'pdf-lib';
|
|
2
|
+
/** /F entry for exported annotations: visible AND printed (PDF 32000-1 §12.5.3).
|
|
3
|
+
* Annotations without the Print bit are silently dropped from print output,
|
|
4
|
+
* so every exporter must set this on each annotation dict it creates. */
|
|
5
|
+
export declare const PRINT_FLAG: PDFNumber;
|
|
6
|
+
/** Print + Locked — stamps stay printable but can't be moved/deleted in
|
|
7
|
+
* other viewers, matching the previous Locked-only behavior. */
|
|
8
|
+
export declare const PRINT_LOCKED_FLAG: PDFNumber;
|
|
@@ -272,7 +272,9 @@ async function createSignatureField(pdfDoc, page, def, fv) {
|
|
|
272
272
|
Rect: [x1, y1, x2, y2],
|
|
273
273
|
P: page.ref,
|
|
274
274
|
Parent: fieldRef,
|
|
275
|
-
|
|
275
|
+
// AnnotationFlags.Print is already the bit value (4) — shifting it
|
|
276
|
+
// again would yield 16 = NoZoom.
|
|
277
|
+
F: AnnotationFlags.Print,
|
|
276
278
|
AP: { N: appearanceRef }
|
|
277
279
|
});
|
|
278
280
|
const widgetRef = context.register(widgetDict);
|
|
@@ -2,6 +2,7 @@ import { degrees, PDFArray, PDFDict, PDFDocument, PDFName, PDFRef, PDFString } f
|
|
|
2
2
|
import { PdfjsAnnotationType } from "../engine/types.js";
|
|
3
3
|
import { pageTransformFromPdfLibPage } from "../pdf-import/transform.js";
|
|
4
4
|
import { writeFormFieldsToPdf } from "./export-form-fields.js";
|
|
5
|
+
import { getUnicodeFont } from "./unicode-font.js";
|
|
5
6
|
import { CircleParser } from "./parse_circle.js";
|
|
6
7
|
import { FreeTextParser } from "./parse_freetext.js";
|
|
7
8
|
import { HighlightParser } from "./parse_highlight.js";
|
|
@@ -299,5 +300,16 @@ export async function exportAnnotationsToPdf({
|
|
|
299
300
|
await parseAnnotationToPdf(annotation, page, pdfDoc);
|
|
300
301
|
}
|
|
301
302
|
}
|
|
302
|
-
return pdfDoc
|
|
303
|
+
return savePdf(pdfDoc);
|
|
304
|
+
}
|
|
305
|
+
async function savePdf(pdfDoc) {
|
|
306
|
+
try {
|
|
307
|
+
return await pdfDoc.save();
|
|
308
|
+
} catch (err) {
|
|
309
|
+
const message = err instanceof Error ? err.message : "";
|
|
310
|
+
if (!/cannot encode/i.test(message)) throw err;
|
|
311
|
+
const font = await getUnicodeFont(pdfDoc);
|
|
312
|
+
pdfDoc.getForm().updateFieldAppearances(font);
|
|
313
|
+
return pdfDoc.save({ updateFieldAppearances: false });
|
|
314
|
+
}
|
|
303
315
|
}
|
|
@@ -3,6 +3,7 @@ import { convertKonvaRectToPdfRect, rgbToPdfColor, stringToPDFHexString } from "
|
|
|
3
3
|
import { pageTransformFromPdfLibPage } from "../pdf-import/transform.js";
|
|
4
4
|
import { AnnotationParser } from "./parse.js";
|
|
5
5
|
import { computeBoundsFromKonvaString } from "./parse_utils.js";
|
|
6
|
+
import { PRINT_FLAG } from "./annotation-flags.js";
|
|
6
7
|
const UNKNOWN_USER = "Unknown user";
|
|
7
8
|
export class CircleParser extends AnnotationParser {
|
|
8
9
|
async parse() {
|
|
@@ -14,6 +15,7 @@ export class CircleParser extends AnnotationParser {
|
|
|
14
15
|
const mainAnn = context.obj({
|
|
15
16
|
Type: PDFName.of("Annot"),
|
|
16
17
|
Subtype: PDFName.of("Circle"),
|
|
18
|
+
F: PRINT_FLAG,
|
|
17
19
|
Rect: rect,
|
|
18
20
|
C: rgbToPdfColor(annotation.color || void 0),
|
|
19
21
|
T: stringToPDFHexString(annotation.title || UNKNOWN_USER),
|
|
@@ -28,6 +30,7 @@ export class CircleParser extends AnnotationParser {
|
|
|
28
30
|
const replyAnn = context.obj({
|
|
29
31
|
Type: PDFName.of("Annot"),
|
|
30
32
|
Subtype: PDFName.of("Text"),
|
|
33
|
+
F: PRINT_FLAG,
|
|
31
34
|
Rect: rect,
|
|
32
35
|
Contents: stringToPDFHexString(comment.content),
|
|
33
36
|
T: stringToPDFHexString(comment.title || UNKNOWN_USER),
|
|
@@ -3,6 +3,9 @@ import { convertKonvaRectToPdfRect, rgbToPdfColor, stringToPDFHexString } from "
|
|
|
3
3
|
import { convertCanvasRectToPdf, pageTransformFromPdfLibPage } from "../pdf-import/transform.js";
|
|
4
4
|
import { AnnotationParser } from "./parse.js";
|
|
5
5
|
import { formAppearanceMatrix } from "./parse_utils.js";
|
|
6
|
+
import { encodeWinAnsi, isWinAnsiEncodable } from "./winansi.js";
|
|
7
|
+
import { getUnicodeFont } from "./unicode-font.js";
|
|
8
|
+
import { PRINT_FLAG } from "./annotation-flags.js";
|
|
6
9
|
const UNKNOWN_USER = "Unknown user";
|
|
7
10
|
function formatPdfNumber(value) {
|
|
8
11
|
if (!Number.isFinite(value)) return "0";
|
|
@@ -63,41 +66,50 @@ export class FreeTextParser extends AnnotationParser {
|
|
|
63
66
|
];
|
|
64
67
|
const appearanceWidth = Math.max(1, textWidth);
|
|
65
68
|
const appearanceHeight = Math.max(1, textHeight);
|
|
69
|
+
const useUnicodeFont = !isWinAnsiEncodable(text);
|
|
70
|
+
let unicodeFont = null;
|
|
71
|
+
if (useUnicodeFont) {
|
|
72
|
+
unicodeFont = await getUnicodeFont(pdfDoc);
|
|
73
|
+
}
|
|
74
|
+
const fontResourceName = useUnicodeFont ? "FUni" : "Helvetica";
|
|
66
75
|
const commands = ["q"];
|
|
67
76
|
for (let i = 0; i < lines.length; i++) {
|
|
68
77
|
const line = lines[i] ?? "";
|
|
69
78
|
if (line.length === 0 && i < lines.length - 1) continue;
|
|
70
79
|
const lineY = appearanceHeight - (i + 0.8) * lineHeight;
|
|
71
80
|
let lineX = 0;
|
|
72
|
-
if (quadding === 1) {
|
|
73
|
-
const lineWidth = line.length * estimatedCharWidth;
|
|
74
|
-
lineX = Math.max(0, (appearanceWidth - lineWidth) / 2);
|
|
75
|
-
} else if (quadding === 2) {
|
|
76
|
-
const lineWidth = line.length * estimatedCharWidth;
|
|
77
|
-
lineX = Math.max(0, appearanceWidth - lineWidth);
|
|
81
|
+
if (quadding === 1 || quadding === 2) {
|
|
82
|
+
const lineWidth = unicodeFont ? unicodeFont.widthOfTextAtSize(line, fontSize) : line.length * estimatedCharWidth;
|
|
83
|
+
lineX = quadding === 1 ? Math.max(0, (appearanceWidth - lineWidth) / 2) : Math.max(0, appearanceWidth - lineWidth);
|
|
78
84
|
}
|
|
85
|
+
const showText = unicodeFont ? `${unicodeFont.encodeText(line).toString()} Tj` : `(${escapePdfString(line)}) Tj`;
|
|
79
86
|
commands.push(
|
|
80
87
|
"BT",
|
|
81
|
-
|
|
88
|
+
`/${fontResourceName} ${formatPdfNumber(fontSize)} Tf`,
|
|
82
89
|
`${formatPdfNumber(r)} ${formatPdfNumber(g)} ${formatPdfNumber(b)} rg`,
|
|
83
90
|
`${formatPdfNumber(lineX)} ${formatPdfNumber(lineY)} Td`,
|
|
84
|
-
|
|
91
|
+
showText,
|
|
85
92
|
"ET"
|
|
86
93
|
);
|
|
87
94
|
}
|
|
88
95
|
commands.push("Q");
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
let fontResourceRef;
|
|
97
|
+
if (unicodeFont) {
|
|
98
|
+
fontResourceRef = unicodeFont.ref;
|
|
99
|
+
} else {
|
|
100
|
+
fontResourceRef = context.register(context.obj({
|
|
101
|
+
Type: PDFName.of("Font"),
|
|
102
|
+
Subtype: PDFName.of("Type1"),
|
|
103
|
+
BaseFont: PDFName.of("Helvetica"),
|
|
104
|
+
Encoding: PDFName.of("WinAnsiEncoding")
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
96
107
|
const appearanceMatrix = formAppearanceMatrix(
|
|
97
108
|
pageTransform.rotation,
|
|
98
109
|
appearanceWidth,
|
|
99
110
|
appearanceHeight
|
|
100
111
|
);
|
|
112
|
+
const streamBytes = unicodeFont ? new TextEncoder().encode(commands.join("\n")) : encodeWinAnsi(commands.join("\n"));
|
|
101
113
|
const appearanceStream = PDFRawStream.of(
|
|
102
114
|
context.obj({
|
|
103
115
|
Type: PDFName.of("XObject"),
|
|
@@ -105,10 +117,10 @@ export class FreeTextParser extends AnnotationParser {
|
|
|
105
117
|
BBox: context.obj([0, 0, appearanceWidth, appearanceHeight]),
|
|
106
118
|
Matrix: context.obj(appearanceMatrix.map((n) => PDFNumber.of(n))),
|
|
107
119
|
Resources: context.obj({
|
|
108
|
-
Font: context.obj({
|
|
120
|
+
Font: context.obj({ [fontResourceName]: fontResourceRef })
|
|
109
121
|
})
|
|
110
122
|
}),
|
|
111
|
-
|
|
123
|
+
streamBytes
|
|
112
124
|
);
|
|
113
125
|
const appearanceRef = context.register(appearanceStream);
|
|
114
126
|
const ap = context.obj({ N: appearanceRef });
|
|
@@ -116,6 +128,7 @@ export class FreeTextParser extends AnnotationParser {
|
|
|
116
128
|
const mainAnn = context.obj({
|
|
117
129
|
Type: PDFName.of("Annot"),
|
|
118
130
|
Subtype: PDFName.of("FreeText"),
|
|
131
|
+
F: PRINT_FLAG,
|
|
119
132
|
Rect: rect,
|
|
120
133
|
NM: PDFString.of(annotation.id),
|
|
121
134
|
Contents: stringToPDFHexString(text),
|
|
@@ -125,8 +138,6 @@ export class FreeTextParser extends AnnotationParser {
|
|
|
125
138
|
M: PDFString.of(annotation.date || ""),
|
|
126
139
|
C: context.obj(rgbToPdfColor(annotation.color || void 0)),
|
|
127
140
|
Border: context.obj([0, 0, 0]),
|
|
128
|
-
F: PDFNumber.of(4),
|
|
129
|
-
// Print flag
|
|
130
141
|
AP: ap
|
|
131
142
|
});
|
|
132
143
|
const mainAnnRef = context.register(mainAnn);
|
|
@@ -135,6 +146,7 @@ export class FreeTextParser extends AnnotationParser {
|
|
|
135
146
|
const replyAnn = context.obj({
|
|
136
147
|
Type: PDFName.of("Annot"),
|
|
137
148
|
Subtype: PDFName.of("Text"),
|
|
149
|
+
F: PRINT_FLAG,
|
|
138
150
|
Rect: convertKonvaRectToPdfRect(annotation.konvaClientRect, pageTransform),
|
|
139
151
|
Contents: stringToPDFHexString(comment.content),
|
|
140
152
|
T: stringToPDFHexString(comment.title || UNKNOWN_USER),
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
pageTransformFromPdfLibPage
|
|
7
7
|
} from "../pdf-import/transform.js";
|
|
8
8
|
import { AnnotationParser } from "./parse.js";
|
|
9
|
+
import { PRINT_FLAG } from "./annotation-flags.js";
|
|
9
10
|
const UNKNOWN_USER = "Unknown user";
|
|
10
11
|
function formatPdfNumber(value) {
|
|
11
12
|
if (!Number.isFinite(value)) return "0";
|
|
@@ -115,6 +116,7 @@ export class HighlightParser extends AnnotationParser {
|
|
|
115
116
|
const mainAnn = context.obj({
|
|
116
117
|
Type: PDFName.of("Annot"),
|
|
117
118
|
Subtype: PDFName.of("Highlight"),
|
|
119
|
+
F: PRINT_FLAG,
|
|
118
120
|
Rect: rect,
|
|
119
121
|
QuadPoints: context.obj(quadPoints),
|
|
120
122
|
C: context.obj(color),
|
|
@@ -131,6 +133,7 @@ export class HighlightParser extends AnnotationParser {
|
|
|
131
133
|
const replyAnn = context.obj({
|
|
132
134
|
Type: PDFName.of("Annot"),
|
|
133
135
|
Subtype: PDFName.of("Text"),
|
|
136
|
+
F: PRINT_FLAG,
|
|
134
137
|
Rect: convertKonvaRectToPdfRect(annotation.konvaClientRect, pageTransform),
|
|
135
138
|
Contents: stringToPDFHexString(comment.content),
|
|
136
139
|
T: stringToPDFHexString(comment.title || UNKNOWN_USER),
|
|
@@ -2,6 +2,7 @@ import { PDFName, PDFNumber, PDFRawStream, PDFString } from "pdf-lib";
|
|
|
2
2
|
import { convertKonvaRectToPdfRect, rgbToPdfColor, stringToPDFHexString } from "../engine/utils.js";
|
|
3
3
|
import { convertCanvasPointToPdf, pageTransformFromPdfLibPage } from "../pdf-import/transform.js";
|
|
4
4
|
import { AnnotationParser } from "./parse.js";
|
|
5
|
+
import { PRINT_FLAG } from "./annotation-flags.js";
|
|
5
6
|
const UNKNOWN_USER = "Unknown user";
|
|
6
7
|
function formatPdfNumber(value) {
|
|
7
8
|
if (!Number.isFinite(value)) return "0";
|
|
@@ -45,7 +46,8 @@ export class InkParser extends AnnotationParser {
|
|
|
45
46
|
transformedPaths.map((path) => context.obj(path))
|
|
46
47
|
);
|
|
47
48
|
const firstLine = lines[0]?.attrs || {};
|
|
48
|
-
const
|
|
49
|
+
const strokeScale = (Math.abs(scaleX) + Math.abs(scaleY)) / 2;
|
|
50
|
+
const strokeWidth = (firstLine.strokeWidth ?? 1) * strokeScale;
|
|
49
51
|
const opacity = firstLine.opacity ?? 1;
|
|
50
52
|
const color = firstLine.stroke ?? annotation.color ?? "rgb(255, 0, 0)";
|
|
51
53
|
const [r, g, b] = rgbToPdfColor(color);
|
|
@@ -120,6 +122,7 @@ export class InkParser extends AnnotationParser {
|
|
|
120
122
|
const mainAnn = context.obj({
|
|
121
123
|
Type: PDFName.of("Annot"),
|
|
122
124
|
Subtype: PDFName.of("Ink"),
|
|
125
|
+
F: PRINT_FLAG,
|
|
123
126
|
Rect: rect,
|
|
124
127
|
InkList: inkList,
|
|
125
128
|
C: context.obj([PDFNumber.of(r), PDFNumber.of(g), PDFNumber.of(b)]),
|
|
@@ -138,6 +141,7 @@ export class InkParser extends AnnotationParser {
|
|
|
138
141
|
const replyAnn = context.obj({
|
|
139
142
|
Type: PDFName.of("Annot"),
|
|
140
143
|
Subtype: PDFName.of("Text"),
|
|
144
|
+
F: PRINT_FLAG,
|
|
141
145
|
Rect: convertKonvaRectToPdfRect(annotation.konvaClientRect, pageTransform),
|
|
142
146
|
Contents: stringToPDFHexString(comment.content),
|
|
143
147
|
T: stringToPDFHexString(comment.title || UNKNOWN_USER),
|
|
@@ -2,6 +2,7 @@ import { PDFName, PDFNumber, PDFRawStream, PDFString } from "pdf-lib";
|
|
|
2
2
|
import { convertKonvaRectToPdfRect, rgbToPdfColor, stringToPDFHexString } from "../engine/utils.js";
|
|
3
3
|
import { convertCanvasPointToPdf, pageTransformFromPdfLibPage } from "../pdf-import/transform.js";
|
|
4
4
|
import { AnnotationParser } from "./parse.js";
|
|
5
|
+
import { PRINT_FLAG } from "./annotation-flags.js";
|
|
5
6
|
const UNKNOWN_USER = "Unknown user";
|
|
6
7
|
function formatPdfNumber(value) {
|
|
7
8
|
if (!Number.isFinite(value)) return "0";
|
|
@@ -39,7 +40,8 @@ export class LineParser extends AnnotationParser {
|
|
|
39
40
|
transformedPaths.map((path) => context.obj(path))
|
|
40
41
|
);
|
|
41
42
|
const firstLine = lines[0]?.attrs || {};
|
|
42
|
-
const
|
|
43
|
+
const strokeScale = (Math.abs(scaleX) + Math.abs(scaleY)) / 2;
|
|
44
|
+
const strokeWidth = (firstLine.strokeWidth ?? 1) * strokeScale;
|
|
43
45
|
const opacity = firstLine.opacity ?? 1;
|
|
44
46
|
const color = firstLine.stroke ?? annotation.color ?? "rgb(255, 0, 0)";
|
|
45
47
|
const [r, g, b] = rgbToPdfColor(color);
|
|
@@ -158,6 +160,7 @@ export class LineParser extends AnnotationParser {
|
|
|
158
160
|
const mainAnn = context.obj({
|
|
159
161
|
Type: PDFName.of("Annot"),
|
|
160
162
|
Subtype: PDFName.of("Ink"),
|
|
163
|
+
F: PRINT_FLAG,
|
|
161
164
|
Rect: rect,
|
|
162
165
|
InkList: inkList,
|
|
163
166
|
C: context.obj([PDFNumber.of(r), PDFNumber.of(g), PDFNumber.of(b)]),
|
|
@@ -176,6 +179,7 @@ export class LineParser extends AnnotationParser {
|
|
|
176
179
|
const replyAnn = context.obj({
|
|
177
180
|
Type: PDFName.of("Annot"),
|
|
178
181
|
Subtype: PDFName.of("Text"),
|
|
182
|
+
F: PRINT_FLAG,
|
|
179
183
|
Rect: convertKonvaRectToPdfRect(annotation.konvaClientRect, pageTransform),
|
|
180
184
|
Contents: stringToPDFHexString(comment.content),
|
|
181
185
|
T: stringToPDFHexString(comment.title || UNKNOWN_USER),
|
|
@@ -3,6 +3,7 @@ import { convertKonvaRectToPdfRect, rgbToPdfColor, stringToPDFHexString } from "
|
|
|
3
3
|
import { convertCanvasPointToPdf, pageTransformFromPdfLibPage } from "../pdf-import/transform.js";
|
|
4
4
|
import { AnnotationParser } from "./parse.js";
|
|
5
5
|
import { computeBoundsFromKonvaString } from "./parse_utils.js";
|
|
6
|
+
import { PRINT_FLAG } from "./annotation-flags.js";
|
|
6
7
|
const UNKNOWN_USER = "Unknown user";
|
|
7
8
|
function parseSvgPathToPoints(data) {
|
|
8
9
|
const commands = data.match(/[a-z][^a-z]*/gi) || [];
|
|
@@ -51,7 +52,8 @@ export class PolylineParser extends AnnotationParser {
|
|
|
51
52
|
})
|
|
52
53
|
);
|
|
53
54
|
const firstLine = lines[0]?.attrs || {};
|
|
54
|
-
const
|
|
55
|
+
const strokeScale = (Math.abs(scaleX) + Math.abs(scaleY)) / 2;
|
|
56
|
+
const strokeWidth = (firstLine.strokeWidth ?? 1) * strokeScale;
|
|
55
57
|
const opacity = firstLine.opacity ?? 1;
|
|
56
58
|
const color = firstLine.stroke ?? annotation.color ?? "rgb(255, 0, 0)";
|
|
57
59
|
const [r, g, b] = rgbToPdfColor(color);
|
|
@@ -62,6 +64,7 @@ export class PolylineParser extends AnnotationParser {
|
|
|
62
64
|
const mainAnn = context.obj({
|
|
63
65
|
Type: PDFName.of("Annot"),
|
|
64
66
|
Subtype: PDFName.of("Ink"),
|
|
67
|
+
F: PRINT_FLAG,
|
|
65
68
|
// Compute Rect from konvaString so it reflects the current position
|
|
66
69
|
// even when konvaClientRect is stale after a move/resize.
|
|
67
70
|
Rect: convertKonvaRectToPdfRect(computeBoundsFromKonvaString(annotation.konvaString) ?? annotation.konvaClientRect, pageTransform),
|
|
@@ -81,6 +84,7 @@ export class PolylineParser extends AnnotationParser {
|
|
|
81
84
|
const replyAnn = context.obj({
|
|
82
85
|
Type: PDFName.of("Annot"),
|
|
83
86
|
Subtype: PDFName.of("Text"),
|
|
87
|
+
F: PRINT_FLAG,
|
|
84
88
|
Rect: convertKonvaRectToPdfRect(computeBoundsFromKonvaString(annotation.konvaString) ?? annotation.konvaClientRect, pageTransform),
|
|
85
89
|
Contents: stringToPDFHexString(comment.content),
|
|
86
90
|
T: stringToPDFHexString(comment.title || UNKNOWN_USER),
|
|
@@ -3,6 +3,7 @@ import { convertKonvaRectToPdfRect, rgbToPdfColor, stringToPDFHexString } from "
|
|
|
3
3
|
import { pageTransformFromPdfLibPage } from "../pdf-import/transform.js";
|
|
4
4
|
import { AnnotationParser } from "./parse.js";
|
|
5
5
|
import { computeBoundsFromKonvaString } from "./parse_utils.js";
|
|
6
|
+
import { PRINT_FLAG } from "./annotation-flags.js";
|
|
6
7
|
const UNKNOWN_USER = "Unknown user";
|
|
7
8
|
export class SquareParser extends AnnotationParser {
|
|
8
9
|
async parse() {
|
|
@@ -14,6 +15,7 @@ export class SquareParser extends AnnotationParser {
|
|
|
14
15
|
const mainAnn = context.obj({
|
|
15
16
|
Type: PDFName.of("Annot"),
|
|
16
17
|
Subtype: PDFName.of("Square"),
|
|
18
|
+
F: PRINT_FLAG,
|
|
17
19
|
Rect: rect,
|
|
18
20
|
C: rgbToPdfColor(annotation.color || void 0),
|
|
19
21
|
T: stringToPDFHexString(annotation.title || UNKNOWN_USER),
|
|
@@ -28,6 +30,7 @@ export class SquareParser extends AnnotationParser {
|
|
|
28
30
|
const replyAnn = context.obj({
|
|
29
31
|
Type: PDFName.of("Annot"),
|
|
30
32
|
Subtype: PDFName.of("Text"),
|
|
33
|
+
F: PRINT_FLAG,
|
|
31
34
|
Rect: rect,
|
|
32
35
|
Contents: stringToPDFHexString(comment.content),
|
|
33
36
|
T: stringToPDFHexString(comment.title || UNKNOWN_USER),
|
|
@@ -3,6 +3,7 @@ import { convertKonvaRectToPdfRect, stringToPDFHexString } from "../engine/utils
|
|
|
3
3
|
import { pageTransformFromPdfLibPage } from "../pdf-import/transform.js";
|
|
4
4
|
import { AnnotationParser } from "./parse.js";
|
|
5
5
|
import { computeBoundsFromKonvaString, formAppearanceMatrix } from "./parse_utils.js";
|
|
6
|
+
import { PRINT_FLAG, PRINT_LOCKED_FLAG } from "./annotation-flags.js";
|
|
6
7
|
const UNKNOWN_USER = "Unknown user";
|
|
7
8
|
const SVG_RASTER_SCALE = 4;
|
|
8
9
|
const MAX_RASTER_EDGE = 4096;
|
|
@@ -170,13 +171,13 @@ export class StampParser extends AnnotationParser {
|
|
|
170
171
|
const stampAnnDict = {
|
|
171
172
|
Type: PDFName.of("Annot"),
|
|
172
173
|
Subtype: PDFName.of("Stamp"),
|
|
174
|
+
F: PRINT_LOCKED_FLAG,
|
|
173
175
|
Rect: rect,
|
|
174
176
|
NM: PDFString.of(annotation.id),
|
|
175
177
|
Contents: stringToPDFHexString(annotation.contentsObj?.text || ""),
|
|
176
178
|
T: stringToPDFHexString(annotation.title || UNKNOWN_USER),
|
|
177
179
|
M: PDFString.of(annotation.date || ""),
|
|
178
|
-
Open: false
|
|
179
|
-
F: PDFNumber.of(128)
|
|
180
|
+
Open: false
|
|
180
181
|
};
|
|
181
182
|
if (apDict) {
|
|
182
183
|
stampAnnDict.AP = apDict;
|
|
@@ -188,6 +189,7 @@ export class StampParser extends AnnotationParser {
|
|
|
188
189
|
const replyAnn = context.obj({
|
|
189
190
|
Type: PDFName.of("Annot"),
|
|
190
191
|
Subtype: PDFName.of("Text"),
|
|
192
|
+
F: PRINT_FLAG,
|
|
191
193
|
Rect: convertKonvaRectToPdfRect(bounds ?? annotation.konvaClientRect, pageTransform),
|
|
192
194
|
Contents: stringToPDFHexString(comment.content),
|
|
193
195
|
T: stringToPDFHexString(comment.title || UNKNOWN_USER),
|
|
@@ -2,6 +2,7 @@ import { PDFName, PDFString } from "pdf-lib";
|
|
|
2
2
|
import { convertKonvaRectToPdfRect, rgbToPdfColor, stringToPDFHexString } from "../engine/utils.js";
|
|
3
3
|
import { convertCanvasPointToPdf, pageTransformFromPdfLibPage } from "../pdf-import/transform.js";
|
|
4
4
|
import { AnnotationParser } from "./parse.js";
|
|
5
|
+
import { PRINT_FLAG } from "./annotation-flags.js";
|
|
5
6
|
const UNKNOWN_USER = "Unknown user";
|
|
6
7
|
function buildQuadPoints(konvaString, t) {
|
|
7
8
|
const konvaGroup = JSON.parse(konvaString);
|
|
@@ -29,6 +30,7 @@ export class StrikeOutParser extends AnnotationParser {
|
|
|
29
30
|
const mainAnn = context.obj({
|
|
30
31
|
Type: PDFName.of("Annot"),
|
|
31
32
|
Subtype: PDFName.of("StrikeOut"),
|
|
33
|
+
F: PRINT_FLAG,
|
|
32
34
|
Rect: convertKonvaRectToPdfRect(annotation.konvaClientRect, pageTransform),
|
|
33
35
|
QuadPoints: quadPoints,
|
|
34
36
|
C: rgbToPdfColor(annotation.color || void 0),
|
|
@@ -43,6 +45,7 @@ export class StrikeOutParser extends AnnotationParser {
|
|
|
43
45
|
const replyAnn = context.obj({
|
|
44
46
|
Type: PDFName.of("Annot"),
|
|
45
47
|
Subtype: PDFName.of("Text"),
|
|
48
|
+
F: PRINT_FLAG,
|
|
46
49
|
Rect: convertKonvaRectToPdfRect(annotation.konvaClientRect, pageTransform),
|
|
47
50
|
Contents: stringToPDFHexString(comment.content),
|
|
48
51
|
T: stringToPDFHexString(comment.title || UNKNOWN_USER),
|
|
@@ -3,6 +3,7 @@ import { convertKonvaRectToPdfRect, rgbToPdfColor, stringToPDFHexString } from "
|
|
|
3
3
|
import { pageTransformFromPdfLibPage } from "../pdf-import/transform.js";
|
|
4
4
|
import { AnnotationParser } from "./parse.js";
|
|
5
5
|
import { computeBoundsFromKonvaString } from "./parse_utils.js";
|
|
6
|
+
import { PRINT_FLAG } from "./annotation-flags.js";
|
|
6
7
|
const UNKNOWN_USER = "Unknown user";
|
|
7
8
|
export class TextParser extends AnnotationParser {
|
|
8
9
|
async parse() {
|
|
@@ -14,6 +15,7 @@ export class TextParser extends AnnotationParser {
|
|
|
14
15
|
const mainAnn = context.obj({
|
|
15
16
|
Type: PDFName.of("Annot"),
|
|
16
17
|
Subtype: PDFName.of("Text"),
|
|
18
|
+
F: PRINT_FLAG,
|
|
17
19
|
Rect: rect,
|
|
18
20
|
NM: PDFString.of(annotation.id),
|
|
19
21
|
Contents: stringToPDFHexString(annotation.contentsObj?.text || ""),
|
|
@@ -29,6 +31,7 @@ export class TextParser extends AnnotationParser {
|
|
|
29
31
|
const replyAnn = context.obj({
|
|
30
32
|
Type: PDFName.of("Annot"),
|
|
31
33
|
Subtype: PDFName.of("Text"),
|
|
34
|
+
F: PRINT_FLAG,
|
|
32
35
|
Rect: rect,
|
|
33
36
|
Contents: stringToPDFHexString(comment.content),
|
|
34
37
|
T: stringToPDFHexString(comment.title || UNKNOWN_USER),
|
|
@@ -2,6 +2,7 @@ import { PDFName, PDFString } from "pdf-lib";
|
|
|
2
2
|
import { convertKonvaRectToPdfRect, rgbToPdfColor, stringToPDFHexString } from "../engine/utils.js";
|
|
3
3
|
import { convertCanvasPointToPdf, pageTransformFromPdfLibPage } from "../pdf-import/transform.js";
|
|
4
4
|
import { AnnotationParser } from "./parse.js";
|
|
5
|
+
import { PRINT_FLAG } from "./annotation-flags.js";
|
|
5
6
|
const UNKNOWN_USER = "Unknown user";
|
|
6
7
|
function buildQuadPoints(konvaString, t) {
|
|
7
8
|
const konvaGroup = JSON.parse(konvaString);
|
|
@@ -29,6 +30,7 @@ export class UnderlineParser extends AnnotationParser {
|
|
|
29
30
|
const mainAnn = context.obj({
|
|
30
31
|
Type: PDFName.of("Annot"),
|
|
31
32
|
Subtype: PDFName.of("Underline"),
|
|
33
|
+
F: PRINT_FLAG,
|
|
32
34
|
Rect: convertKonvaRectToPdfRect(annotation.konvaClientRect, pageTransform),
|
|
33
35
|
QuadPoints: quadPoints,
|
|
34
36
|
C: rgbToPdfColor(annotation.color || void 0),
|
|
@@ -43,6 +45,7 @@ export class UnderlineParser extends AnnotationParser {
|
|
|
43
45
|
const replyAnn = context.obj({
|
|
44
46
|
Type: PDFName.of("Annot"),
|
|
45
47
|
Subtype: PDFName.of("Text"),
|
|
48
|
+
F: PRINT_FLAG,
|
|
46
49
|
Rect: convertKonvaRectToPdfRect(annotation.konvaClientRect, pageTransform),
|
|
47
50
|
Contents: stringToPDFHexString(comment.content),
|
|
48
51
|
T: stringToPDFHexString(comment.title || UNKNOWN_USER),
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PDFDocument, PDFFont } from 'pdf-lib';
|
|
2
|
+
/** Test/SSR hook: replace how the raw font bytes are obtained. */
|
|
3
|
+
export declare function setUnicodeFontLoader(loader: () => Promise<Uint8Array>): void;
|
|
4
|
+
/** Get (or embed once) the Unicode fallback font for this document. */
|
|
5
|
+
export declare function getUnicodeFont(pdfDoc: PDFDocument): Promise<PDFFont>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import fontkit from "@pdf-lib/fontkit";
|
|
2
|
+
let fontBytesPromise = null;
|
|
3
|
+
let loadFontBytes = async () => {
|
|
4
|
+
const { default: fontUrl } = await import(
|
|
5
|
+
// @ts-expect-error -- Vite asset import, no type declaration
|
|
6
|
+
"../../assets/fonts/LiberationSans-Regular.ttf?url"
|
|
7
|
+
);
|
|
8
|
+
const response = await fetch(fontUrl);
|
|
9
|
+
if (!response.ok) {
|
|
10
|
+
throw new Error(`Failed to load Unicode fallback font (${response.status})`);
|
|
11
|
+
}
|
|
12
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
13
|
+
};
|
|
14
|
+
export function setUnicodeFontLoader(loader) {
|
|
15
|
+
loadFontBytes = loader;
|
|
16
|
+
fontBytesPromise = null;
|
|
17
|
+
}
|
|
18
|
+
const fontCache = /* @__PURE__ */ new WeakMap();
|
|
19
|
+
export function getUnicodeFont(pdfDoc) {
|
|
20
|
+
let cached = fontCache.get(pdfDoc);
|
|
21
|
+
if (!cached) {
|
|
22
|
+
cached = (async () => {
|
|
23
|
+
fontBytesPromise ??= loadFontBytes();
|
|
24
|
+
const bytes = await fontBytesPromise;
|
|
25
|
+
pdfDoc.registerFontkit(fontkit);
|
|
26
|
+
return pdfDoc.embedFont(bytes, { subset: true });
|
|
27
|
+
})();
|
|
28
|
+
fontCache.set(pdfDoc, cached);
|
|
29
|
+
}
|
|
30
|
+
return cached;
|
|
31
|
+
}
|