14 #include "pcb-printf.h"
18 #include "../hidint.h"
19 #include "hid/common/hidnogui.h"
20 #include "hid/common/draw_helpers.h"
22 #include "hid/common/hidinit.h"
24 #ifdef HAVE_LIBDMALLOC
28 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented EPS function %s.\n", __FUNCTION__); abort()
30 /*----------------------------------------------------------------------------*/
31 /* Function prototypes */
32 /*----------------------------------------------------------------------------*/
33 static HID_Attribute
* eps_get_export_options (int *n
);
34 static void eps_do_export (HID_Attr_Val
* options
);
35 static void eps_parse_arguments (int *argc
, char ***argv
);
36 static int eps_set_layer (const char *name
, int group
, int empty
);
37 static hidGC
eps_make_gc (void);
38 static void eps_destroy_gc (hidGC gc
);
39 static void eps_use_mask (enum mask_mode mode
);
40 static void eps_set_color (hidGC gc
, const char *name
);
41 static void eps_set_line_cap (hidGC gc
, EndCapStyle style
);
42 static void eps_set_line_width (hidGC gc
, Coord width
);
43 static void eps_set_draw_xor (hidGC gc
, int _xor
);
44 static void eps_draw_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
);
45 static void eps_draw_line (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
);
46 static void eps_draw_arc (hidGC gc
, Coord cx
, Coord cy
, Coord width
, Coord height
, Angle start_angle
, Angle delta_angle
);
47 static void eps_fill_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
);
48 static void eps_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
);
49 static void eps_fill_polygon (hidGC gc
, int n_coords
, Coord
*x
, Coord
*y
);
50 static void eps_calibrate (double xval
, double yval
);
51 static void eps_set_crosshair (int x
, int y
, int action
);
52 /*----------------------------------------------------------------------------*/
54 typedef struct hid_gc_struct
63 static HID_DRAW eps_graphics
;
66 static Coord linewidth
= -1;
67 static int lastcap
= -1;
68 static int lastcolor
= -1;
69 static int print_group
[MAX_LAYER
];
70 static int print_layer
[MAX_LAYER
];
71 static int fast_erase
= -1;
73 static HID_Attribute eps_attribute_list
[] = {
74 /* other HIDs expect this to be first. */
76 /* %start-doc options "92 Encapsulated Postscript Export"
78 @item --eps-file <string>
79 Name of the encapsulated postscript output file. Can contain a path.
83 {"eps-file", "Encapsulated Postscript output file",
84 HID_String
, 0, 0, {0, 0, 0}, 0, 0},
87 /* %start-doc options "92 Encapsulated Postscript Export"
89 @item --eps-scale <num>
90 Scale EPS output by the parameter @samp{num}.
94 {"eps-scale", "EPS scale",
95 HID_Real
, 0, 100, {0, 0, 1.0}, 0, 0},
98 /* %start-doc options "92 Encapsulated Postscript Export"
100 @cindex as-shown (EPS)
102 Export layers as shown on screen.
106 {"as-shown", "Export layers as shown on screen",
107 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
108 #define HA_as_shown 2
110 /* %start-doc options "92 Encapsulated Postscript Export"
113 Convert output to monochrome.
117 {"monochrome", "Convert to monochrome",
118 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
121 /* %start-doc options "92 Encapsulated Postscript Export"
125 Limit the bounds of the EPS file to the visible items.
129 {"only-visible", "Limit the bounds of the EPS file to the visible items",
130 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
131 #define HA_only_visible 4
134 #define NUM_OPTIONS (sizeof(eps_attribute_list)/sizeof(eps_attribute_list[0]))
136 REGISTER_ATTRIBUTES (eps_attribute_list
)
138 static HID_Attr_Val eps_values
[NUM_OPTIONS
];
140 static HID_Attribute
*
141 eps_get_export_options (int *n
)
143 static char *last_made_filename
= 0;
145 if (PCB
) derive_default_filename(PCB
->Filename
, &eps_attribute_list
[HA_psfile
], ".eps", &last_made_filename
);
149 return eps_attribute_list
;
152 static int comp_layer
, solder_layer
;
155 group_for_layer (int l
)
157 if (l
< max_copper_layer
+ 2 && l
>= 0)
158 return GetLayerGroupNumberByNumber (l
);
159 /* else something unique */
160 return max_group
+ 3 + l
;
164 layer_sort (const void *va
, const void *vb
)
168 int al
= group_for_layer (a
);
169 int bl
= group_for_layer (b
);
172 if (a
>= 0 && a
<= max_copper_layer
+ 1)
174 int aside
= (al
== solder_layer
? 0 : al
== comp_layer
? 2 : 1);
175 int bside
= (bl
== solder_layer
? 0 : bl
== comp_layer
? 2 : 1);
177 return bside
- aside
;
184 static const char *filename
;
185 static BoxType
*bounds
;
186 static int in_mono
, as_shown
;
189 eps_hid_export_to_file (FILE * the_file
, HID_Attr_Val
* options
)
192 static int saved_layer_stack
[MAX_LAYER
];
194 FlagType save_thindraw
;
196 save_thindraw
= PCB
->Flags
;
197 CLEAR_FLAG(THINDRAWFLAG
, PCB
);
198 CLEAR_FLAG(THINDRAWPOLYFLAG
, PCB
);
199 CLEAR_FLAG(CHECKPLANESFLAG
, PCB
);
205 region
.X2
= PCB
->MaxWidth
;
206 region
.Y2
= PCB
->MaxHeight
;
208 if (options
[HA_only_visible
].int_value
)
209 bounds
= GetDataBoundingBox (PCB
->Data
);
213 memset (print_group
, 0, sizeof (print_group
));
214 memset (print_layer
, 0, sizeof (print_layer
));
216 /* Figure out which layers actually have stuff on them. */
217 for (i
= 0; i
< max_copper_layer
; i
++)
219 LayerType
*layer
= PCB
->Data
->Layer
+ i
;
221 if (layer
->LineN
|| layer
->TextN
|| layer
->ArcN
|| layer
->PolygonN
)
222 print_group
[GetLayerGroupNumberByNumber (i
)] = 1;
225 /* Now, if only one layer has real stuff on it, we can use the fast
226 erase logic. Otherwise, we have to use the expensive multi-mask
229 for (i
= 0; i
< max_group
; i
++)
233 /* If NO layers had anything on them, at least print the component
234 layer to get the pins. */
237 print_group
[GetLayerGroupNumberByNumber (component_silk_layer
)] = 1;
241 /* "fast_erase" is 1 if we can just paint white to erase. */
242 fast_erase
= fast_erase
== 1 ? 1 : 0;
244 /* Now, for each group we're printing, mark its layers for
246 for (i
= 0; i
< max_copper_layer
; i
++)
247 if (print_group
[GetLayerGroupNumberByNumber (i
)])
251 eps_hid
.poly_before
= 1;
252 eps_hid
.poly_after
= 0;
254 eps_hid
.poly_before
= 0;
255 eps_hid
.poly_after
= 1;
258 memcpy (saved_layer_stack
, LayerStack
, sizeof (LayerStack
));
259 as_shown
= options
[HA_as_shown
].int_value
;
260 if (!options
[HA_as_shown
].int_value
)
262 comp_layer
= GetLayerGroupNumberByNumber (component_silk_layer
);
263 solder_layer
= GetLayerGroupNumberByNumber (solder_silk_layer
);
264 qsort (LayerStack
, max_copper_layer
, sizeof (LayerStack
[0]), layer_sort
);
266 fprintf (f
, "%%!PS-Adobe-3.0 EPSF-3.0\n");
271 in_mono
= options
[HA_mono
].int_value
;
273 #define pcb2em(x) 1 + COORD_TO_INCH (x) * 72.0 * options[HA_scale].real_value
274 fprintf (f
, "%%%%BoundingBox: 0 0 %lli %lli\n",
275 llrint (pcb2em (bounds
->X2
- bounds
->X1
)),
276 llrint (pcb2em (bounds
->Y2
- bounds
->Y1
)) );
277 fprintf (f
, "%%%%HiResBoundingBox: 0.000000 0.000000 %.6f %.6f\n",
278 pcb2em (bounds
->X2
- bounds
->X1
),
279 pcb2em (bounds
->Y2
- bounds
->Y1
));
281 fprintf (f
, "%%%%Pages: 1\n");
283 "save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def\n");
284 fprintf (f
, "%%%%EndProlog\n");
285 fprintf (f
, "%%%%Page: 1 1\n");
286 fprintf (f
, "%%%%BeginDocument: %s\n\n", filename
);
288 fprintf (f
, "72 72 scale\n");
289 fprintf (f
, "1 dup neg scale\n");
290 fprintf (f
, "%g dup scale\n", options
[HA_scale
].real_value
);
291 pcb_fprintf (f
, "%mi %mi translate\n", -bounds
->X1
, -bounds
->Y2
);
292 if (options
[HA_as_shown
].int_value
&& Settings
.ShowSolderSide
)
293 pcb_fprintf (f
, "-1 1 scale %mi 0 translate\n", bounds
->X1
- bounds
->X2
);
297 #define Q (Coord) MIL_TO_COORD(10)
299 "/nclip { %mi %mi moveto %mi %mi lineto %mi %mi lineto %mi %mi lineto %mi %mi lineto eoclip newpath } def\n",
300 bounds
->X1
- Q
, bounds
->Y1
- Q
, bounds
->X1
- Q
, bounds
->Y2
+ Q
,
301 bounds
->X2
+ Q
, bounds
->Y2
+ Q
, bounds
->X2
+ Q
, bounds
->Y1
- Q
,
302 bounds
->X1
- Q
, bounds
->Y1
- Q
);
304 fprintf (f
, "/t { moveto lineto stroke } bind def\n");
305 fprintf (f
, "/tc { moveto lineto strokepath nclip } bind def\n");
306 fprintf (f
, "/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n");
308 " x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def\n");
309 fprintf (f
, "/c { 0 360 arc fill } bind def\n");
310 fprintf (f
, "/cc { 0 360 arc nclip } bind def\n");
312 "/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def\n");
314 hid_expose_callback (&eps_hid
, bounds
, 0);
316 fprintf (f
, "showpage\n");
318 fprintf (f
, "%%%%EndDocument\n");
319 fprintf (f
, "%%%%Trailer\n");
320 fprintf (f
, "cleartomark countdictstack exch sub { end } repeat restore\n");
321 fprintf (f
, "%%%%EOF\n");
323 memcpy (LayerStack
, saved_layer_stack
, sizeof (LayerStack
));
324 PCB
->Flags
= save_thindraw
;
328 eps_do_export (HID_Attr_Val
* options
)
331 int save_ons
[MAX_LAYER
+ 2];
335 eps_get_export_options (0);
336 for (i
= 0; i
< NUM_OPTIONS
; i
++)
337 eps_values
[i
] = eps_attribute_list
[i
].default_val
;
338 options
= eps_values
;
341 filename
= options
[HA_psfile
].str_value
;
343 filename
= "pcb-out.eps";
345 f
= fopen (filename
, "w");
352 if (!options
[HA_as_shown
].int_value
)
353 hid_save_and_show_layer_ons (save_ons
);
354 eps_hid_export_to_file (f
, options
);
355 if (!options
[HA_as_shown
].int_value
)
356 hid_restore_layer_ons (save_ons
);
362 eps_parse_arguments (int *argc
, char ***argv
)
364 hid_register_attributes (eps_attribute_list
,
365 sizeof (eps_attribute_list
) /
366 sizeof (eps_attribute_list
[0]));
367 hid_parse_command_line (argc
, argv
);
375 eps_set_layer (const char *name
, int group
, int empty
)
377 int idx
= (group
>= 0
379 max_group
) ? PCB
->LayerGroups
.Entries
[group
][0] : group
;
381 name
= PCB
->Data
->Layer
[idx
].Name
;
383 if (idx
>= 0 && idx
< max_copper_layer
&& !print_layer
[idx
])
385 if (SL_TYPE (idx
) == SL_ASSY
|| SL_TYPE (idx
) == SL_FAB
)
388 if (strcmp (name
, "invisible") == 0)
391 is_drill
= (SL_TYPE (idx
) == SL_PDRILL
|| SL_TYPE (idx
) == SL_UDRILL
);
392 is_mask
= (SL_TYPE (idx
) == SL_MASK
);
393 is_paste
= (SL_TYPE (idx
) == SL_PASTE
);
395 if (is_mask
|| is_paste
)
398 printf ("Layer %s group %d drill %d mask %d\n", name
, group
, is_drill
,
401 fprintf (f
, "%% Layer %s group %d drill %d mask %d\n", name
, group
,
409 case SL (SILK
, BOTTOM
):
411 return PCB
->ElementOn
;
422 case SL (SILK
, BOTTOM
):
433 hidGC rv
= (hidGC
) malloc (sizeof (hid_gc_struct
));
441 eps_destroy_gc (hidGC gc
)
447 eps_use_mask (enum mask_mode mode
)
449 static int mask_pending
= 0;
456 fprintf (f
, "gsave\n");
459 case HID_MASK_BEFORE
:
466 fprintf (f
, "grestore\n");
474 eps_set_color (hidGC gc
, const char *name
)
476 static void *cache
= 0;
479 if (strcmp (name
, "erase") == 0)
481 gc
->color
= 0xffffff;
482 gc
->erase
= fast_erase
? 0 : 1;
485 if (strcmp (name
, "drill") == 0)
487 gc
->color
= 0xffffff;
492 if (hid_cache_color (0, name
, &cval
, &cache
))
494 gc
->color
= cval
.lval
;
500 else if (name
[0] == '#')
502 unsigned int r
, g
, b
;
503 sscanf (name
+ 1, "%2x%2x%2x", &r
, &g
, &b
);
504 gc
->color
= (r
<< 16) + (g
<< 8) + b
;
511 eps_set_line_cap (hidGC gc
, EndCapStyle style
)
517 eps_set_line_width (hidGC gc
, Coord width
)
523 eps_set_draw_xor (hidGC gc
, int xor_
)
531 if (linewidth
!= gc
->width
)
533 pcb_fprintf (f
, "%mi setlinewidth\n", gc
->width
);
534 linewidth
= gc
->width
;
536 if (lastcap
!= gc
->cap
)
550 fprintf (f
, "%d setlinecap\n", c
);
553 if (lastcolor
!= gc
->color
)
556 #define CV(x,b) (((x>>b)&0xff)/255.0)
557 fprintf (f
, "%g %g %g setrgbcolor\n", CV (c
, 16), CV (c
, 8), CV (c
, 0));
558 lastcolor
= gc
->color
;
562 static void eps_fill_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
);
563 static void eps_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
);
566 eps_draw_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
569 pcb_fprintf (f
, "%mi %mi %mi %mi r\n", x1
, y1
, x2
, y2
);
573 eps_draw_line (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
575 Coord w
= gc
->width
/ 2;
576 if (x1
== x2
&& y1
== y2
)
578 if (gc
->cap
== Square_Cap
)
579 eps_fill_rect (gc
, x1
- w
, y1
- w
, x1
+ w
, y1
+ w
);
581 eps_fill_circle (gc
, x1
, y1
, w
);
585 if (gc
->erase
&& gc
->cap
!= Square_Cap
)
587 double ang
= atan2 (y2
- y1
, x2
- x1
);
588 double dx
= w
* sin (ang
);
589 double dy
= -w
* cos (ang
);
590 double deg
= ang
* 180.0 / M_PI
;
594 pcb_fprintf (f
, "%mi %mi moveto ", vx1
, vy1
);
595 pcb_fprintf (f
, "%mi %mi %mi %g %g arc\n", x2
, y2
, w
, deg
- 90, deg
+ 90);
596 pcb_fprintf (f
, "%mi %mi %mi %g %g arc\n", x1
, y1
, w
, deg
+ 90, deg
+ 270);
597 fprintf (f
, "nclip\n");
601 pcb_fprintf (f
, "%mi %mi %mi %mi %s\n", x1
, y1
, x2
, y2
, gc
->erase
? "tc" : "t");
605 eps_draw_arc (hidGC gc
, Coord cx
, Coord cy
, Coord width
, Coord height
,
606 Angle start_angle
, Angle delta_angle
)
612 ea
= start_angle
+ delta_angle
;
616 sa
= start_angle
+ delta_angle
;
620 printf ("draw_arc %d,%d %dx%d %d..%d %d..%d\n",
621 cx
, cy
, width
, height
, start_angle
, delta_angle
, sa
, ea
);
624 pcb_fprintf (f
, "%ma %ma %mi %mi %mi %mi %g a\n",
625 sa
, ea
, -width
, height
, cx
, cy
, (double) linewidth
/ width
);
629 eps_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
)
632 pcb_fprintf (f
, "%mi %mi %mi %s\n", cx
, cy
, radius
, gc
->erase
? "cc" : "c");
636 eps_fill_polygon (hidGC gc
, int n_coords
, Coord
*x
, Coord
*y
)
641 for (i
= 0; i
< n_coords
; i
++)
643 pcb_fprintf (f
, "%mi %mi %s\n", x
[i
], y
[i
], op
);
646 fprintf (f
, "fill\n");
650 eps_fill_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
653 pcb_fprintf (f
, "%mi %mi %mi %mi r\n", x1
, y1
, x2
, y2
);
657 eps_calibrate (double xval
, double yval
)
663 eps_set_crosshair (int x
, int y
, int action
)
670 memset (&eps_hid
, 0, sizeof (HID
));
671 memset (&eps_graphics
, 0, sizeof (HID_DRAW
));
673 common_nogui_init (&eps_hid
);
674 common_draw_helpers_init (&eps_graphics
);
676 eps_hid
.struct_size
= sizeof (HID
);
677 eps_hid
.name
= "eps";
678 eps_hid
.description
= "Encapsulated Postscript";
679 eps_hid
.exporter
= 1;
680 eps_hid
.poly_after
= 1;
682 eps_hid
.get_export_options
= eps_get_export_options
;
683 eps_hid
.do_export
= eps_do_export
;
684 eps_hid
.parse_arguments
= eps_parse_arguments
;
685 eps_hid
.set_layer
= eps_set_layer
;
686 eps_hid
.calibrate
= eps_calibrate
;
687 eps_hid
.set_crosshair
= eps_set_crosshair
;
689 eps_hid
.graphics
= &eps_graphics
;
691 eps_graphics
.make_gc
= eps_make_gc
;
692 eps_graphics
.destroy_gc
= eps_destroy_gc
;
693 eps_graphics
.use_mask
= eps_use_mask
;
694 eps_graphics
.set_color
= eps_set_color
;
695 eps_graphics
.set_line_cap
= eps_set_line_cap
;
696 eps_graphics
.set_line_width
= eps_set_line_width
;
697 eps_graphics
.set_draw_xor
= eps_set_draw_xor
;
698 eps_graphics
.draw_line
= eps_draw_line
;
699 eps_graphics
.draw_arc
= eps_draw_arc
;
700 eps_graphics
.draw_rect
= eps_draw_rect
;
701 eps_graphics
.fill_circle
= eps_fill_circle
;
702 eps_graphics
.fill_polygon
= eps_fill_polygon
;
703 eps_graphics
.fill_rect
= eps_fill_rect
;
705 hid_register_hid (&eps_hid
);