@unlev/exeq 0.4.2 → 0.5.1
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.css +25 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +31 -3
- package/dist/index.d.ts +31 -3
- package/dist/index.js +139 -44
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +138 -44
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -56,6 +56,17 @@ var CSS_FONT_MAP = {
|
|
|
56
56
|
function getCssFontFamily(fontFamily) {
|
|
57
57
|
return fontFamily ? CSS_FONT_MAP[fontFamily] : void 0;
|
|
58
58
|
}
|
|
59
|
+
function getCssTextStyle(field) {
|
|
60
|
+
const decorations = [];
|
|
61
|
+
if (field.underline) decorations.push("underline");
|
|
62
|
+
if (field.strikethrough) decorations.push("line-through");
|
|
63
|
+
return {
|
|
64
|
+
fontFamily: getCssFontFamily(field.fontFamily),
|
|
65
|
+
fontWeight: field.bold ? "bold" : void 0,
|
|
66
|
+
fontStyle: field.italic ? "italic" : void 0,
|
|
67
|
+
textDecorationLine: decorations.length ? decorations.join(" ") : void 0
|
|
68
|
+
};
|
|
69
|
+
}
|
|
59
70
|
function sortFieldsByPosition(fields) {
|
|
60
71
|
return [...fields].sort((a, b) => {
|
|
61
72
|
if (a.page !== b.page) return a.page - b.page;
|
|
@@ -711,6 +722,15 @@ function FieldPropertyPanel({ field, signerRoles, onUpdate, onDelete, prefillCon
|
|
|
711
722
|
/* @__PURE__ */ jsx2("label", { children: "Font Size (pt)" }),
|
|
712
723
|
/* @__PURE__ */ jsx2("input", { type: "number", min: "6", max: "72", value: field.fontSize, onChange: (e) => onUpdate(field.id, { fontSize: Number(e.target.value) }) })
|
|
713
724
|
] }),
|
|
725
|
+
isText && /* @__PURE__ */ jsxs2("div", { className: "panel-field", children: [
|
|
726
|
+
/* @__PURE__ */ jsx2("label", { children: "Formatting" }),
|
|
727
|
+
/* @__PURE__ */ jsxs2("div", { className: "text-format-buttons", children: [
|
|
728
|
+
/* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${field.bold ? "active" : ""}`, style: { fontWeight: "bold" }, title: "Bold", onClick: () => onUpdate(field.id, { bold: !field.bold }), children: "B" }),
|
|
729
|
+
/* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${field.italic ? "active" : ""}`, style: { fontStyle: "italic" }, title: "Italic", onClick: () => onUpdate(field.id, { italic: !field.italic }), children: "I" }),
|
|
730
|
+
/* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${field.underline ? "active" : ""}`, style: { textDecorationLine: "underline" }, title: "Underline", onClick: () => onUpdate(field.id, { underline: !field.underline }), children: "U" }),
|
|
731
|
+
/* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${field.strikethrough ? "active" : ""}`, style: { textDecorationLine: "line-through" }, title: "Strikethrough", onClick: () => onUpdate(field.id, { strikethrough: !field.strikethrough }), children: "S" })
|
|
732
|
+
] })
|
|
733
|
+
] }),
|
|
714
734
|
isText && /* @__PURE__ */ jsxs2("div", { className: "panel-field-row", children: [
|
|
715
735
|
/* @__PURE__ */ jsxs2("div", { className: "panel-field panel-field-half", children: [
|
|
716
736
|
/* @__PURE__ */ jsx2("label", { children: "Letter Spacing" }),
|
|
@@ -783,6 +803,10 @@ function BulkPropertyPanel({ fields, signerRoles, onUpdate, onAlign, onDelete })
|
|
|
783
803
|
const sharedInkColor = sharedValue(fields.map((f) => f.inkColor || "#000000"));
|
|
784
804
|
const sharedLetterSpacing = sharedValue(fields.map((f) => f.letterSpacing || 0));
|
|
785
805
|
const sharedLineHeight = sharedValue(fields.map((f) => f.lineHeight || 1.2));
|
|
806
|
+
const allBold = fields.every((f) => f.bold);
|
|
807
|
+
const allItalic = fields.every((f) => f.italic);
|
|
808
|
+
const allUnderline = fields.every((f) => f.underline);
|
|
809
|
+
const allStrike = fields.every((f) => f.strikethrough);
|
|
786
810
|
return /* @__PURE__ */ jsxs2("div", { className: "field-property-panel", children: [
|
|
787
811
|
/* @__PURE__ */ jsxs2("div", { className: "panel-header", children: [
|
|
788
812
|
/* @__PURE__ */ jsxs2("h3", { children: [
|
|
@@ -897,6 +921,15 @@ function BulkPropertyPanel({ fields, signerRoles, onUpdate, onAlign, onDelete })
|
|
|
897
921
|
}
|
|
898
922
|
)
|
|
899
923
|
] }),
|
|
924
|
+
hasText && /* @__PURE__ */ jsxs2("div", { className: "panel-field", children: [
|
|
925
|
+
/* @__PURE__ */ jsx2("label", { children: "Formatting" }),
|
|
926
|
+
/* @__PURE__ */ jsxs2("div", { className: "text-format-buttons", children: [
|
|
927
|
+
/* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${allBold ? "active" : ""}`, style: { fontWeight: "bold" }, title: "Bold", onClick: () => onUpdate({ bold: !allBold }), children: "B" }),
|
|
928
|
+
/* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${allItalic ? "active" : ""}`, style: { fontStyle: "italic" }, title: "Italic", onClick: () => onUpdate({ italic: !allItalic }), children: "I" }),
|
|
929
|
+
/* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${allUnderline ? "active" : ""}`, style: { textDecorationLine: "underline" }, title: "Underline", onClick: () => onUpdate({ underline: !allUnderline }), children: "U" }),
|
|
930
|
+
/* @__PURE__ */ jsx2("button", { type: "button", className: `text-format-btn ${allStrike ? "active" : ""}`, style: { textDecorationLine: "line-through" }, title: "Strikethrough", onClick: () => onUpdate({ strikethrough: !allStrike }), children: "S" })
|
|
931
|
+
] })
|
|
932
|
+
] }),
|
|
900
933
|
hasText && /* @__PURE__ */ jsxs2("div", { className: "panel-field-row", children: [
|
|
901
934
|
/* @__PURE__ */ jsxs2("div", { className: "panel-field panel-field-half", children: [
|
|
902
935
|
/* @__PURE__ */ jsx2("label", { children: "Letter Spacing" }),
|
|
@@ -1679,7 +1712,6 @@ function DesignerView({
|
|
|
1679
1712
|
}
|
|
1680
1713
|
}
|
|
1681
1714
|
const inkColor = field.inkColor || "#000000";
|
|
1682
|
-
const cssFontFamily = getCssFontFamily(field.fontFamily);
|
|
1683
1715
|
return /* @__PURE__ */ jsx4(
|
|
1684
1716
|
"div",
|
|
1685
1717
|
{
|
|
@@ -1687,9 +1719,9 @@ function DesignerView({
|
|
|
1687
1719
|
style: {
|
|
1688
1720
|
color: field.value ? inkColor : void 0,
|
|
1689
1721
|
fontSize: `${field.fontSize}pt`,
|
|
1690
|
-
fontFamily: cssFontFamily,
|
|
1691
1722
|
letterSpacing: field.letterSpacing ? `${field.letterSpacing}pt` : void 0,
|
|
1692
|
-
lineHeight: field.lineHeight ? `${field.lineHeight}` : void 0
|
|
1723
|
+
lineHeight: field.lineHeight ? `${field.lineHeight}` : void 0,
|
|
1724
|
+
...getCssTextStyle(field)
|
|
1693
1725
|
},
|
|
1694
1726
|
children: field.value || field.placeholder
|
|
1695
1727
|
}
|
|
@@ -2061,39 +2093,56 @@ import {
|
|
|
2061
2093
|
} from "pdf-lib";
|
|
2062
2094
|
|
|
2063
2095
|
// src/utils/formulaResolver.ts
|
|
2096
|
+
function parseDate(value) {
|
|
2097
|
+
const s = value.trim();
|
|
2098
|
+
if (!s) return null;
|
|
2099
|
+
if (/^\d+(\.\d+)?$/.test(s)) {
|
|
2100
|
+
const serial = parseFloat(s);
|
|
2101
|
+
if (serial > 59) {
|
|
2102
|
+
const utc = new Date(Math.round((serial - 25569) * 864e5));
|
|
2103
|
+
if (!isNaN(utc.getTime())) {
|
|
2104
|
+
return new Date(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate());
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
const iso = s.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
2109
|
+
if (iso) return new Date(+iso[1], +iso[2] - 1, +iso[3]);
|
|
2110
|
+
const d = new Date(s);
|
|
2111
|
+
return isNaN(d.getTime()) ? null : d;
|
|
2112
|
+
}
|
|
2064
2113
|
var BUILTIN_TRANSFORMS = {
|
|
2065
2114
|
// Date transforms (expects a parseable date string)
|
|
2066
2115
|
month: (v) => {
|
|
2067
|
-
const d =
|
|
2068
|
-
return
|
|
2116
|
+
const d = parseDate(v);
|
|
2117
|
+
return d ? String(d.getMonth() + 1) : "";
|
|
2069
2118
|
},
|
|
2070
2119
|
month2: (v) => {
|
|
2071
|
-
const d =
|
|
2072
|
-
return
|
|
2120
|
+
const d = parseDate(v);
|
|
2121
|
+
return d ? String(d.getMonth() + 1).padStart(2, "0") : "";
|
|
2073
2122
|
},
|
|
2074
2123
|
monthname: (v) => {
|
|
2075
|
-
const d =
|
|
2076
|
-
return
|
|
2124
|
+
const d = parseDate(v);
|
|
2125
|
+
return d ? d.toLocaleString("en", { month: "long" }) : "";
|
|
2077
2126
|
},
|
|
2078
2127
|
monthshort: (v) => {
|
|
2079
|
-
const d =
|
|
2080
|
-
return
|
|
2128
|
+
const d = parseDate(v);
|
|
2129
|
+
return d ? d.toLocaleString("en", { month: "short" }) : "";
|
|
2081
2130
|
},
|
|
2082
2131
|
day: (v) => {
|
|
2083
|
-
const d =
|
|
2084
|
-
return
|
|
2132
|
+
const d = parseDate(v);
|
|
2133
|
+
return d ? String(d.getDate()) : "";
|
|
2085
2134
|
},
|
|
2086
2135
|
day2: (v) => {
|
|
2087
|
-
const d =
|
|
2088
|
-
return
|
|
2136
|
+
const d = parseDate(v);
|
|
2137
|
+
return d ? String(d.getDate()).padStart(2, "0") : "";
|
|
2089
2138
|
},
|
|
2090
2139
|
year: (v) => {
|
|
2091
|
-
const d =
|
|
2092
|
-
return
|
|
2140
|
+
const d = parseDate(v);
|
|
2141
|
+
return d ? String(d.getFullYear()) : "";
|
|
2093
2142
|
},
|
|
2094
2143
|
year2: (v) => {
|
|
2095
|
-
const d =
|
|
2096
|
-
return
|
|
2144
|
+
const d = parseDate(v);
|
|
2145
|
+
return d ? String(d.getFullYear()).slice(-2) : "";
|
|
2097
2146
|
},
|
|
2098
2147
|
// String transforms
|
|
2099
2148
|
upper: (v) => v.toUpperCase(),
|
|
@@ -2122,15 +2171,27 @@ var BUILTIN_TRANSFORMS = {
|
|
|
2122
2171
|
};
|
|
2123
2172
|
var FORMULA_RE = /\{\{(.+?)\}\}/g;
|
|
2124
2173
|
var PIPE_RE = /^(.+?)\s*\|\s*(.+)$/;
|
|
2125
|
-
function
|
|
2174
|
+
function todayIso() {
|
|
2175
|
+
const d = /* @__PURE__ */ new Date();
|
|
2176
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
2177
|
+
}
|
|
2178
|
+
function resolveFormula(formula, fields, customTransforms, values) {
|
|
2126
2179
|
const transforms = { ...BUILTIN_TRANSFORMS, ...customTransforms };
|
|
2127
2180
|
return formula.replace(FORMULA_RE, (_match, expr) => {
|
|
2128
2181
|
const pipeMatch = expr.match(PIPE_RE);
|
|
2129
2182
|
const sourceLabel = (pipeMatch ? pipeMatch[1] : expr).trim();
|
|
2130
2183
|
const transformName = pipeMatch ? pipeMatch[2].trim() : null;
|
|
2131
|
-
const
|
|
2132
|
-
|
|
2133
|
-
|
|
2184
|
+
const lowerLabel = sourceLabel.toLowerCase();
|
|
2185
|
+
const sourceField = fields.find((f) => f.label.toLowerCase() === lowerLabel) || fields.find((f) => f.id === sourceLabel);
|
|
2186
|
+
let rawValue = sourceField ? sourceField.value || "" : void 0;
|
|
2187
|
+
if (rawValue === void 0 && values) {
|
|
2188
|
+
const key = Object.keys(values).find((k) => k.toLowerCase() === lowerLabel);
|
|
2189
|
+
if (key !== void 0) rawValue = values[key] || "";
|
|
2190
|
+
}
|
|
2191
|
+
if (rawValue === void 0 && (lowerLabel === "today" || lowerLabel === "now")) {
|
|
2192
|
+
rawValue = todayIso();
|
|
2193
|
+
}
|
|
2194
|
+
if (rawValue === void 0) return "";
|
|
2134
2195
|
if (!transformName) return rawValue;
|
|
2135
2196
|
const fn = transforms[transformName];
|
|
2136
2197
|
if (!fn) return rawValue;
|
|
@@ -2141,20 +2202,28 @@ function resolveFormula(formula, fields, customTransforms) {
|
|
|
2141
2202
|
}
|
|
2142
2203
|
});
|
|
2143
2204
|
}
|
|
2144
|
-
function resolveAllFormulas(fields, customTransforms) {
|
|
2205
|
+
function resolveAllFormulas(fields, customTransforms, values) {
|
|
2145
2206
|
return fields.map((f) => {
|
|
2146
2207
|
if (!f.formula) return f;
|
|
2147
|
-
const computed = resolveFormula(f.formula, fields, customTransforms);
|
|
2208
|
+
const computed = resolveFormula(f.formula, fields, customTransforms, values);
|
|
2148
2209
|
return computed !== f.value ? { ...f, value: computed } : f;
|
|
2149
2210
|
});
|
|
2150
2211
|
}
|
|
2151
2212
|
|
|
2152
2213
|
// src/utils/pdfFiller.ts
|
|
2153
|
-
var
|
|
2154
|
-
Helvetica: StandardFonts.Helvetica,
|
|
2155
|
-
Courier: StandardFonts.Courier,
|
|
2156
|
-
TimesRoman: StandardFonts.TimesRoman
|
|
2214
|
+
var FONT_VARIANTS = {
|
|
2215
|
+
Helvetica: [StandardFonts.Helvetica, StandardFonts.HelveticaBold, StandardFonts.HelveticaOblique, StandardFonts.HelveticaBoldOblique],
|
|
2216
|
+
Courier: [StandardFonts.Courier, StandardFonts.CourierBold, StandardFonts.CourierOblique, StandardFonts.CourierBoldOblique],
|
|
2217
|
+
TimesRoman: [StandardFonts.TimesRoman, StandardFonts.TimesRomanBold, StandardFonts.TimesRomanItalic, StandardFonts.TimesRomanBoldItalic]
|
|
2157
2218
|
};
|
|
2219
|
+
function resolveStandardFont(family, bold, italic) {
|
|
2220
|
+
const variants = FONT_VARIANTS[family] || FONT_VARIANTS.Helvetica;
|
|
2221
|
+
const idx = (bold ? 1 : 0) + (italic ? 2 : 0);
|
|
2222
|
+
return variants[idx];
|
|
2223
|
+
}
|
|
2224
|
+
function fontKey(family, bold, italic) {
|
|
2225
|
+
return `${family}|${bold ? "b" : ""}|${italic ? "i" : ""}`;
|
|
2226
|
+
}
|
|
2158
2227
|
var US_LETTER = [612, 792];
|
|
2159
2228
|
var US_LEGAL = [612, 1008];
|
|
2160
2229
|
var A4 = [595.28, 841.89];
|
|
@@ -2229,7 +2298,7 @@ async function renderFieldsOnPages(pages, fields, getFont, getSignature) {
|
|
|
2229
2298
|
page.drawImage(img, { x, y, width: w, height: h });
|
|
2230
2299
|
}
|
|
2231
2300
|
} else {
|
|
2232
|
-
const font = await getFont(field.fontFamily || "Helvetica");
|
|
2301
|
+
const font = await getFont(field.fontFamily || "Helvetica", field.bold, field.italic);
|
|
2233
2302
|
const spacing = field.letterSpacing || 0;
|
|
2234
2303
|
const textWidthAtSize = (text, size) => font.widthOfTextAtSize(text, size) + spacing * (text.length - 1);
|
|
2235
2304
|
let fontSize = field.autoShrink ? Math.min(field.fontSize, h * 0.7) : field.fontSize;
|
|
@@ -2240,13 +2309,14 @@ async function renderFieldsOnPages(pages, fields, getFont, getSignature) {
|
|
|
2240
2309
|
fontSize -= 0.5;
|
|
2241
2310
|
}
|
|
2242
2311
|
}
|
|
2312
|
+
const textX = x + 2;
|
|
2313
|
+
const baselineY = y + h * 0.3;
|
|
2243
2314
|
if (spacing > 0) {
|
|
2244
|
-
let cx =
|
|
2245
|
-
const cy = y + h * 0.3;
|
|
2315
|
+
let cx = textX;
|
|
2246
2316
|
for (const char of field.value) {
|
|
2247
2317
|
page.drawText(char, {
|
|
2248
2318
|
x: cx,
|
|
2249
|
-
y:
|
|
2319
|
+
y: baselineY,
|
|
2250
2320
|
size: fontSize,
|
|
2251
2321
|
font,
|
|
2252
2322
|
color: inkColor
|
|
@@ -2255,13 +2325,35 @@ async function renderFieldsOnPages(pages, fields, getFont, getSignature) {
|
|
|
2255
2325
|
}
|
|
2256
2326
|
} else {
|
|
2257
2327
|
page.drawText(field.value, {
|
|
2258
|
-
x:
|
|
2259
|
-
y:
|
|
2328
|
+
x: textX,
|
|
2329
|
+
y: baselineY,
|
|
2260
2330
|
size: fontSize,
|
|
2261
2331
|
font,
|
|
2262
2332
|
color: inkColor
|
|
2263
2333
|
});
|
|
2264
2334
|
}
|
|
2335
|
+
if (field.underline || field.strikethrough) {
|
|
2336
|
+
const textWidth = textWidthAtSize(field.value, fontSize);
|
|
2337
|
+
const lineThickness = Math.max(0.5, fontSize * 0.06);
|
|
2338
|
+
if (field.underline) {
|
|
2339
|
+
const uy = baselineY - fontSize * 0.12;
|
|
2340
|
+
page.drawLine({
|
|
2341
|
+
start: { x: textX, y: uy },
|
|
2342
|
+
end: { x: textX + textWidth, y: uy },
|
|
2343
|
+
thickness: lineThickness,
|
|
2344
|
+
color: inkColor
|
|
2345
|
+
});
|
|
2346
|
+
}
|
|
2347
|
+
if (field.strikethrough) {
|
|
2348
|
+
const sy = baselineY + fontSize * 0.3;
|
|
2349
|
+
page.drawLine({
|
|
2350
|
+
start: { x: textX, y: sy },
|
|
2351
|
+
end: { x: textX + textWidth, y: sy },
|
|
2352
|
+
thickness: lineThickness,
|
|
2353
|
+
color: inkColor
|
|
2354
|
+
});
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2265
2357
|
}
|
|
2266
2358
|
}
|
|
2267
2359
|
}
|
|
@@ -2275,18 +2367,19 @@ async function createPdfBuilder(defaults = {}) {
|
|
|
2275
2367
|
const fontCache = /* @__PURE__ */ new Map();
|
|
2276
2368
|
const embeddedPagesByUrl = /* @__PURE__ */ new Map();
|
|
2277
2369
|
const signatureCache = /* @__PURE__ */ new Map();
|
|
2278
|
-
async function getFont(family) {
|
|
2279
|
-
|
|
2370
|
+
async function getFont(family, bold, italic) {
|
|
2371
|
+
const key = fontKey(family, bold, italic);
|
|
2372
|
+
let f = fontCache.get(key);
|
|
2280
2373
|
if (!f) {
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
fontCache.set(family, f);
|
|
2374
|
+
f = await doc.embedFont(resolveStandardFont(family, bold, italic));
|
|
2375
|
+
fontCache.set(key, f);
|
|
2284
2376
|
}
|
|
2285
2377
|
return f;
|
|
2286
2378
|
}
|
|
2287
2379
|
async function ensureFonts(fields) {
|
|
2288
|
-
const keys =
|
|
2289
|
-
for (const
|
|
2380
|
+
const keys = /* @__PURE__ */ new Map();
|
|
2381
|
+
for (const f of fields) keys.set(fontKey(f.fontFamily || "Helvetica", f.bold, f.italic), f);
|
|
2382
|
+
for (const f of keys.values()) await getFont(f.fontFamily || "Helvetica", f.bold, f.italic);
|
|
2290
2383
|
}
|
|
2291
2384
|
async function embedSource(source) {
|
|
2292
2385
|
if (typeof source === "string") {
|
|
@@ -2319,7 +2412,7 @@ async function createPdfBuilder(defaults = {}) {
|
|
|
2319
2412
|
doc,
|
|
2320
2413
|
async addRecord(opts) {
|
|
2321
2414
|
const pageSize = opts.pageSize ?? defaults.pageSize;
|
|
2322
|
-
let fields = opts.resolveFormulas ? resolveAllFormulas(opts.fields, opts.customTransforms) : opts.fields;
|
|
2415
|
+
let fields = opts.resolveFormulas ? resolveAllFormulas(opts.fields, opts.customTransforms, opts.formulaValues) : opts.fields;
|
|
2323
2416
|
if (opts.calibration) {
|
|
2324
2417
|
fields = applyCalibration(
|
|
2325
2418
|
fields,
|
|
@@ -2763,7 +2856,7 @@ ${row.join(",")}`, "csv");
|
|
|
2763
2856
|
fontSize: `${field.fontSize}pt`,
|
|
2764
2857
|
letterSpacing: field.letterSpacing ? `${field.letterSpacing}pt` : void 0,
|
|
2765
2858
|
lineHeight: field.lineHeight ? `${field.lineHeight}` : void 0,
|
|
2766
|
-
|
|
2859
|
+
...getCssTextStyle(field)
|
|
2767
2860
|
};
|
|
2768
2861
|
if (field.type === "dropdown" || field.options && field.options.length > 0) {
|
|
2769
2862
|
return /* @__PURE__ */ jsxs6(
|
|
@@ -3041,6 +3134,7 @@ export {
|
|
|
3041
3134
|
isRedactField,
|
|
3042
3135
|
isSignatureField,
|
|
3043
3136
|
isTextLikeField,
|
|
3137
|
+
parseDate,
|
|
3044
3138
|
postPdfToCallback,
|
|
3045
3139
|
preserveFieldValues,
|
|
3046
3140
|
renderPdfPages,
|