gutterpress 0.11.20-alpha.2 → 0.11.20-alpha.3

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.
Files changed (31) hide show
  1. package/dist/api/index.js +3 -2
  2. package/dist/{build-qmjg9r2d.js → build-a8ycsg80.js} +5 -4
  3. package/dist/{cli-zacevwcy.js → cli-9k2tb493.js} +181 -431
  4. package/dist/{cli-7z29z4wz.js → cli-hn9pk0hp.js} +1 -1
  5. package/dist/cli-sth219v1.js +418 -0
  6. package/dist/{cli-j802s31j.js → cli-x4p99w8d.js} +2 -2
  7. package/dist/{cli-gh0ym80r.js → cli-y9bcya7r.js} +121 -20
  8. package/dist/cli.js +12 -12
  9. package/dist/{doctor-fe7tcs4v.js → doctor-wbjkrcpc.js} +2 -2
  10. package/dist/{engine-yax79k9m.js → engine-fdtv01a2.js} +2 -2
  11. package/dist/{engine-9xb1ky8d.js → engine-yxnnp3hx.js} +1 -1
  12. package/dist/{ext-ahwxt6gv.js → ext-pesyrs68.js} +5 -4
  13. package/dist/{gutterpress-viewer-retj6ym2.js → gutterpress-viewer-1yse8cx3.js} +12 -4
  14. package/dist/{index-6xwtb7cw.js → index-r87y7wzw.js} +1 -1
  15. package/dist/index-sth219v1.js +418 -0
  16. package/dist/{index-razpty47.js → index-tjvrchxj.js} +297 -448
  17. package/dist/{index-3nr5rzzp.js → index-zagagnwq.js} +2 -2
  18. package/dist/index.js +4 -3
  19. package/dist/lib/build-fingerprint.d.ts +8 -0
  20. package/dist/lib/ghostscript.d.ts +70 -16
  21. package/dist/lib/pdf-inspect.d.ts +45 -0
  22. package/dist/{manifest.schema-74s1ykyv.json → manifest.schema-c9x8912a.json} +13 -1
  23. package/dist/{new-ftd4fec4.js → new-8yah8z91.js} +5 -4
  24. package/dist/pdf-inspect-zdmy7qca.js +35 -0
  25. package/dist/{preflight-8sqarcsr.js → preflight-8ccx4kdc.js} +5 -4
  26. package/dist/{preview-q76xn95h.js → preview-w7v9w36q.js} +5 -4
  27. package/dist/{publish-7gdy6gbf.js → publish-g5nh5myh.js} +5 -4
  28. package/dist/schema/manifest.types.d.ts +20 -2
  29. package/dist/test-helpers/testkit.d.ts +2 -2
  30. package/dist/{validate-e3ryegce.js → validate-1yh59x0x.js} +5 -4
  31. package/package.json +1 -1
@@ -148,7 +148,7 @@ import { fileURLToPath } from "node:url";
148
148
  var favicon_default = "./favicon-272ga6y0.ico";
149
149
 
150
150
  // src/assets/manifest.schema.json
151
- var manifest_schema_default = "./manifest.schema-74s1ykyv.json";
151
+ var manifest_schema_default = "./manifest.schema-c9x8912a.json";
152
152
 
153
153
  // src/assets/preview/scripts/preview-interface.js
154
154
  var preview_interface_default = "./preview-interface-nnmrxyqm.js";
@@ -163,7 +163,7 @@ var preview_shell_default = "./preview-shell-wk9k3gcd.js";
163
163
  var CGATS21_CRPC1_default = "./CGATS21_CRPC1-g0e3k7kr.icc";
164
164
 
165
165
  // src/assets/engine/gutterpress-viewer.js
166
- var gutterpress_viewer_default = "./gutterpress-viewer-retj6ym2.js";
166
+ var gutterpress_viewer_default = "./gutterpress-viewer-1yse8cx3.js";
167
167
 
168
168
  // src/assets/engine/gutterpress-agent.js
169
169
  var gutterpress_agent_default = "./gutterpress-agent-cazqstr1.js";
package/dist/index.js CHANGED
@@ -154,14 +154,15 @@ import {
154
154
  testRemoteAccess,
155
155
  updateExtensions,
156
156
  validateProjectExtensions
157
- } from "./index-razpty47.js";
157
+ } from "./index-tjvrchxj.js";
158
158
  import"./index-ht1bcqdd.js";
159
159
  import {
160
160
  BUILD_DIAGNOSTIC_CODES
161
- } from "./index-6xwtb7cw.js";
161
+ } from "./index-r87y7wzw.js";
162
162
  import {
163
163
  BuildError
164
- } from "./index-3nr5rzzp.js";
164
+ } from "./index-zagagnwq.js";
165
+ import"./index-sth219v1.js";
165
166
  import {
166
167
  DEFAULT_PRINT_OPTS,
167
168
  assertMilestone,
@@ -5,6 +5,14 @@ type PdfxFingerprintConfig = {
5
5
  stripAnnotations: boolean | null;
6
6
  /** How near-black text was separated (#331); null when no PDF/X pass ran. Provenance only. */
7
7
  blackText?: "icc" | "k-only" | null;
8
+ /**
9
+ * How pages with transparency were handled (#385): `pdfx.transparency`,
10
+ * `pdfx.flattenPages` and `pdfx.rasterDpi`. null when no PDF/X pass ran
11
+ * (and, for rasterDpi, when unset). Provenance only.
12
+ */
13
+ transparency?: "flatten-page" | "preserve-text" | null;
14
+ flattenPages?: number[] | null;
15
+ rasterDpi?: number | null;
8
16
  };
9
17
  export type BuildFingerprintInput = {
10
18
  command: "build";
@@ -1,3 +1,4 @@
1
+ import type { UnsplittableReason } from "./pdf-inspect";
1
2
  /**
2
3
  * Resolve the Ghostscript command on every supported platform.
3
4
  *
@@ -8,38 +9,39 @@
8
9
  */
9
10
  export declare function resolveGhostscript(targetPlatform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): Promise<string | undefined>;
10
11
  /**
11
- * Whether `pdfBytes` uses any live PDF transparency — the PDF 1.4 imaging
12
- * feature, in ALL the forms Chromium emits it, not just alpha-channel images:
12
+ * The 1-based page numbers of `pdfBytes` that use live PDF transparency — the
13
+ * PDF 1.4 imaging feature, in ALL the forms Chromium emits it, not just
14
+ * alpha-channel images:
13
15
  *
14
16
  * - a transparency **group** (`/Group << /S /Transparency >>`), which is what
15
17
  * CSS `opacity`, `mix-blend-mode` and friends compile down to;
16
18
  * - an **image soft mask** (`/SMask` on an image XObject, pointing at a real
17
19
  * mask rather than the literal `/None` an opaque image also carries) — an
18
20
  * RGBA source image;
19
- * - a **graphics-state** soft mask or constant alpha (`/SMask`, `/ca`, `/CA`
20
- * on an `/ExtGState`).
21
+ * - a **graphics-state** soft mask, constant alpha (`/ca`, `/CA` below 1) or
22
+ * non-Normal blend mode (`/BM`) on an `/ExtGState` — soft `rgba()`
23
+ * shadows and fills.
21
24
  *
22
25
  * PDF/X-1a and PDF/X-3 (as this codebase generates them, `-dCompatibilityLevel=1.3`
23
26
  * in {@link convertToPdfxCmyk}) are both based on PDF 1.3, which predates the
24
27
  * PDF 1.4 transparency model entirely — live transparency has nothing a
25
28
  * PDF-1.3 file can represent it with. Ghostscript's only PDF/X-compliant
26
29
  * option is to flatten the page it appears ON down to a single raster image
27
- * (B.10, measured: a book with alpha-channel artwork loses every embedded
28
- * font and all searchable text in its PDF/X output, identically on both
29
- * engines — this is a Ghostscript/PDF-1.3 property, not an engine bug).
30
- * Detecting it lets the build warn the author PRECISELY, instead of them
31
- * discovering a fontless PDF/X file after the fact.
30
+ * (B.10, measured: text and fonts on that page are lost, identically on both
31
+ * engines — a Ghostscript/PDF-1.3 property, not an engine bug).
32
+ * {@link flattenTransparentPages} (opt-in, `pdfx.transparency: preserve-text`)
33
+ * can instead keep the text live on the pages this returns.
32
34
  *
33
- * This walks the parsed object graph rather than scanning raw bytes. A byte
34
- * scan is NOT sufficient and produced a false "all clear" in review: image
35
+ * This walks each page's parsed object graph rather than scanning raw bytes. A
36
+ * byte scan is NOT sufficient and produced a false "all clear" in review: image
35
37
  * XObjects are streams, so their dicts do sit uncompressed at top level, but
36
38
  * `/ExtGState` and `/Group` dicts are plain objects that Chromium packs into
37
39
  * **object streams** (`/Type /ObjStm`, deflate-compressed), where no regex can
38
- * see them. Measured on four books with known Ghostscript outcomes, this
39
- * predicate is exactly right on all four; the byte scan silently missed the
40
- * CSS-`opacity` book, which rasterizes to zero embedded fonts.
40
+ * see them. Fonts, `/Parent` (which leads to every other page) and `/Annots`
41
+ * are not followed: an annotation's appearance stream is not page content, and
42
+ * PDF/X builds strip annotations before conversion.
41
43
  */
42
- export declare function hasLiveTransparency(pdfBytes: Uint8Array): Promise<boolean>;
44
+ export declare function transparentPages(pdfBytes: Uint8Array): Promise<number[]>;
43
45
  /**
44
46
  * 1-based numbers of the pages that paint a `/ShadingType 1` shading whose
45
47
  * function is `/FunctionType 4` (a PostScript calculator function).
@@ -56,7 +58,7 @@ export declare function hasLiveTransparency(pdfBytes: Uint8Array): Promise<boole
56
58
  *
57
59
  * Walks page resources (and form XObjects they draw) rather than every
58
60
  * object, so only shadings a page can actually paint are reported. Like
59
- * {@link hasLiveTransparency}, it never fails a build: an unparseable PDF
61
+ * {@link transparentPages}, it never fails a build: an unparseable PDF
60
62
  * reports no pages.
61
63
  */
62
64
  export declare function findPostScriptShadingPages(pdfBytes: Uint8Array): Promise<number[]>;
@@ -81,6 +83,58 @@ export declare function findPostScriptShadingPages(pdfBytes: Uint8Array): Promis
81
83
  * directly (pdf-lib, in-process, no second external tool).
82
84
  */
83
85
  export declare function stripAnnotations(pdfPath: string, stagingDir: string): Promise<void>;
86
+ /** Why a transparent page is flattened whole under `preserve-text` instead of split. */
87
+ export type FallbackCause = Exclude<UnsplittableReason, "no-text"> | "listed" | "gradient";
88
+ /**
89
+ * Sort each page that uses transparency (1-based, from {@link transparentPages})
90
+ * for `pdfx.transparency: preserve-text`:
91
+ * - `split`: its artwork is flattened and its text kept live
92
+ * ({@link flattenTransparentPages});
93
+ * - `artOnly`: it shows no text, so there is nothing to keep and Ghostscript
94
+ * flattens it whole, which is as good;
95
+ * - `kept`: it has text but is flattened whole anyway, with the cause the
96
+ * build reports. The author's `pdfx.flattenPages` list wins, then the
97
+ * text's own reason (`unsplittableTextReasons`), then a repeating or conic
98
+ * gradient (#386), whose PostScript-function shading the artwork pass
99
+ * distorts.
100
+ * Every transparent page lands in exactly one group.
101
+ */
102
+ export declare function planTransparentPages(transparent: number[], reasons: Map<number, UnsplittableReason>, flattenPages: number[], gradientPages: number[]): {
103
+ split: number[];
104
+ artOnly: number[];
105
+ kept: Map<number, FallbackCause>;
106
+ };
107
+ /**
108
+ * Make the pages in `pages` (1-based; the `split` group of
109
+ * {@link planTransparentPages}) free of transparency while keeping
110
+ * their text live, so PDF/X (PDF 1.3) conversion has nothing left to flatten
111
+ * into a single bitmap. Opt-in: `pdfx.transparency: preserve-text`.
112
+ *
113
+ * Per affected page, two Ghostscript passes split it in two and pdf-lib
114
+ * stacks the halves back on the ORIGINAL page object:
115
+ *
116
+ * 1. ARTWORK — `pdfimage24 -dFILTERTEXT -r<dpi>` drops the glyphs and
117
+ * composites everything left (soft shadows, alpha images, opacity) into
118
+ * one opaque image (300 DPI unless `pdfx.rasterDpi` says otherwise),
119
+ * straight from the source;
120
+ * 2. TEXT — `-dFILTERIMAGE -dFILTERVECTOR` keeps only the glyphs. It needs
121
+ * `-dNOTRANSPARENCY`: without it Chromium's transparency groups and
122
+ * `/ca`/`/SMask` ExtGStates survive in the text-only file and the next
123
+ * step flattens the page anyway. That is only faithful for text with no
124
+ * transparency of its own, which is why callers leave other pages out;
125
+ * 3. the page's content is replaced by the artwork with the text drawn on
126
+ * top. Editing the original page keeps its boxes (Media/Crop/Trim/Bleed),
127
+ * annotations, the document's metadata, outlines and labels exactly as
128
+ * they were; only its `/Contents`, `/Resources` and `/Group` change.
129
+ *
130
+ * Pages not listed are never touched. Known limits, both consequences of
131
+ * splitting a page into "picture" and "text": the page's vector chrome
132
+ * (rules, backgrounds, shapes) becomes the picture, and text is always the
133
+ * top layer, so text another element covers shows through.
134
+ */
135
+ export declare function flattenTransparentPages(pdfPath: string, pageNumbers: number[], stagingDir: string,
136
+ /** artwork resolution (`pdfx.rasterDpi`) */
137
+ dpi?: number): Promise<void>;
84
138
  type PdfxFlavor = "x1a" | "x3";
85
139
  /**
86
140
  * Stamp the Creator metadata field on an existing PDF.
@@ -134,6 +134,51 @@ export interface OpPass {
134
134
  fonts: FontRef[];
135
135
  }
136
136
  export declare function getOpPass(doc: PDFDocumentProxy): Promise<OpPass>;
137
+ /**
138
+ * Why a page is not split from its artwork: its text cannot be (the first
139
+ * three), or it shows no text at all, so there is none to keep (`no-text`).
140
+ */
141
+ export type UnsplittableReason = "text-transparency" | "type3-font" | "text-pattern-or-clip" | "no-text";
142
+ /**
143
+ * For each 1-based page that `pdfx.transparency: preserve-text` must not split,
144
+ * the first reason found; pages absent from the map can be split. `pages`
145
+ * limits the scan to those pages (the build passes the transparent ones only,
146
+ * so the rest of the book is never decoded).
147
+ *
148
+ * A page's text cannot be split when text SHOWS while transparency is in effect: constant alpha
149
+ * (`ca`/`CA` < 1), a non-Normal blend mode, an active soft mask, or any
150
+ * enclosing transparency group that is composited translucent, blended or
151
+ * masked, or is a knockout group. (Chromium draws `opacity` and
152
+ * `mix-blend-mode` content as a group form XObject under such a state, and
153
+ * resets the state INSIDE the group, so the state at the point the group
154
+ * begins is what counts.) Such text cannot be lifted out of its page and drawn
155
+ * opaque on top of a flattened picture without changing how it looks, so
156
+ * `pdfx.transparency: preserve-text` leaves those pages alone.
157
+ *
158
+ * Also flagged: any page that sets a Type 3 font. Chromium (Skia) emits Type 3
159
+ * for glyphs it can only draw as paths, e.g. the synthetic bold of a
160
+ * single-weight webfont. Their glyph procedures are vector paths, which the
161
+ * text pass's `-dFILTERVECTOR` strips, so the text would print nothing.
162
+ *
163
+ * Also flagged: text painted with a pattern (`scn`/`SCN` to a tiling pattern
164
+ * or shading), as Chromium emits for SVG `<text fill="url(#…)">` and gradient
165
+ * text fills, and text used as a clip (render modes 4-7, `background-clip:
166
+ * text`). The artwork pass removes the glyphs and the text pass's
167
+ * `-dFILTERIMAGE`/`-dFILTERVECTOR` removes their paint, so they would vanish.
168
+ *
169
+ * A plain isolated group composited at alpha 1 / Normal / no mask is NOT
170
+ * counted: painting it is the same as painting its content inline, and
171
+ * Chromium wraps the content of EVERY page in one as soon as any element of
172
+ * the document uses a blend mode (measured on Chromium 141), which would
173
+ * otherwise rule out every page of such a book. The page's OWN `/Group` is
174
+ * likewise ignored.
175
+ *
176
+ * Walks PDF.js's operator list, which has already inlined form XObjects
177
+ * between `paintFormXObjectBegin/End` and reports their `/Group` as
178
+ * `beginGroup/endGroup`. Graphics state is tracked per save/restore (a form
179
+ * XObject is an implicit save/restore).
180
+ */
181
+ export declare function unsplittableTextReasons(pdfBytes: Uint8Array, pages?: number[]): Promise<Map<number, UnsplittableReason>>;
137
182
  /**
138
183
  * Does page `pageNum` (1-based) paint anything at all? False for a page with
139
184
  * no content and for one whose operators only set state or clip. A path op
@@ -155,9 +155,21 @@
155
155
  "enum": ["icc", "k-only"],
156
156
  "default": "icc"
157
157
  },
158
+ "transparency": {
159
+ "type": "string",
160
+ "description": "What a PDF/X build does with a page that uses transparency (an alpha-channel image, a soft `rgba()` shadow, CSS `opacity` or `mix-blend-mode`), which PDF/X (PDF 1.3) cannot represent. `flatten-page` leaves the page to Ghostscript, which rasterizes the WHOLE page: it looks right but loses the page's text and fonts. `preserve-text` flattens only the artwork to a picture (300 DPI, or `rasterDpi`) and draws the text live on top, so the page stays searchable. Text is then always the top layer (text another element covers shows through). A page whose text is translucent or blended, set in a Type 3 font (e.g. a synthetic bold or a text stroke), filled with a pattern or used as a clip, or that has a repeating or conic gradient, falls back to `flatten-page`, and so does any page listed in `flattenPages`. Set `validate.assets.allowAlpha: true` to use alpha-channel images. Same for every preset: `flatten-page`.",
161
+ "enum": ["flatten-page", "preserve-text"],
162
+ "default": "flatten-page"
163
+ },
164
+ "flattenPages": {
165
+ "type": "array",
166
+ "description": "With `transparency: preserve-text`: pages (1-based, the numbers the build reports) left to Ghostscript's whole-page flattening even if they could be split, e.g. a page whose look depends on a cover or tint painted over its text. Page numbers move when the book reflows. Default: none.",
167
+ "items": { "type": "integer", "minimum": 1 },
168
+ "examples": [[4, 13]]
169
+ },
158
170
  "rasterDpi": {
159
171
  "type": "integer",
160
- "description": "Resolution (DPI) of the picture Ghostscript makes of a page it flattens in a PDF/X build because the page uses transparency (PDF/X-1a and X-3 cannot hold it). Lower is smaller and softer; vector content on other pages and the book's own images are not resampled. Unset: Ghostscript's default, 720.",
172
+ "description": "Resolution (DPI) of every picture made from a page that uses transparency: the whole pages Ghostscript flattens and the `preserve-text` artwork. Vector content and the book's own images are not resampled. Unset: Ghostscript's default (720) for whole pages, 300 for `preserve-text` artwork.",
161
173
  "minimum": 72,
162
174
  "maximum": 1200,
163
175
  "examples": [300]
@@ -7,20 +7,21 @@ import {
7
7
  TARGET_IDS,
8
8
  scaffoldExtension,
9
9
  scaffoldProject
10
- } from "./cli-zacevwcy.js";
10
+ } from "./cli-9k2tb493.js";
11
11
  import {
12
12
  resolveGhostscript
13
- } from "./cli-gh0ym80r.js";
13
+ } from "./cli-y9bcya7r.js";
14
14
  import {
15
15
  UsageError,
16
16
  rejectExtraPositionals,
17
17
  rejectUnknownFlags
18
- } from "./cli-7z29z4wz.js";
18
+ } from "./cli-hn9pk0hp.js";
19
19
  import"./cli-ht1bcqdd.js";
20
- import"./cli-j802s31j.js";
20
+ import"./cli-x4p99w8d.js";
21
21
  import {
22
22
  EXIT_CODES
23
23
  } from "./cli-46ycxe6r.js";
24
+ import"./cli-sth219v1.js";
24
25
  import"./cli-eyyggect.js";
25
26
  import {
26
27
  isToolAvailable
@@ -0,0 +1,35 @@
1
+ import {
2
+ DOC_CACHE_MAX,
3
+ clearPdfCache,
4
+ countLinkAnnotations,
5
+ getImageResolutions,
6
+ getOpPass,
7
+ getOutlineCount,
8
+ getPageLabels,
9
+ getPageSize,
10
+ getTextPass,
11
+ isLoadable,
12
+ loadPdf,
13
+ pageHasMarks,
14
+ pendingGraceDestroyCount,
15
+ retainPdfCache,
16
+ unsplittableTextReasons
17
+ } from "./cli-sth219v1.js";
18
+ import"./cli-37x76zdn.js";
19
+ export {
20
+ unsplittableTextReasons,
21
+ retainPdfCache,
22
+ pendingGraceDestroyCount,
23
+ pageHasMarks,
24
+ loadPdf,
25
+ isLoadable,
26
+ getTextPass,
27
+ getPageSize,
28
+ getPageLabels,
29
+ getOutlineCount,
30
+ getOpPass,
31
+ getImageResolutions,
32
+ countLinkAnnotations,
33
+ clearPdfCache,
34
+ DOC_CACHE_MAX
35
+ };
@@ -2,21 +2,22 @@ import {
2
2
  executeValidation,
3
3
  publishTargetFor,
4
4
  reportMissingTools
5
- } from "./cli-zacevwcy.js";
5
+ } from "./cli-9k2tb493.js";
6
6
  import {
7
7
  log
8
- } from "./cli-gh0ym80r.js";
8
+ } from "./cli-y9bcya7r.js";
9
9
  import {
10
10
  UsageError,
11
11
  rejectExtraPositionals,
12
12
  rejectUnknownFlags
13
- } from "./cli-7z29z4wz.js";
13
+ } from "./cli-hn9pk0hp.js";
14
14
  import"./cli-ht1bcqdd.js";
15
- import"./cli-j802s31j.js";
15
+ import"./cli-x4p99w8d.js";
16
16
  import {
17
17
  BuildError,
18
18
  EXIT_CODES
19
19
  } from "./cli-46ycxe6r.js";
20
+ import"./cli-sth219v1.js";
20
21
  import"./cli-eyyggect.js";
21
22
  import"./cli-asap4t1z.js";
22
23
  import"./cli-5qr3z0qa.js";
@@ -6,10 +6,10 @@ import {
6
6
  runBuild,
7
7
  splitOutPath,
8
8
  startPreviewServer
9
- } from "./cli-zacevwcy.js";
9
+ } from "./cli-9k2tb493.js";
10
10
  import {
11
11
  log
12
- } from "./cli-gh0ym80r.js";
12
+ } from "./cli-y9bcya7r.js";
13
13
  import {
14
14
  UsageError,
15
15
  parseFormat,
@@ -17,12 +17,13 @@ import {
17
17
  rejectExtraPositionals,
18
18
  rejectUnknownFlags,
19
19
  resolvePort
20
- } from "./cli-7z29z4wz.js";
20
+ } from "./cli-hn9pk0hp.js";
21
21
  import"./cli-ht1bcqdd.js";
22
- import"./cli-j802s31j.js";
22
+ import"./cli-x4p99w8d.js";
23
23
  import {
24
24
  BuildError
25
25
  } from "./cli-46ycxe6r.js";
26
+ import"./cli-sth219v1.js";
26
27
  import"./cli-eyyggect.js";
27
28
  import"./cli-asap4t1z.js";
28
29
  import"./cli-5qr3z0qa.js";
@@ -11,21 +11,22 @@ import {
11
11
  publishProviderFor,
12
12
  resolvePublishFormat,
13
13
  runPublish
14
- } from "./cli-zacevwcy.js";
14
+ } from "./cli-9k2tb493.js";
15
15
  import {
16
16
  FileTokenStore,
17
17
  log
18
- } from "./cli-gh0ym80r.js";
18
+ } from "./cli-y9bcya7r.js";
19
19
  import {
20
20
  UsageError,
21
21
  rejectExtraPositionals,
22
22
  rejectUnknownFlags
23
- } from "./cli-7z29z4wz.js";
23
+ } from "./cli-hn9pk0hp.js";
24
24
  import"./cli-ht1bcqdd.js";
25
- import"./cli-j802s31j.js";
25
+ import"./cli-x4p99w8d.js";
26
26
  import {
27
27
  EXIT_CODES
28
28
  } from "./cli-46ycxe6r.js";
29
+ import"./cli-sth219v1.js";
29
30
  import"./cli-eyyggect.js";
30
31
  import"./cli-asap4t1z.js";
31
32
  import"./cli-5qr3z0qa.js";
@@ -119,8 +119,24 @@ export interface GutterpressManifest {
119
119
  /** `k-only` prints near-black text on the black plate alone (#331). */
120
120
  blackText?: "icc" | "k-only";
121
121
  /**
122
- * Resolution (DPI) of the picture Ghostscript makes of a page it flattens
123
- * because the page uses transparency. Unset: Ghostscript's default (720).
122
+ * A page that uses transparency, which PDF/X cannot hold (#385).
123
+ * `flatten-page` (default): Ghostscript rasterizes the whole page, text
124
+ * included. `preserve-text`: flatten the artwork only and keep the text
125
+ * live on top; a page whose text cannot be split (translucent or blended,
126
+ * Type 3, pattern-filled or a clip) or that has a repeating or conic
127
+ * gradient falls back to the whole-page flattening.
128
+ */
129
+ transparency?: "flatten-page" | "preserve-text";
130
+ /**
131
+ * `preserve-text` only: pages (1-based, as the build reports them) left to
132
+ * Ghostscript's whole-page flattening, e.g. a page whose look depends on a
133
+ * cover or tint painted over its text.
134
+ */
135
+ flattenPages?: number[];
136
+ /**
137
+ * Resolution (DPI) of every picture made from a transparent page: the
138
+ * whole page Ghostscript flattens, and the `preserve-text` artwork.
139
+ * Unset: Ghostscript's default (720) and 300 for `preserve-text` artwork.
124
140
  */
125
141
  rasterDpi?: number;
126
142
  };
@@ -290,6 +306,8 @@ export interface ResolvedConfig {
290
306
  icc: string;
291
307
  stripAnnotations: boolean;
292
308
  blackText: "icc" | "k-only";
309
+ transparency: "flatten-page" | "preserve-text";
310
+ flattenPages: number[];
293
311
  rasterDpi?: number;
294
312
  };
295
313
  print: {
@@ -106,8 +106,8 @@ export interface GrayRaster {
106
106
  }
107
107
  /** Ghostscript's path, or `null`. Callers self-skip, as the PDF/X suites do. */
108
108
  export declare function resolveRasterizer(): Promise<string | null>;
109
- /** Page 1 of `pdfPath` as an 8-bit grayscale raster at 100 dpi. */
110
- export declare function rasterizePdfPage(gsBin: string, pdfPath: string, outDir: string, tag: string): GrayRaster;
109
+ /** Page `page` (default 1) of `pdfPath` as an 8-bit grayscale raster at 100 dpi. */
110
+ export declare function rasterizePdfPage(gsBin: string, pdfPath: string, outDir: string, tag: string, page?: number): GrayRaster;
111
111
  /**
112
112
  * Mean absolute per-pixel difference. `0` means the two prints are identical —
113
113
  * i.e. the declaration under test changed nothing at all.
@@ -1,20 +1,21 @@
1
1
  import {
2
2
  executeAndReport
3
- } from "./cli-zacevwcy.js";
3
+ } from "./cli-9k2tb493.js";
4
4
  import {
5
5
  log
6
- } from "./cli-gh0ym80r.js";
6
+ } from "./cli-y9bcya7r.js";
7
7
  import {
8
8
  UsageError,
9
9
  rejectExtraPositionals,
10
10
  rejectUnknownFlags
11
- } from "./cli-7z29z4wz.js";
11
+ } from "./cli-hn9pk0hp.js";
12
12
  import"./cli-ht1bcqdd.js";
13
- import"./cli-j802s31j.js";
13
+ import"./cli-x4p99w8d.js";
14
14
  import {
15
15
  BuildError,
16
16
  EXIT_CODES
17
17
  } from "./cli-46ycxe6r.js";
18
+ import"./cli-sth219v1.js";
18
19
  import"./cli-eyyggect.js";
19
20
  import"./cli-asap4t1z.js";
20
21
  import"./cli-5qr3z0qa.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gutterpress",
3
- "version": "0.11.20-alpha.2",
3
+ "version": "0.11.20-alpha.3",
4
4
  "description": "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
5
5
  "author": "itlackey",
6
6
  "license": "MPL-2.0",