"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /* Copyright (C) 1995-2005 Ghostgum Software Pty Ltd. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under licence and may not be copied,
7 modified or distributed except as expressly authorised under the terms
8 of the licence contained in the file LICENCE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostgum.com.au/ or contact Ghostsgum Software Pty Ltd,
12 218 Gallaghers Rd, Glen Waverley VIC 3150, AUSTRALIA,
13 Fax +61 3 9886 6616.
14 */
15
16 /* $Id: epstool.c,v 1.69 2005/06/10 08:45:36 ghostgum Exp $ */
17
18 #include "common.h"
19 #include "dscparse.h"
20 #include "errors.h"
21 #include "iapi.h"
22 #include "gdevdsp.h"
23 #define DEFINE_COPT
24 #include "copt.h"
25 #define DEFINE_CAPP
26 #include "capp.h"
27 #include "cbmp.h"
28 #define DEFINE_CDOC
29 #include "cdoc.h"
30 #include "cdll.h"
31 #include "cgssrv.h"
32 #include "cmac.h"
33 #include "ceps.h"
34 #include "cimg.h"
35 #include "cpagec.h"
36 #include "cres.h"
37 #ifdef __WIN32__
38 #include "wgsver.h"
39 #endif
40 #if defined(UNIX) || defined(OS2)
41 #include <fcntl.h>
42 #include <sys/wait.h>
43 #include <errno.h>
44 #endif
45
46 const char *epstool_name = "epstool";
47 const char *epstool_version = "3.08"; /* should be EPSTOOL_VERSION */
48 const char *epstool_date = "2005-06-06"; /* should be EPSTOOL_DATE */
49 const char *copyright = "Copyright 1995-2005 Ghostgum Software Pty Ltd";
50
51 const char *cmd_help = "\
52 Commands (one only):\n\
53 --add-tiff4-preview or -t4\n\
54 --add-tiff6u-preview or -t6u\n\
55 --add-tiff6p-preview or -t6p\n\
56 --add-tiff-preview or -tg\n\
57 --add-interchange-preview or -i\n\
58 --add-metafile-preview or -w\n\
59 --add-pict-preview\n\
60 --add-user-preview filename\n\
61 --dcs2-multi\n\
62 --dcs2-single\n\
63 --dcs2-report\n\
64 --extract-postscript or -p\n\
65 --extract-preview or -v\n\
66 --bitmap\n\
67 --copy\n\
68 --dump\n\
69 --help or -h\n\
70 --test-eps\n\
71 --version\n\
72 ";
73
74 const char *opt_help = "\
75 Options:\n\
76 --bbox or -b\n\
77 --combine-separations filename\n\
78 --combine-tolerance pts\n\
79 --custom-colours filename\n\
80 --debug or -d\n\
81 --device name\n\
82 --doseps-reverse\n\
83 --dpi resolution\n\
84 --dpi-render resolution\n\
85 --ignore-information\n\
86 --ignore-warnings\n\
87 --ignore-errors\n\
88 --gs command\n\
89 --gs-args arguments\n\
90 --mac-binary\n\
91 --mac-double\n\
92 --mac-rsrc\n\
93 --mac-single\n\
94 --missing-separations\n\
95 --output filename\n\
96 --page-number\n\
97 --quiet\n\
98 --rename-separation old_name new_name\n\
99 --replace-composite\n\
100 ";
101
102
103 typedef enum {
104 CMD_UNKNOWN,
105 CMD_TIFF4,
106 CMD_TIFF6U,
107 CMD_TIFF6P,
108 CMD_TIFF,
109 CMD_INTERCHANGE,
110 CMD_WMF,
111 CMD_PICT,
112 CMD_USER,
113 CMD_DCS2_MULTI,
114 CMD_DCS2_SINGLE,
115 CMD_DCS2_REPORT,
116 CMD_PREVIEW,
117 CMD_POSTSCRIPT,
118 CMD_BITMAP,
119 CMD_COPY,
120 CMD_DUMP,
121 CMD_HELP,
122 CMD_TEST,
123 CMD_VERSION
124 } CMD;
125
126 typedef enum{
127 CUSTOM_CMYK,
128 CUSTOM_RGB
129 } CUSTOM_COLOUR_TYPE;
130 typedef struct CUSTOM_COLOUR_s CUSTOM_COLOUR;
131 struct CUSTOM_COLOUR_s {
132 char name[MAXSTR];
133 CUSTOM_COLOUR_TYPE type;
134 /* if type=CUSTOM_CMYK */
135 float cyan;
136 float magenta;
137 float yellow;
138 float black;
139 /* if type=CUSTOM_RGB */
140 float red;
141 float green;
142 float blue;
143 /* Next colour */
144 CUSTOM_COLOUR *next;
145 };
146 typedef struct OPT_s {
147 CMD cmd;
148 TCHAR device[64]; /* --device name for --bitmap or --add-tiff-preview */
149 BOOL composite; /* --replace-composite */
150 BOOL bbox; /* --bbox */
151 int dscwarn; /* --ignore-warnings etc. */
152 TCHAR gs[MAXSTR]; /* --gs command */
153 TCHAR gsargs[MAXSTR*4]; /* --gs-args arguments */
154 TCHAR input[MAXSTR]; /* filename */
155 TCHAR output[MAXSTR]; /* --output filename or (second) filename */
156 TCHAR user_preview[MAXSTR]; /* --add-user-preview filename */
157 BOOL quiet; /* --quiet */
158 BOOL debug; /* --debug */
159 BOOL doseps_reverse; /* --doseps-reverse */
160 float dpi; /* --dpi resolution */
161 float dpi_render; /* --dpi-render resolution */
162 BOOL help; /* --help */
163 TCHAR custom_colours[MAXSTR]; /* --custom-colours filename */
164 CUSTOM_COLOUR *colours;
165 BOOL missing_separations; /* --missing-separations */
166 TCHAR combine[MAXSTR]; /* --combine-separations filename */
167 int tolerance; /* --combine-tolerance pts */
168 RENAME_SEPARATION *rename_sep; /* --rename-separation */
169 CMAC_TYPE mac_type; /* --mac-binary, --mac-double, --mac-single */
170 /* or --mac-rsrc */
171 int page; /* --page-number for --bitmap */
172 int image_compress; /* IMAGE_COMPRESS_NONE, RLE, LZW */
173 int image_encode; /* IMAGE_ENCODE_HEX, ASCII85 */
174 } OPT;
175
176
177 #define MSGOUT stdout
178 #ifdef UNIX
179 const char gsexe[] = "gs";
180 #define COLOUR_DEVICE "ppmraw"
181 #define GREY_DEVICE "pgmraw"
182 #define MONO_DEVICE "pbmraw"
183 #endif
184
185 #ifdef OS2
186 TCHAR gsexe[MAXSTR] = TEXT("gsos2.exe");
187 #define COLOUR_DEVICE TEXT("bmp16m")
188 #define GREY_DEVICE TEXT("bmpgray")
189 #define MONO_DEVICE TEXT("bmpmono")
190 #endif
191
192 #ifdef _WIN32
193 TCHAR gsexe[MAXSTR] = TEXT("gswin32c.exe");
194 #define COLOUR_DEVICE TEXT("bmp16m")
195 #define GREY_DEVICE TEXT("bmpgray")
196 #define MONO_DEVICE TEXT("bmpmono")
197 #endif
198
199
200 static void print_help(void);
201 static void print_version(void);
202 static int parse_args(OPT *opt, int argc, TCHAR *argv[]);
203 static Doc * epstool_open_document(GSview *app, OPT *opt, TCHAR *name);
204 static int epstool_add_preview(Doc *doc, OPT *opt);
205 static int epstool_dcs2_copy(Doc *doc, Doc *doc2, OPT *opt);
206 static int epstool_dcs2_report(Doc *doc);
207 static int epstool_dcs2_composite(Doc *doc, OPT *opt, GFile *compfile);
208 static int epstool_dcs2_check_files(Doc *doc, OPT *opt);
209 static int epstool_extract(Doc *doc, OPT *opt);
210 static int epstool_bitmap(Doc *doc, OPT *opt);
211 static int epstool_copy(Doc *doc, OPT *opt);
212 static int epstool_copy_bitmap(Doc *doc, OPT *opt);
213 static int epstool_test(Doc *doc, OPT *opt);
214 static void epstool_dump_fn(void *caller_data, const char *str);
215
216 static IMAGE *make_preview_image(Doc *doc, OPT *opt, int page, LPCTSTR device,
217 CDSCBBOX *bbox, CDSCFBBOX *hires_bbox, int calc_bbox);
218 static int make_preview_file(Doc *doc, OPT *opt, int page,
219 LPCTSTR preview, LPCTSTR device,
220 float dpi, CDSCBBOX *bbox, CDSCFBBOX *hires_bbox, int calc_bbox);
221 static int calculate_bbox(Doc *doc, OPT *opt, LPCTSTR psname,
222 CDSCBBOX *bbox, CDSCFBBOX *hires_bbox);
223 static int calc_device_size(float dpi, CDSCBBOX *bbox, CDSCFBBOX *hires_bbox,
224 int *width, int *height, float *xoffset, float *yoffset);
225 static int exec_program(LPTSTR command,
226 int hstdin, int hstdout, int hstderr,
227 LPCTSTR stdin_name, LPCTSTR stdout_name, LPCTSTR stderr_name);
228 static int custom_colours_read(OPT *opt);
229 static CUSTOM_COLOUR *custom_colours_find(OPT *opt, const char *name);
230 static void custom_colours_free(OPT *opt);
231 static int colour_to_cmyk(CDSC *dsc, const char *name,
232 float *cyan, float *magenta, float *yellow, float *black);
233
234
235 static void
236 print_version(void)
237 {
238 fprintf(MSGOUT, "%s %s %s\n", epstool_name, epstool_version, epstool_date);
239 }
240
241 static void
242 print_help(void)
243 {
244 print_version();
245 fprintf(MSGOUT, "%s\n", copyright);
246 fprintf(MSGOUT, "Usage: epstool command [options] inputfile outputfile\n");
247 fprintf(MSGOUT, "%s", cmd_help);
248 fprintf(MSGOUT, "%s", opt_help);
249 }
250
251 /* return 0 on success, or argument index if there is a duplicated
252 * command, a missing parameter, or an unknown argument.
253 */
254 static int
255 parse_args(OPT *opt, int argc, TCHAR *argv[])
256 {
257 int arg;
258 const TCHAR *p;
259 memset(opt, 0, sizeof(OPT));
260 opt->cmd = CMD_UNKNOWN;
261 opt->dpi = 72.0;
262 opt->dpi_render = 0.0;
263 opt->mac_type = CMAC_TYPE_NONE;
264 opt->dscwarn = CDSC_ERROR_NONE;
265 opt->image_encode = IMAGE_ENCODE_ASCII85;
266 opt->image_compress = IMAGE_COMPRESS_LZW;
267 csncpy(opt->gs, gsexe, sizeof(opt->gs)/sizeof(TCHAR)-1);
268 for (arg=1; arg<argc; arg++) {
269 p = argv[arg];
270 if ((cscmp(p, TEXT("--add-tiff4-preview")) == 0) ||
271 (cscmp(p, TEXT("-t4")) == 0)) {
272 if (opt->cmd != CMD_UNKNOWN)
273 return arg;
274 opt->cmd = CMD_TIFF4;
275 }
276 else if ((cscmp(p, TEXT("--add-tiff6u-preview")) == 0) ||
277 (cscmp(p, TEXT("-t6u")) == 0)) {
278 if (opt->cmd != CMD_UNKNOWN)
279 return arg;
280 opt->cmd = CMD_TIFF6U;
281 }
282 else if ((cscmp(p, TEXT("--add-tiff6p-preview")) == 0) ||
283 (cscmp(p, TEXT("-t6p")) == 0)) {
284 if (opt->cmd != CMD_UNKNOWN)
285 return arg;
286 opt->cmd = CMD_TIFF6P;
287 }
288 else if ((cscmp(p, TEXT("--add-tiff-preview")) == 0) ||
289 (cscmp(p, TEXT("-tg")) == 0)) {
290 if (opt->cmd != CMD_UNKNOWN)
291 return arg;
292 opt->cmd = CMD_TIFF;
293 }
294 else if ((cscmp(p, TEXT("--add-interchange-preview")) == 0) ||
295 (cscmp(p, TEXT("-i")) == 0)) {
296 if (opt->cmd != CMD_UNKNOWN)
297 return arg;
298 opt->cmd = CMD_INTERCHANGE;
299 }
300 else if ((cscmp(p, TEXT("--add-metafile-preview")) == 0) ||
301 (cscmp(p, TEXT("-w")) == 0)) {
302 if (opt->cmd != CMD_UNKNOWN)
303 return arg;
304 opt->cmd = CMD_WMF;
305 }
306 else if ((cscmp(p, TEXT("--add-pict-preview")) == 0) ||
307 (cscmp(p, TEXT("-w")) == 0)) {
308 if (opt->cmd != CMD_UNKNOWN)
309 return arg;
310 opt->cmd = CMD_PICT;
311 }
312 else if (cscmp(p, TEXT("--add-user-preview")) == 0) {
313 if (opt->cmd != CMD_UNKNOWN)
314 return arg;
315 opt->cmd = CMD_USER;
316 arg++;
317 if (arg == argc)
318 return arg;
319 csncpy(opt->user_preview, argv[arg],
320 sizeof(opt->user_preview)/sizeof(TCHAR)-1);
321 }
322 else if (cscmp(p, TEXT("--dcs2-multi")) == 0) {
323 if (opt->cmd != CMD_UNKNOWN)
324 return arg;
325 opt->cmd = CMD_DCS2_MULTI;
326 }
327 else if (cscmp(p, TEXT("--dcs2-single")) == 0) {
328 if (opt->cmd != CMD_UNKNOWN)
329 return arg;
330 opt->cmd = CMD_DCS2_SINGLE;
331 }
332 else if (cscmp(p, TEXT("--dcs2-report")) == 0) {
333 if (opt->cmd != CMD_UNKNOWN)
334 return arg;
335 opt->cmd = CMD_DCS2_REPORT;
336 }
337 else if (cscmp(p, TEXT("--dump")) == 0) {
338 if (opt->cmd != CMD_UNKNOWN)
339 return arg;
340 opt->cmd = CMD_DUMP;
341 }
342 else if (cscmp(p, TEXT("--test-eps")) == 0) {
343 if (opt->cmd != CMD_UNKNOWN)
344 return arg;
345 opt->cmd = CMD_TEST;
346 }
347 else if (cscmp(p, TEXT("--replace-composite")) == 0) {
348 opt->composite = TRUE;
349 }
350 else if (cscmp(p, TEXT("--missing-separations")) == 0) {
351 opt->missing_separations = TRUE;
352 }
353 else if (cscmp(p, TEXT("--combine-separations")) == 0) {
354 arg++;
355 if (arg == argc)
356 return arg;
357 csncpy(opt->combine, argv[arg], sizeof(opt->combine)/sizeof(TCHAR)-1);
358 }
359 else if (cscmp(p, TEXT("--combine-tolerance")) == 0) {
360 char buf[MAXSTR];
361 arg++;
362 if (arg == argc)
363 return arg;
364 cs_to_narrow(buf, (int)sizeof(buf)-1, argv[arg], (int)cslen(argv[arg])+1);
365 opt->tolerance = atoi(buf);
366 }
367 else if (cscmp(p, TEXT("--rename-separation")) == 0) {
368 RENAME_SEPARATION *rs = opt->rename_sep;
369 arg++;
370 if (arg+1 == argc)
371 return arg;
372 if (rs) {
373 while (rs && (rs->next != NULL))
374 rs = rs->next;
375 rs->next =
376 (RENAME_SEPARATION *)malloc(sizeof(RENAME_SEPARATION));
377 rs = rs->next;
378 }
379 else {
380 opt->rename_sep = rs =
381 (RENAME_SEPARATION *)malloc(sizeof(RENAME_SEPARATION));
382 }
383 if (rs) {
384 char oldname[MAXSTR];
385 char newname[MAXSTR];
386 char *p;
387 char *q;
388 int len;
389 memset(rs, 0, sizeof(RENAME_SEPARATION));
390 rs->next = NULL;
391 memset(oldname, 0, sizeof(oldname));
392 cs_to_narrow(oldname, (int)sizeof(oldname)-1,
393 argv[arg], (int)cslen(argv[arg])+1);
394 len = (int)strlen(oldname)+1;
395 p = (char *)malloc(len);
396 if (p) {
397 memcpy(p, oldname, len);
398 rs->oldname = p;
399 }
400 arg++;
401 memset(newname, 0, sizeof(newname));
402 cs_to_narrow(newname, (int)sizeof(newname)-1,
403 argv[arg], (int)cslen(argv[arg])+1);
404 len = (int)strlen(newname)+1;
405 q = (char *)malloc(len);
406 if (q) {
407 memcpy(q, newname, len);
408 rs->newname = q;
409 }
410 if ((p == NULL) || (q == NULL)) {
411 fprintf(stderr, "Out of memory\n");
412 return arg;
413 }
414 }
415 else {
416 fprintf(stderr, "Out of memory\n");
417 return arg;
418 }
419 }
420 else if (cscmp(p, TEXT("--custom-colours")) == 0) {
421 arg++;
422 if (arg == argc)
423 return arg;
424 csncpy(opt->custom_colours, argv[arg],
425 sizeof(opt->custom_colours)/sizeof(TCHAR)-1);
426 }
427 else if ((cscmp(p, TEXT("--extract-preview")) == 0) ||
428 (cscmp(p, TEXT("-v")) == 0)) {
429 if (opt->cmd != CMD_UNKNOWN)
430 return arg;
431 opt->cmd = CMD_PREVIEW;
432 }
433 else if ((cscmp(p, TEXT("--extract-postscript")) == 0) ||
434 (cscmp(p, TEXT("-p")) == 0)) {
435 if (opt->cmd != CMD_UNKNOWN)
436 return arg;
437 opt->cmd = CMD_POSTSCRIPT;
438 }
439 else if (cscmp(p, TEXT("--bitmap")) == 0) {
440 if (opt->cmd != CMD_UNKNOWN)
441 return arg;
442 opt->cmd = CMD_BITMAP;
443 }
444 else if (cscmp(p, TEXT("--copy")) == 0) {
445 if (opt->cmd != CMD_UNKNOWN)
446 return arg;
447 opt->cmd = CMD_COPY;
448 }
449 else if (cscmp(p, TEXT("--device")) == 0) {
450 arg++;
451 if (arg == argc)
452 return arg;
453 csncpy(opt->device, argv[arg], sizeof(opt->device)/sizeof(TCHAR)-1);
454 }
455 else if (cscmp(p, TEXT("--page-number")) == 0) {
456 char buf[MAXSTR];
457 arg++;
458 if (arg == argc)
459 return arg;
460 cs_to_narrow(buf, (int)sizeof(buf)-1, argv[arg],
461 (int)cslen(argv[arg])+1);
462 opt->page = atoi(buf) - 1;
463 if (opt->page < 0)
464 opt->page = 0;
465 }
466 else if ((cscmp(p, TEXT("--bbox")) == 0) ||
467 (cscmp(p, TEXT("-b")) == 0)) {
468 opt->bbox = TRUE;
469 }
470 else if (cscmp(p, TEXT("--ignore-information")) == 0) {
471 opt->dscwarn = CDSC_ERROR_INFORM;
472 }
473 else if (cscmp(p, TEXT("--ignore-warnings")) == 0) {
474 opt->dscwarn = CDSC_ERROR_WARN;
475 }
476 else if (cscmp(p, TEXT("--ignore-errors")) == 0) {
477 opt->dscwarn = CDSC_ERROR_ERROR;
478 }
479 else if (cscmp(p, TEXT("--gs")) == 0) {
480 arg++;
481 if (arg == argc)
482 return arg;
483 csncpy(opt->gs, argv[arg], sizeof(opt->gs)/sizeof(TCHAR)-1);
484 }
485 else if (cscmp(p, TEXT("--gs-args")) == 0) {
486 arg++;
487 if (arg == argc)
488 return arg;
489 csncpy(opt->gsargs, argv[arg], sizeof(opt->gsargs)/sizeof(TCHAR)-1);
490 }
491 else if (cscmp(p, TEXT("--mac-binary")) == 0) {
492 opt->mac_type = CMAC_TYPE_MACBIN;
493 }
494 else if (cscmp(p, TEXT("--mac-double")) == 0) {
495 opt->mac_type = CMAC_TYPE_DOUBLE;
496 }
497 else if (cscmp(p, TEXT("--mac-rsrc")) == 0) {
498 opt->mac_type = CMAC_TYPE_RSRC;
499 }
500 else if (cscmp(p, TEXT("--mac-single")) == 0) {
501 opt->mac_type = CMAC_TYPE_SINGLE;
502 }
503 else if (cscmp(p, TEXT("--output")) == 0) {
504 arg++;
505 if (arg == argc)
506 return arg;
507 csncpy(opt->output, argv[arg],
508 sizeof(opt->output)/sizeof(TCHAR)-1);
509 }
510 else if (cscmp(p, TEXT("--quiet")) == 0) {
511 opt->quiet = TRUE;
512 }
513 else if ((cscmp(p, TEXT("--debug")) == 0) ||
514 (cscmp(p, TEXT("-d")) == 0)) {
515 opt->debug = TRUE;
516 }
517 else if ((cscmp(p, TEXT("--doseps-reverse")) == 0) ||
518 (cscmp(p, TEXT("-d")) == 0)) {
519 opt->doseps_reverse = TRUE;
520 }
521 else if (cscmp(p, TEXT("--dpi")) == 0) {
522 char buf[MAXSTR];
523 arg++;
524 if (arg == argc)
525 return arg;
526 cs_to_narrow(buf, (int)sizeof(buf)-1, argv[arg],
527 (int)cslen(argv[arg])+1);
528 opt->dpi = (float)atof(buf);
529 }
530 else if (cscmp(p, TEXT("--dpi-render")) == 0) {
531 char buf[MAXSTR];
532 arg++;
533 if (arg == argc)
534 return arg;
535 cs_to_narrow(buf, (int)sizeof(buf)-1, argv[arg],
536 (int)cslen(argv[arg])+1);
537 opt->dpi_render = (float)atof(buf);
538 }
539 else if (cscmp(p, TEXT("--image-encode")) == 0) {
540 /* Not in user documentation - for debug purposes only */
541 char buf[MAXSTR];
542 arg++;
543 if (arg == argc)
544 return arg;
545 cs_to_narrow(buf, (int)sizeof(buf)-1, argv[arg],
546 (int)cslen(argv[arg])+1);
547 opt->image_encode = atoi(buf);
548 if ((opt->image_encode < IMAGE_ENCODE_HEX) ||
549 (opt->image_encode > IMAGE_ENCODE_ASCII85))
550 opt->image_encode = IMAGE_ENCODE_ASCII85;
551 }
552 else if (cscmp(p, TEXT("--image-compress")) == 0) {
553 /* Not in user documentation - for debug purposes only */
554 char buf[MAXSTR];
555 arg++;
556 if (arg == argc)
557 return arg;
558 cs_to_narrow(buf, (int)sizeof(buf)-1, argv[arg],
559 (int)cslen(argv[arg])+1);
560 opt->image_compress = atoi(buf);
561 if ((opt->image_compress < IMAGE_COMPRESS_NONE) ||
562 (opt->image_compress > IMAGE_COMPRESS_LZW))
563 opt->image_compress = IMAGE_COMPRESS_LZW;
564 }
565 else if ((cscmp(p, TEXT("--help")) == 0) || (cscmp(p, TEXT("-h"))==0)) {
566 opt->help = TRUE;
567 if (opt->cmd != CMD_UNKNOWN)
568 return arg;
569 opt->cmd = CMD_HELP;
570 }
571 else if (cscmp(p, TEXT("--version")) == 0) {
572 if (opt->cmd != CMD_UNKNOWN)
573 return arg;
574 opt->cmd = CMD_VERSION;
575 }
576 else if (*p != '-') {
577 if (opt->input[0] == 0)
578 csncpy(opt->input, argv[arg],
579 sizeof(opt->input)/sizeof(TCHAR)-1);
580 else if (opt->output[0] == 0)
581 csncpy(opt->output, argv[arg],
582 sizeof(opt->output)/sizeof(TCHAR)-1);
583 else
584 return arg;
585 }
586 else {
587 return arg;
588 }
589 }
590 return 0;
591 }
592
593
594 static Doc *
595 epstool_open_document(GSview *app, OPT *opt, TCHAR *name)
596 {
597 int code;
598 Doc *doc;
599 int require_eps = 1;
600 /* Create a document */
601 doc = doc_new(app);
602 if (doc == NULL) {
603 debug |= DEBUG_LOG;
604 app_csmsgf(app, TEXT("Failed to create new Doc\n"));
605 app_unref(app);
606 return NULL;
607 }
608 /* Attach it to application */
609 doc_add(doc, app);
610 doc_dsc_warn(doc, opt->dscwarn);
611 doc_verbose(doc, opt->debug);
612
613 code = doc_open(doc, name);
614 if (code < 0) {
615 debug |= DEBUG_LOG;
616 app_csmsgf(app, TEXT("Error opening file \042%s\042.\n"), name);
617 code = -1;
618 }
619 else if (code > 0) {
620 debug |= DEBUG_LOG;
621 app_csmsgf(app, TEXT(
622 "Input file \042%s\042 didn't have DSC comments.\n"), name);
623 code = -1;
624 }
625
626 /* Some features don't require an EPS input */
627 if (opt->cmd == CMD_DCS2_REPORT)
628 require_eps = 0;
629 if (opt->cmd == CMD_TEST)
630 require_eps = 0;
631 if (opt->cmd == CMD_DUMP)
632 require_eps = 0;
633 if ((opt->cmd == CMD_COPY) && (doc->doctype == DOC_BITMAP))
634 require_eps = 0;
635
636 if ((code == 0) && require_eps &&
637 ((doc->dsc == NULL) || (!doc->dsc->epsf)) ) {
638 debug |= DEBUG_LOG;
639 app_csmsgf(app,
640 TEXT("Input file \042%s\042 is not EPSF.\n"), name);
641 code = -1;
642 }
643 if ((code == 0) && require_eps && (doc->dsc != NULL)) {
644 if ((doc->dsc->worst_error > CDSC_ERROR_INFORM) &&
645 (doc->dsc->worst_error > opt->dscwarn)) {
646 app_csmsgf(app,
647 TEXT("EPS had unacceptable warnings or errors.\n"));
648 code = -1;
649 }
650 }
651 if (code) {
652 doc_close(doc);
653 doc_remove(doc);
654 doc_unref(doc);
655 doc = NULL;
656 }
657 return doc;
658 }
659
660
661 #ifdef UNICODE
662 int wmain(int argc, TCHAR *argv[])
663 #else
664 int main(int argc, char *argv[])
665 #endif
666 {
667 GSview *app;
668 Doc *doc = NULL;
669 Doc *doc2 = NULL;
670 int code = 0;
671 int i, arg;
672 OPT opt;
673
674 #ifdef __WIN32__
675 { /* Find latest version of Ghostscript */
676 char buf[MAXSTR];
677 if (find_gs(buf, sizeof(buf)-1, 550, FALSE)) {
678 narrow_to_cs(gsexe, (int)(sizeof(gsexe)/sizeof(TCHAR)-1),
679 buf, (int)strlen(buf)+1);
680 }
681 }
682 #endif
683
684 memset(&opt, 0, sizeof(opt));
685 arg = parse_args(&opt, argc, argv);
686 debug = 0;
687 if (opt.debug) {
688 debug = DEBUG_LOG | DEBUG_MEM | DEBUG_GENERAL;
689 opt.quiet = 0;
690 }
691 if (!opt.quiet)
692 debug |= DEBUG_LOG; /* enable output */
693 if (opt.help) {
694 print_help();
695 return 1;
696 }
697 if (opt.cmd == CMD_VERSION) {
698 print_version();
699 return 1;
700 }
701 if (opt.dpi_render < opt.dpi)
702 opt.dpi_render = opt.dpi;
703
704 app = app_new(NULL, FALSE);
705 if (app == NULL) {
706 fprintf(MSGOUT, "Can't create epstool app\n");
707 return 1;
708 }
709
710 if (arg != 0) {
711 debug |= DEBUG_LOG;
712 app_csmsgf(app, TEXT("epstool: Error in command line arguments:\n "));
713 for (i=0; i<arg; i++)
714 app_csmsgf(app, TEXT("%s "), argv[i]);
715 app_csmsgf(app, TEXT("\n The next argument is unrecognised, missing, or conflicts:\n "));
716 for (; i<argc; i++)
717 app_csmsgf(app, TEXT("%s "), argv[i]);
718 app_csmsgf(app, TEXT("\n"));
719 app_unref(app);
720 return 1;
721 }
722
723 if ((opt.cmd == CMD_TIFF) && (opt.device[0] == '\0')) {
724 debug |= DEBUG_LOG;
725 app_csmsgf(app, TEXT("--add-tiff-preview requires a device to be specified with --device\n"));
726 code = -1;
727 }
728 if (opt.cmd == CMD_UNKNOWN) {
729 debug |= DEBUG_LOG;
730 app_csmsgf(app, TEXT("No command specified.\n"));
731 code = -1;
732 }
733 if (opt.input[0] == '\0') {
734 debug |= DEBUG_LOG;
735 app_csmsgf(app, TEXT("Input file not specified.\n"));
736 code = -1;
737 }
738 if (opt.custom_colours[0] != '\0') {
739 FILE *f = csfopen(opt.custom_colours, TEXT("rb"));
740 if (f == (FILE*)NULL) {
741 debug |= DEBUG_LOG;
742 app_csmsgf(app, TEXT("Failed to open \042%s\042.\n"),
743 opt.custom_colours);
744 code = -1;
745 }
746 else
747 fclose(f);
748 }
749 if (code == 0) {
750 FILE *f = csfopen(opt.input, TEXT("rb"));
751 if (f == (FILE*)NULL) {
752 debug |= DEBUG_LOG;
753 app_csmsgf(app, TEXT("Failed to open \042%s\042.\n"), opt.input);
754 code = -1;
755 }
756 else
757 fclose(f);
758 }
759 if ((opt.output[0] == '\0') &&
760 !((opt.cmd == CMD_DCS2_REPORT) ||
761 (opt.cmd == CMD_TEST) ||
762 (opt.cmd == CMD_DUMP)) ) {
763 debug |= DEBUG_LOG;
764 app_csmsgf(app, TEXT("Output file not specified.\n"));
765 code = -1;
766 }
767 if ((opt.output[0] == '-') && (opt.output[1] == '\0'))
768 opt.output[0] = '\0'; /* use stdout */
769 if (code != 0) {
770 debug |= DEBUG_LOG;
771 app_csmsgf(app, TEXT("Run \042epstool --help\042 for more details.\n"));
772 app_unref(app);
773 return 1;
774 }
775
776 if (opt.cmd == CMD_DUMP)
777 dump_macfile(opt.input, 1);
778
779 doc = epstool_open_document(app, &opt, opt.input);
780 if (doc == NULL)
781 code = -1;
782
783 if (opt.combine[0]) {
784 /* open second DCS2 input file */
785 doc2 = epstool_open_document(app, &opt, opt.combine);
786 if (doc2 == NULL)
787 code = -1;
788 }
789
790 if ((code == 0) && opt.bbox) {
791 switch (opt.cmd) {
792 case CMD_TIFF4:
793 case CMD_TIFF6U:
794 case CMD_TIFF6P:
795 case CMD_INTERCHANGE:
796 case CMD_WMF:
797 case CMD_COPY:
798 if (doc->dsc->dcs2) {
799 debug |= DEBUG_LOG;
800 app_csmsgf(app, TEXT("Ignoring --bbox for DCS 2.0.\n"));
801 opt.bbox = 0;
802 }
803 /* all others are these OK */
804 break;
805 default:
806 debug |= DEBUG_LOG;
807 app_csmsgf(app, TEXT(
808 "Can't use --bbox with this command. Ignoring --bbox.\n"));
809 opt.bbox = 0;
810 }
811 }
812
813 if (code == 0) {
814 switch (opt.cmd) {
815 case CMD_TIFF4:
816 case CMD_TIFF6U:
817 case CMD_TIFF6P:
818 case CMD_TIFF:
819 case CMD_INTERCHANGE:
820 case CMD_WMF:
821 case CMD_PICT:
822 case CMD_USER:
823 code = epstool_add_preview(doc, &opt);
824 break;
825 case CMD_DCS2_SINGLE:
826 case CMD_DCS2_MULTI:
827 if (doc->dsc->dcs2)
828 code = epstool_dcs2_check_files(doc, &opt);
829 if (code == 0)
830 code = epstool_dcs2_copy(doc, doc2, &opt);
831 break;
832 case CMD_DCS2_REPORT:
833 code = epstool_dcs2_report(doc);
834 break;
835 case CMD_PREVIEW:
836 case CMD_POSTSCRIPT:
837 code = epstool_extract(doc, &opt);
838 break;
839 case CMD_BITMAP:
840 code = epstool_bitmap(doc, &opt);
841 break;
842 case CMD_COPY:
843 code = epstool_copy(doc, &opt);
844 break;
845 case CMD_TEST:
846 code = epstool_test(doc, &opt);
847 break;
848 case CMD_DUMP:
849 if (doc && doc->dsc)
850 dsc_display(doc->dsc, epstool_dump_fn);
851 break;
852 default:
853 case CMD_UNKNOWN:
854 case CMD_HELP:
855 /* should reach here */
856 code = -1;
857 break;
858 }
859 }
860
861
862 if (doc) {
863 doc_close(doc);
864 doc_remove(doc); /* detach doc from app */
865 doc_unref(doc);
866 }
867
868 app_unref(app);
869
870 #ifdef DEBUG_MALLOC
871 debug_memory_report();
872 #endif
873
874 debug &= ~DEBUG_MEM;
875 while (opt.rename_sep) {
876 RENAME_SEPARATION *rs = opt.rename_sep;
877 if (rs->oldname)
878 free((void *)rs->oldname);
879 if (rs->newname)
880 free((void *)rs->newname);
881 opt.rename_sep = rs->next;
882 free(rs);
883 }
884
885 if (!opt.quiet)
886 fprintf(MSGOUT, "%s\n", code == 0 ? "OK" : "Failed");
887 if (code != 0)
888 return 1;
889 return code;
890 }
891
892 /****************************************************************/
893
894 static int
895 epstool_add_preview(Doc *doc, OPT *opt)
896 {
897 int code = 0;
898 CDSCBBOX devbbox = {0,0,595,842};
899 CDSCBBOX bbox = {0, 0, 0, 0};
900 CDSCFBBOX hires_bbox = {0.0, 0.0, 0.0, 0.0};
901 CDSCFBBOX *phires_bbox = NULL;
902 const TCHAR *device = COLOUR_DEVICE;
903 FILE *f;
904 TCHAR preview[MAXSTR];
905 IMAGE *img = NULL;
906 if (opt->device[0] != '\0')
907 device = opt->device;
908 else if (opt->cmd == CMD_INTERCHANGE)
909 device = MONO_DEVICE;
910 if (opt->cmd == CMD_TIFF4)
911 device = MONO_DEVICE;
912
913 if (doc->dsc->bbox) {
914 bbox = *doc->dsc->bbox;
915 }
916 else
917 opt->bbox = 1;
918
919 if (doc->dsc->hires_bbox) {
920 hires_bbox = *doc->dsc->hires_bbox;
921 phires_bbox = &hires_bbox;
922 }
923
924 if (opt->cmd == CMD_USER) {
925 /* Attempt to load BMP or PPM */
926 /* If these fail, assume it is TIFF or WMF */
927 img = bmpfile_to_image(opt->user_preview);
928 if (img == NULL)
929 img = pnmfile_to_image(opt->user_preview);
930 }
931 else if (opt->cmd == CMD_TIFF) {
932 /* We'll use ghostscript to make the image. */
933 }
934 else {
935 img = make_preview_image(doc, opt, 0, device,
936 &bbox, &hires_bbox, opt->bbox);
937 if (img == NULL) {
938 app_csmsgf(doc->app, TEXT("Couldn't make preview image\n"));
939 return -1;
940 }
941 if ((hires_bbox.fllx < hires_bbox.furx) &&
942 (hires_bbox.flly < hires_bbox.fury))
943 phires_bbox = &hires_bbox;
944
945 }
946 if (img) {
947 devbbox.llx = devbbox.lly = 0;
948 devbbox.urx = img->width;
949 devbbox.ury = img->height;
950 }
951
952 /* add preview to EPS file */
953
954 switch (opt->cmd) {
955 case CMD_TIFF4:
956 code = make_eps_tiff(doc, img, devbbox, &bbox, phires_bbox,
957 opt->dpi, opt->dpi, TRUE, FALSE, opt->doseps_reverse,
958 opt->output);
959 break;
960 case CMD_TIFF6U:
961 code = make_eps_tiff(doc, img, devbbox, &bbox, phires_bbox,
962 opt->dpi, opt->dpi, FALSE, FALSE, opt->doseps_reverse,
963 opt->output);
964 break;
965 case CMD_TIFF6P:
966 code = make_eps_tiff(doc, img, devbbox, &bbox, phires_bbox,
967 opt->dpi, opt->dpi, FALSE, TRUE, opt->doseps_reverse,
968 opt->output);
969 break;
970 case CMD_TIFF:
971 /* create preview file */
972 preview[0] = '\0';
973 if ((f = app_temp_file(doc->app, preview,
974 sizeof(preview)/sizeof(TCHAR))) == (FILE *)NULL) {
975 app_csmsgf(doc->app,
976 TEXT("Can't create temporary tiff file \042%s\042\n"),
977 preview);
978 code = -1;
979 }
980 else {
981 fclose(f);
982 if (code == 0)
983 code = make_preview_file(doc, opt, 0, preview,
984 device, opt->dpi, &bbox, &hires_bbox, opt->bbox);
985 if (code == 0)
986 code = make_eps_user(doc, preview, opt->doseps_reverse,
987 opt->output);
988 if (!(debug & DEBUG_GENERAL))
989 csunlink(preview);
990 }
991 break;
992 case CMD_INTERCHANGE:
993 code = make_eps_interchange(doc, img, devbbox,
994 &bbox, phires_bbox, opt->output);
995 break;
996 case CMD_WMF:
997 code = make_eps_metafile(doc, img, devbbox, &bbox, phires_bbox,
998 opt->dpi, opt->dpi, opt->doseps_reverse, opt->output);
999 break;
1000 case CMD_PICT:
1001 code = make_eps_pict(doc, img, &bbox, phires_bbox,
1002 opt->dpi, opt->dpi, opt->mac_type, opt->output);
1003 break;
1004 case CMD_USER:
1005 if (img)
1006 code = make_eps_tiff(doc, img, devbbox, &bbox, phires_bbox,
1007 opt->dpi, opt->dpi, FALSE, TRUE, opt->doseps_reverse,
1008 opt->output);
1009 else
1010 code = make_eps_user(doc, opt->user_preview,
1011 opt->doseps_reverse, opt->output);
1012 break;
1013 default:
1014 return 0;
1015 }
1016
1017 if (img)
1018 bitmap_image_free(img);
1019 return code;
1020 }
1021
1022 /****************************************************************/
1023
1024 static int
1025 epstool_extract(Doc *doc, OPT *opt)
1026 {
1027 int code;
1028 if ((doc->dsc != (CDSC *)NULL) &&
1029 (doc->dsc->macbin != (CDSCMACBIN *)NULL))
1030 code = extract_macbin(doc, opt->output, opt->cmd == CMD_PREVIEW);
1031 else
1032 code = extract_doseps(doc, opt->output, opt->cmd == CMD_PREVIEW);
1033 return code;
1034 }
1035
1036 /****************************************************************/
1037
1038 static int
1039 epstool_bitmap(Doc *doc, OPT *opt)
1040 {
1041 int code = 0;
1042 CDSCBBOX bbox;
1043 CDSCFBBOX hires_bbox;
1044 LPCTSTR device = COLOUR_DEVICE;
1045 int page = opt->page;
1046 if (opt->device[0] != '\0')
1047 device = opt->device;
1048
1049 if (doc->dsc->bbox)
1050 bbox = *doc->dsc->bbox;
1051 else {
1052 bbox.llx = bbox.lly = bbox.urx = bbox.ury = 0;
1053 opt->bbox = 1;
1054 }
1055
1056 if (doc->dsc->hires_bbox)
1057 hires_bbox = *doc->dsc->hires_bbox;
1058 else {
1059 hires_bbox.fllx = (float)bbox.llx;
1060 hires_bbox.flly = (float)bbox.lly;
1061 hires_bbox.furx = (float)bbox.urx;
1062 hires_bbox.fury = (float)bbox.ury;
1063 }
1064
1065 if (doc->dsc->page_count == 0)
1066 page = 0;
1067 else if ((opt->page < 0) || (opt->page >= (int)doc->dsc->page_count))
1068 return -1; /* invalid page */
1069
1070 code = make_preview_file(doc, opt, page, opt->output,
1071 device, opt->dpi, &bbox, &hires_bbox, opt->bbox);
1072
1073 return code;
1074 }
1075
1076 /****************************************************************/
1077
1078 static int
1079 epstool_copy(Doc *doc, OPT *opt)
1080 {
1081 int code = 0;
1082
1083 /*
1084 * "epstool --copy" can also convert a BMP, PBM or PNG to EPS
1085 * for testing the DCS 2.0 composite image writing code.
1086 * This isn't in the user documentation.
1087 */
1088 if (doc->doctype == DOC_BITMAP)
1089 return epstool_copy_bitmap(doc, opt);
1090
1091 /* Copy an EPS to another EPS */
1092 if (opt->bbox) {
1093 CDSCBBOX bbox;
1094 CDSCFBBOX hires_bbox;
1095 GFile *f;
1096 TCHAR tpsname[MAXSTR];
1097
1098 memset(tpsname, 0, sizeof(tpsname));
1099 memset(&bbox, 0, sizeof(bbox));
1100 memset(&hires_bbox, 0, sizeof(hires_bbox));
1101 if (doc->dsc->bbox)
1102 memcpy(&bbox, &doc->dsc->bbox, sizeof(bbox));
1103 if (doc->dsc->hires_bbox)
1104 memcpy(&hires_bbox, &doc->dsc->hires_bbox, sizeof(hires_bbox));
1105
1106 /* Copy page to temporary file */
1107 if ((f = app_temp_gfile(doc->app, tpsname,
1108 sizeof(tpsname)/sizeof(TCHAR))) == (GFile *)NULL) {
1109 app_csmsgf(doc->app,
1110 TEXT("Can't create temporary ps file \042%s\042\n"),
1111 tpsname);
1112 return -1;
1113 }
1114 code = copy_page_temp(doc, f, 0);
1115 gfile_close(f);
1116 if (code != 0) {
1117 if (!(debug & DEBUG_GENERAL))
1118 csunlink(tpsname);
1119 return -1;
1120 }
1121 code = calculate_bbox(doc, opt, tpsname, &bbox, &hires_bbox);
1122
1123 if (code == 0)
1124 code = copy_eps(doc, opt->output, &bbox, &hires_bbox, 0, FALSE);
1125
1126 /* delete temporary ps file */
1127 if (!(debug & DEBUG_GENERAL))
1128 csunlink(tpsname);
1129 }
1130 else {
1131 code = copy_eps(doc, opt->output, doc->dsc->bbox,
1132 doc->dsc->hires_bbox, 0, FALSE);
1133 }
1134
1135 return code;
1136 }
1137
1138 /* Save a BMP, PBM or PNG as an EPS file */
1139 static int
1140 epstool_copy_bitmap(Doc *doc, OPT *opt)
1141 {
1142 int code = 0;
1143 IMAGE *img;
1144 img = bmpfile_to_image(doc->name);
1145 if (img == NULL)
1146 img = pnmfile_to_image(doc->name);
1147 if (img == NULL)
1148 img = pngfile_to_image(doc->name);
1149 if (img == NULL)
1150 code = -1;
1151
1152 if (code == 0) {
1153 GFile *f = NULL;
1154 double width = (img->width * 72.0 / opt->dpi);
1155 double height = (img->height * 72.0 / opt->dpi);
1156
1157 if ((img == NULL) || (img->image == NULL))
1158 code = -1;
1159
1160 if (code == 0) {
1161 f = gfile_open(opt->output, gfile_modeWrite | gfile_modeCreate);
1162 if (f == NULL) {
1163 code = -1;
1164 app_msgf(doc->app,
1165 "Failed to open \042%s\042 for writing\n", opt->output);
1166 }
1167 }
1168
1169 if (code == 0)
1170 code = image_to_eps(f, img, 0, 0,
1171 (int)(width + 0.999), (int)(height + 0.999),
1172 0.0, 0.0, (float)width, (float)height,
1173 opt->image_encode, opt->image_compress);
1174 if (f)
1175 gfile_close(f);
1176 }
1177 return code;
1178 }
1179
1180 /****************************************************************/
1181
1182 /* If multi is TRUE, write DCS 2.0 multiple file, otherwise
1183 * write the single file version.
1184 */
1185 static int
1186 epstool_dcs2_copy(Doc *doc, Doc *doc2, OPT *opt)
1187 {
1188 GFile *infile = NULL;
1189 GFile *doc2file = NULL;
1190 GFile *outfile = NULL;
1191 DSC_OFFSET complen = 0;
1192 int code = 0;
1193 GFile *compfile = NULL;
1194 TCHAR compname[MAXSTR];
1195 TCHAR temp_outname[MAXSTR];
1196
1197 if (doc->dsc->dcs2 == NULL) {
1198 app_csmsgf(doc->app, TEXT("Input file is not DCS 2.0\n"));
1199 return -1;
1200 }
1201 memset(compname, 0, sizeof(compname));
1202 if (opt->composite) {
1203 /* Replace composite (first page) with a raster generated
1204 * from the separations.
1205 */
1206 if ((compfile = app_temp_gfile(doc->app, compname,
1207 sizeof(compname)/sizeof(TCHAR))) == (GFile *)NULL) {
1208 app_csmsgf(doc->app,
1209 TEXT("Can't create temporary composite EPS file \042%s\042\n"),
1210 compname);
1211 return -1;
1212 }
1213 custom_colours_read(opt);
1214 code = epstool_dcs2_composite(doc, opt, compfile);
1215 custom_colours_free(opt);
1216 gfile_close(compfile);
1217 if (code == 0) {
1218 compfile = gfile_open(compname, gfile_modeRead);
1219 if (compfile == (GFile *)NULL)
1220 code = -1;
1221 }
1222 if (code) {
1223 if (!(debug & DEBUG_GENERAL) && compname[0])
1224 csunlink(compname);
1225 return -1;
1226 }
1227 }
1228
1229 /* Let's convert from single file to multi file */
1230 if (code == 0)
1231 code = (infile = gfile_open(doc_name(doc), gfile_modeRead))
1232 == (GFile *)NULL;
1233 if ((code == 0) && doc2)
1234 code = (doc2file = gfile_open(doc_name(doc2), gfile_modeRead))
1235 == (GFile *)NULL;
1236 if (opt->cmd == CMD_DCS2_SINGLE) {
1237 if (code == 0) /* write first pass to temporary file, not opt->output */
1238 code = (outfile = app_temp_gfile(doc->app, temp_outname,
1239 sizeof(temp_outname)/sizeof(TCHAR))) == (GFile *)NULL;
1240 if (code == 0)
1241 code = copy_dcs2(doc, infile, doc2, doc2file,
1242 outfile, temp_outname,
1243 0 /* offset */,
1244 FALSE /* multi */,
1245 FALSE /* write all */,
1246 opt->missing_separations,
1247 &complen, compfile, opt->rename_sep, opt->tolerance);
1248 gfile_seek(infile, 0, gfile_begin);
1249 if (compfile)
1250 gfile_seek(compfile, 0, gfile_begin);
1251 gfile_close(outfile);
1252 outfile = NULL;
1253 if (!(debug & DEBUG_GENERAL) && temp_outname[0])
1254 csunlink(temp_outname);
1255 }
1256 if (code == 0) {
1257 code = (outfile = gfile_open(opt->output,
1258 gfile_modeWrite | gfile_modeCreate)) == (GFile *)NULL;
1259 if (code)
1260 app_msgf(doc->app,
1261 "Failed to open \042%s\042 for writing\n", opt->output);
1262 }
1263 if (code == 0)
1264 code = copy_dcs2(doc, infile, doc2, doc2file,
1265 outfile, opt->output,
1266 0 /* offset */,
1267 opt->cmd == CMD_DCS2_MULTI,
1268 TRUE /* write all */,
1269 opt->missing_separations,
1270 &complen, compfile, opt->rename_sep, opt->tolerance);
1271 if (infile != (GFile *)NULL)
1272 gfile_close(infile);
1273 if (doc2file != (GFile *)NULL)
1274 gfile_close(doc2file);
1275 if (outfile != (GFile *)NULL)
1276 gfile_close(outfile);
1277 if (compfile != (GFile *)NULL)
1278 gfile_close(compfile);
1279 if (!(debug & DEBUG_GENERAL) && compname[0])
1280 csunlink(compname);
1281
1282 return code;
1283 }
1284
1285 static int
1286 epstool_dcs2_report(Doc *doc)
1287 {
1288 int i;
1289 int code = 0;
1290 CDSC *dsc = doc->dsc;
1291 const char *type = "Unknown";
1292 const char *preview = "Unknown";
1293
1294 if (dsc && dsc->dcs2) {
1295 DSC_OFFSET length = 0;
1296 GFile *f;
1297 /* Check for missing composite */
1298 if ((dsc->page_count == 0) ||
1299 (dsc->page[0].begin == dsc->page[0].end)) {
1300 app_msgf(doc->app, TEXT("WARNING: Missing composite, so a separation offset is probably wrong.\n"));
1301 code = 2;
1302 }
1303 /* Check for separations that extend beyond EOF */
1304 if ((f = gfile_open(doc_name(doc), gfile_modeRead)) != (GFile *)NULL) {
1305 length = gfile_get_length(f);
1306 gfile_close(f);
1307 }
1308 for (i=0; i<(int)dsc->page_count; i++) {
1309 if ((dsc->page[i].begin > length) ||
1310 (dsc->page[i].end > length)) {
1311 app_msgf(doc->app,
1312 TEXT("WARNING: separation %s extends beyond EOF\n"),
1313 dsc->page[i].label);
1314 code = 2;
1315 }
1316 }
1317 }
1318
1319 /* Document type */
1320 if (dsc == NULL) {
1321 if (doc->doctype == DOC_PDF)
1322 type = "PDF";
1323 else
1324 type = "Unknown";
1325 }
1326 else if (dsc->dcs2) {
1327 if (dsc->dcs1)
1328 type = "DCS1.0";
1329 else
1330 type = "DCS2.0";
1331 }
1332 else if (dsc->epsf)
1333 type = "EPSF";
1334 else if (dsc->pdf)
1335 type = "PDF";
1336 else
1337 type = "DSC";
1338 fprintf(stdout, "Type\t%s\n", type);
1339 if (dsc == NULL)
1340 return 1;
1341
1342 /* Preview type */
1343 switch (dsc->preview) {
1344 default:
1345 case CDSC_NOPREVIEW:
1346 preview = "None";
1347 break;
1348 case CDSC_EPSI:
1349 preview = "Interchange";
1350 break;
1351 case CDSC_TIFF:
1352 preview = "TIFF";
1353 break;
1354 case CDSC_WMF:
1355 preview = "WMF";
1356 break;
1357 case CDSC_PICT:
1358 preview = "PICT";
1359 break;
1360 }
1361 fprintf(stdout, "Preview\t%s\n", preview);
1362
1363 if (dsc->bbox)
1364 fprintf(stdout, "BoundingBox\t%d\t%d\t%d\t%d\n",
1365 dsc->bbox->llx, dsc->bbox->lly,
1366 dsc->bbox->urx, dsc->bbox->ury);
1367 else
1368 fprintf(stdout, "BoundingBox\n");
1369 if (dsc->hires_bbox)
1370 fprintf(stdout, "HiBoundingBox\t%g\t%g\t%g\t%g\n",
1371 dsc->hires_bbox->fllx, dsc->hires_bbox->flly,
1372 dsc->hires_bbox->furx, dsc->hires_bbox->fury);
1373 else
1374 fprintf(stdout, "HiResBoundingBox\n");
1375
1376
1377 if (!dsc->dcs2)
1378 return 1;
1379
1380 /* Pages */
1381 for (i=0; i<(int)dsc->page_count; i++) {
1382 int found = -1;
1383 const char *name = dsc->page[i].label;
1384 float cyan, magenta, yellow, black;
1385 cyan = magenta = yellow = black = 0.0;
1386 if (name == NULL)
1387 name = "Unknown";
1388 if (strcmp(name, "Composite") != 0)
1389 found = colour_to_cmyk(dsc, name, &cyan, &magenta, &yellow, &black);
1390 if (found == 0)
1391 fprintf(stdout, "%s\t%lu\t%g\t%g\t%g\t%g\n", name,
1392 (unsigned long)(dsc->page[i].end - dsc->page[i].begin),
1393 cyan, magenta, yellow, black);
1394 else
1395 fprintf(stdout, "%s\t%lu\n", name,
1396 (unsigned long)(dsc->page[i].end - dsc->page[i].begin));
1397 }
1398 return code;
1399 }
1400
1401 /* Check that all separations actually exist */
1402 static int
1403 epstool_dcs2_check_files(Doc *doc, OPT *opt)
1404 {
1405 int code = 0;
1406 int i;
1407 CDSC *dsc = doc->dsc;
1408 GFile *f;
1409 const char *fname;
1410 const char **renamed1 = NULL;
1411 for (i=1; (i<(int)dsc->page_count); i++) {
1412 /* First find length of separation */
1413 fname = dsc_find_platefile(dsc, i);
1414 if (fname) {
1415 TCHAR wfname[MAXSTR];
1416 narrow_to_cs(wfname, (int)(sizeof(wfname)/sizeof(TCHAR)-1),
1417 fname, (int)strlen(fname)+1);
1418 if ((f = gfile_open(wfname, gfile_modeRead)) != (GFile *)NULL) {
1419 gfile_close(f);
1420 }
1421 else {
1422 if (!opt->missing_separations)
1423 code = -1;
1424 if (!opt->quiet)
1425 app_msgf(doc->app,
1426 "Separation \042%s\042 is missing file \042%s\042\n",
1427 dsc->page[i].label, fname);
1428 }
1429 }
1430 else {
1431 if (dsc->page[i].end <= dsc->page[i].begin) {
1432 if (!opt->quiet)
1433 app_msgf(doc->app,
1434 "Separation \042%s\042 is empty\n",
1435 dsc->page[i].label);
1436 if (!opt->missing_separations)
1437 code = -1;
1438 }
1439 }
1440 }
1441 /* Test if duplicate separations would occur */
1442 renamed1 = (const char **)malloc(sizeof(const char *) * dsc->page_count);
1443 if (renamed1 != NULL) {
1444 if (rename_separations(dsc, opt->rename_sep, renamed1) != 0) {
1445 code = -1;
1446 if (!opt->quiet)
1447 app_msgf(doc->app, "Duplicate separations are not permitted.\n");
1448 }
1449 free((void *)renamed1);
1450 }
1451
1452 return code;
1453 }
1454
1455 /****************************************************************/
1456 /* Read --custom-colours file etc. */
1457
1458 static int
1459 custom_colours_read(OPT *opt)
1460 {
1461 FILE *f;
1462 char line[MAXSTR];
1463 CUSTOM_COLOUR colour;
1464 CUSTOM_COLOUR *pcolour;
1465 CUSTOM_COLOUR *tail = opt->colours;
1466 int i;
1467 char *s;
1468 int code = 0;
1469 if (opt->custom_colours[0]) {
1470 /* read CMYK colours from file */
1471 f = csfopen(opt->custom_colours, TEXT("r"));
1472 if (f == NULL)
1473 return -1;
1474 while (tail && tail->next)
1475 tail = tail->next;
1476 while (fgets(line, sizeof(line), f) != NULL) {
1477 memset(&colour, 0, sizeof(colour));
1478 i = 0;
1479 s = line;
1480 if (strncmp(line, "%%CMYKCustomColor:", 18) == 0) {
1481 s += 18;
1482 colour.type = CUSTOM_CMYK;
1483 while (*s && (*s == ' '))
1484 s++;
1485 /* Get the colour values */
1486 s = strtok(s, " \t\r\n");
1487 if (s != NULL) {
1488 colour.cyan = (float)atof(s);
1489 s = strtok(NULL, " \t\r\n");
1490 }
1491 if (s != NULL) {
1492 colour.magenta = (float)atof(s);
1493 s = strtok(NULL, " \t\r\n");
1494 }
1495 if (s != NULL) {
1496 colour.yellow = (float)atof(s);
1497 s = strtok(NULL, " \t\r\n");
1498 }
1499 if (s != NULL) {
1500 colour.black = (float)atof(s);
1501 s = strtok(NULL, "\t\r\n");
1502 }
1503 }
1504 else if (strncmp(line, "%%RGBCustomColor:", 17) == 0) {
1505 s += 17;
1506 colour.type = CUSTOM_RGB;
1507 while (*s && (*s == ' '))
1508 s++;
1509 /* Get the colour values */
1510 s = strtok(s, " \t\r\n");
1511 if (s != NULL) {
1512 colour.red = (float)atof(s);
1513 s = strtok(NULL, " \t\r\n");
1514 }
1515 if (s != NULL) {
1516 colour.green = (float)atof(s);
1517 s = strtok(NULL, " \t\r\n");
1518 }
1519 if (s != NULL) {
1520 colour.blue = (float)atof(s);
1521 s = strtok(NULL, "\t\r\n");
1522 }
1523 }
1524 else {
1525 s = NULL;
1526 }
1527
1528 if (s != NULL) {
1529 /* Get the colour name */
1530 while (*s && (*s == ' '))
1531 s++;
1532 if (*s == '(') {
1533 s++;
1534 while (*s && (*s != ')')) {
1535 if (i < (int)sizeof(colour.name)-1)
1536 colour.name[i++] = *s;
1537 s++;
1538 }
1539 if (*s == ')')
1540 s++;
1541 }
1542 else {
1543 while (*s && (*s != ' ') && (*s != '\t') &&
1544 (*s != '\r') && (*s != '\n')) {
1545 if (i < (int)sizeof(colour.name)-1)
1546 colour.name[i++] = *s;
1547 s++;
1548 }
1549 }
1550 colour.name[i] = '\0';
1551 }
1552 if (debug & DEBUG_GENERAL) {
1553 if (s == NULL)
1554 fprintf(stdout, "Unrecognised line: %s\n", line);
1555 else if (colour.type == CUSTOM_CMYK)
1556 fprintf(stdout, "CMYK Colour: %g %g %g %g (%s)\n",
1557 colour.cyan, colour.magenta, colour.yellow,
1558 colour.black, colour.name);
1559 else if (colour.type == CUSTOM_RGB)
1560 fprintf(stdout, "RGB Colour: %g %g %g (%s)\n",
1561 colour.red, colour.green, colour.blue,
1562 colour.name);
1563 else
1564 fprintf(stdout, "Unrecognised colour\n");
1565 }
1566 if (s == NULL) {
1567 if (code == 0)
1568 code = 1;
1569 }
1570 else {
1571 pcolour = (CUSTOM_COLOUR *)malloc(sizeof(CUSTOM_COLOUR));
1572 if (pcolour == NULL)
1573 code = -1;
1574 else {
1575 /* append to list */
1576 memcpy(pcolour, &colour, sizeof(colour));
1577 if (tail) {
1578 tail->next = pcolour;
1579 tail = pcolour;
1580 }
1581 else
1582 opt->colours = tail = pcolour;
1583 }
1584 }
1585 }
1586 fclose(f);
1587 }
1588 return code;
1589 }
1590
1591 static void
1592 custom_colours_free(OPT *opt)
1593 {
1594 CUSTOM_COLOUR *pcolour;
1595 while (opt->colours) {
1596 pcolour = opt->colours;
1597 opt->colours = opt->colours->next;
1598 free(pcolour);
1599 }
1600 }
1601
1602 static CUSTOM_COLOUR *
1603 custom_colours_find(OPT *opt, const char *name)
1604 {
1605 CUSTOM_COLOUR *pcolour = opt->colours;
1606 while (pcolour) {
1607 if (strcmp(name, pcolour->name) == 0)
1608 break;
1609 pcolour = pcolour->next;
1610 }
1611 return pcolour;
1612 }
1613
1614 /****************************************************************/
1615 static float
1616 round_float(float f, int n)
1617 {
1618 return (float)( ((int)(f * n + 0.5)) / (float)n );
1619 }
1620
1621 /* Calculate the bounding box using the ghostscript bbox device */
1622 static int
1623 calculate_bbox(Doc *doc, OPT *opt, LPCTSTR psname, CDSCBBOX *bbox, CDSCFBBOX *hires_bbox)
1624 {
1625 FILE *bboxfile;
1626 TCHAR bboxname[MAXSTR];
1627 TCHAR command[MAXSTR*8];
1628 char line[MAXSTR];
1629 int got_bbox = 0;
1630 int got_hires_bbox = 0;
1631 int code = 0;
1632 int llx, lly, urx, ury;
1633 float fllx, flly, furx, fury;
1634 const int pagesize = 9400; /* Must be < 9419 on 7.07, < 150976 on 8.x */
1635 const int offset = 3000;
1636 if ((bboxfile = app_temp_file(doc->app, bboxname,
1637 sizeof(bboxname)/sizeof(TCHAR))) == (FILE *)NULL) {
1638 app_csmsgf(doc->app, TEXT("Can't create temporary bbox file \042%s\042\n"),
1639 bboxname);
1640 return -1;
1641 }
1642 fclose(bboxfile);
1643
1644 csnprintf(command, sizeof(command)/sizeof(TCHAR), TEXT(
1645 "\042%s\042 %s -dNOPAUSE -dBATCH -sDEVICE=bbox %s \
1646 -c \042<</PageSize [%d %d] /PageOffset [%d %d]>> setpagedevice\042 -f \042%s\042"),
1647 opt->gs, opt->quiet ? TEXT("-dQUIET") : TEXT(""), opt->gsargs,
1648 pagesize, pagesize, offset, offset, psname);
1649 if (!opt->quiet)
1650 app_csmsgf(doc->app, TEXT("%s\n"), command);
1651 code = exec_program(command, -1, fileno(stdout), -1, NULL, NULL, bboxname);
1652 if (code != 0)
1653 app_csmsgf(doc->app,
1654 TEXT("Ghostscript failed to obtain bounding box\n"));
1655
1656 /* Now scan for bounding box info */
1657 if (code == 0) {
1658 if ((bboxfile = csfopen(bboxname, TEXT("rb"))) == (FILE *)NULL) {
1659 app_csmsgf(doc->app,
1660 TEXT("Can't open temporary bbox file \042%s\042\n"),
1661 bboxname);
1662 code = -1;
1663 }
1664 }
1665
1666 if (code == 0) {
1667 while (fgets(line, sizeof(line), bboxfile) != NULL) {
1668 if (strncmp(line, "%%BoundingBox: ", 15) == 0) {
1669 if (!opt->quiet)
1670 app_msgf(doc->app, "%s", line);
1671 if (sscanf(line+15, "%d %d %d %d", &llx, &lly, &urx, &ury)
1672 == 4) {
1673 bbox->llx = llx-offset;
1674 bbox->lly = lly-offset;
1675 bbox->urx = urx-offset;
1676 bbox->ury = ury-offset;
1677 got_bbox = 1;
1678 }
1679 }
1680 else if (strncmp(line, "%%HiResBoundingBox: ", 20) == 0) {
1681 if (!opt->quiet)
1682 app_msgf(doc->app, "%s", line);
1683 if (sscanf(line+20, "%f %f %f %f", &fllx, &flly, &furx, &fury)
1684 == 4) {
1685 hires_bbox->fllx = round_float(fllx-offset, 1000);
1686 hires_bbox->flly = round_float(flly-offset, 1000);
1687 hires_bbox->furx = round_float(furx-offset, 1000);
1688 hires_bbox->fury = round_float(fury-offset, 1000);
1689 got_hires_bbox = 1;
1690 }
1691 }
1692 if (got_bbox && got_hires_bbox)
1693 break;
1694 }
1695 }
1696
1697 fclose(bboxfile);
1698 if (!(debug & DEBUG_GENERAL))
1699 csunlink(bboxname);
1700
1701 if ((code == 0) && (!got_bbox)) {
1702 app_csmsgf(doc->app, TEXT("Didn't get bounding box\n"));
1703 code = -1;
1704 }
1705 if ((code == 0) && (!got_hires_bbox)) {
1706 app_csmsgf(doc->app, TEXT("Didn't get hires bounding box\n"));
1707 code = -1;
1708 }
1709 return code;
1710 }
1711
1712 static int
1713 calc_device_size(float dpi, CDSCBBOX *bbox, CDSCFBBOX *hires_bbox,
1714 int *width, int *height, float *xoffset, float *yoffset)
1715 {
1716 int code = 0;
1717 int hires_bbox_valid = 1;
1718 if ((bbox->llx >= bbox->urx) ||
1719 (bbox->lly >= bbox->ury)) {
1720 code = -1;
1721 }
1722
1723 if ((hires_bbox->fllx > hires_bbox->furx) ||
1724 (hires_bbox->flly > hires_bbox->fury)) {
1725 hires_bbox_valid = 0;
1726 code = -1;
1727 }
1728 if ((hires_bbox->fllx == hires_bbox->furx) ||
1729 (hires_bbox->flly == hires_bbox->fury)) {
1730 hires_bbox_valid = 0;
1731 /* ignore hires_bbox */
1732 }
1733
1734 /* Make the preview image */
1735 if (hires_bbox_valid) {
1736 *width = (int)((hires_bbox->furx - hires_bbox->fllx)*dpi/72.0+0.5);
1737 *height = (int)((hires_bbox->fury - hires_bbox->flly)*dpi/72.0+0.5);
1738 *xoffset = -hires_bbox->fllx;
1739 *yoffset = -hires_bbox->flly;
1740 }
1741 else {
1742 *width = (int)((bbox->urx - bbox->llx)*dpi/72.0+0.5);
1743 *height = (int)((bbox->ury - bbox->lly)*dpi/72.0+0.5);
1744 *xoffset = (float)(-bbox->llx);
1745 *yoffset = (float)(-bbox->lly);
1746 }
1747 return 0;
1748 }
1749
1750
1751 static int
1752 make_preview_file(Doc *doc, OPT *opt, int page,
1753 LPCTSTR preview, LPCTSTR device,
1754 float dpi, CDSCBBOX *bbox, CDSCFBBOX *hires_bbox, int calc_bbox)
1755 {
1756 GFile *f;
1757 int code = 0;
1758 TCHAR tpsname[MAXSTR];
1759 TCHAR command[MAXSTR*8];
1760 int width, height;
1761 float xoffset, yoffset;
1762
1763 /* Copy page to temporary file */
1764 if ((f = app_temp_gfile(doc->app, tpsname,
1765 sizeof(tpsname)/sizeof(TCHAR))) == (GFile *)NULL) {
1766 app_csmsgf(doc->app,
1767 TEXT("Can't create temporary ps file \042%s\042\n"),
1768 tpsname);
1769 return -1;
1770 }
1771 code = copy_page_temp(doc, f, page);
1772 gfile_close(f);
1773 if (code != 0) {
1774 if (!(debug & DEBUG_GENERAL))
1775 csunlink(tpsname);
1776 return -1;
1777 }
1778
1779 /* Get bbox */
1780 if ((code == 0) && calc_bbox)
1781 code = calculate_bbox(doc, opt, tpsname, bbox, hires_bbox);
1782 width = height = 0;
1783 xoffset = yoffset = 0.0;
1784 if (code == 0)
1785 code = calc_device_size(dpi, bbox, hires_bbox, &width, &height,
1786 &xoffset, &yoffset);
1787 if (code) {
1788 app_csmsgf(doc->app, TEXT("BoundingBox is invalid\n"));
1789 if (!(debug & DEBUG_GENERAL))
1790 csunlink(tpsname);
1791 return -1;
1792 }
1793
1794 /* Make the preview image */
1795 csnprintf(command, sizeof(command)/sizeof(TCHAR),
1796 TEXT("\042%s\042 %s -dNOPAUSE -dBATCH -sDEVICE=%s -sOutputFile=\042%s\042 -r%g -g%dx%d %s -c %f %f translate -f \042%s\042"),
1797 opt->gs, opt->quiet ? TEXT("-dQUIET") : TEXT(""),
1798 device, (preview[0]=='\0' ? TEXT("-") : preview), dpi, width, height,
1799 opt->gsargs, xoffset, yoffset, tpsname);
1800 if (!opt->quiet)
1801 app_csmsgf(doc->app, TEXT("%s\n"), command);
1802 code = exec_program(command, -1, fileno(stdout), fileno(stderr),
1803 NULL, NULL, NULL);
1804 if (code != 0)
1805 app_csmsgf(doc->app,
1806 TEXT("Ghostscript failed to create preview image\n"));
1807
1808 /* delete temporary ps file */
1809 if (!(debug & DEBUG_GENERAL))
1810 csunlink(tpsname);
1811
1812 return code;
1813 }
1814
1815
1816 static IMAGE *
1817 make_preview_image(Doc *doc, OPT *opt, int page, LPCTSTR device,
1818 CDSCBBOX *bbox, CDSCFBBOX *hires_bbox, int calc_bbox)
1819 {
1820 IMAGE *img = NULL;
1821 IMAGE *newimg = NULL;
1822 TCHAR preview[MAXSTR];
1823 GFile *f;
1824 int code = 0;
1825
1826 /* Create a temporary file for ghostscript bitmap output */
1827 if ((f = app_temp_gfile(doc->app, preview,
1828 sizeof(preview)/sizeof(TCHAR))) == (GFile *)NULL) {
1829 app_csmsgf(doc->app,
1830 TEXT("Can't create temporary bitmap file \042%s\042\n"),
1831 preview);
1832 code = -1;
1833 }
1834 else
1835 gfile_close(f);
1836
1837 if (code == 0)
1838 code = make_preview_file(doc, opt, page,
1839 preview, device, opt->dpi_render, bbox, hires_bbox, calc_bbox);
1840
1841 if (code == 0) {
1842 /* Load image */
1843 img = bmpfile_to_image(preview);
1844 if (img == NULL)
1845 img = pnmfile_to_image(preview);
1846 }
1847
1848 if (img && (opt->dpi_render != opt->dpi)) {
1849 /* downscale it */
1850 newimg = (IMAGE *)malloc(sizeof(IMAGE));
1851 if (newimg != NULL) {
1852 int ncomp;
1853 int width, height;
1854 float xoffset, yoffset;
1855 memset(newimg, 0, sizeof(newimg));
1856 calc_device_size(opt->dpi, bbox, hires_bbox, &width, &height,
1857 &xoffset, &yoffset);
1858 newimg->width = width;
1859 newimg->height = height;
1860 newimg->format = img->format;
1861 if ((newimg->format & DISPLAY_COLORS_MASK)
1862 == DISPLAY_COLORS_CMYK)
1863 ncomp = 4;
1864 else if ((newimg->format & DISPLAY_COLORS_MASK)
1865 == DISPLAY_COLORS_RGB)
1866 ncomp = 3;
1867 else
1868 ncomp = 1;
1869 newimg->raster = newimg->width * ncomp; /* bytes per row */
1870 newimg->image = malloc(newimg->raster * newimg->height);
1871 if (newimg->image == NULL) {
1872 free(newimg);
1873 newimg = NULL;
1874 }
1875 }
1876 if (newimg != NULL) {
1877 memset(newimg->image, 0, newimg->raster * newimg->height);
1878 if (image_down_scale(newimg, img) != 0) {
1879 bitmap_image_free(newimg);
1880 newimg = NULL;
1881 }
1882 }
1883 if (newimg != NULL) {
1884 bitmap_image_free(img);
1885 img = newimg;
1886 }
1887 }
1888
1889 if (!(debug & DEBUG_GENERAL))
1890 csunlink(preview);
1891 return img;
1892 }
1893
1894
1895 /****************************************************************/
1896 int
1897 epstool_dcs2_composite(Doc *doc, OPT *opt, GFile *compfile)
1898 {
1899 CDSC *dsc = doc->dsc;
1900 IMAGE img;
1901 IMAGE *layer = NULL;
1902 int width, height;
1903 float xoffset, yoffset;
1904 float cyan, magenta, yellow, black;
1905 int code = 0;
1906 int i;
1907 CDSCBBOX bbox = {0, 0, 0, 0};
1908 CDSCFBBOX hires_bbox = {0.0, 0.0, 0.0, 0.0};
1909 int hires_bbox_valid = 0;
1910
1911 /* Require original to be DCS 2.0 */
1912 if (doc->dsc == NULL)
1913 return -1;
1914 if (doc->dsc->dcs2 == NULL)
1915 return -1;
1916
1917 if (dsc->bbox) {
1918 bbox = *dsc->bbox;
1919 }
1920 else
1921 return -1;
1922 if (dsc->hires_bbox) {
1923 hires_bbox = *dsc->hires_bbox;
1924 hires_bbox_valid = 1;
1925 }
1926
1927 /* Make a CMYK image for the composite */
1928 code = calc_device_size(opt->dpi, &bbox, &hires_bbox, &width, &height,
1929 &xoffset, &yoffset);
1930 if (code) {
1931 app_csmsgf(doc->app, TEXT("BoundingBox is invalid\n"));
1932 return -1;
1933 }
1934 memset(&img, 0, sizeof(img));
1935 img.width = width;
1936 img.height = height;
1937 img.raster = img.width * 4;
1938 img.format = DISPLAY_COLORS_CMYK | DISPLAY_ALPHA_NONE |
1939 DISPLAY_DEPTH_8 | DISPLAY_BIGENDIAN | DISPLAY_TOPFIRST;
1940 img.image = (unsigned char *)malloc(img.raster * img.height);
1941 if (img.image == NULL)
1942 return -1;
1943 memset(img.image, 0, img.raster * img.height);
1944
1945 /* For each plate, make an image, then merge it into
1946 * the composite
1947 */
1948 for (i=1; i<(int)dsc->page_count; i++) {
1949 /* find colour */
1950 int found;
1951 CUSTOM_COLOUR *ccolour = NULL;
1952 const char *name = dsc->page[i].label;
1953 if (name == NULL) {
1954 app_msgf(doc->app, "Page %d doesn't have a label\n", i);
1955 code = -1;
1956 break;
1957 }
1958 found = colour_to_cmyk(dsc, name, &cyan, &magenta, &yellow, &black);
1959 if ((ccolour = custom_colours_find(opt, name)) != NULL) {
1960 /* Use local colour overrides from --custom-colours */
1961 found = 0;
1962 if (ccolour->type == CUSTOM_RGB) {
1963 cyan = (float)(1.0 - ccolour->red);
1964 magenta = (float)(1.0 - ccolour->green);
1965 yellow = (float)(1.0 - ccolour->blue);
1966 black = min(cyan, min(magenta, yellow));
1967 if (black > 0.0) {
1968 cyan -= black;
1969 magenta -= black;
1970 yellow -= black;
1971 }
1972 }
1973 else {
1974 cyan = ccolour->cyan;
1975 magenta = ccolour->magenta;
1976 yellow = ccolour->yellow;
1977 black = ccolour->black;
1978 }
1979 }
1980 if (found < 0) {
1981 app_msgf(doc->app, "Unrecognised colour (%s)\n", name);
1982 code = -1;
1983 break;
1984 }
1985
1986 if ((cyan == 0.0) && (magenta == 0.0) && (yellow == 0.0) &&
1987 (black == 0.0)) {
1988 if (!opt->quiet)
1989 app_msgf(doc->app, "Skipping blank separation %s\n", name);
1990 continue;
1991 }
1992 if (!opt->quiet)
1993 app_msgf(doc->app, "Creating image from separation %s\n", name);
1994 /* Now get the separation image */
1995 layer = make_preview_image(doc, opt, i, GREY_DEVICE,
1996 &bbox, &hires_bbox, FALSE);
1997 if (layer == NULL) {
1998 app_msgf(doc->app, "Failed to make image for separation (%s)\n",
1999 name);
2000 code = -1;
2001 break;
2002 }
2003 else {
2004 if (!opt->quiet)
2005 app_msgf(doc->app, "Merging separation %g %g %g %g %s\n",
2006 cyan, magenta, yellow, black, name);
2007 code = image_merge_cmyk(&img, layer, cyan, magenta, yellow, black);
2008 bitmap_image_free(layer);
2009 if (code < 0) {
2010 app_msgf(doc->app, "Failed to merge separation (%s)\n", name);
2011 code = -1;
2012 break;
2013 }
2014 }
2015
2016 }
2017
2018
2019 if (code == 0) {
2020 if (!opt->quiet)
2021 app_msgf(doc->app, "Writing composite as EPS\n");
2022 code = image_to_eps(compfile, &img,
2023 bbox.llx, bbox.lly, bbox.urx, bbox.ury,
2024 hires_bbox.fllx, hires_bbox.flly,
2025 hires_bbox.furx, hires_bbox.fury,
2026 opt->image_encode,
2027 opt->image_compress);
2028 }
2029
2030 free(img.image);
2031 return code;
2032 }
2033
2034 /* Return 0 if CMYK set from the DSC comments, -1 if not set */
2035 static int
2036 colour_to_cmyk(CDSC *dsc, const char *name,
2037 float *cyan, float *magenta, float *yellow, float *black)
2038 {
2039 int code = 0;
2040 CDSCCOLOUR *colour = dsc->colours;
2041 if (name == NULL)
2042 return -1;
2043 while (colour) {
2044 if (colour->name && (dsc_stricmp(colour->name, name)==0))
2045 break;
2046 colour = colour->next;
2047 }
2048
2049 if (colour && (colour->custom == CDSC_CUSTOM_COLOUR_CMYK)) {
2050 *cyan = colour->cyan;
2051 *magenta = colour->magenta;
2052 *yellow = colour->yellow;
2053 *black = colour->black;
2054 }
2055 else if (colour && (colour->custom == CDSC_CUSTOM_COLOUR_RGB)) {
2056 *cyan = (float)(1.0 - colour->red);
2057 *magenta = (float)(1.0 - colour->green);
2058 *yellow = (float)(1.0 - colour->blue);
2059 *black = min(*cyan, min(*magenta, *yellow));
2060 if (*black > 0.0) {
2061 *cyan -= *black;
2062 *magenta -= *black;
2063 *yellow -= *black;
2064 }
2065 }
2066 else {
2067 if (dsc_stricmp(name, "Cyan") == 0) {
2068 *cyan = 1.0;
2069 *magenta = *yellow = *black = 0.0;
2070 }
2071 else if (dsc_stricmp(name, "Magenta") == 0) {
2072 *magenta = 1.0;
2073 *cyan = *yellow = *black = 0.0;
2074 }
2075 else if (dsc_stricmp(name, "Yellow") == 0) {
2076 *yellow = 1.0;
2077 *cyan = *magenta = *black = 0.0;
2078 }
2079 else if (dsc_stricmp(name, "Black") == 0) {
2080 *black = 1.0;
2081 *cyan = *yellow = *magenta = 0.0;
2082 }
2083 else {
2084 code = -1;
2085 }
2086 }
2087 return code;
2088 }
2089
2090 const char *epswarn_prolog[] = {
2091 "%!\n",
2092 "% This code is wrapped around an EPS file to partly test if it complies\n",
2093 "% with the EPS specfication.\n",
2094 "\n",
2095 "/eps_warn_file (%stdout) (w) file def\n",
2096 "\n",
2097 "globaldict begin /eps_warn_ok true def end\n",
2098 "\n",
2099 "/eps_write_only { % name string -- name\n",
2100 " eps_warn_file exch writestring\n",
2101 " eps_warn_file ( /) writestring\n",
2102 " dup eps_warn_file exch 32 string cvs writestring\n",
2103 " eps_warn_file (\\n) writestring \n",
2104 " eps_warn_file flushfile\n",
2105 "} bind def\n",
2106 "\n",
2107 "/eps_write { % name string -- name\n",
2108 " eps_write_only\n",
2109 " //globaldict /eps_warn_ok false put\n",
2110 "} bind def\n",
2111 "\n",
2112 "/eps_warn { % name --\n",
2113 " (EPSWARN FAIL: EPS file must not use) \n",
2114 " eps_write\n",
2115 " //systemdict exch get exec\n",
2116 "} bind def\n",
2117 "\n",
2118 "% Prohibited operators in systemdict\n",
2119 "/banddevice {/banddevice eps_warn} def\n",
2120 "/clear {/clear eps_warn} def\n",
2121 "/cleardictstack {/cleardictstack eps_warn} def\n",
2122 "/copypage {/copypage eps_warn} def\n",
2123 "/erasepage {/erasepage eps_warn} def\n",
2124 "/exitserver {/exitserver eps_warn} def % this won't work - exitserver is in serverdict\n",
2125 "/serverdict {/serverdict eps_warn} def % so use this to provide warnings instead\n",
2126 "/statusdict {/statusdict eps_warn} def\n",
2127 "/framedevice {/framedevice eps_warn} def\n",
2128 "/grestoreall {/grestoreall eps_warn} def\n",
2129 "/initclip {/initclip eps_warn} def\n",
2130 "/initgraphics {/initgraphics eps_warn} def\n",
2131 "/initmatrix {/initmatrix eps_warn} def\n",
2132 "/renderbands {/renderbands eps_warn} def\n",
2133 "/setglobal {/setglobal eps_warn} def\n",
2134 "/setpagedevice {/setpagedevice eps_warn} def\n",
2135 "/setpageparams {/setpageparams eps_warn} def\n",
2136 "/setshared {/setshared eps_warn} def\n",
2137 "/startjob {/startjob eps_warn} def\n",
2138 "% If quit is executed, then epswarn_check will never be run.\n",
2139 "/quit {\n",
2140 " % systemdict /quit doesn't work when it has been redefined in userdict\n",
2141 " /quit (EPSWARN FAIL: EPS file must not use) eps_write\n",
2142 " //globaldict /eps_warn_ok false put\n",
2143 " //systemdict begin quit \n",
2144 "} def\n",
2145 "\n",
2146 "% These page sizes are defined in userdict, not systemdict\n",
2147 "/eps_pagesize_warn {\n",
2148 " (EPSWARN FAIL: EPS file must not set page size:)\n",
2149 " eps_write pop\n",
2150 "} def\n",
2151 "/11x17 {/11x17 eps_pagesize_warn} def\n",
2152 "/a3 {/a3 eps_pagesize_warn} def\n",
2153 "/a4 {/a4 eps_pagesize_warn} def\n",
2154 "/a4small {/a4small eps_pagesize_warn} def\n",
2155 "/a5 {/a5 eps_pagesize_warn} def\n",
2156 "/ledger {/ledger eps_pagesize_warn} def\n",
2157 "/legal {/legal eps_pagesize_warn} def\n",
2158 "/letter {/letter eps_pagesize_warn} def\n",
2159 "/lettersmall {/lettersmall eps_pagesize_warn} def\n",
2160 "/note {/note eps_pagesize_warn} def\n",
2161 "\n",
2162 "% These operators can only be used if the parameter\n",
2163 "% is saved and restored afterwards, or if setting\n",
2164 "% them takes into account their previous value.\n",
2165 "% For example 'matrix setmatrix' is not permitted,\n",
2166 "% but 'matrix current matrix setmatrix' is allowed.\n",
2167 "/eps_warntwo {\n",
2168 " (EPSWARN WARNING: EPS file should be careful using) \n",
2169 " eps_write_only\n",
2170 " //systemdict exch get exec\n",
2171 "} def\n",
2172 "/nulldevice {/nulldevice eps_warntwo} def % can't test this\n",
2173 "/setgstate {/setgstate eps_warntwo} def % can't test this\n",
2174 "/sethalftone {/sethalftone eps_warntwo} def\n",
2175 "/setmatrix {/setmatrix eps_warntwo} def\n",
2176 "/setscreen {/setscreen eps_warntwo} def\n",
2177 "/settransfer {/settransfer eps_warntwo} def\n",
2178 "/setcolortransfer {/setcolortransfer eps_warntwo} def\n",
2179 "\n",
2180 "% Take snapshot of some items\n",
2181 "count /eps_count exch def\n",
2182 "countdictstack /eps_countdictstack exch def\n",
2183 "currentpagedevice /PageCount get /eps_pagecount exch def\n",
2184 "/eps_showpage_count 0 def\n",
2185 "\n",
2186 "\n",
2187 "/epswarn_check_write { % string --\n",
2188 " eps_warn_file exch writestring\n",
2189 " eps_warn_file flushfile\n",
2190 " //globaldict /eps_warn_ok false put\n",
2191 "} def\n",
2192 "\n",
2193 "/epswarn_check {\n",
2194 " % count\n",
2195 " count eps_count ne {\n",
2196 " (EPSWARN FAIL: EPS file altered operand stack count\\n) epswarn_check_write \n",
2197 " } if\n",
2198 " //systemdict /clear get exec\n",
2199 " % countdictstack\n",
2200 " countdictstack eps_countdictstack ne {\n",
2201 " (EPSWARN FAIL: EPS file altered dictionary stack count\\n) \n",
2202 " epswarn_check_write\n",
2203 " } if\n",
2204 " countdictstack eps_countdictstack sub {end} repeat\n",
2205 " % real page count\n",
2206 " currentpagedevice /PageCount get eps_pagecount ne {\n",
2207 " (EPSWARN FAIL: EPS file forcibly output a page\\n) epswarn_check_write\n",
2208 " } if\n",
2209 " % showpage count\n",
2210 " eps_showpage_count 1 gt {\n",
2211 " (EPSWARN FAIL: EPS file used showpage more than once\\n) epswarn_check_write\n",
2212 " } if\n",
2213 "} def\n",
2214 "\n",
2215 "% EPS files are normally encapsulated inside a save/restore\n",
2216 "save /epswarn_save exch def\n",
2217 "\n",
2218 "% redefine showpage, and count how many times it is called\n",
2219 "/showpage { userdict dup /eps_showpage_count get 1 add \n",
2220 " /eps_showpage_count exch put \n",
2221 "} def\n",
2222 "\n",
2223 "% Now for something to test this\n",
2224 "\n",
2225 NULL};
2226
2227 const char epswarn_epilog[] = "\
2228 %!\n\
2229 % Check that all is well\n\
2230 epswarn_check\n\
2231 %epswarn_save restore\n\
2232 //globaldict /eps_warn_ok get not \n\
2233 {eps_warn_file (\nEPSWARN FAIL\\n) writestring} \n\
2234 {eps_warn_file (\nEPSWARN PASS\\n) writestring} \n\
2235 ifelse\n\
2236 systemdict begin % so quit works...\n\
2237 ";
2238
2239
2240 /* Test if an EPS file really is EPS compliant */
2241 static int
2242 epstool_test(Doc *doc, OPT *opt)
2243 {
2244 GFile *f;
2245 int code = 0;
2246 TCHAR tpsname[MAXSTR];
2247 TCHAR command[MAXSTR*8];
2248 unsigned int len;
2249 FILE *testfile = NULL;
2250 TCHAR testname[MAXSTR];
2251 CDSCBBOX bbox;
2252 CDSCFBBOX hires_bbox;
2253 BOOL found_error = FALSE;
2254 BOOL found_warning = FALSE;
2255 BOOL found_pass = FALSE;
2256 BOOL bbox_valid = FALSE;
2257 char line[256];
2258 int i;
2259 BOOL dsc_error = FALSE;
2260 BOOL dsc_warning = FALSE;
2261
2262 if (doc->dsc) {
2263 dsc_error = (doc->dsc->worst_error == CDSC_ERROR_ERROR);
2264 dsc_warning = (doc->dsc->worst_error == CDSC_ERROR_WARN);
2265 }
2266
2267 /* Copy prolog, page and epilog to a temporary file */
2268 if ((f = app_temp_gfile(doc->app, tpsname,
2269 sizeof(tpsname)/sizeof(TCHAR))) == (GFile *)NULL) {
2270 app_csmsgf(doc->app,
2271 TEXT("Can't create temporary ps file \042%s\042\n"),
2272 tpsname);
2273 return -1;
2274 }
2275 for (i=0; epswarn_prolog[i]; i++) {
2276 len = (int)strlen(epswarn_prolog[i]);
2277 if (!code && (len != gfile_write(f, epswarn_prolog[i], len)))
2278 code = -1;
2279 }
2280 code = copy_page_nosave(doc, f, 0);
2281 len = (int)strlen(epswarn_epilog);
2282 if (len != gfile_write(f, epswarn_epilog, len))
2283 code = -1;
2284 gfile_close(f);
2285 if (code != 0) {
2286 if (!(debug & DEBUG_GENERAL))
2287 csunlink(tpsname);
2288 return -1;
2289 }
2290
2291 if ((testfile = app_temp_file(doc->app, testname,
2292 sizeof(testname)/sizeof(TCHAR))) == (FILE *)NULL) {
2293 app_csmsgf(doc->app, TEXT("Can't create temporary file \042%s\042\n"),
2294 testname);
2295 if (!(debug & DEBUG_GENERAL))
2296 csunlink(tpsname);
2297 return -1;
2298 }
2299 fclose(testfile);
2300 testfile = NULL;
2301
2302 /* Interpret the file to test it */
2303 csnprintf(command, sizeof(command)/sizeof(TCHAR),
2304 TEXT("\042%s\042 %s -dNOEPS -dNOPAUSE -dBATCH -dNODISPLAY %s \042%s\042"),
2305 opt->gs, opt->quiet ? TEXT("-dQUIET") : TEXT(""),
2306 opt->gsargs, tpsname);
2307 if (!opt->quiet)
2308 app_csmsgf(doc->app, TEXT("%s\n"), command);
2309 code = exec_program(command, -1, -1 , fileno(stderr),
2310 NULL, testname, NULL);
2311 if (code != 0)
2312 app_csmsgf(doc->app,
2313 TEXT("Ghostscript failed to interpret file\n"));
2314 /* delete temporary ps file */
2315 if (!(debug & DEBUG_GENERAL))
2316 csunlink(tpsname);
2317
2318 /* Now check testfile for reports of problems */
2319 if (code == 0) {
2320 if ((testfile = csfopen(testname, TEXT("rb"))) == (FILE *)NULL) {
2321 app_csmsgf(doc->app,
2322 TEXT("Can't open temporary file \042%s\042\n"),
2323 testname);
2324 code = -1;
2325 }
2326 }
2327
2328 if (code == 0) {
2329 while (fgets(line, sizeof(line), testfile) != NULL) {
2330 if (!opt->quiet)
2331 app_msgf(doc->app, "%s", line);
2332 if (strncmp(line, "EPSWARN FAIL: ", 14) == 0)
2333 found_error = TRUE;
2334 else if (strncmp(line, "EPSWARN WARNING: ", 17) == 0)
2335 found_warning = TRUE;
2336 else if (strncmp(line, "EPSWARN PASS", 12) == 0)
2337 found_pass = TRUE;
2338 }
2339 }
2340 if (testfile)
2341 fclose(testfile);
2342 if (!(debug & DEBUG_GENERAL))
2343 csunlink(testname);
2344 if (!opt->quiet)
2345 app_csmsg(doc->app, TEXT("\n"));
2346
2347 if ((code == 0) && (doc->dsc) && (doc->dsc->bbox)) {
2348 /* Copy page to temporary file */
2349 if ((f = app_temp_gfile(doc->app, tpsname,
2350 sizeof(tpsname)/sizeof(TCHAR))) == (GFile *)NULL) {
2351 app_csmsgf(doc->app,
2352 TEXT("Can't create temporary ps file \042%s\042\n"),
2353 tpsname);
2354 return -1;
2355 }
2356 code = copy_page_temp(doc, f, 0);
2357 gfile_close(f);
2358 if (code != 0) {
2359 if (!(debug & DEBUG_GENERAL))
2360 csunlink(tpsname);
2361 return -1;
2362 }
2363 code = calculate_bbox(doc, opt, tpsname, &bbox, &hires_bbox);
2364 if (!opt->quiet)
2365 app_csmsg(doc->app, TEXT("\n"));
2366 if (code == 0) {
2367 if ( (bbox.llx >= doc->dsc->bbox->llx-1) &&
2368 (bbox.lly >= doc->dsc->bbox->lly-1) &&
2369 (bbox.urx <= doc->dsc->bbox->urx+1) &&
2370 (bbox.ury <= doc->dsc->bbox->ury+1)) {
2371 bbox_valid = TRUE;
2372 }
2373 if (!opt->quiet) {
2374 app_csmsgf(doc->app,
2375 TEXT("File has %%%%BoundingBox: %d %d %d %d\n"),
2376 doc->dsc->bbox->llx, doc->dsc->bbox->lly,
2377 doc->dsc->bbox->urx, doc->dsc->bbox->ury);
2378 app_csmsgf(doc->app,
2379 TEXT("Correct is %%%%BoundingBox: %d %d %d %d\n"),
2380 bbox.llx, bbox.lly, bbox.urx, bbox.ury);
2381 if (!bbox_valid)
2382 app_csmsgf(doc->app,
2383 TEXT("File bounding box needs to be larger\n"));
2384 }
2385 }
2386 else {
2387 if (!opt->quiet)
2388 app_csmsgf(doc->app,
2389 TEXT("Failed to calculate bounding box\n"));
2390 }
2391
2392 /* delete temporary ps file */
2393 if (!(debug & DEBUG_GENERAL))
2394 csunlink(tpsname);
2395 }
2396 else {
2397 if (!opt->quiet)
2398 app_csmsgf(doc->app,
2399 TEXT("Missing %%%%BoundingBox\n"));
2400 }
2401
2402 if (found_error || !found_pass || !bbox_valid ||
2403 dsc_error || dsc_warning ||
2404 !doc->dsc || !doc->dsc->epsf)
2405 code = -1;
2406
2407 if (!opt->quiet) {
2408 if (found_warning)
2409 app_csmsgf(doc->app, TEXT("File used operators that sometimes cause problems in an EPS file.\n"));
2410 if (found_error)
2411 app_csmsgf(doc->app, TEXT("File used PostScript operators that are prohibited in an EPS file.\n"));
2412 if (found_pass)
2413 app_csmsgf(doc->app, TEXT("PostScript appears well behaved.\n"));
2414 if (doc->dsc && doc->dsc->epsf)
2415 app_csmsgf(doc->app, TEXT("File claims to be EPS.\n"));
2416 else
2417 app_csmsgf(doc->app, TEXT("File is not EPS.\n"));
2418 }
2419
2420 if (code != 0)
2421 fprintf(MSGOUT, "FAIL: File does not comply with EPS specification.\n");
2422 else
2423 fprintf(MSGOUT, "PASS: File appears to be well behaved EPS.\n");
2424
2425 return code;
2426 }
2427
2428 static void epstool_dump_fn(void *caller_data, const char *str)
2429 {
2430 fputs(str, stdout);
2431 }
2432
2433
2434 /****************************************************************/
2435 /* Functions from GSview app that we need. */
2436 /* Some of these should be moved from capp.c to a separate file. */
2437
2438 #ifdef _MSC_VER
2439 # pragma warning(disable:4100) /* ignore "Unreferenced formal parameter" */
2440 #endif
2441
2442 int
2443 app_platform_init(GSview *a)
2444 {
2445 return 0;
2446 }
2447
2448 int
2449 app_platform_finish(GSview *a)
2450 {
2451 return 0;
2452 }
2453
2454 int
2455 app_lock(GSview *a)
2456 {
2457 return 0;
2458 }
2459
2460 int
2461 app_unlock(GSview *a)
2462 {
2463 return 0;
2464 }
2465
2466 void
2467 app_log(const char *str, int len)
2468 {
2469 fwrite(str, 1, len, MSGOUT);
2470 }
2471
2472 int
2473 cs_to_narrow(char *nstr, int nlen, LPCTSTR wstr, int wlen)
2474 {
2475 #ifdef UNICODE
2476 return WideCharToMultiByte(CP_ACP, 0, wstr, wlen, nstr, nlen, NULL, NULL);
2477 #else
2478 return char_to_narrow(nstr, nlen, wstr, wlen);
2479 #endif
2480 }
2481
2482 int
2483 narrow_to_cs(TCHAR *wstr, int wlen, const char *nstr, int nlen)
2484 {
2485 #ifdef UNICODE
2486 return MultiByteToWideChar(CP_ACP, 0, nstr, nlen, wstr, wlen);
2487 #else
2488 return narrow_to_char(wstr, wlen, nstr, nlen);
2489 #endif
2490 }
2491
2492 int get_dsc_response(GSview *app, LPCTSTR str)
2493 {
2494 app_csmsgf(app, TEXT("\n%s\n"), str);
2495 return CDSC_RESPONSE_OK;
2496 }
2497
2498 int
2499 load_string(GSview *a, int id, TCHAR *buf, int len)
2500 {
2501 char msg[MAXSTR];
2502 const char *s = NULL;
2503 int reslen;
2504 int dscmsg = (id - CDSC_RESOURCE_BASE) / 2;
2505 if (buf && len)
2506 buf[0] = '\0';
2507 /* CDSC_MESSAGE_INCORRECT_USAGE should be dsc->max_error */
2508 if (a /* ignore unused parameter GSview *a */
2509 && (dscmsg >= 0) && (dscmsg <= CDSC_MESSAGE_INCORRECT_USAGE)) {
2510 if (((id - CDSC_RESOURCE_BASE) & 1) == 0)
2511 s = dsc_message[dscmsg];
2512 else
2513 s = "";
2514 }
2515 else
2516 switch (id) {
2517 case IDS_DSC_LINEFMT:
2518 s = "%sAt line %d:";
2519 break;
2520 case IDS_DSC_INFO:
2521 s = "DSC Information\n";
2522 break;
2523 case IDS_DSC_WARN:
2524 s = "DSC Warning\n";
2525 break;
2526 case IDS_DSC_ERROR:
2527 s = "DSC Error\n";
2528 break;
2529 }
2530
2531 if (s == NULL) {
2532 snprintf(msg, sizeof(msg), "String %d\n", id);
2533 s = msg;
2534 }
2535
2536 reslen = narrow_to_cs(NULL, 0, s, (int)strlen(s)+1);
2537 if (reslen > len)
2538 return reslen;
2539 return narrow_to_cs(buf, len, s, (int)strlen(s)+1);
2540 }
2541
2542 int app_msg_box(GSview *a, LPCTSTR str, int icon)
2543 {
2544 app_csmsgf(a, TEXT("%s\n"), str);
2545 return 0;
2546 }
2547
2548 int
2549 gssrv_request(GSSRV *s, GSREQ *reqnew)
2550 {
2551 return -1;
2552 }
2553
2554 int
2555 pagecache_unref_all(GSview *a)
2556 {
2557 return 0;
2558 }
2559
2560
2561 void
2562 doc_savestat(Doc *doc)
2563 {
2564 }
2565
2566 int
2567 image_platform_init(IMAGE *img)
2568 {
2569 return 0;
2570 }
2571
2572 unsigned int
2573 image_platform_format(unsigned int format)
2574 {
2575 return format;
2576 }
2577
2578 #ifdef _MSC_VER
2579 # pragma warning(default:4100)
2580 #endif
2581
2582 /****************************************************************/
2583 /* platform specific code for running another program */
2584
2585 /*
2586 * If hstdin not -1, duplicate handle and give to program,
2587 * else if stdin_name not NULL, open filename and give to program.
2588 * Same for hstdout/stdout_name and hstderr/stderr_name.
2589 */
2590 #ifdef __WIN32__
2591 int
2592 exec_program(LPTSTR command,
2593 int hstdin, int hstdout, int hstderr,
2594 LPCTSTR stdin_name, LPCTSTR stdout_name, LPCTSTR stderr_name)
2595 {
2596 int code = 0;
2597 HANDLE hChildStdinRd = INVALID_HANDLE_VALUE;
2598 HANDLE hChildStdoutWr = INVALID_HANDLE_VALUE;
2599 HANDLE hChildStderrWr = INVALID_HANDLE_VALUE;
2600 HANDLE hStdin = INVALID_HANDLE_VALUE;
2601 HANDLE hStderr = INVALID_HANDLE_VALUE;
2602 HANDLE hStdout = INVALID_HANDLE_VALUE;
2603 SECURITY_ATTRIBUTES saAttr;
2604 STARTUPINFO siStartInfo;
2605 PROCESS_INFORMATION piProcInfo;
2606 DWORD exitcode = (DWORD)-1;
2607
2608 /* Set the bInheritHandle flag so pipe handles are inherited. */
2609 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
2610 saAttr.bInheritHandle = TRUE;
2611 saAttr.lpSecurityDescriptor = NULL;
2612
2613 /* if handles are provided, use them */
2614 if ((hstdin != -1)) {
2615 INTPTR handle;
2616 handle = _get_osfhandle(hstdin);
2617 if (handle == -1)
2618 code = -1;
2619 if (code == 0) {
2620 hStdin = (HANDLE)handle;
2621 if (!DuplicateHandle(GetCurrentProcess(), hStdin,
2622 GetCurrentProcess(), &hChildStdinRd, 0,
2623 TRUE, /* inherited */
2624 DUPLICATE_SAME_ACCESS))
2625 code = -1;
2626 }
2627 }
2628 if ((code==0) && (hstdout != -1)) {
2629 INTPTR handle;
2630 handle = _get_osfhandle(hstdout);
2631 if (handle == -1)
2632 code = -1;
2633 if (code == 0) {
2634 hStdout = (HANDLE)handle;
2635 if (!DuplicateHandle(GetCurrentProcess(), hStdout,
2636 GetCurrentProcess(), &hChildStdoutWr, 0,
2637 TRUE, /* inherited */
2638 DUPLICATE_SAME_ACCESS))
2639 code = -1;
2640 }
2641 }
2642 if ((code==0) && (hstderr != -1)) {
2643 INTPTR handle;
2644 handle = _get_osfhandle(hstderr);
2645 if (handle == -1)
2646 code = -1;
2647 if (code == 0) {
2648 hStderr = (HANDLE)handle;
2649 if (!DuplicateHandle(GetCurrentProcess(), hStderr,
2650 GetCurrentProcess(), &hChildStderrWr, 0,
2651 TRUE, /* inherited */
2652 DUPLICATE_SAME_ACCESS))
2653 code = -1;
2654 }
2655 }
2656
2657 /* If files are requested, create them */
2658 if ((code==0) && stdin_name && (hChildStdinRd == INVALID_HANDLE_VALUE)) {
2659 hChildStdinRd = CreateFile(stdin_name, GENERIC_READ,
2660 0 /* no file sharing */,
2661 &saAttr /* allow handle to be inherited */,
2662 OPEN_EXISTING, 0, NULL);
2663 if (hChildStdinRd == INVALID_HANDLE_VALUE)
2664 code = -1;
2665 }
2666 if ((code==0) && stdout_name && (hChildStdoutWr == INVALID_HANDLE_VALUE)) {
2667 hChildStdoutWr = CreateFile(stdout_name, GENERIC_WRITE,
2668 0 /* no file sharing */,
2669 &saAttr /* allow handle to be inherited */,
2670 OPEN_ALWAYS, 0, NULL);
2671 if (hChildStdoutWr == INVALID_HANDLE_VALUE)
2672 code = -1;
2673 }
2674 if ((code==0) && stderr_name && (hChildStderrWr == INVALID_HANDLE_VALUE)) {
2675 hChildStderrWr = CreateFile(stderr_name, GENERIC_WRITE,
2676 0 /* no file sharing */,
2677 &saAttr /* allow handle to be inherited */,
2678 OPEN_ALWAYS, 0, NULL);
2679 if (hChildStderrWr == INVALID_HANDLE_VALUE)
2680 code = -1;
2681 }
2682
2683 /* Set up members of STARTUPINFO structure. */
2684 siStartInfo.cb = sizeof(STARTUPINFO);
2685 siStartInfo.lpReserved = NULL;
2686 siStartInfo.lpDesktop = NULL;
2687 siStartInfo.lpTitle = NULL; /* use executable name as title */
2688 /* next two lines ignored */
2689 siStartInfo.dwX = siStartInfo.dwY = (DWORD)CW_USEDEFAULT;
2690 siStartInfo.dwXSize = siStartInfo.dwYSize = (DWORD)CW_USEDEFAULT;
2691 siStartInfo.dwXCountChars = 80;
2692 siStartInfo.dwYCountChars = 25;
2693 siStartInfo.dwFillAttribute = 0; /* ignored */
2694 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
2695 siStartInfo.wShowWindow = SW_SHOWNORMAL; /* ignored */
2696 siStartInfo.cbReserved2 = 0;
2697 siStartInfo.lpReserved2 = NULL;
2698 siStartInfo.hStdInput = hChildStdinRd;
2699 siStartInfo.hStdOutput = hChildStdoutWr;
2700 siStartInfo.hStdError = hChildStderrWr;
2701 memset(&piProcInfo, 0, sizeof(piProcInfo));
2702
2703 if ((code == 0) && !CreateProcess(NULL,
2704 command,
2705 NULL, /* process security attributes */
2706 NULL, /* primary thread security attributes */
2707 TRUE, /* handles are inherited */
2708 0, /* creation flags */
2709 NULL, /* environment */
2710 NULL, /* use parent's current directory */
2711 &siStartInfo, /* STARTUPINFO pointer */
2712 &piProcInfo)) { /* receives PROCESS_INFORMATION */
2713 code = -1;
2714 }
2715
2716 /* close our copy of the handles */
2717 if (hChildStdinRd != INVALID_HANDLE_VALUE)
2718 CloseHandle(hChildStdinRd);
2719 if (hChildStdoutWr != INVALID_HANDLE_VALUE)
2720 CloseHandle(hChildStdoutWr);
2721 if (hChildStderrWr != INVALID_HANDLE_VALUE)
2722 CloseHandle(hChildStderrWr);
2723
2724 if (code == 0) {
2725 /* wait for process to finish */
2726 WaitForSingleObject(piProcInfo.hProcess, 300000);
2727 GetExitCodeProcess(piProcInfo.hProcess, &exitcode);
2728 CloseHandle(piProcInfo.hProcess);
2729 CloseHandle(piProcInfo.hThread);
2730 }
2731
2732 if (code)
2733 return code;
2734 return (int)exitcode;
2735 }
2736 #endif
2737
2738 #if defined(UNIX)
2739 int
2740 exec_program(LPTSTR command,
2741 int hstdin, int hstdout, int hstderr,
2742 LPCTSTR stdin_name, LPCTSTR stdout_name, LPCTSTR stderr_name)
2743 {
2744 int code = 0;
2745 int hChildStdinRd = -1;
2746 int hChildStdoutWr = -1;
2747 int hChildStderrWr = -1;
2748 int handle;
2749 pid_t pid;
2750 int exitcode;
2751 #define MAXARG 64
2752 char *argv[MAXARG+1];
2753 int argc = 0;
2754 char *args, *d, *e, *p;
2755
2756 /* Parse command line handling quotes. */
2757 memset(argv, 0, sizeof(argv));
2758 argc = 0;
2759 args = (char *)malloc(strlen(command)+1);
2760 if (args == (char *)NULL)
2761 return -1;
2762 p = command;
2763 d = args;
2764 while (*p) {
2765 /* for each argument */
2766 if (argc >= MAXARG - 1) {
2767 fprintf(stderr, "Too many arguments\n");
2768 free(args);
2769 return -1;
2770 }
2771
2772 e = d;
2773 while ((*p) && (*p != ' ')) {
2774 if (*p == '\042') {
2775 /* Remove quotes, skipping over embedded spaces. */
2776 /* Doesn't handle embedded quotes. */
2777 p++;
2778 while ((*p) && (*p != '\042'))
2779 *d++ =*p++;
2780 }
2781 else
2782 *d++ = *p;
2783 if (*p)
2784 p++;
2785 }
2786 *d++ = '\0';
2787 argv[argc++] = e;
2788
2789 while ((*p) && (*p == ' '))
2790 p++; /* Skip over trailing spaces */
2791 }
2792 argv[argc] = NULL;
2793
2794 pid = fork();
2795 if (pid == (pid_t)-1) {
2796 /* fork failed */
2797 fprintf(stderr, "Failed to fork, error=%d\n", errno);
2798 return -1;
2799 }
2800 else if (pid == 0) {
2801 /* child */
2802 /* if handles are provided, use them */
2803 if ((code == 0) && (hstdin != -1)) {
2804 hChildStdinRd = dup2(hstdin, 0);
2805 if (hChildStdinRd == -1)
2806 code = -1;
2807 }
2808 if ((code==0) && (hstdout != -1)) {
2809 hChildStdoutWr = dup2(hstdout, 1);
2810 if (hChildStdoutWr == -1)
2811 code = -1;
2812 }
2813 if ((code==0) && (hstderr != -1)) {
2814 hChildStderrWr = dup2(hstderr, 2);
2815 if (hChildStderrWr == -1)
2816 code = -1;
2817 }
2818 if ((code==0) && stdin_name && (hChildStdinRd == -1)) {
2819 handle = open(stdin_name, O_RDONLY);
2820 hChildStdinRd = dup2(handle, 0);
2821 if (handle != -1)
2822 close(handle);
2823 if (hChildStdinRd == -1)
2824 code = -1;
2825 }
2826 if ((code==0) && stdout_name && (hChildStdoutWr == -1)) {
2827 handle = open(stdout_name, O_WRONLY | O_CREAT);
2828 hChildStdoutWr = dup2(handle, 1);
2829 if (handle != -1)
2830 close(handle);
2831 if (hChildStdoutWr == -1)
2832 code = -1;
2833 }
2834 if ((code==0) && stderr_name && (hChildStderrWr == -1)) {
2835 handle = open(stderr_name, O_WRONLY | O_CREAT);
2836 hChildStderrWr = dup2(handle, 2);
2837 if (handle != -1)
2838 close(handle);
2839 if (hChildStderrWr == -1)
2840 code = -1;
2841 }
2842
2843 if (code) {
2844 fprintf(stderr, "Failed to open stdin/out/err, error=%d\n", errno);
2845 if (hChildStdinRd)
2846 close(hChildStdinRd);
2847 if (hChildStdoutWr)
2848 close(hChildStdoutWr);
2849 if (hChildStderrWr)
2850 close(hChildStderrWr);
2851 exit(1);
2852 }
2853
2854 /* Now execute it */
2855 if (execvp(argv[0], argv) == -1) {
2856 fprintf(stderr, "Failed to execute ghostscript, error=%d\n", errno);
2857 exit(1);
2858 }
2859 }
2860
2861 /* parent - wait for child to finish */
2862 free(args);
2863 wait(&exitcode);
2864 return exitcode;
2865 }
2866 #endif
2867
2868 /*
2869 * If hstdin not -1, duplicate handle and give to program,
2870 * else if stdin_name not NULL, open filename and give to program.
2871 * Same for hstdout/stdout_name and hstderr/stderr_name.
2872 */
2873 #ifdef OS2
2874 int
2875 exec_program(LPTSTR command,
2876 int hstdin, int hstdout, int hstderr,
2877 LPCTSTR stdin_name, LPCTSTR stdout_name, LPCTSTR stderr_name)
2878 {
2879 HFILE hStdin = 0;
2880 HFILE hStdout = 1;
2881 HFILE hStderr = 2;
2882 HFILE hOldStdin;
2883 HFILE hOldStdout;
2884 HFILE hOldStderr;
2885 HFILE hNewStdin = -1;
2886 HFILE hNewStdout = -1;
2887 HFILE hNewStderr = -1;
2888 APIRET rc = 0;
2889 ULONG action;
2890 CHAR szFailName[CCHMAXPATH];
2891 RESULTCODES resc;
2892 PSZ cmd;
2893 PSZ args;
2894 int cmdlen;
2895
2896 /* Copy command into format needed by DosExecPgm */
2897 cmdlen = strlen(command)+1;
2898 cmd = (char *)malloc(cmdlen+1);
2899 if (cmd) {
2900 char *p;
2901 memset(cmd, 0, cmdlen+1);
2902 strncpy(cmd, command, cmdlen);
2903 p = args = cmd;
2904 if (*p == '"') {
2905 p++;
2906 args = p;
2907 while (*p && (*p != '"'))
2908 p++;
2909 }
2910 else {
2911 while (*p && (*p != 0))
2912 p++;
2913 }
2914 *p = '\0';
2915 }
2916 else
2917 return -1;
2918
2919 /* save existing stdio handles */
2920 hOldStdin = 0xffffffff; /* allocate new handle */
2921 if (rc == 0)
2922 rc = DosDupHandle(hStdin, &hOldStdin);
2923 hOldStdout = 0xffffffff; /* allocate new handle */
2924 if (rc == 0)
2925 rc = DosDupHandle(hStdout, &hOldStdout);
2926 hOldStderr = 0xffffffff; /* allocate new handle */
2927 if (rc == 0)
2928 rc = DosDupHandle(hStderr, &hOldStderr);
2929 if (rc != 0) {
2930 free(cmd);
2931 return -1;
2932 }
2933
2934 /* if handles or files are provided, use them */
2935 if ((hstdin != -1)) {
2936 if (rc == 0)
2937 DosDupHandle((HFILE)hstdin, &hStdin);
2938 }
2939 else if ((rc == 0) && stdin_name) {
2940 rc = DosOpen((PCSZ)stdin_name, /* filename */
2941 &hNewStdin, /* pointer to handle */
2942 &action, /* pointer to result */
2943 0, /* initial length */
2944 FILE_NORMAL, /* normal file */
2945 OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
2946 OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE,
2947 0);
2948 if (rc == 0)
2949 rc= DosDupHandle(hNewStdin, &hStdin);
2950 }
2951
2952 if ((hstdout != -1)) {
2953 if (rc == 0)
2954 DosDupHandle((HFILE)hstdout, &hStdout);
2955 }
2956 else if ((rc == 0) && stdout_name) {
2957 rc = DosOpen((PCSZ)stdout_name, /* filename */
2958 &hNewStdout, /* pointer to handle */
2959 &action, /* pointer to result */
2960 0, /* initial length */
2961 FILE_NORMAL, /* normal file */
2962 OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS,
2963 OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE,
2964 0);
2965 if (rc == 0)
2966 rc= DosDupHandle(hNewStdout, &hStdout);
2967 }
2968 if ((hstderr != -1)) {
2969 if (rc == 0)
2970 DosDupHandle((HFILE)hstderr, &hStderr);
2971 }
2972 else if ((rc == 0) && stderr_name) {
2973 rc = DosOpen((PCSZ)stderr_name, /* filename */
2974 &hNewStderr, /* pointer to handle */
2975 &action, /* pointer to result */
2976 0, /* initial length */
2977 FILE_NORMAL, /* normal file */
2978 OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS,
2979 OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE,
2980 0);
2981 if (rc == 0)
2982 rc= DosDupHandle(hNewStderr, &hStderr);
2983 }
2984 if (rc != 0) {
2985 free(cmd);
2986 return -1;
2987 }
2988
2989 rc = DosExecPgm(szFailName, sizeof(szFailName),
2990 EXEC_SYNC, args, (PSZ)NULL, &resc, args);
2991
2992 /* Put stdio back to original handles */
2993 DosDupHandle(hOldStdin, &hStdin);
2994 DosDupHandle(hOldStdout, &hStdout);
2995 DosDupHandle(hOldStderr, &hStderr);
2996 DosClose(hOldStdin);
2997 DosClose(hOldStdout);
2998 DosClose(hOldStderr);
2999 if (hNewStdin != -1)
3000 DosClose(hNewStdin);
3001 if (hNewStdout != -1)
3002 DosClose(hNewStdout);
3003 if (hNewStderr != -1)
3004 DosClose(hNewStderr);
3005
3006 if (rc)
3007 return -1;
3008 return (int)resc.codeResult;
3009 }
3010 #endif