layoutbridge-light 0.0.0-stage → 1.0.0
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/CHANGELOG.md +22 -0
- package/LICENSE +26 -0
- package/README.de.md +338 -0
- package/README.md +325 -2
- package/THIRD-PARTY-NOTICES.md +2878 -0
- package/dist/src/mcp/catalog.js +126 -0
- package/dist/src/mcp/config.js +211 -0
- package/dist/src/mcp/dispatch.js +164 -0
- package/dist/src/mcp/epub-check.js +331 -0
- package/dist/src/mcp/epub-orientation.js +132 -0
- package/dist/src/mcp/license/free-tools.js +16 -0
- package/dist/src/mcp/license/gate.js +210 -0
- package/dist/src/mcp/license/index.js +107 -0
- package/dist/src/mcp/license/instance-name.js +57 -0
- package/dist/src/mcp/license/key-source.js +59 -0
- package/dist/src/mcp/license/lemonsqueezy-verifier.js +207 -0
- package/dist/src/mcp/license/placeholder-verifier.js +10 -0
- package/dist/src/mcp/license/polar-ids.js +100 -0
- package/dist/src/mcp/license/polar-verifier.js +285 -0
- package/dist/src/mcp/license/product-ids.js +73 -0
- package/dist/src/mcp/license/state-store.js +91 -0
- package/dist/src/mcp/license/types.js +11 -0
- package/dist/src/mcp/logging.js +271 -0
- package/dist/src/mcp/product-info.js +54 -0
- package/dist/src/mcp/product.js +56 -0
- package/dist/src/mcp/server.js +253 -0
- package/dist/src/mcp/setup.js +680 -0
- package/dist/src/mcp/start.cjs +117 -0
- package/dist/src/mcp/tool-definition.js +2 -0
- package/dist/src/mcp/tools.js +2425 -0
- package/dist/src/mcp/typography-rules.js +70 -0
- package/dist/src/transport/com.js +250 -0
- package/dist/src/transport/osascript.js +171 -0
- package/dist/src/transport/queue.js +19 -0
- package/dist/src/transport/script-bundle.js +92 -0
- package/dist/src/transport/transport.js +30 -0
- package/indesign/commands/10-app.js +6 -0
- package/indesign/commands/20-documents.js +517 -0
- package/indesign/commands/22-document-setup.js +204 -0
- package/indesign/commands/23-save-package.js +258 -0
- package/indesign/commands/25-export.js +448 -0
- package/indesign/commands/26-export-image.js +202 -0
- package/indesign/commands/27-textdefaults.js +151 -0
- package/indesign/commands/28-selection.js +174 -0
- package/indesign/commands/30-pages.js +1032 -0
- package/indesign/commands/31-view.js +210 -0
- package/indesign/commands/32-sections.js +203 -0
- package/indesign/commands/35-parents.js +428 -0
- package/indesign/commands/37-layout.js +837 -0
- package/indesign/commands/40-frames.js +851 -0
- package/indesign/commands/41-shapes.js +505 -0
- package/indesign/commands/42-groups.js +117 -0
- package/indesign/commands/43-layers.js +310 -0
- package/indesign/commands/44-effects.js +274 -0
- package/indesign/commands/45-frame-options.js +247 -0
- package/indesign/commands/47-anchored.js +331 -0
- package/indesign/commands/50-modify.js +781 -0
- package/indesign/commands/52-align.js +139 -0
- package/indesign/commands/55-fit.js +106 -0
- package/indesign/commands/60-images.js +1128 -0
- package/indesign/commands/62-embed.js +120 -0
- package/indesign/commands/69-placeholders.js +127 -0
- package/indesign/commands/70-text.js +675 -0
- package/indesign/commands/71-outlines.js +92 -0
- package/indesign/commands/72-place-text.js +476 -0
- package/indesign/commands/73-story-lock.js +157 -0
- package/indesign/commands/74-stories.js +121 -0
- package/indesign/commands/75-tables.js +676 -0
- package/indesign/commands/76-text-variables.js +260 -0
- package/indesign/commands/77-story-options.js +86 -0
- package/indesign/commands/78-frame-lines.js +452 -0
- package/indesign/commands/79-check-typography.js +341 -0
- package/indesign/commands/80-styles.js +1865 -0
- package/indesign/commands/81-composition.js +355 -0
- package/indesign/commands/82-object-styles.js +263 -0
- package/indesign/commands/83-drop-caps.js +87 -0
- package/indesign/commands/83-indents-tabs.js +264 -0
- package/indesign/commands/84-import-styles.js +142 -0
- package/indesign/commands/85-swatches.js +112 -0
- package/indesign/commands/86-gradients.js +185 -0
- package/indesign/commands/87-replace-swatch.js +180 -0
- package/indesign/commands/88-replace-font.js +212 -0
- package/indesign/commands/89-toc-index.js +945 -0
- package/indesign/commands/90-print-on-demand.js +495 -0
- package/indesign/commands/91-epub.js +546 -0
- package/indesign/interpreter.js +779 -0
- package/package.json +41 -4
- package/rules/typography-rules.json +31 -0
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
/* Bereich A – Export und Preflight. */
|
|
2
|
+
|
|
3
|
+
/* ------------------------------------------------------------ export_pdf */
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* Vorgaben ohne Angabe im Aufruf: Hauptpreset = lokalisiertes "High Quality
|
|
7
|
+
* Print", kein zweiter Durchgang. Hauswerte (Preset-Namen, Groessenschwelle)
|
|
8
|
+
* kommen aus der Serverkonfiguration und stehen dann schon in den args
|
|
9
|
+
* (E-54, A-6.3).
|
|
10
|
+
*/
|
|
11
|
+
/* Lokalisierte Namen der mitgelieferten Vorgabe "High Quality Print". */
|
|
12
|
+
var IDC_HQ_PRESET_PATTERN = /high quality print|qualitativ hochwertiger druck|hochwertiger druck/i;
|
|
13
|
+
|
|
14
|
+
function idcPdfPresetByName(name) {
|
|
15
|
+
var preset;
|
|
16
|
+
if (typeof name !== 'string' || name.length === 0) { return null; }
|
|
17
|
+
try {
|
|
18
|
+
preset = app.pdfExportPresets.itemByName(name);
|
|
19
|
+
if (preset && preset.isValid === true) { return preset; }
|
|
20
|
+
} catch (e) { /* nicht vorhanden */ }
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function idcPdfPresetNames() {
|
|
25
|
+
var names = [];
|
|
26
|
+
var i;
|
|
27
|
+
try {
|
|
28
|
+
for (i = 0; i < app.pdfExportPresets.length; i++) {
|
|
29
|
+
names.push(String(app.pdfExportPresets.item(i).name));
|
|
30
|
+
}
|
|
31
|
+
} catch (e) { /* leer */ }
|
|
32
|
+
return names;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function idcHighQualityPreset() {
|
|
36
|
+
var i, preset;
|
|
37
|
+
try {
|
|
38
|
+
for (i = 0; i < app.pdfExportPresets.length; i++) {
|
|
39
|
+
preset = app.pdfExportPresets.item(i);
|
|
40
|
+
if (IDC_HQ_PRESET_PATTERN.test(String(preset.name))) { return preset; }
|
|
41
|
+
}
|
|
42
|
+
} catch (e) { /* keine */ }
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Seitenindex zu einem Namen aus einem Seitenbereich; "+3" = dritte Seite absolut. */
|
|
47
|
+
function idcPageIndexByName(doc, text) {
|
|
48
|
+
var name = text;
|
|
49
|
+
var i, n;
|
|
50
|
+
if (name.charAt(0) === '+') {
|
|
51
|
+
n = Number(name.substr(1));
|
|
52
|
+
if (isNaN(n) || n < 1 || n > doc.pages.length) { return -1; }
|
|
53
|
+
return n - 1;
|
|
54
|
+
}
|
|
55
|
+
for (i = 0; i < doc.pages.length; i++) {
|
|
56
|
+
if (String(doc.pages.item(i).name) === name) { return i; }
|
|
57
|
+
}
|
|
58
|
+
return -1;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function idcTrim(text) {
|
|
62
|
+
return String(text).replace(/^\s+/, '').replace(/\s+$/, '');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/*
|
|
66
|
+
* Seitenbereich wie in InDesigns Exportdialog ("6-8", "1, 3-5", "+2-+4")
|
|
67
|
+
* gegen die angezeigten Seitennamen aufloesen. Liefert die Zahl der Seiten.
|
|
68
|
+
*/
|
|
69
|
+
function idcCountPagesInRange(doc, rangeText) {
|
|
70
|
+
var parts = String(rangeText).split(',');
|
|
71
|
+
var count = 0;
|
|
72
|
+
var p, part, single, from, to, cut, left, right, found;
|
|
73
|
+
|
|
74
|
+
for (p = 0; p < parts.length; p++) {
|
|
75
|
+
part = idcTrim(parts[p]);
|
|
76
|
+
if (part === '') { continue; }
|
|
77
|
+
single = idcPageIndexByName(doc, part);
|
|
78
|
+
if (single >= 0) { count += 1; continue; }
|
|
79
|
+
|
|
80
|
+
found = false;
|
|
81
|
+
for (cut = 1; cut < part.length; cut++) {
|
|
82
|
+
if (part.charAt(cut) !== '-') { continue; }
|
|
83
|
+
left = idcTrim(part.substr(0, cut));
|
|
84
|
+
right = idcTrim(part.substr(cut + 1));
|
|
85
|
+
from = idcPageIndexByName(doc, left);
|
|
86
|
+
to = idcPageIndexByName(doc, right);
|
|
87
|
+
if (from >= 0 && to >= 0) { found = true; break; }
|
|
88
|
+
}
|
|
89
|
+
if (!found) {
|
|
90
|
+
IDC.fail('invalid_argument',
|
|
91
|
+
'page_range "' + rangeText + '": "' + part + '" names no page of this document (page names are the printed page numbers; "+3" addresses the third page).',
|
|
92
|
+
{ page_range: String(rangeText), part: part });
|
|
93
|
+
}
|
|
94
|
+
if (to < from) {
|
|
95
|
+
IDC.fail('invalid_argument', 'page_range "' + rangeText + '": "' + part + '" runs backwards.',
|
|
96
|
+
{ page_range: String(rangeText), part: part });
|
|
97
|
+
}
|
|
98
|
+
count += to - from + 1;
|
|
99
|
+
}
|
|
100
|
+
if (count === 0) {
|
|
101
|
+
IDC.fail('invalid_argument', 'page_range "' + rangeText + '" selects no page.', { page_range: String(rangeText) });
|
|
102
|
+
}
|
|
103
|
+
return count;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/*
|
|
107
|
+
* Dokumentanschnitt nur fuer einen Aufruf (A-43 Nr. 1, KDP-Befund 1): Die
|
|
108
|
+
* mitgelieferten Vorgaben ([PDF/X-1a:2001] u. a.) exportieren ohne
|
|
109
|
+
* Anschnitt, und sie lassen sich nicht aendern (InDesign 21.6: "Die Datei kann
|
|
110
|
+
* nicht erstellt werden"). Deshalb wird die Vorgabe dupliziert
|
|
111
|
+
* (PDFExportPreset.duplicate(), Adobe-DOM), am Duplikat
|
|
112
|
+
* useDocumentBleedWithPDF gesetzt, damit exportiert und das Duplikat danach
|
|
113
|
+
* entfernt. Ohne Vorgabe (aktuelle Exporteinstellungen) wird
|
|
114
|
+
* app.pdfExportPreferences.useDocumentBleedWithPDF gesetzt und zurueckgestellt.
|
|
115
|
+
* bleed null = wie die Vorgabe.
|
|
116
|
+
*/
|
|
117
|
+
function idcExportPdfOnce(doc, file, preset, rangeText, bleed) {
|
|
118
|
+
var prefs = app.pdfExportPreferences;
|
|
119
|
+
var prevRange = null;
|
|
120
|
+
var prevView = null;
|
|
121
|
+
var prevBleed = null;
|
|
122
|
+
var rangeSet = false;
|
|
123
|
+
var viewSet = false;
|
|
124
|
+
var bleedSet = false;
|
|
125
|
+
var temp = null;
|
|
126
|
+
var used = preset;
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
if (bleed !== null && preset !== null) {
|
|
130
|
+
try {
|
|
131
|
+
temp = preset.duplicate();
|
|
132
|
+
temp.useDocumentBleedWithPDF = bleed;
|
|
133
|
+
used = temp;
|
|
134
|
+
} catch (eDup) {
|
|
135
|
+
IDC.fail('script_error', 'Could not prepare the preset with use_document_bleed: ' + String(eDup.message ? eDup.message : eDup),
|
|
136
|
+
{ preset: String(preset.name) });
|
|
137
|
+
}
|
|
138
|
+
} else if (bleed !== null) {
|
|
139
|
+
prevBleed = prefs.useDocumentBleedWithPDF;
|
|
140
|
+
prefs.useDocumentBleedWithPDF = bleed;
|
|
141
|
+
bleedSet = true;
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
prevView = prefs.viewPDF;
|
|
145
|
+
prefs.viewPDF = false;
|
|
146
|
+
viewSet = true;
|
|
147
|
+
} catch (e0) { /* nicht jede Fassung kennt viewPDF */ }
|
|
148
|
+
prevRange = prefs.pageRange;
|
|
149
|
+
prefs.pageRange = rangeText === null ? PageRange.ALL_PAGES : rangeText;
|
|
150
|
+
rangeSet = true;
|
|
151
|
+
if (used !== null) { doc.exportFile(ExportFormat.PDF_TYPE, file, false, used); }
|
|
152
|
+
else { doc.exportFile(ExportFormat.PDF_TYPE, file, false); }
|
|
153
|
+
} catch (e) {
|
|
154
|
+
if (e && e.isIdcError) { throw e; }
|
|
155
|
+
IDC.fail('io_error', 'PDF export failed: ' + String(e.message ? e.message : e),
|
|
156
|
+
{ path: IDC.fsPath(file), preset: preset === null ? null : String(preset.name) });
|
|
157
|
+
} finally {
|
|
158
|
+
if (rangeSet) { try { prefs.pageRange = prevRange; } catch (e1) { /* egal */ } }
|
|
159
|
+
if (viewSet) { try { prefs.viewPDF = prevView; } catch (e2) { /* egal */ } }
|
|
160
|
+
if (bleedSet) { try { prefs.useDocumentBleedWithPDF = prevBleed; } catch (e3) { /* egal */ } }
|
|
161
|
+
if (temp !== null) { try { temp.remove(); } catch (e4) { /* bleibt als Kopie stehen */ } }
|
|
162
|
+
}
|
|
163
|
+
/*
|
|
164
|
+
* Frisches File-Objekt: ExtendScript haelt length im Objekt fest, nach dem
|
|
165
|
+
* zweiten Export stand sonst noch die Groesse des ersten drin (am lebenden
|
|
166
|
+
* InDesign 21.5 am 04.09.2026 gesehen).
|
|
167
|
+
*/
|
|
168
|
+
return IDC.fileSize(IDC.fileFor(IDC.fsPath(file)));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
IDC.register('export_pdf', { needs_document: true, read_only: false, ruler: 'none' },
|
|
172
|
+
function (ctx) {
|
|
173
|
+
var args = ctx.args;
|
|
174
|
+
var doc = ctx.doc;
|
|
175
|
+
var file, rangeText, exportedCount, preset, presetUsed, bytes, fallbackName, threshold, fallback;
|
|
176
|
+
|
|
177
|
+
if (typeof args.path !== 'string' || args.path.length === 0) {
|
|
178
|
+
IDC.fail('invalid_argument', 'path is required (the target file path, not output_path).', null);
|
|
179
|
+
}
|
|
180
|
+
file = IDC.fileFor(args.path);
|
|
181
|
+
if (!IDC.fileParentExists(file)) {
|
|
182
|
+
IDC.fail('io_error', 'The folder for the target path does not exist: ' + args.path, { path: args.path });
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
rangeText = null;
|
|
186
|
+
if (args.page_range !== undefined && args.page_range !== null && idcTrim(args.page_range) !== ''
|
|
187
|
+
&& idcTrim(args.page_range).toLowerCase() !== 'all') {
|
|
188
|
+
rangeText = idcTrim(args.page_range);
|
|
189
|
+
exportedCount = idcCountPagesInRange(doc, rangeText);
|
|
190
|
+
} else {
|
|
191
|
+
exportedCount = doc.pages.length;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/* Preset-Kette: Wunschpreset, sonst High Quality Print, sonst aktuelle Vorgaben. */
|
|
195
|
+
var wanted = null;
|
|
196
|
+
if (args.preset !== undefined && args.preset !== null && String(args.preset) !== '') {
|
|
197
|
+
wanted = String(args.preset);
|
|
198
|
+
}
|
|
199
|
+
preset = wanted === null ? null : idcPdfPresetByName(wanted);
|
|
200
|
+
presetUsed = wanted;
|
|
201
|
+
if (preset === null) {
|
|
202
|
+
preset = idcHighQualityPreset();
|
|
203
|
+
if (preset !== null) {
|
|
204
|
+
presetUsed = String(preset.name);
|
|
205
|
+
if (wanted !== null) {
|
|
206
|
+
ctx.warn('PDF preset "' + wanted + '" not found; used "' + presetUsed + '" instead. Available: ' + idcPdfPresetNames().join(', '));
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
presetUsed = '[current export preferences]';
|
|
210
|
+
if (wanted !== null) {
|
|
211
|
+
ctx.warn('PDF preset "' + wanted + '" not found and no High Quality Print preset either; exported with the current export preferences. Available: ' + idcPdfPresetNames().join(', '));
|
|
212
|
+
} else {
|
|
213
|
+
ctx.warn('No High Quality Print preset found; exported with the current export preferences. Available: ' + idcPdfPresetNames().join(', '));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
var bleed = null;
|
|
219
|
+
if (args.use_document_bleed !== undefined && args.use_document_bleed !== null) {
|
|
220
|
+
if (args.use_document_bleed !== true && args.use_document_bleed !== false) {
|
|
221
|
+
IDC.fail('invalid_argument', 'use_document_bleed must be true or false.', { use_document_bleed: args.use_document_bleed });
|
|
222
|
+
}
|
|
223
|
+
bleed = args.use_document_bleed;
|
|
224
|
+
}
|
|
225
|
+
var docBleed = idcDocumentBleedMm(doc);
|
|
226
|
+
if (bleed === true && docBleed !== null && docBleed.top === 0 && docBleed.bottom === 0 && docBleed.inside_or_left === 0 && docBleed.outside_or_right === 0) {
|
|
227
|
+
ctx.warn('use_document_bleed is true, but the document bleed (Anschnitt) is 0 mm on every edge – set_document_bleed first.');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
bytes = idcExportPdfOnce(doc, file, preset, rangeText, bleed);
|
|
231
|
+
|
|
232
|
+
fallbackName = args.fallback_preset === undefined || args.fallback_preset === null
|
|
233
|
+
? '' : String(args.fallback_preset);
|
|
234
|
+
threshold = args.fallback_over_bytes === undefined || args.fallback_over_bytes === null
|
|
235
|
+
? 0 : Number(args.fallback_over_bytes);
|
|
236
|
+
|
|
237
|
+
if (fallbackName !== '' && threshold > 0 && bytes !== null && bytes > threshold) {
|
|
238
|
+
fallback = idcPdfPresetByName(fallbackName);
|
|
239
|
+
if (fallback === null) {
|
|
240
|
+
ctx.warn('PDF is ' + bytes + ' bytes (over ' + threshold + '), but fallback preset "' + fallbackName + '" was not found; first export kept.');
|
|
241
|
+
} else {
|
|
242
|
+
ctx.warn('PDF was ' + bytes + ' bytes (over ' + threshold + '); exported again with "' + fallbackName + '". A spread preset turns single pages into spreads (Doppelseiten) – check exported_page_count.');
|
|
243
|
+
bytes = idcExportPdfOnce(doc, file, fallback, rangeText, bleed);
|
|
244
|
+
preset = fallback;
|
|
245
|
+
presetUsed = fallbackName;
|
|
246
|
+
if (bytes !== null && bytes > threshold) {
|
|
247
|
+
ctx.warn('Still ' + bytes + ' bytes after the fallback export.');
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
ctx.changes = { exported_files: [IDC.fsPath(file)] };
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
path: IDC.fsPath(file),
|
|
256
|
+
page_count: exportedCount,
|
|
257
|
+
exported_page_count: exportedCount,
|
|
258
|
+
document_page_count: doc.pages.length,
|
|
259
|
+
bytes: bytes,
|
|
260
|
+
preset_used: presetUsed,
|
|
261
|
+
page_range_used: rangeText === null ? 'all' : rangeText,
|
|
262
|
+
document_bleed_used: idcBleedInEffect(preset, bleed),
|
|
263
|
+
document_bleed_mm: docBleed
|
|
264
|
+
};
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
/* Anschnitt des Dokuments in mm (innen/links, aussen/rechts wie InDesign). */
|
|
268
|
+
function idcDocumentBleedMm(doc) {
|
|
269
|
+
var prefs = doc.documentPreferences;
|
|
270
|
+
try {
|
|
271
|
+
return {
|
|
272
|
+
top: IDC.round(Number(prefs.documentBleedTopOffset)),
|
|
273
|
+
bottom: IDC.round(Number(prefs.documentBleedBottomOffset)),
|
|
274
|
+
inside_or_left: IDC.round(Number(prefs.documentBleedInsideOrLeftOffset)),
|
|
275
|
+
outside_or_right: IDC.round(Number(prefs.documentBleedOutsideOrRightOffset))
|
|
276
|
+
};
|
|
277
|
+
} catch (e) { return null; }
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/* Hat der Export den Dokumentanschnitt benutzt? Aufrufwert, sonst die Vorgabe; null = unbekannt. */
|
|
281
|
+
function idcBleedInEffect(preset, bleed) {
|
|
282
|
+
if (bleed !== null) { return bleed; }
|
|
283
|
+
try {
|
|
284
|
+
if (preset !== null) { return preset.useDocumentBleedWithPDF === true; }
|
|
285
|
+
return app.pdfExportPreferences.useDocumentBleedWithPDF === true;
|
|
286
|
+
} catch (e) { return null; }
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/* ---------------------------------------------------- preflight_document */
|
|
290
|
+
|
|
291
|
+
function idcPreflightProfileNames() {
|
|
292
|
+
var names = [];
|
|
293
|
+
var i;
|
|
294
|
+
try {
|
|
295
|
+
for (i = 0; i < app.preflightProfiles.length; i++) {
|
|
296
|
+
names.push(String(app.preflightProfiles.item(i).name));
|
|
297
|
+
}
|
|
298
|
+
} catch (e) { /* leer */ }
|
|
299
|
+
return names;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function idcText(value) {
|
|
303
|
+
if (value === null || value === undefined) { return null; }
|
|
304
|
+
return String(value);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/*
|
|
308
|
+
* aggregatedResults ist [Dokumentname, Profilname, Eintraege[]]. Die Form
|
|
309
|
+
* eines Eintrags ist in Adobes Dokumentation nur als "Array of Strings or
|
|
310
|
+
* Numbers or Arrays" beschrieben; deshalb werden beide beobachtete Formen
|
|
311
|
+
* gelesen: [Kategorie, Beschreibung, Seite, Objekt] und
|
|
312
|
+
* [Kategorie, Beschreibung, [[Seite, Objekt], ...]].
|
|
313
|
+
*/
|
|
314
|
+
function idcParsePreflightFindings(raw) {
|
|
315
|
+
var out = [];
|
|
316
|
+
var list, i, entry, category, description, rest, j, sub;
|
|
317
|
+
|
|
318
|
+
if (!IDC.isArray(raw)) { return out; }
|
|
319
|
+
list = (raw.length >= 3 && IDC.isArray(raw[2])) ? raw[2] : raw;
|
|
320
|
+
|
|
321
|
+
for (i = 0; i < list.length; i++) {
|
|
322
|
+
entry = list[i];
|
|
323
|
+
if (!IDC.isArray(entry)) { continue; }
|
|
324
|
+
category = idcText(entry[0]);
|
|
325
|
+
description = idcText(entry[1]);
|
|
326
|
+
rest = entry.length > 2 ? entry[2] : undefined;
|
|
327
|
+
|
|
328
|
+
if (IDC.isArray(rest)) {
|
|
329
|
+
if (rest.length === 0) {
|
|
330
|
+
out.push({ category: category, description: description, page_name: null, item: null });
|
|
331
|
+
}
|
|
332
|
+
for (j = 0; j < rest.length; j++) {
|
|
333
|
+
sub = rest[j];
|
|
334
|
+
if (IDC.isArray(sub)) {
|
|
335
|
+
out.push({
|
|
336
|
+
category: category,
|
|
337
|
+
description: description,
|
|
338
|
+
page_name: sub.length > 0 ? idcText(sub[0]) : null,
|
|
339
|
+
item: sub.length > 1 ? idcText(sub[1]) : null
|
|
340
|
+
});
|
|
341
|
+
} else {
|
|
342
|
+
out.push({
|
|
343
|
+
category: category,
|
|
344
|
+
description: description,
|
|
345
|
+
page_name: idcText(sub),
|
|
346
|
+
item: entry.length > 3 ? idcText(entry[3]) : null
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
} else {
|
|
351
|
+
out.push({
|
|
352
|
+
category: category,
|
|
353
|
+
description: description,
|
|
354
|
+
page_name: rest === undefined ? null : idcText(rest),
|
|
355
|
+
item: entry.length > 3 ? idcText(entry[3]) : null
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return out;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
IDC.register('preflight_document', { needs_document: true, read_only: true, ruler: 'none' },
|
|
363
|
+
function (ctx) {
|
|
364
|
+
var args = ctx.args;
|
|
365
|
+
var doc = ctx.doc;
|
|
366
|
+
var profiles = idcPreflightProfileNames();
|
|
367
|
+
var maxFindings, profile, working, process, waited, summary, raw, findings, capped;
|
|
368
|
+
|
|
369
|
+
if (args.list_profiles_only === true) {
|
|
370
|
+
return { profiles: profiles, profile_count: profiles.length };
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
maxFindings = args.max_findings === undefined || args.max_findings === null ? 100 : Number(args.max_findings);
|
|
374
|
+
if (isNaN(maxFindings) || maxFindings < 1 || maxFindings > 500) {
|
|
375
|
+
IDC.fail('invalid_argument', 'max_findings must be between 1 and 500.', { max_findings: args.max_findings });
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
profile = null;
|
|
379
|
+
if (args.profile_name !== undefined && args.profile_name !== null && String(args.profile_name) !== '') {
|
|
380
|
+
try {
|
|
381
|
+
profile = app.preflightProfiles.itemByName(String(args.profile_name));
|
|
382
|
+
if (!profile || profile.isValid !== true) { profile = null; }
|
|
383
|
+
} catch (e) { profile = null; }
|
|
384
|
+
if (profile === null) {
|
|
385
|
+
IDC.fail('not_found', 'Preflight profile "' + args.profile_name + '" not found.',
|
|
386
|
+
{ profile_name: String(args.profile_name), available: profiles });
|
|
387
|
+
}
|
|
388
|
+
} else {
|
|
389
|
+
/*
|
|
390
|
+
* Das Arbeitsprofil des Dokuments kann ein ungueltiges Objekt sein –
|
|
391
|
+
* oder laut Adobes DOM auch nur ein Name (String). Beides abfangen.
|
|
392
|
+
*/
|
|
393
|
+
try {
|
|
394
|
+
working = doc.preflightOptions.preflightWorkingProfile;
|
|
395
|
+
if (typeof working === 'string' && working !== '') {
|
|
396
|
+
working = app.preflightProfiles.itemByName(working);
|
|
397
|
+
}
|
|
398
|
+
if (working && working.isValid === true) { profile = working; }
|
|
399
|
+
} catch (e2) { profile = null; }
|
|
400
|
+
if (profile === null) {
|
|
401
|
+
if (app.preflightProfiles.length === 0) {
|
|
402
|
+
IDC.fail('invalid_state', 'InDesign has no preflight profile at all.', null);
|
|
403
|
+
}
|
|
404
|
+
profile = app.preflightProfiles.item(0);
|
|
405
|
+
ctx.warn('The document has no valid working profile; used the first available profile "' + String(profile.name) + '".');
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
try {
|
|
410
|
+
process = app.preflightProcesses.add(doc, profile);
|
|
411
|
+
} catch (e3) {
|
|
412
|
+
IDC.fail('script_error', 'Could not start the preflight process: ' + String(e3.message ? e3.message : e3), null);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
try {
|
|
416
|
+
/*
|
|
417
|
+
* waitForProcess(sekunden) blockiert, bis der Prozess fertig ist oder
|
|
418
|
+
* die Zeit um ist. Adobes Dokumentation und alle bekannten Praxisskripte
|
|
419
|
+
* rufen es genau einmal auf und werten den Rueckgabewert nicht aus –
|
|
420
|
+
* am lebenden InDesign 21.5 kam er sofort und ohne true zurueck, eine
|
|
421
|
+
* Warteschleife darauf drehte leer (04.09.2026). Deshalb: einmal warten,
|
|
422
|
+
* dann lesen.
|
|
423
|
+
*/
|
|
424
|
+
var startedAt = new Date().getTime();
|
|
425
|
+
try { process.waitForProcess(600); } catch (eWait) { /* dann eben ohne Warten lesen */ }
|
|
426
|
+
waited = Math.round((new Date().getTime() - startedAt) / 1000);
|
|
427
|
+
if (waited >= 600) {
|
|
428
|
+
IDC.fail('timeout', 'Preflight did not finish within ' + waited + ' seconds.', null);
|
|
429
|
+
}
|
|
430
|
+
summary = idcTrim(String(process.processResults));
|
|
431
|
+
raw = process.aggregatedResults;
|
|
432
|
+
findings = idcParsePreflightFindings(raw);
|
|
433
|
+
} finally {
|
|
434
|
+
try { process.remove(); } catch (e4) { /* Prozess bleibt dann stehen, stoert nicht */ }
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
capped = findings.length > maxFindings ? findings.slice(0, maxFindings) : findings;
|
|
438
|
+
if (findings.length > maxFindings) {
|
|
439
|
+
ctx.warn(findings.length + ' findings, only the first ' + maxFindings + ' returned (max_findings).');
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
return {
|
|
443
|
+
profile_used: String(profile.name),
|
|
444
|
+
summary: summary,
|
|
445
|
+
error_count: findings.length,
|
|
446
|
+
findings: capped
|
|
447
|
+
};
|
|
448
|
+
});
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/* Wunschliste J Nr. 5 (Sitzung 7) – Seiten als Bild: export_page_image. */
|
|
2
|
+
|
|
3
|
+
function idcImageQualityFor(format, name) {
|
|
4
|
+
var table = format === 'jpeg' ? (typeof JPEGOptionsQuality === 'undefined' ? null : JPEGOptionsQuality)
|
|
5
|
+
: (typeof PNGQualityEnum === 'undefined' ? null : PNGQualityEnum);
|
|
6
|
+
if (table === null) { return null; }
|
|
7
|
+
if (name === 'low') { return table.LOW; }
|
|
8
|
+
if (name === 'medium') { return table.MEDIUM; }
|
|
9
|
+
if (name === 'high') { return table.HIGH; }
|
|
10
|
+
return table.MAXIMUM;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function idcImageColorSpaceFor(format, name) {
|
|
14
|
+
var table = format === 'jpeg' ? (typeof JpegColorSpaceEnum === 'undefined' ? null : JpegColorSpaceEnum)
|
|
15
|
+
: (typeof PNGColorSpaceEnum === 'undefined' ? null : PNGColorSpaceEnum);
|
|
16
|
+
if (table === null) { return null; }
|
|
17
|
+
if (name === 'gray') { return table.GRAY; }
|
|
18
|
+
if (name === 'cmyk') { return table.CMYK; }
|
|
19
|
+
return table.RGB;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* Seiten aus page_ids oder page_range: [{ page, name }] in Dokumentreihenfolge.
|
|
24
|
+
* Hoechstens 48 Seiten (eine Bilddatei je Seite); maxPages 0 = ohne Grenze
|
|
25
|
+
* (check_typography, A-69 Teil 2: dort liest page_range nur, schreibt nichts).
|
|
26
|
+
*/
|
|
27
|
+
function idcPagesForExport(doc, args, maxPages) {
|
|
28
|
+
var out = [];
|
|
29
|
+
var i, j, found, parts, part, single, cut, left, right, from, to;
|
|
30
|
+
var wanted = {};
|
|
31
|
+
if (args.page_ids !== undefined && args.page_ids !== null) {
|
|
32
|
+
if (!IDC.isArray(args.page_ids) || args.page_ids.length === 0) {
|
|
33
|
+
IDC.fail('invalid_argument', 'page_ids must be a non-empty list of page ids.', { page_ids: args.page_ids });
|
|
34
|
+
}
|
|
35
|
+
for (i = 0; i < args.page_ids.length; i++) {
|
|
36
|
+
found = IDC.pageById(doc, args.page_ids[i]);
|
|
37
|
+
if (found === null || found.is_parent_page) {
|
|
38
|
+
IDC.fail('not_found', 'No document page with page_id ' + args.page_ids[i] + ' (master pages cannot be exported as images).', { page_id: args.page_ids[i] });
|
|
39
|
+
}
|
|
40
|
+
wanted[Number(found.page.id)] = true;
|
|
41
|
+
}
|
|
42
|
+
} else if (args.page_range !== undefined && args.page_range !== null) {
|
|
43
|
+
parts = String(args.page_range).split(',');
|
|
44
|
+
for (i = 0; i < parts.length; i++) {
|
|
45
|
+
part = idcTrim(parts[i]);
|
|
46
|
+
if (part === '') { continue; }
|
|
47
|
+
single = idcPageIndexByName(doc, part);
|
|
48
|
+
if (single >= 0) { wanted[Number(doc.pages.item(single).id)] = true; continue; }
|
|
49
|
+
from = -1; to = -1;
|
|
50
|
+
for (cut = 1; cut < part.length; cut++) {
|
|
51
|
+
if (part.charAt(cut) !== '-') { continue; }
|
|
52
|
+
left = idcTrim(part.substr(0, cut));
|
|
53
|
+
right = idcTrim(part.substr(cut + 1));
|
|
54
|
+
from = idcPageIndexByName(doc, left);
|
|
55
|
+
to = idcPageIndexByName(doc, right);
|
|
56
|
+
if (from >= 0 && to >= 0) { break; }
|
|
57
|
+
from = -1; to = -1;
|
|
58
|
+
}
|
|
59
|
+
if (from < 0 || to < 0) {
|
|
60
|
+
IDC.fail('invalid_argument', 'page_range "' + args.page_range + '": "' + part + '" names no page of this document (page names are the printed page numbers; "+3" addresses the third page).',
|
|
61
|
+
{ page_range: String(args.page_range), part: part });
|
|
62
|
+
}
|
|
63
|
+
if (to < from) {
|
|
64
|
+
IDC.fail('invalid_argument', 'page_range "' + args.page_range + '": "' + part + '" runs backwards.', { page_range: String(args.page_range), part: part });
|
|
65
|
+
}
|
|
66
|
+
for (j = from; j <= to; j++) { wanted[Number(doc.pages.item(j).id)] = true; }
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
IDC.fail('invalid_argument', 'Pass page_ids or page_range.', null);
|
|
70
|
+
}
|
|
71
|
+
for (i = 0; i < doc.pages.length; i++) {
|
|
72
|
+
if (wanted[Number(doc.pages.item(i).id)]) { out.push({ page: doc.pages.item(i), name: String(doc.pages.item(i).name) }); }
|
|
73
|
+
}
|
|
74
|
+
if (out.length === 0) { IDC.fail('invalid_argument', 'No page selected.', null); }
|
|
75
|
+
if (maxPages === undefined || maxPages === null) { maxPages = 48; }
|
|
76
|
+
if (maxPages > 0 && out.length > maxPages) { IDC.fail('invalid_argument', 'At most ' + maxPages + ' pages per call.', { count: out.length }); }
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* Dateiname mit Seitenname vor der Endung: Seite.png + "8" -> Seite_8.png. */
|
|
81
|
+
function idcPageFileName(path, pageName, single) {
|
|
82
|
+
var dot = path.lastIndexOf('.');
|
|
83
|
+
var slash = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
|
|
84
|
+
var safe = String(pageName).replace(/[^A-Za-z0-9_.+-]/g, '_');
|
|
85
|
+
if (single) { return path; }
|
|
86
|
+
if (dot > slash) { return path.substr(0, dot) + '_' + safe + path.substr(dot); }
|
|
87
|
+
return path + '_' + safe;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
IDC.register('export_page_image', { needs_document: true, read_only: false, ruler: 'none' },
|
|
91
|
+
function (ctx) {
|
|
92
|
+
var args = ctx.args;
|
|
93
|
+
var doc = ctx.doc;
|
|
94
|
+
var format = args.format === undefined || args.format === null ? 'png' : args.format;
|
|
95
|
+
var dpi = args.dpi === undefined || args.dpi === null ? 150 : args.dpi;
|
|
96
|
+
var quality = args.quality === undefined || args.quality === null ? 'high' : args.quality;
|
|
97
|
+
var colorSpace = args.color_space === undefined || args.color_space === null ? 'rgb' : args.color_space;
|
|
98
|
+
var transparent = args.transparent_background === true;
|
|
99
|
+
var useBleed = args.use_bleed === true;
|
|
100
|
+
var antiAlias = args.anti_alias !== false;
|
|
101
|
+
var path = args.path;
|
|
102
|
+
var pages, prefs, saved = {}, keys, k, file, files = [], i, target, sizeAfter, exportFormat, ext, prevExportFormatOk;
|
|
103
|
+
|
|
104
|
+
if (typeof path !== 'string' || path === '') {
|
|
105
|
+
IDC.fail('invalid_argument', 'path is required: the target file (for several pages the page name is inserted before the extension).', null);
|
|
106
|
+
}
|
|
107
|
+
if (format !== 'png' && format !== 'jpeg') {
|
|
108
|
+
IDC.fail('invalid_argument', 'format must be png or jpeg.', { format: format });
|
|
109
|
+
}
|
|
110
|
+
if (typeof dpi !== 'number' || !isFinite(dpi) || dpi < 36 || dpi > 600) {
|
|
111
|
+
IDC.fail('invalid_argument', 'dpi must be between 36 and 600.', { dpi: dpi });
|
|
112
|
+
}
|
|
113
|
+
if (quality !== 'low' && quality !== 'medium' && quality !== 'high' && quality !== 'maximum') {
|
|
114
|
+
IDC.fail('invalid_argument', 'quality must be low, medium, high or maximum.', { quality: quality });
|
|
115
|
+
}
|
|
116
|
+
if (colorSpace !== 'rgb' && colorSpace !== 'gray' && !(colorSpace === 'cmyk' && format === 'jpeg')) {
|
|
117
|
+
IDC.fail('invalid_argument', 'color_space must be rgb or gray (jpeg also cmyk).', { color_space: colorSpace, format: format });
|
|
118
|
+
}
|
|
119
|
+
ext = format === 'png' ? '.png' : '.jpg';
|
|
120
|
+
if (!(new RegExp('\\.(' + (format === 'png' ? 'png' : 'jpe?g') + ')$', 'i')).test(path)) {
|
|
121
|
+
ctx.warn('path does not end in ' + ext + '; InDesign writes ' + format.toUpperCase() + ' data regardless.');
|
|
122
|
+
}
|
|
123
|
+
pages = idcPagesForExport(doc, args);
|
|
124
|
+
file = IDC.fileFor(path);
|
|
125
|
+
if (!IDC.fileParentExists(file)) {
|
|
126
|
+
IDC.fail('io_error', 'The folder for ' + path + ' does not exist.', { path: path });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
prefs = format === 'png' ? app.pngExportPreferences : app.jpegExportPreferences;
|
|
130
|
+
if (prefs === undefined || prefs === null) {
|
|
131
|
+
IDC.fail('invalid_state', 'This InDesign runtime has no ' + format.toUpperCase() + ' export preferences.', null);
|
|
132
|
+
}
|
|
133
|
+
exportFormat = format === 'png' ? ExportFormat.PNG_FORMAT : ExportFormat.JPG;
|
|
134
|
+
|
|
135
|
+
/* Vorgaben merken, setzen, am Ende zurueckstellen. */
|
|
136
|
+
keys = format === 'png'
|
|
137
|
+
? ['exportResolution', 'pngQuality', 'pngColorSpace', 'transparentBackground', 'antiAlias', 'useDocumentBleeds', 'pngExportRange', 'pageString', 'exportingSpread', 'simulateOverprint']
|
|
138
|
+
: ['exportResolution', 'jpegQuality', 'jpegColorSpace', 'antiAlias', 'useDocumentBleeds', 'jpegExportRange', 'pageString', 'exportingSpread', 'simulateOverprint', 'jpegRenderingStyle'];
|
|
139
|
+
for (k = 0; k < keys.length; k++) {
|
|
140
|
+
try { saved[keys[k]] = prefs[keys[k]]; } catch (e0) { /* Eigenschaft fehlt */ }
|
|
141
|
+
}
|
|
142
|
+
var setPref = function (key, value) {
|
|
143
|
+
if (value === null || value === undefined) { return; }
|
|
144
|
+
try { prefs[key] = value; } catch (e1) { ctx.warn('Could not set export preference ' + key + ': ' + String(e1.message ? e1.message : e1)); }
|
|
145
|
+
};
|
|
146
|
+
try {
|
|
147
|
+
setPref('exportResolution', dpi);
|
|
148
|
+
setPref('antiAlias', antiAlias);
|
|
149
|
+
setPref('useDocumentBleeds', useBleed);
|
|
150
|
+
setPref('simulateOverprint', false);
|
|
151
|
+
setPref('exportingSpread', false);
|
|
152
|
+
if (format === 'png') {
|
|
153
|
+
setPref('pngQuality', idcImageQualityFor('png', quality));
|
|
154
|
+
setPref('pngColorSpace', idcImageColorSpaceFor('png', colorSpace));
|
|
155
|
+
setPref('transparentBackground', transparent);
|
|
156
|
+
if (typeof ExportRangeOrAllPages !== 'undefined') { setPref('pngExportRange', ExportRangeOrAllPages.EXPORT_RANGE); }
|
|
157
|
+
} else {
|
|
158
|
+
setPref('jpegQuality', idcImageQualityFor('jpeg', quality));
|
|
159
|
+
setPref('jpegColorSpace', idcImageColorSpaceFor('jpeg', colorSpace));
|
|
160
|
+
if (typeof JPEGOptionsFormat !== 'undefined') { setPref('jpegRenderingStyle', JPEGOptionsFormat.BASELINE_ENCODING); }
|
|
161
|
+
if (typeof ExportRangeOrAllPages !== 'undefined') { setPref('jpegExportRange', ExportRangeOrAllPages.EXPORT_RANGE); }
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
for (i = 0; i < pages.length; i++) {
|
|
165
|
+
target = idcPageFileName(path, pages[i].name, pages.length === 1);
|
|
166
|
+
setPref('pageString', pages[i].name);
|
|
167
|
+
try {
|
|
168
|
+
doc.exportFile(exportFormat, IDC.fileFor(target), false);
|
|
169
|
+
} catch (e2) {
|
|
170
|
+
IDC.fail('io_error', 'Image export of page ' + pages[i].name + ' failed: ' + String(e2.message ? e2.message : e2) +
|
|
171
|
+
(files.length > 0 ? ' (' + files.length + ' page(s) exported before)' : ''), { path: target, page_name: pages[i].name, exported: files });
|
|
172
|
+
}
|
|
173
|
+
sizeAfter = IDC.fileSize(IDC.fileFor(target));
|
|
174
|
+
if (sizeAfter === null || sizeAfter === 0) {
|
|
175
|
+
/* InDesign haengt bei Bedarf selbst den Seitennamen an – dann dort nachsehen. */
|
|
176
|
+
var alt = idcPageFileName(path, pages[i].name, false);
|
|
177
|
+
var alt2 = alt.replace('_' + String(pages[i].name).replace(/[^A-Za-z0-9_.+-]/g, '_'), String(pages[i].name));
|
|
178
|
+
if (IDC.fileSize(IDC.fileFor(alt)) > 0) { target = alt; sizeAfter = IDC.fileSize(IDC.fileFor(alt)); }
|
|
179
|
+
else if (IDC.fileSize(IDC.fileFor(alt2)) > 0) { target = alt2; sizeAfter = IDC.fileSize(IDC.fileFor(alt2)); }
|
|
180
|
+
else { ctx.warn('Page ' + pages[i].name + ': no file found at ' + target + ' after the export.'); }
|
|
181
|
+
}
|
|
182
|
+
files.push({ page_id: Number(pages[i].page.id), page_name: pages[i].name, path: target, bytes: sizeAfter });
|
|
183
|
+
}
|
|
184
|
+
} finally {
|
|
185
|
+
for (k = 0; k < keys.length; k++) {
|
|
186
|
+
if (saved[keys[k]] !== undefined) {
|
|
187
|
+
try { prefs[keys[k]] = saved[keys[k]]; } catch (e3) { ctx.warn('Could not restore export preference ' + keys[k] + '.'); }
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
format: format,
|
|
194
|
+
dpi: dpi,
|
|
195
|
+
quality: quality,
|
|
196
|
+
color_space: colorSpace,
|
|
197
|
+
transparent_background: format === 'png' ? transparent : null,
|
|
198
|
+
use_bleed: useBleed,
|
|
199
|
+
count: files.length,
|
|
200
|
+
files: files
|
|
201
|
+
};
|
|
202
|
+
});
|