Rename HID_DRAW_API to just HID_DRAW
[geda-pcb/pcjc2.git] / src / hid / ps / ps.c
blobf40c66de2b94e64b8cc92d232f4d36c3071d3473
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
5 #include <stdio.h>
6 #include <stdarg.h> /* not used */
7 #include <stdlib.h>
8 #include <string.h>
9 #include <assert.h> /* not used */
10 #include <time.h>
12 #include "global.h"
13 #include "data.h"
14 #include "misc.h"
15 #include "error.h"
16 #include "draw.h"
17 #include "pcb-printf.h"
19 #include "hid.h"
20 #include "../hidint.h"
21 #include "hid/common/hidnogui.h"
22 #include "hid/common/draw_helpers.h"
23 #include "../ps/ps.h"
24 #include "../../print.h"
25 #include "hid/common/hidinit.h"
27 #ifdef HAVE_LIBDMALLOC
28 #include <dmalloc.h>
29 #endif
31 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented PS function %s.\n", __FUNCTION__); abort()
33 static int ps_set_layer (const char *name, int group, int empty);
34 static void use_gc (hidGC gc);
36 typedef struct hid_gc_struct
38 HID *me_pointer;
39 EndCapStyle cap;
40 Coord width;
41 unsigned char r, g, b;
42 int erase;
43 int faded;
44 } hid_gc_struct;
46 static const char *medias[] = {
47 "A0", "A1", "A2", "A3", "A4", "A5",
48 "A6", "A7", "A8", "A9", "A10",
49 "B0", "B1", "B2", "B3", "B4", "B5",
50 "B6", "B7", "B8", "B9", "B10",
51 "Letter", "11x17", "Ledger",
52 "Legal", "Executive",
53 "A-Size", "B-size",
54 "C-Size", "D-size", "E-size",
55 "US-Business_Card", "Intl-Business_Card",
59 typedef struct
61 char *name;
62 Coord Width, Height;
63 Coord MarginX, MarginY;
64 } MediaType;
67 * Metric ISO sizes in mm. See http://en.wikipedia.org/wiki/ISO_paper_sizes
69 * A0 841 x 1189
70 * A1 594 x 841
71 * A2 420 x 594
72 * A3 297 x 420
73 * A4 210 x 297
74 * A5 148 x 210
75 * A6 105 x 148
76 * A7 74 x 105
77 * A8 52 x 74
78 * A9 37 x 52
79 * A10 26 x 37
81 * B0 1000 x 1414
82 * B1 707 x 1000
83 * B2 500 x 707
84 * B3 353 x 500
85 * B4 250 x 353
86 * B5 176 x 250
87 * B6 125 x 176
88 * B7 88 x 125
89 * B8 62 x 88
90 * B9 44 x 62
91 * B10 31 x 44
93 * awk '{printf(" {\"%s\", %d, %d, MARGINX, MARGINY},\n", $2, $3*100000/25.4, $5*100000/25.4)}'
95 * See http://en.wikipedia.org/wiki/Paper_size#Loose_sizes for some of the other sizes. The
96 * {A,B,C,D,E}-Size here are the ANSI sizes and not the architectural sizes.
99 #define MARGINX MIL_TO_COORD(500)
100 #define MARGINY MIL_TO_COORD(500)
102 static MediaType media_data[] = {
103 {"A0", MM_TO_COORD(841), MM_TO_COORD(1189), MARGINX, MARGINY},
104 {"A1", MM_TO_COORD(594), MM_TO_COORD(841), MARGINX, MARGINY},
105 {"A2", MM_TO_COORD(420), MM_TO_COORD(594), MARGINX, MARGINY},
106 {"A3", MM_TO_COORD(297), MM_TO_COORD(420), MARGINX, MARGINY},
107 {"A4", MM_TO_COORD(210), MM_TO_COORD(297), MARGINX, MARGINY},
108 {"A5", MM_TO_COORD(148), MM_TO_COORD(210), MARGINX, MARGINY},
109 {"A6", MM_TO_COORD(105), MM_TO_COORD(148), MARGINX, MARGINY},
110 {"A7", MM_TO_COORD(74), MM_TO_COORD(105), MARGINX, MARGINY},
111 {"A8", MM_TO_COORD(52), MM_TO_COORD(74), MARGINX, MARGINY},
112 {"A9", MM_TO_COORD(37), MM_TO_COORD(52), MARGINX, MARGINY},
113 {"A10", MM_TO_COORD(26), MM_TO_COORD(37), MARGINX, MARGINY},
114 {"B0", MM_TO_COORD(1000), MM_TO_COORD(1414), MARGINX, MARGINY},
115 {"B1", MM_TO_COORD(707), MM_TO_COORD(1000), MARGINX, MARGINY},
116 {"B2", MM_TO_COORD(500), MM_TO_COORD(707), MARGINX, MARGINY},
117 {"B3", MM_TO_COORD(353), MM_TO_COORD(500), MARGINX, MARGINY},
118 {"B4", MM_TO_COORD(250), MM_TO_COORD(353), MARGINX, MARGINY},
119 {"B5", MM_TO_COORD(176), MM_TO_COORD(250), MARGINX, MARGINY},
120 {"B6", MM_TO_COORD(125), MM_TO_COORD(176), MARGINX, MARGINY},
121 {"B7", MM_TO_COORD(88), MM_TO_COORD(125), MARGINX, MARGINY},
122 {"B8", MM_TO_COORD(62), MM_TO_COORD(88), MARGINX, MARGINY},
123 {"B9", MM_TO_COORD(44), MM_TO_COORD(62), MARGINX, MARGINY},
124 {"B10", MM_TO_COORD(31), MM_TO_COORD(44), MARGINX, MARGINY},
125 {"Letter", INCH_TO_COORD(8.5), INCH_TO_COORD(11), MARGINX, MARGINY},
126 {"11x17", INCH_TO_COORD(11), INCH_TO_COORD(17), MARGINX, MARGINY},
127 {"Ledger", INCH_TO_COORD(17), INCH_TO_COORD(11), MARGINX, MARGINY},
128 {"Legal", INCH_TO_COORD(8.5), INCH_TO_COORD(14), MARGINX, MARGINY},
129 {"Executive", INCH_TO_COORD(7.5), INCH_TO_COORD(10), MARGINX, MARGINY},
130 {"A-size", INCH_TO_COORD(8.5), INCH_TO_COORD(11), MARGINX, MARGINY},
131 {"B-size", INCH_TO_COORD(11), INCH_TO_COORD(17), MARGINX, MARGINY},
132 {"C-size", INCH_TO_COORD(17), INCH_TO_COORD(22), MARGINX, MARGINY},
133 {"D-size", INCH_TO_COORD(22), INCH_TO_COORD(34), MARGINX, MARGINY},
134 {"E-size", INCH_TO_COORD(34), INCH_TO_COORD(44), MARGINX, MARGINY},
135 {"US-Business_Card", INCH_TO_COORD(3.5), INCH_TO_COORD(2.0), 0, 0},
136 {"Intl-Business_Card", INCH_TO_COORD(3.375), INCH_TO_COORD(2.125), 0, 0}
139 #undef MARGINX
140 #undef MARGINY
142 HID_Attribute ps_attribute_list[] = {
143 /* other HIDs expect this to be first. */
145 /* %start-doc options "91 Postscript Export"
146 @ftable @code
147 @item --psfile <string>
148 Name of the postscript output file. Can contain a path.
149 @end ftable
150 %end-doc
152 {"psfile", "Postscript output file",
153 HID_String, 0, 0, {0, 0, 0}, 0, 0},
154 #define HA_psfile 0
156 /* %start-doc options "91 Postscript Export"
157 @ftable @code
158 @cindex drill-helper
159 @item --drill-helper
160 Print a centering target in large drill holes.
161 @end ftable
162 %end-doc
164 {"drill-helper", "Print a centering target in large drill holes",
165 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
166 #define HA_drillhelper 1
168 /* %start-doc options "91 Postscript Export"
169 @ftable @code
170 @cindex align-marks
171 @item --align-marks
172 Print alignment marks on each sheet. This is meant to ease alignment during exposure.
173 @end ftable
174 %end-doc
176 {"align-marks", "Print alignment marks on each sheet",
177 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0},
178 #define HA_alignmarks 2
180 /* %start-doc options "91 Postscript Export"
181 @ftable @code
182 @item --outline
183 Print the contents of the outline layer on each sheet.
184 @end ftable
185 %end-doc
187 {"outline", "Print outline on each sheet",
188 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0},
189 #define HA_outline 3
190 /* %start-doc options "91 Postscript Export"
191 @ftable @code
192 @item --mirror
193 Print mirror image.
194 @end ftable
195 %end-doc
197 {"mirror", "Print mirror image of every page",
198 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
199 #define HA_mirror 4
201 /* %start-doc options "91 Postscript Export"
202 @ftable @code
203 @item --fill-page
204 Scale output to make the board fit the page.
205 @end ftable
206 %end-doc
208 {"fill-page", "Scale board to fill page",
209 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
210 #define HA_fillpage 5
212 /* %start-doc options "91 Postscript Export"
213 @ftable @code
214 @item --auto-mirror
215 Print mirror image of appropriate layers.
216 @end ftable
217 %end-doc
219 {"auto-mirror", "Print mirror image of appropriate layers",
220 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0},
221 #define HA_automirror 6
223 /* %start-doc options "91 Postscript Export"
224 @ftable @code
225 @item --ps-color
226 Postscript output in color.
227 @end ftable
228 %end-doc
230 {"ps-color", "Prints in color",
231 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
232 #define HA_color 7
234 /* %start-doc options "91 Postscript Export"
235 @ftable @code
236 @cindex ps-bloat
237 @item --ps-bloat <num>
238 Amount to add to trace/pad/pin edges.
239 @end ftable
240 %end-doc
242 {"ps-bloat", "Amount to add to trace/pad/pin edges",
243 HID_Coord, -MIL_TO_COORD (100), MIL_TO_COORD (100), {0, 0, 0}, 0, 0},
244 #define HA_psbloat 8
246 /* %start-doc options "91 Postscript Export"
247 @ftable @code
248 @cindex ps-invert
249 @item --ps-invert
250 Draw objects as white-on-black.
251 @end ftable
252 %end-doc
254 {"ps-invert", "Draw objects as white-on-black",
255 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
256 #define HA_psinvert 9
258 /* %start-doc options "91 Postscript Export"
259 @ftable @code
260 @item --media <media-name>
261 Size of the media, the postscript is fitted to. The parameter
262 @code{<media-name>} can be any of the standard names for paper size: @samp{A0}
263 to @samp{A10}, @samp{B0} to @samp{B10}, @samp{Letter}, @samp{11x17},
264 @samp{Ledger}, @samp{Legal}, @samp{Executive}, @samp{A-Size}, @samp{B-size},
265 @samp{C-Size}, @samp{D-size}, @samp{E-size}, @samp{US-Business_Card},
266 @samp{Intl-Business_Card}.
267 @end ftable
268 %end-doc
270 {"media", "media type",
271 HID_Enum, 0, 0, {22, 0, 0}, medias, 0},
272 #define HA_media 10
274 /* %start-doc options "91 Postscript Export"
275 @ftable @code
276 @cindex psfade
277 @item --psfade <num>
278 Fade amount for assembly drawings (0.0=missing, 1.0=solid).
279 @end ftable
280 %end-doc
282 {"psfade", "Fade amount for assembly drawings (0.0=missing, 1.0=solid)",
283 HID_Real, 0, 1, {0, 0, 0.40}, 0, 0},
284 #define HA_psfade 11
286 /* %start-doc options "91 Postscript Export"
287 @ftable @code
288 @item --scale <num>
289 Scale value to compensate for printer sizing errors (1.0 = full scale).
290 @end ftable
291 %end-doc
293 {"scale", "Scale value to compensate for printer sizing errors (1.0 = full scale)",
294 HID_Real, 0.01, 4, {0, 0, 1.00}, 0, 0},
295 #define HA_scale 12
297 /* %start-doc options "91 Postscript Export"
298 @ftable @code
299 @cindex multi-file
300 @item --multi-file
301 Produce multiple files, one per page, instead of a single multi page file.
302 @end ftable
303 %end-doc
305 {"multi-file", "Produce multiple files, one per page, instead of a single file",
306 HID_Boolean, 0, 0, {0, 0, 0.40}, 0, 0},
307 #define HA_multifile 13
309 /* %start-doc options "91 Postscript Export"
310 @ftable @code
311 @item --xcalib <num>
312 Paper width. Used for x-Axis calibration.
313 @end ftable
314 %end-doc
316 {"xcalib", "Paper width. Used for x-Axis calibration",
317 HID_Real, 0, 0, {0, 0, 1.0}, 0, 0},
318 #define HA_xcalib 14
320 /* %start-doc options "91 Postscript Export"
321 @ftable @code
322 @item --ycalib <num>
323 Paper height. Used for y-Axis calibration.
324 @end ftable
325 %end-doc
327 {"ycalib", "Paper height. Used for y-Axis calibration",
328 HID_Real, 0, 0, {0, 0, 1.0}, 0, 0},
329 #define HA_ycalib 15
331 /* %start-doc options "91 Postscript Export"
332 @ftable @code
333 @item --drill-copper
334 Draw drill holes in pins / vias, instead of leaving solid copper.
335 @end ftable
336 %end-doc
338 {"drill-copper", "Draw drill holes in pins / vias, instead of leaving solid copper",
339 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0},
340 #define HA_drillcopper 16
342 /* %start-doc options "91 Postscript Export"
343 @ftable @code
344 @cindex show-legend
345 @item --show-legend
346 Print file name and scale on printout.
347 @end ftable
348 %end-doc
350 {"show-legend", "Print file name and scale on printout",
351 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0},
352 #define HA_legend 17
355 #define NUM_OPTIONS (sizeof(ps_attribute_list)/sizeof(ps_attribute_list[0]))
357 REGISTER_ATTRIBUTES (ps_attribute_list)
359 /* All file-scope data is in global struct */
360 static struct {
361 double calibration_x, calibration_y;
363 FILE *f;
364 int pagecount;
365 Coord linewidth;
366 bool print_group[MAX_LAYER];
367 bool print_layer[MAX_LAYER];
368 double fade_ratio;
369 bool multi_file;
370 Coord media_width, media_height, ps_width, ps_height;
372 const char *filename;
373 bool drill_helper;
374 bool align_marks;
375 bool outline;
376 bool mirror;
377 bool fillpage;
378 bool automirror;
379 bool incolor;
380 bool doing_toc;
381 Coord bloat;
382 bool invert;
383 int media_idx;
384 bool drillcopper;
385 bool legend;
387 LayerType *outline_layer;
389 double scale_factor;
391 BoxType region;
393 HID_Attr_Val ps_values[NUM_OPTIONS];
395 bool is_mask;
396 bool is_drill;
397 bool is_assy;
398 bool is_copper;
399 bool is_paste;
400 } global;
402 static HID_Attribute *
403 ps_get_export_options (int *n)
405 static char *last_made_filename = 0;
406 if (PCB)
407 derive_default_filename(PCB->Filename, &ps_attribute_list[HA_psfile], ".ps", &last_made_filename);
409 if (n)
410 *n = NUM_OPTIONS;
411 return ps_attribute_list;
414 static int
415 group_for_layer (int l)
417 if (l < max_copper_layer + 2 && l >= 0)
418 return GetLayerGroupNumberByNumber (l);
419 /* else something unique */
420 return max_group + 3 + l;
423 static int
424 layer_sort (const void *va, const void *vb)
426 int a = *(int *) va;
427 int b = *(int *) vb;
428 int d = group_for_layer (b) - group_for_layer (a);
429 if (d)
430 return d;
431 return b - a;
434 void
435 ps_start_file (FILE *f)
437 time_t currenttime = time( NULL );
439 fprintf (f, "%%!PS-Adobe-3.0\n");
441 /* Document Structuring Conventions (DCS): */
443 /* Start General Header Comments: */
446 * %%Title DCS provides text title for the document that is useful
447 * for printing banner pages.
449 fprintf (f, "%%%%Title: %s\n", PCB->Filename);
452 * %%CreationDate DCS indicates the date and time the document was
453 * created. Neither the date nor time need be in any standard
454 * format. This comment is meant to be used purely for informational
455 * purposes, such as printing on banner pages.
457 fprintf (f, "%%%%CreationDate: %s", asctime (localtime (&currenttime)));
460 * %%Creator DCS indicates the document creator, usually the name of
461 * the document composition software.
463 fprintf (f, "%%%%Creator: PCB release: %s " VERSION "\n", Progname);
466 * %%Version DCS comment can be used to note the version and
467 * revision number of a document or resource. A document manager may
468 * wish to provide version control services, or allow substitution
469 * of compatible versions/revisions of a resource or document.
471 * The format should be in the form of 'procname':
472 * <procname>::= < name> < version> < revision>
473 * < name> ::= < text>
474 * < version> ::= < real>
475 * < revision> ::= < uint>
477 * If a version numbering scheme is not used, these fields should
478 * still be filled with a dummy value of 0.
480 * There is currently no code in PCB to manage this revision number.
483 fprintf (f, "%%%%Version: (PCB %s " VERSION ") 0.0 0\n", Progname );
487 * %%PageOrder DCS is intended to help document managers determine
488 * the order of pages in the document file, which in turn enables a
489 * document manager optionally to reorder the pages. 'Ascend'-The
490 * pages are in ascending order for example, 1-2-3-4-5-6.
492 fprintf (f, "%%%%PageOrder: Ascend\n" );
495 * %%Pages: < numpages> | (atend) < numpages> ::= < uint> (Total
496 * %%number of pages)
498 * %%Pages DCS defines the number of virtual pages that a document
499 * will image. (atend) defers the count until the end of the file,
500 * which is useful for dynamically generated contents.
502 fprintf (f, "%%%%Pages: (atend)\n" );
505 * %%DocumentMedia: <name> <width> <height> <weight> <color> <type>
507 * Substitute 0 or "" for N/A. Width and height are in points
508 * (1/72").
510 * Media sizes are in PCB units
512 pcb_fprintf (f, "%%%%DocumentMedia: %s %mi %mi 0 \"\" \"\"\n",
513 media_data[global.media_idx].name,
514 72 * media_data[global.media_idx].Width,
515 72 * media_data[global.media_idx].Height);
516 pcb_fprintf (f, "%%%%DocumentPaperSizes: %s\n", media_data[global.media_idx].name);
518 /* End General Header Comments. */
520 /* General Body Comments go here. Currently there are none. */
523 * %%EndComments DCS indicates an explicit end to the header
524 * comments of the document. All global DCS's must preceded
525 * this. A blank line gives an implicit end to the comments.
527 fprintf (f, "%%%%EndComments\n\n" );
530 static void
531 ps_end_file (FILE *f)
534 * %%Trailer DCS must only occur once at the end of the document
535 * script. Any post-processing or cleanup should be contained in
536 * the trailer of the document, which is anything that follows the
537 * %%Trailer comment. Any of the document level structure comments
538 * that were deferred by using the (atend) convention must be
539 * mentioned in the trailer of the document after the %%Trailer
540 * comment.
542 fprintf (f, "%%%%Trailer\n" );
545 * %%Pages was deferred until the end of the document via the
546 * (atend) mentioned, in the General Header section.
548 fprintf (f, "%%%%Pages: %d\n", global.pagecount);
551 * %%EOF DCS signifies the end of the document. When the document
552 * manager sees this comment, it issues an end-of-file signal to the
553 * PostScript interpreter. This is done so system-dependent file
554 * endings, such as Control-D and end-of-file packets, do not
555 * confuse the PostScript interpreter.
557 fprintf (f, "%%%%EOF\n" );
560 static FILE *
561 psopen (const char *base, const char *which)
563 FILE *ps_open_file;
564 char *buf, *suff, *buf2;
566 if (!global.multi_file)
567 return fopen (base, "w");
569 buf = (char *)malloc (strlen (base) + strlen (which) + 5);
571 suff = (char *)strrchr (base, '.');
572 if (suff)
574 strcpy (buf, base);
575 buf2 = strrchr (buf, '.');
576 sprintf(buf2, ".%s.%s", which, suff+1);
578 else
580 sprintf(buf, "%s.%s.ps", base, which);
582 printf("PS: open %s\n", buf);
583 ps_open_file = fopen(buf, "w");
584 free (buf);
585 return ps_open_file;
588 /* This is used by other HIDs that use a postscript format, like lpr
589 or eps. */
590 void
591 ps_hid_export_to_file (FILE * the_file, HID_Attr_Val * options)
593 int i;
594 static int saved_layer_stack[MAX_LAYER];
595 FlagType save_thindraw;
597 save_thindraw = PCB->Flags;
598 CLEAR_FLAG(THINDRAWFLAG, PCB);
599 CLEAR_FLAG(THINDRAWPOLYFLAG, PCB);
600 CLEAR_FLAG(CHECKPLANESFLAG, PCB);
602 global.f = the_file;
603 global.drill_helper = options[HA_drillhelper].int_value;
604 global.align_marks = options[HA_alignmarks].int_value;
605 global.outline = options[HA_outline].int_value;
606 global.mirror = options[HA_mirror].int_value;
607 global.fillpage = options[HA_fillpage].int_value;
608 global.automirror = options[HA_automirror].int_value;
609 global.incolor = options[HA_color].int_value;
610 global.bloat = options[HA_psbloat].coord_value;
611 global.invert = options[HA_psinvert].int_value;
612 global.fade_ratio = CLAMP (options[HA_psfade].real_value, 0, 1);
613 global.media_idx = options[HA_media].int_value;
614 global.media_width = media_data[global.media_idx].Width;
615 global.media_height = media_data[global.media_idx].Height;
616 global.ps_width = global.media_width
617 - 2.0 * media_data[global.media_idx].MarginX;
618 global.ps_height = global.media_height
619 - 2.0 * media_data[global.media_idx].MarginY;
620 global.scale_factor = options[HA_scale].real_value;
621 global.calibration_x = options[HA_xcalib].real_value;
622 global.calibration_y = options[HA_ycalib].real_value;
623 global.drillcopper = options[HA_drillcopper].int_value;
624 global.legend = options[HA_legend].int_value;
626 if (the_file)
627 ps_start_file (the_file);
629 if (global.fillpage)
631 double zx, zy;
632 if (PCB->MaxWidth > PCB->MaxHeight)
634 zx = global.ps_height / PCB->MaxWidth;
635 zy = global.ps_width / PCB->MaxHeight;
637 else
639 zx = global.ps_height / PCB->MaxHeight;
640 zy = global.ps_width / PCB->MaxWidth;
642 global.scale_factor *= MIN (zx, zy);
645 memset (global.print_group, 0, sizeof (global.print_group));
646 memset (global.print_layer, 0, sizeof (global.print_layer));
648 global.outline_layer = NULL;
650 for (i = 0; i < max_copper_layer; i++)
652 LayerType *layer = PCB->Data->Layer + i;
653 if (layer->LineN || layer->TextN || layer->ArcN || layer->PolygonN)
654 global.print_group[GetLayerGroupNumberByNumber (i)] = 1;
656 if (strcmp (layer->Name, "outline") == 0 ||
657 strcmp (layer->Name, "route") == 0)
659 global.outline_layer = layer;
662 global.print_group[GetLayerGroupNumberByNumber (solder_silk_layer)] = 1;
663 global.print_group[GetLayerGroupNumberByNumber (component_silk_layer)] = 1;
664 for (i = 0; i < max_copper_layer; i++)
665 if (global.print_group[GetLayerGroupNumberByNumber (i)])
666 global.print_layer[i] = 1;
668 memcpy (saved_layer_stack, LayerStack, sizeof (LayerStack));
669 qsort (LayerStack, max_copper_layer, sizeof (LayerStack[0]), layer_sort);
671 global.linewidth = -1;
672 /* reset static vars */
673 ps_set_layer (NULL, 0, -1);
674 use_gc (NULL);
676 global.region.X1 = 0;
677 global.region.Y1 = 0;
678 global.region.X2 = PCB->MaxWidth;
679 global.region.Y2 = PCB->MaxHeight;
681 if (!global.multi_file)
683 /* %%Page DSC requires both a label and an ordinal */
684 fprintf (the_file, "%%%%Page: TableOfContents 1\n");
685 fprintf (the_file, "/Times-Roman findfont 24 scalefont setfont\n");
686 fprintf (the_file, "/rightshow { /s exch def s stringwidth pop -1 mul 0 rmoveto s show } def\n");
687 fprintf (the_file, "/y 72 9 mul def /toc { 100 y moveto show /y y 24 sub def } bind def\n");
688 fprintf (the_file, "/tocp { /y y 12 sub def 90 y moveto rightshow } bind def\n");
690 global.doing_toc = 1;
691 global.pagecount = 1; /* 'pagecount' is modified by hid_expose_callback() call */
692 hid_expose_callback (&ps_hid, &global.region, 0);
695 global.pagecount = 1; /* Reset 'pagecount' if single file */
696 global.doing_toc = 0;
697 ps_set_layer (NULL, 0, -1); /* reset static vars */
698 hid_expose_callback (&ps_hid, &global.region, 0);
700 if (the_file)
701 fprintf (the_file, "showpage\n");
703 memcpy (LayerStack, saved_layer_stack, sizeof (LayerStack));
704 PCB->Flags = save_thindraw;
707 static void
708 ps_do_export (HID_Attr_Val * options)
710 FILE *fh;
711 int save_ons[MAX_LAYER + 2];
712 int i;
714 if (!options)
716 ps_get_export_options (0);
717 for (i = 0; i < NUM_OPTIONS; i++)
718 global.ps_values[i] = ps_attribute_list[i].default_val;
719 options = global.ps_values;
722 global.filename = options[HA_psfile].str_value;
723 if (!global.filename)
724 global.filename = "pcb-out.ps";
726 global.multi_file = options[HA_multifile].int_value;
728 if (global.multi_file)
729 fh = 0;
730 else
732 fh = psopen (global.filename, "toc");
733 if (!fh)
735 perror (global.filename);
736 return;
740 hid_save_and_show_layer_ons (save_ons);
741 ps_hid_export_to_file (fh, options);
742 hid_restore_layer_ons (save_ons);
744 global.multi_file = 0;
745 if (fh)
747 ps_end_file (fh);
748 fclose (fh);
752 static void
753 ps_parse_arguments (int *argc, char ***argv)
755 hid_register_attributes (ps_attribute_list, NUM_OPTIONS);
756 hid_parse_command_line (argc, argv);
759 static void
760 corner (FILE *fh, Coord x, Coord y, int dx, int dy)
762 Coord len = MIL_TO_COORD (2000);
763 Coord len2 = MIL_TO_COORD (200);
764 Coord thick = 0;
766 * Originally 'thick' used thicker lines. Currently is uses
767 * Postscript's "device thin" line - i.e. zero width means one
768 * device pixel. The code remains in case you want to make them
769 * thicker - it needs to offset everything so that the *edge* of the
770 * thick line lines up with the edge of the board, not the *center*
771 * of the thick line.
774 pcb_fprintf (fh, "gsave %mi setlinewidth %mi %mi translate %d %d scale\n",
775 thick * 2, x, y, dx, dy);
776 pcb_fprintf (fh, "%mi %mi moveto %mi %mi %mi 0 90 arc %mi %mi lineto\n",
777 len, thick, thick, thick, len2 + thick, thick, len);
778 if (dx < 0 && dy < 0)
779 pcb_fprintf (fh, "%mi %mi moveto 0 %mi rlineto\n", len2 * 2 + thick, thick, -len2);
780 fprintf (fh, "stroke grestore\n");
783 static int
784 ps_set_layer (const char *name, int group, int empty)
786 static int lastgroup = -1;
787 time_t currenttime;
788 int idx = (group >= 0 && group < max_group)
789 ? PCB->LayerGroups.Entries[group][0]
790 : group;
791 if (name == 0)
792 name = PCB->Data->Layer[idx].Name;
794 if (empty == -1)
795 lastgroup = -1;
796 if (empty)
797 return 0;
799 if (idx >= 0 && idx < max_copper_layer && !global.print_layer[idx])
800 return 0;
802 if (strcmp (name, "invisible") == 0)
803 return 0;
805 global.is_drill = (SL_TYPE (idx) == SL_PDRILL || SL_TYPE (idx) == SL_UDRILL);
806 global.is_mask = (SL_TYPE (idx) == SL_MASK);
807 global.is_assy = (SL_TYPE (idx) == SL_ASSY);
808 global.is_copper = (SL_TYPE (idx) == 0);
809 global.is_paste = (SL_TYPE (idx) == SL_PASTE);
810 #if 0
811 printf ("Layer %s group %d drill %d mask %d\n", name, group, global.is_drill,
812 global.is_mask);
813 #endif
815 if (global.doing_toc)
817 if (group < 0 || group != lastgroup)
819 if (global.pagecount == 1)
821 currenttime = time (NULL);
822 fprintf (global.f, "30 30 moveto (%s) show\n", PCB->Filename);
824 fprintf (global.f, "(%d.) tocp\n", global.pagecount);
825 fprintf (global.f, "(Table of Contents \\(This Page\\)) toc\n" );
827 fprintf (global.f, "(Created on %s) toc\n", asctime (localtime (&currenttime)));
828 fprintf (global.f, "( ) tocp\n" );
831 global.pagecount++;
832 lastgroup = group;
833 fprintf (global.f, "(%d.) tocp\n", global.pagecount);
835 fprintf (global.f, "(%s) toc\n", name);
836 return 0;
839 if (group < 0 || group != lastgroup)
841 double boffset;
842 int mirror_this = 0;
843 lastgroup = group;
845 if (global.pagecount != 0)
847 pcb_fprintf (global.f, "showpage\n");
849 global.pagecount++;
850 if (global.multi_file)
852 if (global.f)
854 ps_end_file (global.f);
855 fclose (global.f);
857 global.f = psopen (global.filename, layer_type_to_file_name (idx, FNS_fixed));
858 if (!global.f)
860 perror (global.filename);
861 return 0;
864 ps_start_file (global.f);
868 * %%Page DSC comment marks the beginning of the PostScript
869 * language instructions that describe a particular
870 * page. %%Page: requires two arguments: a page label and a
871 * sequential page number. The label may be anything, but the
872 * ordinal page number must reflect the position of that page in
873 * the body of the PostScript file and must start with 1, not 0.
875 fprintf (global.f, "%%%%Page: %s %d\n", layer_type_to_file_name(idx, FNS_fixed), global.pagecount);
877 if (global.mirror)
878 mirror_this = !mirror_this;
879 if (global.automirror
881 ((idx >= 0 && group == GetLayerGroupNumberByNumber (solder_silk_layer))
882 || (idx < 0 && SL_SIDE (idx) == SL_BOTTOM_SIDE)))
883 mirror_this = !mirror_this;
885 fprintf (global.f, "/Helvetica findfont 10 scalefont setfont\n");
886 if (global.legend)
888 fprintf (global.f, "30 30 moveto (%s) show\n", PCB->Filename);
889 if (PCB->Name)
890 fprintf (global.f, "30 41 moveto (%s, %s) show\n",
891 PCB->Name, layer_type_to_file_name (idx, FNS_fixed));
892 else
893 fprintf (global.f, "30 41 moveto (%s) show\n",
894 layer_type_to_file_name (idx, FNS_fixed));
895 if (mirror_this)
896 fprintf (global.f, "( \\(mirrored\\)) show\n");
898 if (global.fillpage)
899 fprintf (global.f, "(, not to scale) show\n");
900 else
901 fprintf (global.f, "(, scale = 1:%.3f) show\n", global.scale_factor);
903 fprintf (global.f, "newpath\n");
905 pcb_fprintf (global.f, "72 72 scale %mi %mi translate\n",
906 global.media_width / 2, global.media_height / 2);
908 boffset = global.media_height / 2;
909 if (PCB->MaxWidth > PCB->MaxHeight)
911 fprintf (global.f, "90 rotate\n");
912 boffset = global.media_width / 2;
913 fprintf (global.f, "%g %g scale %% calibration\n", global.calibration_y, global.calibration_x);
915 else
916 fprintf (global.f, "%g %g scale %% calibration\n", global.calibration_x, global.calibration_y);
918 if (mirror_this)
919 fprintf (global.f, "1 -1 scale\n");
921 fprintf (global.f, "%g dup neg scale\n",
922 (SL_TYPE (idx) == SL_FAB) ? 1.0 : global.scale_factor);
923 pcb_fprintf (global.f, "%mi %mi translate\n", -PCB->MaxWidth / 2, -PCB->MaxHeight / 2);
925 /* Keep the drill list from falling off the left edge of the paper,
926 * even if it means some of the board falls off the right edge.
927 * If users don't want to make smaller boards, or use fewer drill
928 * sizes, they can always ignore this sheet. */
929 if (SL_TYPE (idx) == SL_FAB) {
930 Coord natural = boffset - MIL_TO_COORD(500) - PCB->MaxHeight / 2;
931 Coord needed = PrintFab_overhang ();
932 pcb_fprintf (global.f, "%% PrintFab overhang natural %mi, needed %mi\n", natural, needed);
933 if (needed > natural)
934 pcb_fprintf (global.f, "0 %mi translate\n", needed - natural);
937 if (global.invert)
939 fprintf (global.f, "/gray { 1 exch sub setgray } bind def\n");
940 fprintf (global.f,
941 "/rgb { 1 1 3 { pop 1 exch sub 3 1 roll } for setrgbcolor } bind def\n");
943 else
945 fprintf (global.f, "/gray { setgray } bind def\n");
946 fprintf (global.f, "/rgb { setrgbcolor } bind def\n");
949 if ((global.outline && !global.outline_layer) || global.invert)
951 pcb_fprintf (global.f,
952 "0 setgray 0 setlinewidth 0 0 moveto 0 "
953 "%mi lineto %mi %mi lineto %mi 0 lineto closepath %s\n",
954 PCB->MaxHeight, PCB->MaxWidth, PCB->MaxHeight, PCB->MaxWidth,
955 global.invert ? "fill" : "stroke");
958 if (global.align_marks)
960 corner (global.f, 0, 0, -1, -1);
961 corner (global.f, PCB->MaxWidth, 0, 1, -1);
962 corner (global.f, PCB->MaxWidth, PCB->MaxHeight, 1, 1);
963 corner (global.f, 0, PCB->MaxHeight, -1, 1);
966 global.linewidth = -1;
967 use_gc (NULL); /* reset static vars */
969 fprintf (global.f,
970 "/ts 1 def\n"
971 "/ty ts neg def /tx 0 def /Helvetica findfont ts scalefont setfont\n"
972 "/t { moveto lineto stroke } bind def\n"
973 "/dr { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n"
974 " x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath stroke } bind def\n"
975 "/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n"
976 " x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def\n"
977 "/c { 0 360 arc fill } bind def\n"
978 "/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def\n");
979 if (global.drill_helper)
980 pcb_fprintf (global.f,
981 "/dh { gsave %mi setlinewidth 0 gray %mi 0 360 arc stroke grestore} bind def\n",
982 (Coord) MIN_PINORVIAHOLE, (Coord) (MIN_PINORVIAHOLE * 3 / 2));
984 #if 0
985 /* Try to outsmart ps2pdf's heuristics for page rotation, by putting
986 * text on all pages -- even if that text is blank */
987 if (SL_TYPE (idx) != SL_FAB)
988 fprintf (global.f,
989 "gsave tx ty translate 1 -1 scale 0 0 moveto (Layer %s) show grestore newpath /ty ty ts sub def\n",
990 name);
991 else
992 fprintf (global.f, "gsave tx ty translate 1 -1 scale 0 0 moveto ( ) show grestore newpath /ty ty ts sub def\n");
993 #endif
995 /* If we're printing a copper layer other than the outline layer,
996 and we want to "print outlines", and we have an outline layer,
997 print the outline layer on this layer also. */
998 if (global.outline &&
999 global.is_copper &&
1000 global.outline_layer != NULL &&
1001 global.outline_layer != PCB->Data->Layer+idx &&
1002 strcmp (name, "outline") != 0 &&
1003 strcmp (name, "route") != 0
1006 DrawLayer (global.outline_layer, &global.region);
1009 return 1;
1012 static hidGC
1013 ps_make_gc (void)
1015 hidGC rv = (hidGC) calloc (1, sizeof (hid_gc_struct));
1016 rv->me_pointer = &ps_hid;
1017 rv->cap = Trace_Cap;
1018 return rv;
1021 static void
1022 ps_destroy_gc (hidGC gc)
1024 free (gc);
1027 static void
1028 ps_use_mask (enum mask_mode mode)
1030 /* does nothing */
1033 static void
1034 ps_set_color (hidGC gc, const char *name)
1036 if (strcmp (name, "erase") == 0 || strcmp (name, "drill") == 0)
1038 gc->r = gc->g = gc->b = 255;
1039 gc->erase = 1;
1041 else if (global.incolor)
1043 int r, g, b;
1044 sscanf (name + 1, "%02x%02x%02x", &r, &g, &b);
1045 gc->r = r;
1046 gc->g = g;
1047 gc->b = b;
1048 gc->erase = 0;
1050 else
1052 gc->r = gc->g = gc->b = 0;
1053 gc->erase = 0;
1057 static void
1058 ps_set_line_cap (hidGC gc, EndCapStyle style)
1060 gc->cap = style;
1063 static void
1064 ps_set_line_width (hidGC gc, Coord width)
1066 gc->width = width;
1069 static void
1070 ps_set_draw_xor (hidGC gc, int xor_)
1075 static void
1076 ps_set_draw_faded (hidGC gc, int faded)
1078 gc->faded = faded;
1081 static void
1082 use_gc (hidGC gc)
1084 static int lastcap = -1;
1085 static int lastcolor = -1;
1087 if (gc == NULL)
1089 lastcap = lastcolor = -1;
1090 return;
1092 if (gc->me_pointer != &ps_hid)
1094 fprintf (stderr, "Fatal: GC from another HID passed to ps HID\n");
1095 abort ();
1097 if (global.linewidth != gc->width)
1099 pcb_fprintf (global.f, "%mi setlinewidth\n",
1100 gc->width + (gc->erase ? -2 : 2) * global.bloat);
1101 global.linewidth = gc->width;
1103 if (lastcap != gc->cap)
1105 int c;
1106 switch (gc->cap)
1108 case Round_Cap:
1109 case Trace_Cap:
1110 c = 1;
1111 break;
1112 default:
1113 case Square_Cap:
1114 c = 2;
1115 break;
1117 fprintf (global.f, "%d setlinecap %d setlinejoin\n", c, c);
1118 lastcap = gc->cap;
1120 #define CBLEND(gc) (((gc->r)<<24)|((gc->g)<<16)|((gc->b)<<8)|(gc->faded))
1121 if (lastcolor != CBLEND (gc))
1123 if (global.is_drill || global.is_mask)
1125 fprintf (global.f, "%d gray\n", gc->erase ? 0 : 1);
1126 lastcolor = 0;
1128 else
1130 double r, g, b;
1131 r = gc->r;
1132 g = gc->g;
1133 b = gc->b;
1134 if (gc->faded)
1136 r = (1 - global.fade_ratio) * 255 + global.fade_ratio * r;
1137 g = (1 - global.fade_ratio) * 255 + global.fade_ratio * g;
1138 b = (1 - global.fade_ratio) * 255 + global.fade_ratio * b;
1140 if (gc->r == gc->g && gc->g == gc->b)
1141 fprintf (global.f, "%g gray\n", r / 255.0);
1142 else
1143 fprintf (global.f, "%g %g %g rgb\n", r / 255.0, g / 255.0, b / 255.0);
1144 lastcolor = CBLEND (gc);
1149 static void
1150 ps_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
1152 use_gc (gc);
1153 pcb_fprintf (global.f, "%mi %mi %mi %mi dr\n", x1, y1, x2, y2);
1156 static void ps_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2);
1157 static void ps_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius);
1159 static void
1160 ps_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
1162 #if 0
1163 /* If you're etching your own paste mask, this will reduce the
1164 amount of brass you need to etch by drawing outlines for large
1165 pads. See also ps_fill_rect. */
1166 if (is_paste && gc->width > 2500 && gc->cap == Square_Cap
1167 && (x1 == x2 || y1 == y2))
1169 Coord t, w;
1170 if (x1 > x2)
1171 { t = x1; x1 = x2; x2 = t; }
1172 if (y1 > y2)
1173 { t = y1; y1 = y2; y2 = t; }
1174 w = gc->width/2;
1175 ps_fill_rect (gc, x1-w, y1-w, x2+w, y2+w);
1176 return;
1178 #endif
1179 if (x1 == x2 && y1 == y2)
1181 Coord w = gc->width / 2;
1182 if (gc->cap == Square_Cap)
1183 ps_fill_rect (gc, x1 - w, y1 - w, x1 + w, y1 + w);
1184 else
1185 ps_fill_circle (gc, x1, y1, w);
1186 return;
1188 use_gc (gc);
1189 pcb_fprintf (global.f, "%mi %mi %mi %mi t\n", x1, y1, x2, y2);
1192 static void
1193 ps_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height,
1194 Angle start_angle, Angle delta_angle)
1196 Angle sa, ea;
1197 if (delta_angle > 0)
1199 sa = start_angle;
1200 ea = start_angle + delta_angle;
1202 else
1204 sa = start_angle + delta_angle;
1205 ea = start_angle;
1207 #if 0
1208 printf ("draw_arc %d,%d %dx%d %d..%d %d..%d\n",
1209 cx, cy, width, height, start_angle, delta_angle, sa, ea);
1210 #endif
1211 use_gc (gc);
1212 pcb_fprintf (global.f, "%ma %ma %mi %mi %mi %mi %g a\n",
1213 sa, ea, -width, height, cx, cy,
1214 (double) (global.linewidth + 2 * global.bloat) / (double) width);
1217 static void
1218 ps_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius)
1220 use_gc (gc);
1221 if (!gc->erase || !global.is_copper || global.drillcopper)
1223 if (gc->erase && global.is_copper && global.drill_helper
1224 && radius >= PCB->minDrill / 4)
1225 radius = PCB->minDrill / 4;
1226 pcb_fprintf (global.f, "%mi %mi %mi c\n",
1227 cx, cy, radius + (gc->erase ? -1 : 1) * global.bloat);
1231 static void
1232 ps_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y)
1234 int i;
1235 char *op = "moveto";
1236 use_gc (gc);
1237 for (i = 0; i < n_coords; i++)
1239 pcb_fprintf (global.f, "%mi %mi %s\n", x[i], y[i], op);
1240 op = "lineto";
1242 fprintf (global.f, "fill\n");
1245 static void
1246 ps_fill_pcb_polygon (hidGC gc, PolygonType * poly, const BoxType * clip_box)
1248 /* Ignore clip_box, just draw everything */
1250 VNODE *v;
1251 PLINE *pl;
1252 char *op;
1254 use_gc (gc);
1256 pl = poly->Clipped->contours;
1260 v = pl->head.next;
1261 op = "moveto";
1264 pcb_fprintf (global.f, "%mi %mi %s\n", v->point[0], v->point[1], op);
1265 op = "lineto";
1267 while ((v = v->next) != pl->head.next);
1269 while ((pl = pl->next) != NULL);
1271 fprintf (global.f, "fill\n");
1274 static void
1275 ps_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
1277 use_gc (gc);
1278 if (x1 > x2)
1280 Coord t = x1;
1281 x1 = x2;
1282 x2 = t;
1284 if (y1 > y2)
1286 Coord t = y1;
1287 y1 = y2;
1288 y2 = t;
1290 #if 0
1291 /* See comment in ps_draw_line. */
1292 if (is_paste && (x2-x1)>2500 && (y2-y1)>2500)
1294 linewidth = 1000;
1295 lastcap = Round_Cap;
1296 fprintf(f, "1000 setlinewidth 1 setlinecap 1 setlinejoin\n");
1297 fprintf(f, "%d %d moveto %d %d lineto %d %d lineto %d %d lineto closepath stroke\n",
1298 x1+500-bloat, y1+500-bloat,
1299 x1+500-bloat, y2-500+bloat,
1300 x2-500+bloat, y2-500+bloat,
1301 x2-500+bloat, y1+500-bloat);
1302 return;
1304 #endif
1305 pcb_fprintf (global.f, "%mi %mi %mi %mi r\n",
1306 x1 - global.bloat, y1 - global.bloat,
1307 x2 + global.bloat, y2 + global.bloat);
1310 HID_Attribute ps_calib_attribute_list[] = {
1311 {"lprcommand", "Command to print",
1312 HID_String, 0, 0, {0, 0, 0}, 0, 0},
1315 static const char * const calib_lines[] = {
1316 "%!PS-Adobe-3.0\n",
1317 "%%Title: Calibration Page\n",
1318 "%%PageOrder: Ascend\n",
1319 "%%Pages: 1\n",
1320 "%%EndComments\n",
1321 "\n",
1322 "%%Page: Calibrate 1\n",
1323 "72 72 scale\n",
1324 "\n",
1325 "0 setlinewidth\n",
1326 "0.375 0.375 moveto\n",
1327 "8.125 0.375 lineto\n",
1328 "8.125 10.625 lineto\n",
1329 "0.375 10.625 lineto\n",
1330 "closepath stroke\n",
1331 "\n",
1332 "0.5 0.5 translate\n",
1333 "0.001 setlinewidth\n",
1334 "\n",
1335 "/Times-Roman findfont 0.2 scalefont setfont\n",
1336 "\n",
1337 "/sign {\n",
1338 " 0 lt { -1 } { 1 } ifelse\n",
1339 "} def\n",
1340 "\n",
1341 "/cbar {\n",
1342 " /units exch def\n",
1343 " /x exch def\n",
1344 " /y exch def \n",
1345 "\n",
1346 " /x x sign 0.5 mul def\n",
1347 "\n",
1348 " 0 setlinewidth\n",
1349 " newpath x y 0.25 0 180 arc gsave 0.85 setgray fill grestore closepath stroke\n",
1350 " newpath x 0 0.25 180 360 arc gsave 0.85 setgray fill grestore closepath stroke\n",
1351 " 0.001 setlinewidth\n",
1352 "\n",
1353 " x 0 moveto\n",
1354 " x y lineto\n",
1355 "% -0.07 -0.2 rlineto 0.14 0 rmoveto -0.07 0.2 rlineto\n",
1356 " x y lineto\n",
1357 " -0.1 0 rlineto 0.2 0 rlineto\n",
1358 " stroke\n",
1359 " x 0 moveto\n",
1360 "% -0.07 0.2 rlineto 0.14 0 rmoveto -0.07 -0.2 rlineto\n",
1361 " x 0 moveto\n",
1362 " -0.1 0 rlineto 0.2 0 rlineto\n",
1363 " stroke\n",
1364 "\n",
1365 " x 0.1 add\n",
1366 " y 0.2 sub moveto\n",
1367 " units show\n",
1368 "} bind def\n",
1369 "\n",
1370 "/y 9 def\n",
1371 "/t {\n",
1372 " /str exch def\n",
1373 " 1.5 y moveto str show\n",
1374 " /y y 0.25 sub def\n",
1375 "} bind def\n",
1376 "\n",
1377 "(Please measure ONE of the horizontal lines, in the units indicated for)t\n",
1378 "(that line, and enter that value as X. Similarly, measure ONE of the)t\n",
1379 "(vertical lines and enter that value as Y. Measurements should be)t\n",
1380 "(between the flat faces of the semicircles.)t\n",
1381 "()t\n",
1382 "(The large box is 10.25 by 7.75 inches)t\n",
1383 "\n",
1384 "/in { } bind def\n",
1385 "/cm { 2.54 div } bind def\n",
1386 "/mm { 25.4 div } bind def\n",
1387 "\n",
1391 static int
1392 guess(double val, double close_to, double *calib)
1394 if (val >= close_to * 0.9
1395 && val <= close_to * 1.1)
1397 *calib = close_to / val;
1398 return 0;
1400 return 1;
1403 void
1404 ps_calibrate_1 (double xval, double yval, int use_command)
1406 HID_Attr_Val vals[3];
1407 FILE *ps_cal_file;
1408 int used_popen = 0, c;
1410 if (xval > 0 && yval > 0)
1412 if (guess (xval, 4, &global.calibration_x))
1413 if (guess (xval, 15, &global.calibration_x))
1414 if (guess (xval, 7.5, &global.calibration_x))
1416 if (xval < 2)
1417 ps_attribute_list[HA_xcalib].default_val.real_value =
1418 global.calibration_x = xval;
1419 else
1420 Message("X value of %g is too far off.\n"
1421 "Expecting it near: 1.0, 4.0, 15.0, 7.5\n", xval);
1423 if (guess (yval, 4, &global.calibration_y))
1424 if (guess (yval, 20, &global.calibration_y))
1425 if (guess (yval, 10, &global.calibration_y))
1427 if (yval < 2)
1428 ps_attribute_list[HA_ycalib].default_val.real_value =
1429 global.calibration_y = yval;
1430 else
1431 Message("Y value of %g is too far off.\n"
1432 "Expecting it near: 1.0, 4.0, 20.0, 10.0\n", yval);
1434 return;
1437 if (ps_calib_attribute_list[0].default_val.str_value == NULL)
1439 ps_calib_attribute_list[0].default_val.str_value = strdup ("lpr");
1442 if (gui->attribute_dialog (ps_calib_attribute_list, 1, vals, _("Print Calibration Page"), _("Generates a printer calibration page")))
1443 return;
1445 if (use_command || strchr (vals[0].str_value, '|'))
1447 const char *cmd = vals[0].str_value;
1448 while (*cmd == ' ' || *cmd == '|')
1449 cmd ++;
1450 ps_cal_file = popen (cmd, "w");
1451 used_popen = 1;
1453 else
1454 ps_cal_file = fopen (vals[0].str_value, "w");
1456 for (c=0; calib_lines[c]; c++)
1457 fputs(calib_lines[c], ps_cal_file);
1459 fprintf (ps_cal_file, "4 in 0.5 (Y in) cbar\n");
1460 fprintf (ps_cal_file, "20 cm 1.5 (Y cm) cbar\n");
1461 fprintf (ps_cal_file, "10 in 2.5 (Y in) cbar\n");
1462 fprintf (ps_cal_file, "-90 rotate\n");
1463 fprintf (ps_cal_file, "4 in -0.5 (X in) cbar\n");
1464 fprintf (ps_cal_file, "15 cm -1.5 (X cm) cbar\n");
1465 fprintf (ps_cal_file, "7.5 in -2.5 (X in) cbar\n");
1467 fprintf (ps_cal_file, "showpage\n");
1469 fprintf (ps_cal_file, "%%%%EOF\n");
1471 if (used_popen)
1472 pclose (ps_cal_file);
1473 else
1474 fclose (ps_cal_file);
1477 static void
1478 ps_calibrate (double xval, double yval)
1480 ps_calibrate_1 (xval, yval, 0);
1483 static void
1484 ps_set_crosshair (int x, int y, int action)
1488 #include "dolists.h"
1490 HID ps_hid;
1491 static HID_DRAW ps_graphics;
1493 void ps_ps_init (HID *hid)
1495 hid->get_export_options = ps_get_export_options;
1496 hid->do_export = ps_do_export;
1497 hid->parse_arguments = ps_parse_arguments;
1498 hid->set_layer = ps_set_layer;
1499 hid->calibrate = ps_calibrate;
1500 hid->set_crosshair = ps_set_crosshair;
1503 void ps_ps_graphics_init (HID_DRAW *graphics)
1505 graphics->make_gc = ps_make_gc;
1506 graphics->destroy_gc = ps_destroy_gc;
1507 graphics->use_mask = ps_use_mask;
1508 graphics->set_color = ps_set_color;
1509 graphics->set_line_cap = ps_set_line_cap;
1510 graphics->set_line_width = ps_set_line_width;
1511 graphics->set_draw_xor = ps_set_draw_xor;
1512 graphics->set_draw_faded = ps_set_draw_faded;
1513 graphics->draw_line = ps_draw_line;
1514 graphics->draw_arc = ps_draw_arc;
1515 graphics->draw_rect = ps_draw_rect;
1516 graphics->fill_circle = ps_fill_circle;
1517 graphics->fill_polygon = ps_fill_polygon;
1518 graphics->fill_rect = ps_fill_rect;
1520 graphics->fill_pcb_polygon = ps_fill_pcb_polygon;
1523 void
1524 hid_ps_init ()
1526 memset (&ps_hid, 0, sizeof (HID));
1527 memset (&ps_graphics, 0, sizeof (HID_DRAW));
1529 common_nogui_init (&ps_hid);
1530 common_draw_helpers_init (&ps_graphics);
1531 ps_ps_init (&ps_hid);
1532 ps_ps_graphics_init (&ps_graphics);
1534 ps_hid.struct_size = sizeof (HID);
1535 ps_hid.name = "ps";
1536 ps_hid.description = "Postscript export";
1537 ps_hid.exporter = 1;
1538 ps_hid.poly_before = 1;
1540 ps_hid.graphics = &ps_graphics;
1542 hid_register_hid (&ps_hid);
1544 hid_eps_init ();
1545 #include "ps_lists.h"