gutterpress 0.11.17-alpha.2 → 0.11.17-alpha.4
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/api/index.d.ts +4 -0
- package/dist/api/index.js +11 -2
- package/dist/black-text-gray-7dz61456.js +15 -0
- package/dist/{build-1p999cmg.js → build-fam0tqg6.js} +5 -4
- package/dist/checks/pdf/black-text.d.ts +3 -0
- package/dist/checks/pdf/index.d.ts +2 -0
- package/dist/checks/pdf/signature.d.ts +3 -0
- package/dist/{cli-6z5zthzt.js → cli-2kc34kme.js} +470 -489
- package/dist/{cli-70xgehq2.js → cli-8apk8571.js} +1 -1
- package/dist/cli-ht1bcqdd.js +493 -0
- package/dist/{cli-gymfg04q.js → cli-jyy9pqf3.js} +15 -10
- package/dist/{cli-ppc0vz4b.js → cli-pqcb2nnb.js} +1 -1
- package/dist/cli.js +12 -12
- package/dist/{doctor-reqpnn3h.js → doctor-zre5k5fg.js} +2 -2
- package/dist/engine/compiler/build.d.ts +3 -2
- package/dist/engine/compiler/postprocess.d.ts +6 -4
- package/dist/engine/shared/synthesis.d.ts +29 -5
- package/dist/{engine-5jzhjjvv.js → engine-3xqgm82d.js} +2 -2
- package/dist/{engine-078ggczp.js → engine-zdb41ay1.js} +1 -1
- package/dist/{ext-dsbfejt3.js → ext-hfqcg6ax.js} +5 -4
- package/dist/{gutterpress-viewer-zkv2stfy.js → gutterpress-viewer-1n793gwd.js} +5 -3
- package/dist/{index-c275p061.js → index-gp503ze9.js} +1622 -1332
- package/dist/{index-5dcj1vts.js → index-hrx0gfkj.js} +23 -684
- package/dist/index-ht1bcqdd.js +493 -0
- package/dist/index-q1xqxrh9.js +949 -0
- package/dist/index.js +12 -3
- package/dist/lib/black-text-gray.d.ts +55 -8
- package/dist/lib/build-fingerprint.d.ts +2 -0
- package/dist/lib/engine.d.ts +2 -1
- package/dist/lib/lint-rules.d.ts +9 -0
- package/dist/lib/markdown/assemble.d.ts +3 -5
- package/dist/lib/markdown/index.d.ts +3 -8
- package/dist/lib/markdown/renderer.d.ts +9 -1
- package/dist/lib/page-size.d.ts +66 -0
- package/dist/lib/pdf-inspect.d.ts +6 -0
- package/dist/lib/printsafe.d.ts +8 -1
- package/dist/lib/project-scaffold.d.ts +3 -9
- package/dist/lib/remote-auth/github-repos.d.ts +7 -0
- package/dist/lib/remote-auth/online-backup.d.ts +51 -0
- package/dist/lib/snippets.d.ts +3 -0
- package/dist/{manifest.schema-40sfq49z.json → manifest.schema-gh0jjve9.json} +14 -2
- package/dist/{new-m5y2wepr.js → new-bjdf7bhg.js} +5 -4
- package/dist/{plugin.js-m4a7m3t4.tpl → plugin.js-cswq7wvd.tpl} +4 -1
- package/dist/{plugin.test.js-6n8ct5e3.tpl → plugin.test.js-xgxrd8hf.tpl} +4 -1
- package/dist/{preflight-bwpqwwny.js → preflight-gvw01661.js} +5 -4
- package/dist/preview/file-watcher.d.ts +2 -4
- package/dist/{preview-62y7qhkp.js → preview-1cschq8s.js} +5 -4
- package/dist/{publish-k2zyt3x6.js → publish-ddqrb8s9.js} +5 -4
- package/dist/render.js +30 -5
- package/dist/schema/manifest.types.d.ts +17 -0
- package/dist/{validate-fgwwxtbn.js → validate-3hjkgxrz.js} +5 -4
- package/package.json +1 -1
- package/dist/index-eyaj6nkc.js +0 -267
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__require
|
|
3
|
+
} from "./cli-37x76zdn.js";
|
|
4
|
+
|
|
5
|
+
// src/lib/black-text-gray.ts
|
|
6
|
+
var MAX_CHANNEL = 0.12;
|
|
7
|
+
var MAX_SPREAD = 0.04;
|
|
8
|
+
function isNearBlack([r, g, b]) {
|
|
9
|
+
const max = Math.max(r, g, b);
|
|
10
|
+
return max <= MAX_CHANNEL && max - Math.min(r, g, b) <= MAX_SPREAD;
|
|
11
|
+
}
|
|
12
|
+
var WS = new Set([0, 9, 10, 12, 13, 32]);
|
|
13
|
+
var DELIM = new Set("()<>[]{}/%".split("").map((c) => c.charCodeAt(0)));
|
|
14
|
+
function* tokenize(s) {
|
|
15
|
+
let i = 0;
|
|
16
|
+
const n = s.length;
|
|
17
|
+
while (i < n) {
|
|
18
|
+
const c = s.charCodeAt(i);
|
|
19
|
+
if (WS.has(c)) {
|
|
20
|
+
i++;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const start = i;
|
|
24
|
+
if (c === 37) {
|
|
25
|
+
while (i < n && s[i] !== `
|
|
26
|
+
` && s[i] !== "\r")
|
|
27
|
+
i++;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (c === 40) {
|
|
31
|
+
let depth = 0;
|
|
32
|
+
while (i < n) {
|
|
33
|
+
const d = s[i++];
|
|
34
|
+
if (d === "\\")
|
|
35
|
+
i++;
|
|
36
|
+
else if (d === "(")
|
|
37
|
+
depth++;
|
|
38
|
+
else if (d === ")" && --depth === 0)
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
yield { text: s.slice(start, i), start, end: i, op: false };
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (c === 60 && s[i + 1] === "<") {
|
|
45
|
+
i += 2;
|
|
46
|
+
yield { text: "<<", start, end: i, op: false };
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (c === 62 && s[i + 1] === ">") {
|
|
50
|
+
i += 2;
|
|
51
|
+
yield { text: ">>", start, end: i, op: false };
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (c === 60) {
|
|
55
|
+
while (i < n && s[i] !== ">")
|
|
56
|
+
i++;
|
|
57
|
+
i++;
|
|
58
|
+
yield { text: s.slice(start, i), start, end: i, op: false };
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (c === 91 || c === 93 || c === 62 || c === 123 || c === 125 || c === 41) {
|
|
62
|
+
i++;
|
|
63
|
+
yield { text: s[start], start, end: i, op: false };
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
i++;
|
|
67
|
+
while (i < n && !WS.has(s.charCodeAt(i)) && !DELIM.has(s.charCodeAt(i)))
|
|
68
|
+
i++;
|
|
69
|
+
const text = s.slice(start, i);
|
|
70
|
+
const isOperand = c === 47 || /^[+-]?(\d+\.?\d*|\.\d+)$/.test(text);
|
|
71
|
+
yield { text, start, end: i, op: !isOperand };
|
|
72
|
+
if (text === "ID") {
|
|
73
|
+
const m = /\sEI(?=\s|$)/g;
|
|
74
|
+
m.lastIndex = i;
|
|
75
|
+
const hit = m.exec(s);
|
|
76
|
+
i = hit ? hit.index + hit[0].length : n;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
var LARGE_TEXT_PT = 24;
|
|
81
|
+
var SIZE_EPS = 0.05;
|
|
82
|
+
var area = (m) => Math.sqrt(Math.abs(m[0] * m[3] - m[1] * m[2]));
|
|
83
|
+
|
|
84
|
+
class TextScale {
|
|
85
|
+
ctm;
|
|
86
|
+
font = 0;
|
|
87
|
+
tm = 1;
|
|
88
|
+
stack = [];
|
|
89
|
+
constructor(ctm) {
|
|
90
|
+
this.ctm = ctm;
|
|
91
|
+
}
|
|
92
|
+
get unit() {
|
|
93
|
+
return this.ctm;
|
|
94
|
+
}
|
|
95
|
+
get size() {
|
|
96
|
+
return this.font * this.tm * this.ctm;
|
|
97
|
+
}
|
|
98
|
+
op(op, nums) {
|
|
99
|
+
switch (op) {
|
|
100
|
+
case "q":
|
|
101
|
+
this.stack.push([this.ctm, this.font]);
|
|
102
|
+
return false;
|
|
103
|
+
case "Q": {
|
|
104
|
+
const p = this.stack.pop();
|
|
105
|
+
if (p)
|
|
106
|
+
[this.ctm, this.font] = p;
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
case "cm":
|
|
110
|
+
if (nums.length === 6)
|
|
111
|
+
this.ctm *= area(nums);
|
|
112
|
+
return true;
|
|
113
|
+
case "BT":
|
|
114
|
+
this.tm = 1;
|
|
115
|
+
return true;
|
|
116
|
+
case "Tm":
|
|
117
|
+
if (nums.length === 6)
|
|
118
|
+
this.tm = area(nums);
|
|
119
|
+
return true;
|
|
120
|
+
case "Tf":
|
|
121
|
+
this.font = Math.abs(nums[nums.length - 1] ?? 0) || 0;
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function rewriteBlackText(src, ctx = {}) {
|
|
128
|
+
let fill = null;
|
|
129
|
+
let stroke = null;
|
|
130
|
+
const stack = [];
|
|
131
|
+
const scale = new TextScale(ctx.baseScale ?? 1);
|
|
132
|
+
let inText = false;
|
|
133
|
+
let fillDirty = false;
|
|
134
|
+
let strokeDirty = false;
|
|
135
|
+
const spans = [];
|
|
136
|
+
let lastOp = "";
|
|
137
|
+
let rect = null;
|
|
138
|
+
const edits = [];
|
|
139
|
+
let operands = [];
|
|
140
|
+
const rgbOf = () => {
|
|
141
|
+
if (operands.length !== 3)
|
|
142
|
+
return null;
|
|
143
|
+
const v = operands.map((t) => Number(t.text));
|
|
144
|
+
return v.some((x) => Number.isNaN(x)) ? null : { rgb: v, raw: operands.map((t) => t.text).join(" ") };
|
|
145
|
+
};
|
|
146
|
+
const isSmall = () => scale.size <= LARGE_TEXT_PT + SIZE_EPS;
|
|
147
|
+
let fillIns = null;
|
|
148
|
+
let strokeIns = null;
|
|
149
|
+
const syncOne = (colour, dirty, ins, at, gray, op) => {
|
|
150
|
+
if (!colour || !isNearBlack(colour.rgb))
|
|
151
|
+
return [dirty, ins];
|
|
152
|
+
const small = isSmall();
|
|
153
|
+
if (small && !dirty) {
|
|
154
|
+
const e = { start: at, end: at, text: ` ${gray}` };
|
|
155
|
+
edits.push(e);
|
|
156
|
+
return [true, e];
|
|
157
|
+
}
|
|
158
|
+
if (!small && dirty) {
|
|
159
|
+
if (ins)
|
|
160
|
+
ins.text = "";
|
|
161
|
+
else
|
|
162
|
+
edits.push({ start: at, end: at, text: ` ${colour.raw} ${op}` });
|
|
163
|
+
return [false, null];
|
|
164
|
+
}
|
|
165
|
+
return [dirty, ins];
|
|
166
|
+
};
|
|
167
|
+
const sync = (at) => {
|
|
168
|
+
[fillDirty, fillIns] = syncOne(fill, fillDirty, fillIns, at, "0 g", "rg");
|
|
169
|
+
[strokeDirty, strokeIns] = syncOne(stroke, strokeDirty, strokeIns, at, "0 G", "RG");
|
|
170
|
+
};
|
|
171
|
+
const flush = (s) => {
|
|
172
|
+
for (const r of s.rects) {
|
|
173
|
+
if (r.thickness > 0.2 * s.maxSmall)
|
|
174
|
+
continue;
|
|
175
|
+
edits.push({ start: r.start, end: r.start, text: "q 0 g " }, { start: r.end, end: r.end, text: " Q" });
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
for (const t of tokenize(src)) {
|
|
179
|
+
if (!t.op) {
|
|
180
|
+
operands.push(t);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const op = t.text;
|
|
184
|
+
const nums = operands.map((o) => Number(o.text));
|
|
185
|
+
const sizeMayHaveChanged = scale.op(op, nums);
|
|
186
|
+
switch (op) {
|
|
187
|
+
case "q":
|
|
188
|
+
stack.push([fill, stroke]);
|
|
189
|
+
break;
|
|
190
|
+
case "Q": {
|
|
191
|
+
const p = stack.pop();
|
|
192
|
+
if (p)
|
|
193
|
+
[fill, stroke] = p;
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case "BT":
|
|
197
|
+
inText = true;
|
|
198
|
+
fillDirty = strokeDirty = false;
|
|
199
|
+
fillIns = strokeIns = null;
|
|
200
|
+
sync(t.end);
|
|
201
|
+
break;
|
|
202
|
+
case "Tf":
|
|
203
|
+
case "Tm":
|
|
204
|
+
if (inText && sizeMayHaveChanged)
|
|
205
|
+
sync(t.end);
|
|
206
|
+
break;
|
|
207
|
+
case "ET":
|
|
208
|
+
if (inText) {
|
|
209
|
+
let ins = "";
|
|
210
|
+
if (fillDirty && fill)
|
|
211
|
+
ins += `${fill.raw} rg `;
|
|
212
|
+
if (strokeDirty && stroke)
|
|
213
|
+
ins += `${stroke.raw} RG `;
|
|
214
|
+
if (ins)
|
|
215
|
+
edits.push({ start: t.start, end: t.start, text: ins });
|
|
216
|
+
}
|
|
217
|
+
inText = false;
|
|
218
|
+
fillIns = strokeIns = null;
|
|
219
|
+
break;
|
|
220
|
+
case "rg":
|
|
221
|
+
case "RG": {
|
|
222
|
+
const c = rgbOf();
|
|
223
|
+
const isFill = op === "rg";
|
|
224
|
+
if (isFill)
|
|
225
|
+
fill = c;
|
|
226
|
+
else
|
|
227
|
+
stroke = c;
|
|
228
|
+
if (inText && c && isNearBlack(c.rgb) && isSmall()) {
|
|
229
|
+
edits.push({ start: operands[0].start, end: t.end, text: isFill ? "0 g" : "0 G" });
|
|
230
|
+
if (isFill)
|
|
231
|
+
fillDirty = true;
|
|
232
|
+
else
|
|
233
|
+
strokeDirty = true;
|
|
234
|
+
} else if (inText) {
|
|
235
|
+
if (isFill)
|
|
236
|
+
fillDirty = false;
|
|
237
|
+
else
|
|
238
|
+
strokeDirty = false;
|
|
239
|
+
}
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
case "g":
|
|
243
|
+
case "k":
|
|
244
|
+
case "sc":
|
|
245
|
+
case "scn":
|
|
246
|
+
case "cs":
|
|
247
|
+
fill = null;
|
|
248
|
+
if (inText)
|
|
249
|
+
fillDirty = false;
|
|
250
|
+
break;
|
|
251
|
+
case "G":
|
|
252
|
+
case "K":
|
|
253
|
+
case "SC":
|
|
254
|
+
case "SCN":
|
|
255
|
+
case "CS":
|
|
256
|
+
stroke = null;
|
|
257
|
+
if (inText)
|
|
258
|
+
strokeDirty = false;
|
|
259
|
+
break;
|
|
260
|
+
case "Do": {
|
|
261
|
+
const name = operands[operands.length - 1]?.text;
|
|
262
|
+
if (name?.startsWith("/"))
|
|
263
|
+
ctx.onDo?.(name.slice(1), scale.unit);
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
case "BDC":
|
|
267
|
+
case "BMC":
|
|
268
|
+
spans.push({ hasSmall: false, maxSmall: 0, rects: [] });
|
|
269
|
+
break;
|
|
270
|
+
case "EMC": {
|
|
271
|
+
const s = spans.pop();
|
|
272
|
+
if (!s)
|
|
273
|
+
break;
|
|
274
|
+
const parent = spans[spans.length - 1];
|
|
275
|
+
if (s.hasSmall)
|
|
276
|
+
flush(s);
|
|
277
|
+
else
|
|
278
|
+
parent?.rects.push(...s.rects);
|
|
279
|
+
if (parent && s.hasSmall) {
|
|
280
|
+
parent.hasSmall = true;
|
|
281
|
+
parent.maxSmall = Math.max(parent.maxSmall, s.maxSmall);
|
|
282
|
+
}
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
case "Tj":
|
|
286
|
+
case "TJ":
|
|
287
|
+
case "'":
|
|
288
|
+
case '"': {
|
|
289
|
+
fillIns = strokeIns = null;
|
|
290
|
+
const span = spans[spans.length - 1];
|
|
291
|
+
if (span && inText && isSmall()) {
|
|
292
|
+
span.hasSmall = true;
|
|
293
|
+
span.maxSmall = Math.max(span.maxSmall, scale.size);
|
|
294
|
+
}
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
case "re":
|
|
298
|
+
rect = !inText && fill && isNearBlack(fill.rgb) && operands.length === 4 && nums.every((x) => !Number.isNaN(x)) ? { start: operands[0].start, thickness: Math.min(Math.abs(nums[2]), Math.abs(nums[3])) * scale.unit } : null;
|
|
299
|
+
break;
|
|
300
|
+
case "f":
|
|
301
|
+
case "F":
|
|
302
|
+
case "f*":
|
|
303
|
+
if (rect && lastOp === "re")
|
|
304
|
+
spans[spans.length - 1]?.rects.push({ ...rect, end: t.end });
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
lastOp = op;
|
|
308
|
+
operands = [];
|
|
309
|
+
}
|
|
310
|
+
return applyEdits(src, edits);
|
|
311
|
+
}
|
|
312
|
+
function applyEdits(s, edits) {
|
|
313
|
+
if (!edits.length)
|
|
314
|
+
return s;
|
|
315
|
+
edits.sort((a, b) => a.start - b.start);
|
|
316
|
+
let out = "";
|
|
317
|
+
let pos = 0;
|
|
318
|
+
for (const e of edits) {
|
|
319
|
+
out += s.slice(pos, e.start) + e.text;
|
|
320
|
+
pos = e.end;
|
|
321
|
+
}
|
|
322
|
+
return out + s.slice(pos);
|
|
323
|
+
}
|
|
324
|
+
function isRichBlack(c) {
|
|
325
|
+
const [cy, m, y, k] = c;
|
|
326
|
+
const lo = Math.min(cy, m, y);
|
|
327
|
+
return k >= 0.7 && lo >= 0.3 && Math.max(cy, m, y) - lo <= 0.25;
|
|
328
|
+
}
|
|
329
|
+
function countRichBlackText(src, ctx = {}) {
|
|
330
|
+
const scale = new TextScale(ctx.baseScale ?? 1);
|
|
331
|
+
let fill = null;
|
|
332
|
+
const stack = [];
|
|
333
|
+
let count = 0;
|
|
334
|
+
let operands = [];
|
|
335
|
+
for (const t of tokenize(src)) {
|
|
336
|
+
if (!t.op) {
|
|
337
|
+
operands.push(t);
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
const op = t.text;
|
|
341
|
+
const nums = operands.map((o) => Number(o.text));
|
|
342
|
+
scale.op(op, nums);
|
|
343
|
+
switch (op) {
|
|
344
|
+
case "q":
|
|
345
|
+
stack.push(fill);
|
|
346
|
+
break;
|
|
347
|
+
case "Q":
|
|
348
|
+
if (stack.length)
|
|
349
|
+
fill = stack.pop() ?? null;
|
|
350
|
+
break;
|
|
351
|
+
case "k":
|
|
352
|
+
fill = nums.length === 4 && !nums.some(Number.isNaN) ? nums : null;
|
|
353
|
+
break;
|
|
354
|
+
case "sc":
|
|
355
|
+
case "scn":
|
|
356
|
+
fill = nums.length === 4 && !nums.some(Number.isNaN) ? nums : null;
|
|
357
|
+
break;
|
|
358
|
+
case "g":
|
|
359
|
+
case "rg":
|
|
360
|
+
case "cs":
|
|
361
|
+
fill = null;
|
|
362
|
+
break;
|
|
363
|
+
case "Do": {
|
|
364
|
+
const name = operands[operands.length - 1]?.text;
|
|
365
|
+
if (name?.startsWith("/"))
|
|
366
|
+
ctx.onDo?.(name.slice(1), scale.unit);
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
case "Tj":
|
|
370
|
+
case "TJ":
|
|
371
|
+
case "'":
|
|
372
|
+
case '"':
|
|
373
|
+
if (fill && isRichBlack(fill) && scale.size <= LARGE_TEXT_PT + SIZE_EPS)
|
|
374
|
+
count++;
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
377
|
+
operands = [];
|
|
378
|
+
}
|
|
379
|
+
return count;
|
|
380
|
+
}
|
|
381
|
+
async function visitContent(doc, visit) {
|
|
382
|
+
const { PDFName, PDFRawStream, PDFArray, PDFRef, PDFDict, decodePDFRawStream } = await import("pdf-lib");
|
|
383
|
+
const ctx = doc.context;
|
|
384
|
+
const SKIP = ["Filter", "DecodeParms", "Length"].map((k) => PDFName.of(k));
|
|
385
|
+
let changed = false;
|
|
386
|
+
const decode = (s) => {
|
|
387
|
+
try {
|
|
388
|
+
return Buffer.from(decodePDFRawStream(s).decode()).toString("latin1");
|
|
389
|
+
} catch {
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
const replace = (ref, old, text) => {
|
|
394
|
+
const entries = {};
|
|
395
|
+
for (const [k, v] of old.dict.entries())
|
|
396
|
+
if (!SKIP.includes(k))
|
|
397
|
+
entries[k.decodeText()] = v;
|
|
398
|
+
ctx.assign(ref, ctx.flateStream(Buffer.from(text, "latin1"), entries));
|
|
399
|
+
changed = true;
|
|
400
|
+
};
|
|
401
|
+
const formScale = new Map;
|
|
402
|
+
const formPages = new Map;
|
|
403
|
+
const formMatrixScale = (form) => {
|
|
404
|
+
const m = form.dict.lookupMaybe(PDFName.of("Matrix"), PDFArray);
|
|
405
|
+
const nums = m?.asArray().map((n) => Number(n.toString()));
|
|
406
|
+
return nums?.length === 6 && !nums.some(Number.isNaN) ? area(nums) : 1;
|
|
407
|
+
};
|
|
408
|
+
const pages = doc.getPages();
|
|
409
|
+
for (let p = 0;p < pages.length; p++) {
|
|
410
|
+
const page = pages[p];
|
|
411
|
+
const contents = page.node.Contents();
|
|
412
|
+
const refs = [];
|
|
413
|
+
if (contents instanceof PDFArray) {
|
|
414
|
+
for (let i = 0;i < contents.size(); i++) {
|
|
415
|
+
const r = contents.get(i);
|
|
416
|
+
if (r instanceof PDFRef)
|
|
417
|
+
refs.push(r);
|
|
418
|
+
}
|
|
419
|
+
} else if (contents instanceof PDFRawStream) {
|
|
420
|
+
const r = page.node.get(PDFName.of("Contents"));
|
|
421
|
+
if (r instanceof PDFRef)
|
|
422
|
+
refs.push(r);
|
|
423
|
+
}
|
|
424
|
+
const streams = refs.map((r) => ctx.lookup(r));
|
|
425
|
+
if (!refs.length || !streams.every((s) => s instanceof PDFRawStream))
|
|
426
|
+
continue;
|
|
427
|
+
const parts = streams.map((s) => decode(s));
|
|
428
|
+
if (parts.some((q) => q === null))
|
|
429
|
+
continue;
|
|
430
|
+
const joined = parts.join(`
|
|
431
|
+
`);
|
|
432
|
+
const xobjects = page.node.Resources()?.lookupMaybe(PDFName.of("XObject"), PDFDict);
|
|
433
|
+
const next = visit(joined, {
|
|
434
|
+
baseScale: 1,
|
|
435
|
+
pages: [p + 1],
|
|
436
|
+
onDo: (name, scale) => {
|
|
437
|
+
const ref = xobjects?.get(PDFName.of(name));
|
|
438
|
+
const form = ref instanceof PDFRef ? ctx.lookup(ref) : undefined;
|
|
439
|
+
if (!(ref instanceof PDFRef) || !(form instanceof PDFRawStream))
|
|
440
|
+
return;
|
|
441
|
+
if (form.dict.get(PDFName.of("Subtype")) !== PDFName.of("Form"))
|
|
442
|
+
return;
|
|
443
|
+
const at = scale * formMatrixScale(form);
|
|
444
|
+
formScale.set(ref.tag, Math.min(formScale.get(ref.tag) ?? Infinity, at));
|
|
445
|
+
(formPages.get(ref.tag) ?? formPages.set(ref.tag, new Set).get(ref.tag)).add(p + 1);
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
if (next === joined)
|
|
449
|
+
continue;
|
|
450
|
+
replace(refs[0], streams[0], next);
|
|
451
|
+
page.node.set(PDFName.of("Contents"), refs[0]);
|
|
452
|
+
}
|
|
453
|
+
for (const [ref, obj] of ctx.enumerateIndirectObjects()) {
|
|
454
|
+
if (!(obj instanceof PDFRawStream))
|
|
455
|
+
continue;
|
|
456
|
+
if (obj.dict.get(PDFName.of("Subtype")) !== PDFName.of("Form"))
|
|
457
|
+
continue;
|
|
458
|
+
const text = decode(obj);
|
|
459
|
+
if (text === null)
|
|
460
|
+
continue;
|
|
461
|
+
const next = visit(text, {
|
|
462
|
+
baseScale: formScale.get(ref.tag) ?? 0,
|
|
463
|
+
pages: [...formPages.get(ref.tag) ?? []]
|
|
464
|
+
});
|
|
465
|
+
if (next !== text)
|
|
466
|
+
replace(ref, obj, next);
|
|
467
|
+
}
|
|
468
|
+
return changed;
|
|
469
|
+
}
|
|
470
|
+
async function blackTextToGray(pdf) {
|
|
471
|
+
const { PDFDocument } = await import("pdf-lib");
|
|
472
|
+
const doc = await PDFDocument.load(pdf, { updateMetadata: false });
|
|
473
|
+
const changed = await visitContent(doc, (src, info) => rewriteBlackText(src, info));
|
|
474
|
+
return changed ? doc.save({ updateFieldAppearances: false }) : pdf;
|
|
475
|
+
}
|
|
476
|
+
async function findRichBlackText(pdf) {
|
|
477
|
+
const { PDFDocument } = await import("pdf-lib");
|
|
478
|
+
const doc = await PDFDocument.load(pdf, { updateMetadata: false });
|
|
479
|
+
let runs = 0;
|
|
480
|
+
const pages = new Set;
|
|
481
|
+
await visitContent(doc, (src, info) => {
|
|
482
|
+
const n = countRichBlackText(src, info);
|
|
483
|
+
if (n) {
|
|
484
|
+
runs += n;
|
|
485
|
+
for (const p of info.pages)
|
|
486
|
+
pages.add(p);
|
|
487
|
+
}
|
|
488
|
+
return src;
|
|
489
|
+
});
|
|
490
|
+
return { runs, pages: [...pages].sort((a, b) => a - b) };
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
export { LARGE_TEXT_PT, rewriteBlackText, countRichBlackText, blackTextToGray, findRichBlackText };
|
|
@@ -681,10 +681,15 @@ function planRectoBlanks(sites) {
|
|
|
681
681
|
return wrong;
|
|
682
682
|
});
|
|
683
683
|
}
|
|
684
|
-
function
|
|
684
|
+
function lastPageMode(print) {
|
|
685
|
+
return print.lastPage ?? (print.reserveLastPage ? "blank" : undefined);
|
|
686
|
+
}
|
|
687
|
+
function signaturePadding(pageCount, signature = 1, lastPage) {
|
|
685
688
|
const size = signature > 1 ? signature : 1;
|
|
689
|
+
if (lastPage === "short-by-one")
|
|
690
|
+
return (size - (pageCount + 1) % size) % size;
|
|
686
691
|
const padded = (size - pageCount % size) % size;
|
|
687
|
-
return padded === 0 &&
|
|
692
|
+
return padded === 0 && lastPage === "blank" ? size : padded;
|
|
688
693
|
}
|
|
689
694
|
var WHICH_VALUES = new Set(["first", "start", "last", "first-except"]);
|
|
690
695
|
function parseWhich(raw) {
|
|
@@ -1111,7 +1116,7 @@ import { fileURLToPath } from "node:url";
|
|
|
1111
1116
|
var favicon_default = "./favicon-wkbm9cjn.ico";
|
|
1112
1117
|
|
|
1113
1118
|
// src/assets/manifest.schema.json
|
|
1114
|
-
var manifest_schema_default = "./manifest.schema-
|
|
1119
|
+
var manifest_schema_default = "./manifest.schema-gh0jjve9.json";
|
|
1115
1120
|
|
|
1116
1121
|
// src/assets/preview/scripts/preview-interface.js
|
|
1117
1122
|
var preview_interface_default = "./preview-interface-c44qk17f.js";
|
|
@@ -1126,7 +1131,7 @@ var preview_shell_default = "./preview-shell-xwn84kqr.js";
|
|
|
1126
1131
|
var CGATS21_CRPC1_default = "./CGATS21_CRPC1-g0e3k7kr.icc";
|
|
1127
1132
|
|
|
1128
1133
|
// src/assets/engine/gutterpress-viewer.js
|
|
1129
|
-
var gutterpress_viewer_default = "./gutterpress-viewer-
|
|
1134
|
+
var gutterpress_viewer_default = "./gutterpress-viewer-1n793gwd.js";
|
|
1130
1135
|
|
|
1131
1136
|
// src/assets/engine/gutterpress-agent.js
|
|
1132
1137
|
var gutterpress_agent_default = "./gutterpress-agent-cazqstr1.js";
|
|
@@ -1156,7 +1161,7 @@ var package_default = "./package-9rv69pxm.json";
|
|
|
1156
1161
|
var README_default = "./README-vsnsc1b3.md";
|
|
1157
1162
|
|
|
1158
1163
|
// src/assets/extension-templates/plugin/plugin.js.tpl
|
|
1159
|
-
var plugin_js_default = "./plugin.js-
|
|
1164
|
+
var plugin_js_default = "./plugin.js-cswq7wvd.tpl";
|
|
1160
1165
|
|
|
1161
1166
|
// src/assets/extension-templates/plugin/styles/plugin.css
|
|
1162
1167
|
var plugin_default = "./plugin-spbcem4j.css";
|
|
@@ -1171,7 +1176,7 @@ var fixture_default = "./fixture-2qnyqgb5.md";
|
|
|
1171
1176
|
var expected_default = "./expected-ycmacem8.html";
|
|
1172
1177
|
|
|
1173
1178
|
// src/assets/extension-templates/plugin/test/plugin.test.js.tpl
|
|
1174
|
-
var plugin_test_js_default = "./plugin.test.js-
|
|
1179
|
+
var plugin_test_js_default = "./plugin.test.js-xgxrd8hf.tpl";
|
|
1175
1180
|
|
|
1176
1181
|
// src/assets/extension-templates/theme/package.json
|
|
1177
1182
|
var package_default2 = "./package-aenwjew3.json";
|
|
@@ -1455,7 +1460,7 @@ async function postprocess(input, opts) {
|
|
|
1455
1460
|
g.media.width - inset,
|
|
1456
1461
|
g.media.height - inset
|
|
1457
1462
|
];
|
|
1458
|
-
const padded = signaturePadding(doc.getPageCount(), opts.signature, opts.
|
|
1463
|
+
const padded = signaturePadding(doc.getPageCount(), opts.signature, opts.lastPage);
|
|
1459
1464
|
for (let i = 0;i < padded; i++)
|
|
1460
1465
|
doc.addPage([g.media.width, g.media.height]);
|
|
1461
1466
|
const wantMarks = opts.marks || g.marks.includes("crop") || g.marks.includes("cross");
|
|
@@ -2232,12 +2237,12 @@ ${mapCss}`;
|
|
|
2232
2237
|
const post = await postprocess(bytes, {
|
|
2233
2238
|
geometry: tier2.geometry,
|
|
2234
2239
|
signature: opts.signature,
|
|
2235
|
-
|
|
2240
|
+
lastPage: opts.lastPage,
|
|
2236
2241
|
marks: opts.marks,
|
|
2237
2242
|
title: opts.title,
|
|
2238
2243
|
author: opts.author
|
|
2239
2244
|
});
|
|
2240
|
-
log(`postprocess: ${post.pageCount} pages` + (post.padded ? ` (+${post.padded} blank${opts.
|
|
2245
|
+
log(`postprocess: ${post.pageCount} pages` + (post.padded ? ` (+${post.padded} blank${opts.lastPage ? `; last page: ${opts.lastPage}` : ""})` : ""));
|
|
2241
2246
|
return {
|
|
2242
2247
|
bytes: post.bytes,
|
|
2243
2248
|
tier,
|
|
@@ -2597,4 +2602,4 @@ ${lines.length ? lines.join(`
|
|
|
2597
2602
|
`);
|
|
2598
2603
|
}
|
|
2599
2604
|
|
|
2600
|
-
export { getAssetsDir, getAssetPath, MARGIN_BOX_IGNORED_PROPERTIES, build };
|
|
2605
|
+
export { lastPageMode, getAssetsDir, getAssetPath, MARGIN_BOX_IGNORED_PROPERTIES, build };
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
// package.json
|
|
5
5
|
var package_default = {
|
|
6
6
|
name: "gutterpress",
|
|
7
|
-
version: "0.11.17-alpha.
|
|
7
|
+
version: "0.11.17-alpha.4",
|
|
8
8
|
description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
9
9
|
author: "itlackey",
|
|
10
10
|
license: "MPL-2.0",
|
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
UsageError,
|
|
7
7
|
package_default,
|
|
8
8
|
rejectUnknownFlags
|
|
9
|
-
} from "./cli-
|
|
9
|
+
} from "./cli-pqcb2nnb.js";
|
|
10
10
|
import {
|
|
11
11
|
EXIT_CODES
|
|
12
12
|
} from "./cli-46ycxe6r.js";
|
|
@@ -18,14 +18,14 @@ import {
|
|
|
18
18
|
import { defineCommand, parseArgs, runMain } from "citty";
|
|
19
19
|
import { statSync } from "node:fs";
|
|
20
20
|
var SUBCOMMANDS = {
|
|
21
|
-
new: () => import("./new-
|
|
22
|
-
preview: () => import("./preview-
|
|
23
|
-
build: () => import("./build-
|
|
24
|
-
publish: () => import("./publish-
|
|
25
|
-
validate: () => import("./validate-
|
|
26
|
-
preflight: () => import("./preflight-
|
|
27
|
-
doctor: () => import("./doctor-
|
|
28
|
-
ext: () => import("./ext-
|
|
21
|
+
new: () => import("./new-bjdf7bhg.js").then((m) => m.default),
|
|
22
|
+
preview: () => import("./preview-1cschq8s.js").then((m) => m.default),
|
|
23
|
+
build: () => import("./build-fam0tqg6.js").then((m) => m.default),
|
|
24
|
+
publish: () => import("./publish-ddqrb8s9.js").then((m) => m.default),
|
|
25
|
+
validate: () => import("./validate-3hjkgxrz.js").then((m) => m.default),
|
|
26
|
+
preflight: () => import("./preflight-gvw01661.js").then((m) => m.default),
|
|
27
|
+
doctor: () => import("./doctor-zre5k5fg.js").then((m) => m.default),
|
|
28
|
+
ext: () => import("./ext-hfqcg6ax.js").then((m) => m.default)
|
|
29
29
|
};
|
|
30
30
|
var VERSION = package_default.version;
|
|
31
31
|
var main = defineCommand({
|
|
@@ -50,7 +50,7 @@ async function preflightRequiredInvocations(rawArgs) {
|
|
|
50
50
|
const [command, ...commandArgs] = rawArgs;
|
|
51
51
|
try {
|
|
52
52
|
if (command === "new") {
|
|
53
|
-
const { newArgs } = await import("./new-
|
|
53
|
+
const { newArgs } = await import("./new-bjdf7bhg.js");
|
|
54
54
|
rejectUnknownFlags(commandArgs, newArgs, "new");
|
|
55
55
|
const parsed = parseArgs(commandArgs, {
|
|
56
56
|
...newArgs,
|
|
@@ -62,7 +62,7 @@ async function preflightRequiredInvocations(rawArgs) {
|
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
64
|
if (command === "preflight") {
|
|
65
|
-
const { preflightArgs } = await import("./preflight-
|
|
65
|
+
const { preflightArgs } = await import("./preflight-gvw01661.js");
|
|
66
66
|
rejectUnknownFlags(commandArgs, preflightArgs, "preflight");
|
|
67
67
|
const parsed = parseArgs(commandArgs, {
|
|
68
68
|
...preflightArgs,
|
|
@@ -82,7 +82,7 @@ async function preflightRequiredInvocations(rawArgs) {
|
|
|
82
82
|
}
|
|
83
83
|
if (subcommand.startsWith("-"))
|
|
84
84
|
return;
|
|
85
|
-
const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-
|
|
85
|
+
const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-hfqcg6ax.js");
|
|
86
86
|
if (!EXT_SUBCOMMANDS.includes(subcommand)) {
|
|
87
87
|
throw new UsageError(`gutterpress ext: unknown command "${subcommand}"`);
|
|
88
88
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getSystemDiagnostics,
|
|
3
3
|
log
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-8apk8571.js";
|
|
5
5
|
import {
|
|
6
6
|
UsageError,
|
|
7
7
|
rejectExtraPositionals,
|
|
8
8
|
rejectUnknownFlags
|
|
9
|
-
} from "./cli-
|
|
9
|
+
} from "./cli-pqcb2nnb.js";
|
|
10
10
|
import"./cli-46ycxe6r.js";
|
|
11
11
|
import"./cli-7fkhgtfn.js";
|
|
12
12
|
import"./cli-37x76zdn.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Browser } from "../shared/cdp.ts";
|
|
2
2
|
import { type GcpmModel } from "../shared/gcpm-extract.ts";
|
|
3
|
+
import { type LastPageMode } from "../shared/synthesis.ts";
|
|
3
4
|
import { type Tier2Output } from "./tier2.ts";
|
|
4
5
|
import { type PostprocessResult } from "./postprocess.ts";
|
|
5
6
|
/**
|
|
@@ -19,8 +20,8 @@ export interface BuildOptions {
|
|
|
19
20
|
input: string;
|
|
20
21
|
output?: string;
|
|
21
22
|
signature?: number;
|
|
22
|
-
/**
|
|
23
|
-
|
|
23
|
+
/** the printer-reserved last page: see `LastPageMode` in shared/synthesis.ts */
|
|
24
|
+
lastPage?: LastPageMode;
|
|
24
25
|
marks?: boolean;
|
|
25
26
|
slugPt?: number;
|
|
26
27
|
bleedPt?: number;
|