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 eps_gc_struct
56 struct hid_gc_struct hid_gc
; /* Parent */
65 static HID_DRAW eps_graphics
;
66 static HID_DRAW_CLASS eps_graphics_class
;
69 static Coord linewidth
= -1;
70 static int lastcap
= -1;
71 static int lastcolor
= -1;
72 static int print_group
[MAX_GROUP
];
73 static int print_layer
[MAX_LAYER
];
74 static int fast_erase
= -1;
76 static HID_Attribute eps_attribute_list
[] = {
77 /* other HIDs expect this to be first. */
79 /* %start-doc options "92 Encapsulated Postscript Export"
81 @item --eps-file <string>
82 Name of the encapsulated postscript output file. Can contain a path.
86 {"eps-file", "Encapsulated Postscript output file",
87 HID_String
, 0, 0, {0, 0, 0}, 0, 0},
90 /* %start-doc options "92 Encapsulated Postscript Export"
92 @item --eps-scale <num>
93 Scale EPS output by the parameter @samp{num}.
97 {"eps-scale", "EPS scale",
98 HID_Real
, 0, 100, {0, 0, 1.0}, 0, 0},
101 /* %start-doc options "92 Encapsulated Postscript Export"
103 @cindex as-shown (EPS)
105 Export layers as shown on screen.
109 {"as-shown", "Export layers as shown on screen",
110 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
111 #define HA_as_shown 2
113 /* %start-doc options "92 Encapsulated Postscript Export"
116 Convert output to monochrome.
120 {"monochrome", "Convert to monochrome",
121 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
124 /* %start-doc options "92 Encapsulated Postscript Export"
128 Limit the bounds of the EPS file to the visible items.
132 {"only-visible", "Limit the bounds of the EPS file to the visible items",
133 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
134 #define HA_only_visible 4
137 #define NUM_OPTIONS (sizeof(eps_attribute_list)/sizeof(eps_attribute_list[0]))
139 REGISTER_ATTRIBUTES (eps_attribute_list
)
141 static HID_Attr_Val eps_values
[NUM_OPTIONS
];
143 static HID_Attribute
*
144 eps_get_export_options (int *n
)
146 static char *last_made_filename
= 0;
148 if (PCB
) derive_default_filename(PCB
->Filename
, &eps_attribute_list
[HA_psfile
], ".eps", &last_made_filename
);
152 return eps_attribute_list
;
155 static int top_group
, bottom_group
;
158 layer_stack_sort (const void *va
, const void *vb
)
160 int a_layer
= *(int *) va
;
161 int b_layer
= *(int *) vb
;
162 int a_group
= GetLayerGroupNumberByNumber (a_layer
);
163 int b_group
= GetLayerGroupNumberByNumber (b_layer
);
164 int aside
= (a_group
== bottom_group
? 0 : a_group
== top_group
? 2 : 1);
165 int bside
= (b_group
== bottom_group
? 0 : b_group
== top_group
? 2 : 1);
168 return bside
- aside
;
170 if (b_group
!= a_group
)
171 return b_group
- a_group
;
173 return b_layer
- a_layer
;
176 static const char *filename
;
177 static BoxType
*bounds
;
178 static int in_mono
, as_shown
;
181 eps_hid_export_to_file (FILE * the_file
, HID_Attr_Val
* options
)
184 static int saved_layer_stack
[MAX_LAYER
];
186 FlagType save_thindraw
;
188 save_thindraw
= PCB
->Flags
;
189 CLEAR_FLAG(THINDRAWFLAG
, PCB
);
190 CLEAR_FLAG(THINDRAWPOLYFLAG
, PCB
);
191 CLEAR_FLAG(CHECKPLANESFLAG
, PCB
);
197 region
.X2
= PCB
->MaxWidth
;
198 region
.Y2
= PCB
->MaxHeight
;
200 if (options
[HA_only_visible
].int_value
)
201 bounds
= GetDataBoundingBox (PCB
->Data
);
205 memset (print_group
, 0, sizeof (print_group
));
206 memset (print_layer
, 0, sizeof (print_layer
));
208 /* Figure out which layers actually have stuff on them. */
209 for (i
= 0; i
< max_copper_layer
; i
++)
211 LayerType
*layer
= PCB
->Data
->Layer
+ i
;
213 if (layer
->LineN
|| layer
->TextN
|| layer
->ArcN
|| layer
->PolygonN
)
214 print_group
[GetLayerGroupNumberByNumber (i
)] = 1;
217 /* Now, if only one layer has real stuff on it, we can use the fast
218 erase logic. Otherwise, we have to use the expensive multi-mask
221 for (i
= 0; i
< max_group
; i
++)
225 /* If NO layers had anything on them, at least print the component
226 layer to get the pins. */
229 print_group
[GetLayerGroupNumberBySide (TOP_SIDE
)] = 1;
233 /* "fast_erase" is 1 if we can just paint white to erase. */
234 fast_erase
= fast_erase
== 1 ? 1 : 0;
236 /* Now, for each group we're printing, mark its layers for
238 for (i
= 0; i
< max_copper_layer
; i
++)
239 if (print_group
[GetLayerGroupNumberByNumber (i
)])
243 eps_graphics
.poly_before
= true;
244 eps_graphics
.poly_after
= false;
246 eps_graphics
.poly_before
= false;
247 eps_graphics
.poly_after
= true;
250 memcpy (saved_layer_stack
, LayerStack
, sizeof (LayerStack
));
251 as_shown
= options
[HA_as_shown
].int_value
;
252 if (!options
[HA_as_shown
].int_value
)
254 top_group
= GetLayerGroupNumberBySide (TOP_SIDE
);
255 bottom_group
= GetLayerGroupNumberBySide (BOTTOM_SIDE
);
256 qsort (LayerStack
, max_copper_layer
, sizeof (LayerStack
[0]), layer_stack_sort
);
258 fprintf (f
, "%%!PS-Adobe-3.0 EPSF-3.0\n");
263 in_mono
= options
[HA_mono
].int_value
;
265 #define pcb2em(x) 1 + COORD_TO_INCH (x) * 72.0 * options[HA_scale].real_value
266 fprintf (f
, "%%%%BoundingBox: 0 0 %lli %lli\n",
267 llrint (pcb2em (bounds
->X2
- bounds
->X1
)),
268 llrint (pcb2em (bounds
->Y2
- bounds
->Y1
)) );
269 fprintf (f
, "%%%%HiResBoundingBox: 0.000000 0.000000 %.6f %.6f\n",
270 pcb2em (bounds
->X2
- bounds
->X1
),
271 pcb2em (bounds
->Y2
- bounds
->Y1
));
273 fprintf (f
, "%%%%Pages: 1\n");
275 "save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def\n");
276 fprintf (f
, "%%%%EndProlog\n");
277 fprintf (f
, "%%%%Page: 1 1\n");
278 fprintf (f
, "%%%%BeginDocument: %s\n\n", filename
);
280 fprintf (f
, "72 72 scale\n");
281 fprintf (f
, "1 dup neg scale\n");
282 fprintf (f
, "%g dup scale\n", options
[HA_scale
].real_value
);
283 pcb_fprintf (f
, "%mi %mi translate\n", -bounds
->X1
, -bounds
->Y2
);
284 if (options
[HA_as_shown
].int_value
&& Settings
.ShowBottomSide
)
285 pcb_fprintf (f
, "-1 1 scale %mi 0 translate\n", bounds
->X1
- bounds
->X2
);
289 #define Q (Coord) MIL_TO_COORD(10)
291 "/nclip { %mi %mi moveto %mi %mi lineto %mi %mi lineto %mi %mi lineto %mi %mi lineto eoclip newpath } def\n",
292 bounds
->X1
- Q
, bounds
->Y1
- Q
, bounds
->X1
- Q
, bounds
->Y2
+ Q
,
293 bounds
->X2
+ Q
, bounds
->Y2
+ Q
, bounds
->X2
+ Q
, bounds
->Y1
- Q
,
294 bounds
->X1
- Q
, bounds
->Y1
- Q
);
296 fprintf (f
, "/t { moveto lineto stroke } bind def\n");
297 fprintf (f
, "/tc { moveto lineto strokepath nclip } bind def\n");
298 fprintf (f
, "/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n");
300 " x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def\n");
301 fprintf (f
, "/c { 0 360 arc fill } bind def\n");
302 fprintf (f
, "/cc { 0 360 arc nclip } bind def\n");
304 "/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def\n");
306 hid_expose_callback (&eps_hid
, bounds
, 0);
308 fprintf (f
, "showpage\n");
310 fprintf (f
, "%%%%EndDocument\n");
311 fprintf (f
, "%%%%Trailer\n");
312 fprintf (f
, "cleartomark countdictstack exch sub { end } repeat restore\n");
313 fprintf (f
, "%%%%EOF\n");
315 memcpy (LayerStack
, saved_layer_stack
, sizeof (LayerStack
));
316 PCB
->Flags
= save_thindraw
;
320 eps_do_export (HID_Attr_Val
* options
)
323 int save_ons
[MAX_LAYER
+ 2];
327 eps_get_export_options (0);
328 for (i
= 0; i
< NUM_OPTIONS
; i
++)
329 eps_values
[i
] = eps_attribute_list
[i
].default_val
;
330 options
= eps_values
;
333 filename
= options
[HA_psfile
].str_value
;
335 filename
= "pcb-out.eps";
337 f
= fopen (filename
, "w");
344 if (!options
[HA_as_shown
].int_value
)
345 hid_save_and_show_layer_ons (save_ons
);
346 eps_hid_export_to_file (f
, options
);
347 if (!options
[HA_as_shown
].int_value
)
348 hid_restore_layer_ons (save_ons
);
354 eps_parse_arguments (int *argc
, char ***argv
)
356 hid_register_attributes (eps_attribute_list
,
357 sizeof (eps_attribute_list
) /
358 sizeof (eps_attribute_list
[0]));
359 hid_parse_command_line (argc
, argv
);
367 eps_set_layer (const char *name
, int group
, int empty
)
369 int idx
= (group
>= 0
371 max_group
) ? PCB
->LayerGroups
.Entries
[group
][0] : group
;
373 name
= PCB
->Data
->Layer
[idx
].Name
;
375 if (idx
>= 0 && idx
< max_copper_layer
&& !print_layer
[idx
])
377 if (SL_TYPE (idx
) == SL_ASSY
|| SL_TYPE (idx
) == SL_FAB
)
380 if (strcmp (name
, "invisible") == 0)
383 is_drill
= (SL_TYPE (idx
) == SL_PDRILL
|| SL_TYPE (idx
) == SL_UDRILL
);
384 is_mask
= (SL_TYPE (idx
) == SL_MASK
);
385 is_paste
= (SL_TYPE (idx
) == SL_PASTE
);
387 if (is_mask
|| is_paste
)
390 printf ("Layer %s group %d drill %d mask %d\n", name
, group
, is_drill
,
393 fprintf (f
, "%% Layer %s group %d drill %d mask %d\n", name
, group
,
401 case SL (SILK
, BOTTOM
):
403 return PCB
->ElementOn
;
414 case SL (SILK
, BOTTOM
):
425 hidGC gc
= (hidGC
) calloc (1, sizeof (struct eps_gc_struct
));
426 epsGC eps_gc
= (epsGC
)gc
;
429 gc
->hid_draw
= &eps_graphics
;
431 eps_gc
->cap
= Trace_Cap
;
439 eps_destroy_gc (hidGC gc
)
445 eps_use_mask (enum mask_mode mode
)
447 static int mask_pending
= 0;
454 fprintf (f
, "gsave\n");
457 case HID_MASK_BEFORE
:
464 fprintf (f
, "grestore\n");
472 eps_set_color (hidGC gc
, const char *name
)
474 epsGC eps_gc
= (epsGC
)gc
;
475 static void *cache
= 0;
478 if (strcmp (name
, "erase") == 0)
480 eps_gc
->color
= 0xffffff;
481 eps_gc
->erase
= fast_erase
? 0 : 1;
484 if (strcmp (name
, "drill") == 0)
486 eps_gc
->color
= 0xffffff;
491 if (hid_cache_color (0, name
, &cval
, &cache
))
493 eps_gc
->color
= cval
.lval
;
499 else if (name
[0] == '#')
501 unsigned int r
, g
, b
;
502 sscanf (name
+ 1, "%2x%2x%2x", &r
, &g
, &b
);
503 eps_gc
->color
= (r
<< 16) + (g
<< 8) + b
;
510 eps_set_line_cap (hidGC gc
, EndCapStyle style
)
512 epsGC eps_gc
= (epsGC
)gc
;
518 eps_set_line_width (hidGC gc
, Coord width
)
520 epsGC eps_gc
= (epsGC
)gc
;
522 eps_gc
->width
= width
;
526 eps_set_draw_xor (hidGC gc
, int xor_
)
534 epsGC eps_gc
= (epsGC
)gc
;
536 if (linewidth
!= eps_gc
->width
)
538 pcb_fprintf (f
, "%mi setlinewidth\n", eps_gc
->width
);
539 linewidth
= eps_gc
->width
;
541 if (lastcap
!= eps_gc
->cap
)
555 fprintf (f
, "%d setlinecap\n", c
);
556 lastcap
= eps_gc
->cap
;
558 if (lastcolor
!= eps_gc
->color
)
560 int c
= eps_gc
->color
;
561 #define CV(x,b) (((x>>b)&0xff)/255.0)
562 fprintf (f
, "%g %g %g setrgbcolor\n", CV (c
, 16), CV (c
, 8), CV (c
, 0));
563 lastcolor
= eps_gc
->color
;
567 static void eps_fill_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
);
568 static void eps_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
);
571 eps_draw_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
574 pcb_fprintf (f
, "%mi %mi %mi %mi r\n", x1
, y1
, x2
, y2
);
578 eps_draw_line (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
580 epsGC eps_gc
= (epsGC
)gc
;
581 Coord w
= eps_gc
->width
/ 2;
583 if (x1
== x2
&& y1
== y2
)
585 if (eps_gc
->cap
== Square_Cap
)
586 eps_fill_rect (gc
, x1
- w
, y1
- w
, x1
+ w
, y1
+ w
);
588 eps_fill_circle (gc
, x1
, y1
, w
);
592 if (eps_gc
->erase
&& eps_gc
->cap
!= Square_Cap
)
594 double ang
= atan2 (y2
- y1
, x2
- x1
);
595 double dx
= w
* sin (ang
);
596 double dy
= -w
* cos (ang
);
597 double deg
= ang
* 180.0 / M_PI
;
601 pcb_fprintf (f
, "%mi %mi moveto ", vx1
, vy1
);
602 pcb_fprintf (f
, "%mi %mi %mi %g %g arc\n", x2
, y2
, w
, deg
- 90, deg
+ 90);
603 pcb_fprintf (f
, "%mi %mi %mi %g %g arc\n", x1
, y1
, w
, deg
+ 90, deg
+ 270);
604 fprintf (f
, "nclip\n");
608 pcb_fprintf (f
, "%mi %mi %mi %mi %s\n", x1
, y1
, x2
, y2
, eps_gc
->erase
? "tc" : "t");
612 eps_draw_arc (hidGC gc
, Coord cx
, Coord cy
, Coord width
, Coord height
,
613 Angle start_angle
, Angle delta_angle
)
619 ea
= start_angle
+ delta_angle
;
623 sa
= start_angle
+ delta_angle
;
627 printf ("draw_arc %d,%d %dx%d %d..%d %d..%d\n",
628 cx
, cy
, width
, height
, start_angle
, delta_angle
, sa
, ea
);
631 pcb_fprintf (f
, "%ma %ma %mi %mi %mi %mi %g a\n",
632 sa
, ea
, -width
, height
, cx
, cy
, (double) linewidth
/ width
);
636 eps_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
)
638 epsGC eps_gc
= (epsGC
)gc
;
641 pcb_fprintf (f
, "%mi %mi %mi %s\n", cx
, cy
, radius
, eps_gc
->erase
? "cc" : "c");
645 eps_fill_polygon (hidGC gc
, int n_coords
, Coord
*x
, Coord
*y
)
650 for (i
= 0; i
< n_coords
; i
++)
652 pcb_fprintf (f
, "%mi %mi %s\n", x
[i
], y
[i
], op
);
655 fprintf (f
, "fill\n");
659 eps_fill_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
662 pcb_fprintf (f
, "%mi %mi %mi %mi r\n", x1
, y1
, x2
, y2
);
666 eps_calibrate (double xval
, double yval
)
672 eps_set_crosshair (int x
, int y
, int action
)
679 memset (&eps_hid
, 0, sizeof (HID
));
680 memset (&eps_graphics
, 0, sizeof (HID_DRAW
));
681 memset (&eps_graphics_class
, 0, sizeof (HID_DRAW_CLASS
));
683 common_nogui_init (&eps_hid
);
685 eps_hid
.struct_size
= sizeof (HID
);
686 eps_hid
.name
= "eps";
687 eps_hid
.description
= "Encapsulated Postscript";
688 eps_hid
.exporter
= 1;
690 eps_hid
.get_export_options
= eps_get_export_options
;
691 eps_hid
.do_export
= eps_do_export
;
692 eps_hid
.parse_arguments
= eps_parse_arguments
;
693 eps_hid
.calibrate
= eps_calibrate
;
694 eps_hid
.set_crosshair
= eps_set_crosshair
;
696 eps_hid
.graphics
= &eps_graphics
;
698 common_draw_helpers_class_init (&eps_graphics_class
);
700 eps_graphics_class
.set_layer
= eps_set_layer
;
701 eps_graphics_class
.make_gc
= eps_make_gc
;
702 eps_graphics_class
.destroy_gc
= eps_destroy_gc
;
703 eps_graphics_class
.use_mask
= eps_use_mask
;
704 eps_graphics_class
.set_color
= eps_set_color
;
705 eps_graphics_class
.set_line_cap
= eps_set_line_cap
;
706 eps_graphics_class
.set_line_width
= eps_set_line_width
;
707 eps_graphics_class
.set_draw_xor
= eps_set_draw_xor
;
708 eps_graphics_class
.draw_line
= eps_draw_line
;
709 eps_graphics_class
.draw_arc
= eps_draw_arc
;
710 eps_graphics_class
.draw_rect
= eps_draw_rect
;
711 eps_graphics_class
.fill_circle
= eps_fill_circle
;
712 eps_graphics_class
.fill_polygon
= eps_fill_polygon
;
713 eps_graphics_class
.fill_rect
= eps_fill_rect
;
715 eps_graphics
.klass
= &eps_graphics_class
;
716 eps_graphics
.poly_after
= true;
717 common_draw_helpers_init (&eps_graphics
);
719 hid_register_hid (&eps_hid
);