Index: trunk/scconfig/hooks.c =================================================================== --- trunk/scconfig/hooks.c (revision 1262) +++ trunk/scconfig/hooks.c (revision 1263) @@ -38,56 +38,64 @@ {"disable-gpmi", "libs/script/gpmi", arg_lib_nodes, "$do not compile the gpmi (scripting) plugin"}, {"buildin-gpmi", "/local/pcb/gpmi/buildin", arg_true, "$static link the gpmi plugin into the executable"}, - {"plugin-gpmi", "/local/pcb/gpmi/buildin", arg_false, "$the gpmi plugin is dynamic loadable"}, + {"plugin-gpmi", "/local/pcb/gpmi/buildin", arg_false, "$the gpmi plugin is a dynamic loadable"}, {"disable-autoroute", "/local/pcb/autoroute/enable", arg_false, "$do not compile the autorouter"}, {"buildin-autoroute", "/local/pcb/autoroute/buildin", arg_true, "$static link the autorouter plugin into the executable"}, - {"plugin-autoroute", "/local/pcb/autoroute/buildin", arg_false, "$the autorouter plugin is dynamic loadable"}, + {"plugin-autoroute", "/local/pcb/autoroute/buildin", arg_false, "$the autorouter plugin is a dynamic loadable"}, {"disable-autoplace", "/local/pcb/autoplace/enable", arg_false, "$do not compile the autoplace"}, {"buildin-autoplace", "/local/pcb/autoplace/buildin", arg_true, "$static link the autoplace plugin into the executable"}, - {"plugin-autoplace", "/local/pcb/autoplace/buildin", arg_false, "$the autoplace plugin is dynamic loadable"}, + {"plugin-autoplace", "/local/pcb/autoplace/buildin", arg_false, "$the autoplace plugin is a dynamic loadable"}, {"disable-vendordrill", "/local/pcb/vendordrill/enable", arg_false, "$do not compile the vendor drill mapping"}, {"buildin-vendordrill", "/local/pcb/vendordrill/buildin", arg_true, "$static link the vendor drill mapping plugin into the executable"}, - {"plugin-vendordrill", "/local/pcb/vendordrill/buildin", arg_false, "$the vendor drill mapping plugin is dynamic loadable"}, + {"plugin-vendordrill", "/local/pcb/vendordrill/buildin", arg_false, "$the vendor drill mapping plugin is a dynamic loadable"}, {"disable-puller", "/local/pcb/puller/enable", arg_false, "$do not compile the puller"}, {"buildin-puller", "/local/pcb/puller/buildin", arg_true, "$static link the puller plugin into the executable"}, - {"plugin-puller", "/local/pcb/puller/buildin", arg_false, "$the puller plugin is dynamic loadable"}, + {"plugin-puller", "/local/pcb/puller/buildin", arg_false, "$the puller plugin is a dynamic loadable"}, {"disable-edif", "/local/pcb/edif/enable", arg_false, "$do not compile the edif"}, {"buildin-edif", "/local/pcb/edif/buildin", arg_true, "$static link the edif plugin into the executable"}, - {"plugin-edif", "/local/pcb/edif/buildin", arg_false, "$the edif plugin is dynamic loadable"}, + {"plugin-edif", "/local/pcb/edif/buildin", arg_false, "$the edif plugin is a dynamic loadable"}, {"disable-djopt", "/local/pcb/djopt/enable", arg_false, "$do not compile the djopt"}, {"buildin-djopt", "/local/pcb/djopt/buildin", arg_true, "$static link the djopt plugin into the executable"}, - {"plugin-djopt", "/local/pcb/djopt/buildin", arg_false, "$the djopt plugin is dynamic loadable"}, + {"plugin-djopt", "/local/pcb/djopt/buildin", arg_false, "$the djopt plugin is a dynamic loadable"}, {"disable-mincut", "/local/pcb/mincut/enable", arg_false, "$do not compile the mincut"}, {"buildin-mincut", "/local/pcb/mincut/buildin", arg_true, "$static link the mincut plugin into the executable"}, - {"plugin-mincut", "/local/pcb/mincut/buildin", arg_false, "$the mincut plugin is dynamic loadable"}, + {"plugin-mincut", "/local/pcb/mincut/buildin", arg_false, "$the mincut plugin is a dynamic loadable"}, {"disable-toporouter", "/local/pcb/toporouter/enable", arg_false, "$do not compile the toporouter"}, {"buildin-toporouter", "/local/pcb/toporouter/buildin", arg_true, "$static link the toporouter plugin into the executable"}, - {"plugin-toporouter", "/local/pcb/toporouter/buildin", arg_false, "$the toporouter plugin is dynamic loadable"}, + {"plugin-toporouter", "/local/pcb/toporouter/buildin", arg_false, "$the toporouter plugin is a dynamic loadable"}, {"disable-oldactions", "/local/pcb/oldactions/enable", arg_false, "$do not compile the oldactions"}, {"buildin-oldactions", "/local/pcb/oldactions/buildin", arg_true, "$static link the oldactions plugin into the executable"}, - {"plugin-oldactions", "/local/pcb/oldactions/buildin", arg_false, "$the oldactions plugin is dynamic loadable"}, + {"plugin-oldactions", "/local/pcb/oldactions/buildin", arg_false, "$the oldactions plugin is a dynamic loadable"}, {"disable-renumber", "/local/pcb/renumber/enable", arg_false, "$do not compile the renumber action"}, {"buildin-renumber", "/local/pcb/renumber/buildin", arg_true, "$static link the renumber action into the executable"}, - {"plugin-renumber", "/local/pcb/renumber/buildin", arg_false, "$the renumber action is dynamic loadable plugin"}, + {"plugin-renumber", "/local/pcb/renumber/buildin", arg_false, "$the renumber action is a dynamic loadable plugin"}, {"disable-stroke", "/local/pcb/stroke/enable", arg_false, "$do not compile libstroke gestures"}, {"buildin-stroke", "/local/pcb/stroke/buildin", arg_true, "$static link libstroke gestures into the executable"}, - {"plugin-stroke", "/local/pcb/stroke/buildin", arg_false, "$libstroke gestures is dynamic loadable plugin"}, + {"plugin-stroke", "/local/pcb/stroke/buildin", arg_false, "$libstroke gestures is a dynamic loadable plugin"}, {"disable-import_sch", "/local/pcb/import_sch/enable", arg_false, "$do not compile the import schematics action"}, {"buildin-import_sch", "/local/pcb/import_sch/buildin", arg_true, "$static link the import schematics action into the executable"}, - {"plugin-import_sch", "/local/pcb/import_sch/buildin", arg_false, "$the import schematics action is dynamic loadable plugin"}, + {"plugin-import_sch", "/local/pcb/import_sch/buildin", arg_false, "$the import schematics action is a dynamic loadable plugin"}, + {"disable-export_ps", "/local/pcb/export_ps/enable", arg_false, "$do not compile the postscript exporter"}, + {"buildin-export_ps", "/local/pcb/export_ps/buildin", arg_true, "$static link the postscript exporter into the executable"}, + {"plugin-export_ps", "/local/pcb/export_ps/buildin", arg_false, "$the postscript exporter is a dynamic loadable plugin"}, + + {"disable-export_lpr", "/local/pcb/export_lpr/enable", arg_false, "$do not compile the lpr printer"}, + {"buildin-export_lpr", "/local/pcb/export_lpr/buildin", arg_true, "$static link the lpr printer into the executable"}, + {"plugin-export_lpr", "/local/pcb/export_lpr/buildin", arg_false, "$the lpr printer is a dynamic loadable plugin"}, + {NULL, NULL, NULL, NULL} }; @@ -196,6 +204,14 @@ put("/local/pcb/import_sch/enable", strue); put("/local/pcb/import_sch/buildin", strue); + db_mkdir("/local/pcb/export_ps"); + put("/local/pcb/export_ps/enable", strue); + put("/local/pcb/export_ps/buildin", strue); + + db_mkdir("/local/pcb/export_lpr"); + put("/local/pcb/export_lpr/enable", strue); + put("/local/pcb/export_lpr/buildin", strue); + return 0; } @@ -332,6 +348,14 @@ put("/local/global_cflags", tmp); } + /* some internal dependencies */ + if (!istrue(get("/local/pcb/export_ps/enable")) || !istrue(get("/local/pcb/export_ps/buildin"))) { + if (istrue(get("/local/pcb/export_lpr/enable"))) { + report_repeat("WARNING: disabling the lpr exporter because the ps exporter is not enabled as a buildin...\n"); + hook_custom_arg("disable-export_ps", NULL); + } + } + return 0; } @@ -459,14 +483,18 @@ plugin_stat("Autoplace: ", "/local/pcb/autoplace"); plugin_stat("Vendor drill mapping: ", "/local/pcb/vendordrill"); plugin_stat("Puller: ", "/local/pcb/puller"); - plugin_stat("Edif: ", "/local/pcb/edif"); plugin_stat("djopt: ", "/local/pcb/djopt"); plugin_stat("Mincut: ", "/local/pcb/mincut"); plugin_stat("renumber:", "/local/pcb/renumber"); plugin_stat("old actions:", "/local/pcb/oldactions"); - plugin_stat("import_sch:", "/local/pcb/import_sch"); plugin_stat("stroke:", "/local/pcb/stroke"); + plugin_stat("import_sch:", "/local/pcb/import_sch"); + plugin_stat("Edif: ", "/local/pcb/edif"); + + plugin_stat("export_ps:", "/local/pcb/export_ps"); + plugin_stat("export_lpr:", "/local/pcb/export_lpr"); + if (repeat != NULL) printf("\n%s\n", repeat); Index: trunk/src/Makefile.in =================================================================== --- trunk/src/Makefile.in (revision 1262) +++ trunk/src/Makefile.in (revision 1263) @@ -1,6 +1,3 @@ -# lpr bom gcode gerber nelma png ps - - # TODO default compiler flags put /local/pcb/CFLAGS cc/rdynamic append /local/pcb/CFLAGS cc/cflags @@ -137,12 +134,10 @@ include {Makefile.in.mod/lesstif} include {Makefile.in.mod/batch} include {Makefile.in.mod/bom} -include {Makefile.in.mod/ps} include {Makefile.in.mod/png} include {Makefile.in.mod/gerber} include {Makefile.in.mod/gcode} include {Makefile.in.mod/nelma} -include {Makefile.in.mod/lpr} include {../src_plugins/autoplace/Plug.tmpasm} include {../src_plugins/autoroute/Plug.tmpasm} @@ -157,7 +152,10 @@ include {../src_plugins/renumber/Plug.tmpasm} include {../src_plugins/stroke/Plug.tmpasm} include {../src_plugins/import_sch/Plug.tmpasm} +include {../src_plugins/export_ps/Plug.tmpasm} +include {../src_plugins/export_lpr/Plug.tmpasm} + append /local/pcb/CFLAGS /target/libs/sul/glib/cflags append /local/pcb/LIBS /target/libs/sul/glib/ldflags Index: trunk/src/Makefile.in.mod/ps =================================================================== --- trunk/src/Makefile.in.mod/ps (revision 1262) +++ trunk/src/Makefile.in.mod/ps (nonexistent) @@ -1,14 +0,0 @@ -append /local/pcb/HIDS {ps} -append /local/pcb/CFLAGS {-I./hid/ps} -append /local/pcb/OBJS [@ - hid/ps/ps.o - hid/ps/eps.o -@] - -append /local/pcb/ACTION_REG_SRC [@ - hid/ps/ps.c - hid/ps/eps.c - hid/ps/hid.conf -@] - - Index: trunk/src/Makefile.in.mod/lpr =================================================================== --- trunk/src/Makefile.in.mod/lpr (revision 1262) +++ trunk/src/Makefile.in.mod/lpr (nonexistent) @@ -1,4 +0,0 @@ -append /local/pcb/HIDS {lpr} -append /local/pcb/OBJS {hid/lpr/lpr.o} - - Index: trunk/src/hid/ps/ps.c =================================================================== --- trunk/src/hid/ps/ps.c (revision 1262) +++ trunk/src/hid/ps/ps.c (nonexistent) @@ -1,1602 +0,0 @@ -/* $Id$ */ - -#include "config.h" - -#include -#include /* not used */ -#include -#include -#include /* not used */ -#include - -#include "global.h" -#include "data.h" -#include "misc.h" -#include "error.h" -#include "draw.h" -#include "pcb-printf.h" - -#include "hid.h" -#include "../hidint.h" -#include "hid/common/hidnogui.h" -#include "hid/common/draw_helpers.h" -#include "../ps/ps.h" -#include "../../print.h" -#include "hid/common/hidinit.h" - - -RCSID("$Id$"); - -#define CRASH fprintf(stderr, "HID error: pcb called unimplemented PS function %s.\n", __FUNCTION__); abort() - -const char *ps_cookie = "ps HID"; - -static int ps_set_layer(const char *name, int group, int empty); -static void use_gc(hidGC gc); - -typedef struct hid_gc_struct { - HID *me_pointer; - EndCapStyle cap; - Coord width; - unsigned char r, g, b; - int erase; - int faded; -} hid_gc_struct; - -static const char *medias[] = { - "A0", "A1", "A2", "A3", "A4", "A5", - "A6", "A7", "A8", "A9", "A10", - "B0", "B1", "B2", "B3", "B4", "B5", - "B6", "B7", "B8", "B9", "B10", - "Letter", "11x17", "Ledger", - "Legal", "Executive", - "A-Size", "B-size", - "C-Size", "D-size", "E-size", - "US-Business_Card", "Intl-Business_Card", - 0 -}; - -typedef struct { - char *name; - Coord Width, Height; - Coord MarginX, MarginY; -} MediaType, *MediaTypePtr; - -/* - * Metric ISO sizes in mm. See http://en.wikipedia.org/wiki/ISO_paper_sizes - * - * A0 841 x 1189 - * A1 594 x 841 - * A2 420 x 594 - * A3 297 x 420 - * A4 210 x 297 - * A5 148 x 210 - * A6 105 x 148 - * A7 74 x 105 - * A8 52 x 74 - * A9 37 x 52 - * A10 26 x 37 - * - * B0 1000 x 1414 - * B1 707 x 1000 - * B2 500 x 707 - * B3 353 x 500 - * B4 250 x 353 - * B5 176 x 250 - * B6 125 x 176 - * B7 88 x 125 - * B8 62 x 88 - * B9 44 x 62 - * B10 31 x 44 - * - * awk '{printf(" {\"%s\", %d, %d, MARGINX, MARGINY},\n", $2, $3*100000/25.4, $5*100000/25.4)}' - * - * See http://en.wikipedia.org/wiki/Paper_size#Loose_sizes for some of the other sizes. The - * {A,B,C,D,E}-Size here are the ANSI sizes and not the architectural sizes. - */ - -#define MARGINX MIL_TO_COORD(500) -#define MARGINY MIL_TO_COORD(500) - -static MediaType media_data[] = { - {"A0", MM_TO_COORD(841), MM_TO_COORD(1189), MARGINX, MARGINY}, - {"A1", MM_TO_COORD(594), MM_TO_COORD(841), MARGINX, MARGINY}, - {"A2", MM_TO_COORD(420), MM_TO_COORD(594), MARGINX, MARGINY}, - {"A3", MM_TO_COORD(297), MM_TO_COORD(420), MARGINX, MARGINY}, - {"A4", MM_TO_COORD(210), MM_TO_COORD(297), MARGINX, MARGINY}, - {"A5", MM_TO_COORD(148), MM_TO_COORD(210), MARGINX, MARGINY}, - {"A6", MM_TO_COORD(105), MM_TO_COORD(148), MARGINX, MARGINY}, - {"A7", MM_TO_COORD(74), MM_TO_COORD(105), MARGINX, MARGINY}, - {"A8", MM_TO_COORD(52), MM_TO_COORD(74), MARGINX, MARGINY}, - {"A9", MM_TO_COORD(37), MM_TO_COORD(52), MARGINX, MARGINY}, - {"A10", MM_TO_COORD(26), MM_TO_COORD(37), MARGINX, MARGINY}, - {"B0", MM_TO_COORD(1000), MM_TO_COORD(1414), MARGINX, MARGINY}, - {"B1", MM_TO_COORD(707), MM_TO_COORD(1000), MARGINX, MARGINY}, - {"B2", MM_TO_COORD(500), MM_TO_COORD(707), MARGINX, MARGINY}, - {"B3", MM_TO_COORD(353), MM_TO_COORD(500), MARGINX, MARGINY}, - {"B4", MM_TO_COORD(250), MM_TO_COORD(353), MARGINX, MARGINY}, - {"B5", MM_TO_COORD(176), MM_TO_COORD(250), MARGINX, MARGINY}, - {"B6", MM_TO_COORD(125), MM_TO_COORD(176), MARGINX, MARGINY}, - {"B7", MM_TO_COORD(88), MM_TO_COORD(125), MARGINX, MARGINY}, - {"B8", MM_TO_COORD(62), MM_TO_COORD(88), MARGINX, MARGINY}, - {"B9", MM_TO_COORD(44), MM_TO_COORD(62), MARGINX, MARGINY}, - {"B10", MM_TO_COORD(31), MM_TO_COORD(44), MARGINX, MARGINY}, - {"Letter", INCH_TO_COORD(8.5), INCH_TO_COORD(11), MARGINX, MARGINY}, - {"11x17", INCH_TO_COORD(11), INCH_TO_COORD(17), MARGINX, MARGINY}, - {"Ledger", INCH_TO_COORD(17), INCH_TO_COORD(11), MARGINX, MARGINY}, - {"Legal", INCH_TO_COORD(8.5), INCH_TO_COORD(14), MARGINX, MARGINY}, - {"Executive", INCH_TO_COORD(7.5), INCH_TO_COORD(10), MARGINX, MARGINY}, - {"A-size", INCH_TO_COORD(8.5), INCH_TO_COORD(11), MARGINX, MARGINY}, - {"B-size", INCH_TO_COORD(11), INCH_TO_COORD(17), MARGINX, MARGINY}, - {"C-size", INCH_TO_COORD(17), INCH_TO_COORD(22), MARGINX, MARGINY}, - {"D-size", INCH_TO_COORD(22), INCH_TO_COORD(34), MARGINX, MARGINY}, - {"E-size", INCH_TO_COORD(34), INCH_TO_COORD(44), MARGINX, MARGINY}, - {"US-Business_Card", INCH_TO_COORD(3.5), INCH_TO_COORD(2.0), 0, 0}, - {"Intl-Business_Card", INCH_TO_COORD(3.375), INCH_TO_COORD(2.125), 0, 0} -}; - -#undef MARGINX -#undef MARGINY - -HID_Attribute ps_attribute_list[] = { - /* other HIDs expect this to be first. */ - -/* %start-doc options "91 Postscript Export" -@ftable @code -@item --psfile -Name of the postscript output file. Can contain a path. -@end ftable -%end-doc -*/ - {"psfile", "Postscript output file", - HID_String, 0, 0, {0, 0, 0}, 0, 0}, -#define HA_psfile 0 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@cindex drill-helper -@item --drill-helper -Print a centering target in large drill holes. -@end ftable -%end-doc -*/ - {"drill-helper", "Print a centering target in large drill holes", - HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, -#define HA_drillhelper 1 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@cindex align-marks -@item --align-marks -Print alignment marks on each sheet. This is meant to ease alignment during exposure. -@end ftable -%end-doc -*/ - {"align-marks", "Print alignment marks on each sheet", - HID_Boolean, 0, 0, {1, 0, 0}, 0, 0}, -#define HA_alignmarks 2 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@item --outline -Print the contents of the outline layer on each sheet. -@end ftable -%end-doc -*/ - {"outline", "Print outline on each sheet", - HID_Boolean, 0, 0, {1, 0, 0}, 0, 0}, -#define HA_outline 3 -/* %start-doc options "91 Postscript Export" -@ftable @code -@item --mirror -Print mirror image. -@end ftable -%end-doc -*/ - {"mirror", "Print mirror image of every page", - HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, -#define HA_mirror 4 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@item --fill-page -Scale output to make the board fit the page. -@end ftable -%end-doc -*/ - {"fill-page", "Scale board to fill page", - HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, -#define HA_fillpage 5 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@item --auto-mirror -Print mirror image of appropriate layers. -@end ftable -%end-doc -*/ - {"auto-mirror", "Print mirror image of appropriate layers", - HID_Boolean, 0, 0, {1, 0, 0}, 0, 0}, -#define HA_automirror 6 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@item --ps-color -Postscript output in color. -@end ftable -%end-doc -*/ - {"ps-color", "Prints in color", - HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, -#define HA_color 7 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@cindex ps-bloat -@item --ps-bloat -Amount to add to trace/pad/pin edges. -@end ftable -%end-doc -*/ - {"ps-bloat", "Amount to add to trace/pad/pin edges", - HID_Coord, -MIL_TO_COORD(100), MIL_TO_COORD(100), {0, 0, 0}, 0, 0}, -#define HA_psbloat 8 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@cindex ps-invert -@item --ps-invert -Draw objects as white-on-black. -@end ftable -%end-doc -*/ - {"ps-invert", "Draw objects as white-on-black", - HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, -#define HA_psinvert 9 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@item --media -Size of the media, the postscript is fitted to. The parameter -@code{} can be any of the standard names for paper size: @samp{A0} -to @samp{A10}, @samp{B0} to @samp{B10}, @samp{Letter}, @samp{11x17}, -@samp{Ledger}, @samp{Legal}, @samp{Executive}, @samp{A-Size}, @samp{B-size}, -@samp{C-Size}, @samp{D-size}, @samp{E-size}, @samp{US-Business_Card}, -@samp{Intl-Business_Card}. -@end ftable -%end-doc -*/ - {"media", "media type", - HID_Enum, 0, 0, {22, 0, 0}, medias, 0}, -#define HA_media 10 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@cindex psfade -@item --psfade -Fade amount for assembly drawings (0.0=missing, 1.0=solid). -@end ftable -%end-doc -*/ - {"psfade", "Fade amount for assembly drawings (0.0=missing, 1.0=solid)", - HID_Real, 0, 1, {0, 0, 0.40}, 0, 0}, -#define HA_psfade 11 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@item --scale -Scale value to compensate for printer sizing errors (1.0 = full scale). -@end ftable -%end-doc -*/ - {"scale", "Scale value to compensate for printer sizing errors (1.0 = full scale)", - HID_Real, 0.01, 4, {0, 0, 1.00}, 0, 0}, -#define HA_scale 12 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@cindex multi-file -@item --multi-file -Produce multiple files, one per page, instead of a single multi page file. -@end ftable -%end-doc -*/ - {"multi-file", "Produce multiple files, one per page, instead of a single file", - HID_Boolean, 0, 0, {0, 0, 0.40}, 0, 0}, -#define HA_multifile 13 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@item --xcalib -Paper width. Used for x-Axis calibration. -@end ftable -%end-doc -*/ - {"xcalib", "Paper width. Used for x-Axis calibration", - HID_Real, 0, 0, {0, 0, 1.0}, 0, 0}, -#define HA_xcalib 14 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@item --ycalib -Paper height. Used for y-Axis calibration. -@end ftable -%end-doc -*/ - {"ycalib", "Paper height. Used for y-Axis calibration", - HID_Real, 0, 0, {0, 0, 1.0}, 0, 0}, -#define HA_ycalib 15 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@item --drill-copper -Draw drill holes in pins / vias, instead of leaving solid copper. -@end ftable -%end-doc -*/ - {"drill-copper", "Draw drill holes in pins / vias, instead of leaving solid copper", - HID_Boolean, 0, 0, {1, 0, 0}, 0, 0}, -#define HA_drillcopper 16 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@cindex show-legend -@item --show-legend -Print file name and scale on printout. -@end ftable -%end-doc -*/ - {"show-legend", "Print file name and scale on printout", - HID_Boolean, 0, 0, {1, 0, 0}, 0, 0}, -#define HA_legend 17 - -/* %start-doc options "91 Postscript Export" -@ftable @code -@item --polygrid -If non-zero grid polygons instead of filling them with gridlines spaced as specified. -@end ftable -%end-doc -*/ - {"polygrid", "When non-zero: grid polygons instead of filling with gridlines spaced as specified", - HID_Real, 0, 10, {0, 0, 0.0}, 0, 0}, -#define HA_polygrid 18 - -}; - -#define NUM_OPTIONS (sizeof(ps_attribute_list)/sizeof(ps_attribute_list[0])) - -REGISTER_ATTRIBUTES(ps_attribute_list, ps_cookie) - -/* All file-scope data is in global struct */ - static struct { - double calibration_x, calibration_y; - - FILE *f; - int pagecount; - Coord linewidth; - bool print_group[MAX_LAYER]; - bool print_layer[MAX_LAYER]; - double fade_ratio; - bool multi_file; - Coord media_width, media_height, ps_width, ps_height; - - const char *filename; - bool drill_helper; - bool align_marks; - bool outline; - bool mirror; - bool fillpage; - bool automirror; - bool incolor; - bool doing_toc; - Coord bloat; - bool invert; - int media_idx; - bool drillcopper; - bool legend; - - LayerTypePtr outline_layer; - - double scale_factor; - - BoxType region; - - HID_Attr_Val ps_values[NUM_OPTIONS]; - - bool is_mask; - bool is_drill; - bool is_assy; - bool is_copper; - bool is_paste; - - double polygrid; - } global; - - static HID_Attribute *ps_get_export_options(int *n) -{ - static char *last_made_filename = 0; - if (PCB) - derive_default_filename(PCB->Filename, &ps_attribute_list[HA_psfile], ".ps", &last_made_filename); - - if (n) - *n = NUM_OPTIONS; - return ps_attribute_list; -} - -static int group_for_layer(int l) -{ - if (l < max_copper_layer + 2 && l >= 0) - return GetLayerGroupNumberByNumber(l); - /* else something unique */ - return max_group + 3 + l; -} - -static int layer_sort(const void *va, const void *vb) -{ - int a = *(int *) va; - int b = *(int *) vb; - int d = group_for_layer(b) - group_for_layer(a); - if (d) - return d; - return b - a; -} - -void ps_start_file(FILE * f) -{ - time_t currenttime = time(NULL); - - fprintf(f, "%%!PS-Adobe-3.0\n"); - - /* Document Structuring Conventions (DCS): */ - - /* Start General Header Comments: */ - - /* - * %%Title DCS provides text title for the document that is useful - * for printing banner pages. - */ - fprintf(f, "%%%%Title: %s\n", PCB->Filename); - - /* - * %%CreationDate DCS indicates the date and time the document was - * created. Neither the date nor time need be in any standard - * format. This comment is meant to be used purely for informational - * purposes, such as printing on banner pages. - */ - fprintf(f, "%%%%CreationDate: %s", asctime(localtime(¤ttime))); - - /* - * %%Creator DCS indicates the document creator, usually the name of - * the document composition software. - */ - fprintf(f, "%%%%Creator: PCB release: %s " VERSION "\n", Progname); - - /* - * %%Version DCS comment can be used to note the version and - * revision number of a document or resource. A document manager may - * wish to provide version control services, or allow substitution - * of compatible versions/revisions of a resource or document. - * - * The format should be in the form of 'procname': - * ::= < name> < version> < revision> - * < name> ::= < text> - * < version> ::= < real> - * < revision> ::= < uint> - * - * If a version numbering scheme is not used, these fields should - * still be filled with a dummy value of 0. - * - * There is currently no code in PCB to manage this revision number. - * - */ - fprintf(f, "%%%%Version: (PCB %s " VERSION ") 0.0 0\n", Progname); - - - /* - * %%PageOrder DCS is intended to help document managers determine - * the order of pages in the document file, which in turn enables a - * document manager optionally to reorder the pages. 'Ascend'-The - * pages are in ascending order for example, 1-2-3-4-5-6. - */ - fprintf(f, "%%%%PageOrder: Ascend\n"); - - /* - * %%Pages: < numpages> | (atend) < numpages> ::= < uint> (Total - * %%number of pages) - * - * %%Pages DCS defines the number of virtual pages that a document - * will image. (atend) defers the count until the end of the file, - * which is useful for dynamically generated contents. - */ - fprintf(f, "%%%%Pages: (atend)\n"); - - /* - * %%DocumentMedia: - * - * Substitute 0 or "" for N/A. Width and height are in points - * (1/72"). - * - * Media sizes are in PCB units - */ - pcb_fprintf(f, "%%%%DocumentMedia: %s %mi %mi 0 \"\" \"\"\n", - media_data[global.media_idx].name, - 72 * media_data[global.media_idx].Width, 72 * media_data[global.media_idx].Height); - pcb_fprintf(f, "%%%%DocumentPaperSizes: %s\n", media_data[global.media_idx].name); - - /* End General Header Comments. */ - - /* General Body Comments go here. Currently there are none. */ - - /* - * %%EndComments DCS indicates an explicit end to the header - * comments of the document. All global DCS's must preceded - * this. A blank line gives an implicit end to the comments. - */ - fprintf(f, "%%%%EndComments\n\n"); -} - -static void ps_end_file(FILE * f) -{ - /* - * %%Trailer DCS must only occur once at the end of the document - * script. Any post-processing or cleanup should be contained in - * the trailer of the document, which is anything that follows the - * %%Trailer comment. Any of the document level structure comments - * that were deferred by using the (atend) convention must be - * mentioned in the trailer of the document after the %%Trailer - * comment. - */ - fprintf(f, "%%%%Trailer\n"); - - /* - * %%Pages was deferred until the end of the document via the - * (atend) mentioned, in the General Header section. - */ - fprintf(f, "%%%%Pages: %d\n", global.pagecount); - - /* - * %%EOF DCS signifies the end of the document. When the document - * manager sees this comment, it issues an end-of-file signal to the - * PostScript interpreter. This is done so system-dependent file - * endings, such as Control-D and end-of-file packets, do not - * confuse the PostScript interpreter. - */ - fprintf(f, "%%%%EOF\n"); -} - -static FILE *psopen(const char *base, const char *which) -{ - FILE *ps_open_file; - char *buf, *suff, *buf2; - - if (!global.multi_file) - return fopen(base, "w"); - - buf = (char *) malloc(strlen(base) + strlen(which) + 5); - - suff = (char *) strrchr(base, '.'); - if (suff) { - strcpy(buf, base); - buf2 = strrchr(buf, '.'); - sprintf(buf2, ".%s.%s", which, suff + 1); - } - else { - sprintf(buf, "%s.%s.ps", base, which); - } - printf("PS: open %s\n", buf); - ps_open_file = fopen(buf, "w"); - free(buf); - return ps_open_file; -} - -/* This is used by other HIDs that use a postscript format, like lpr - or eps. */ -void ps_hid_export_to_file(FILE * the_file, HID_Attr_Val * options) -{ - int i; - static int saved_layer_stack[MAX_LAYER]; - FlagType save_thindraw; - - save_thindraw = PCB->Flags; - CLEAR_FLAG(THINDRAWFLAG, PCB); - CLEAR_FLAG(THINDRAWPOLYFLAG, PCB); - CLEAR_FLAG(CHECKPLANESFLAG, PCB); - - global.f = the_file; - global.drill_helper = options[HA_drillhelper].int_value; - global.align_marks = options[HA_alignmarks].int_value; - global.outline = options[HA_outline].int_value; - global.mirror = options[HA_mirror].int_value; - global.fillpage = options[HA_fillpage].int_value; - global.automirror = options[HA_automirror].int_value; - global.incolor = options[HA_color].int_value; - global.bloat = options[HA_psbloat].int_value; - global.invert = options[HA_psinvert].int_value; - global.fade_ratio = PCB_CLAMP(options[HA_psfade].real_value, 0, 1); - global.media_idx = options[HA_media].int_value; - global.media_width = media_data[global.media_idx].Width; - global.media_height = media_data[global.media_idx].Height; - global.ps_width = global.media_width - 2.0 * media_data[global.media_idx].MarginX; - global.ps_height = global.media_height - 2.0 * media_data[global.media_idx].MarginY; - global.scale_factor = options[HA_scale].real_value; - global.calibration_x = options[HA_xcalib].real_value; - global.calibration_y = options[HA_ycalib].real_value; - global.drillcopper = options[HA_drillcopper].int_value; - global.legend = options[HA_legend].int_value; - global.polygrid = options[HA_polygrid].real_value; - - if (the_file) - ps_start_file(the_file); - - if (global.fillpage) { - double zx, zy; - if (PCB->MaxWidth > PCB->MaxHeight) { - zx = global.ps_height / PCB->MaxWidth; - zy = global.ps_width / PCB->MaxHeight; - } - else { - zx = global.ps_height / PCB->MaxHeight; - zy = global.ps_width / PCB->MaxWidth; - } - global.scale_factor *= MIN(zx, zy); - } - - memset(global.print_group, 0, sizeof(global.print_group)); - memset(global.print_layer, 0, sizeof(global.print_layer)); - - global.outline_layer = NULL; - - for (i = 0; i < max_copper_layer; i++) { - LayerType *layer = PCB->Data->Layer + i; - if (!LAYER_IS_EMPTY(layer)) - global.print_group[GetLayerGroupNumberByNumber(i)] = 1; - - if (strcmp(layer->Name, "outline") == 0 || strcmp(layer->Name, "route") == 0) { - global.outline_layer = layer; - } - } - global.print_group[GetLayerGroupNumberByNumber(solder_silk_layer)] = 1; - global.print_group[GetLayerGroupNumberByNumber(component_silk_layer)] = 1; - for (i = 0; i < max_copper_layer; i++) - if (global.print_group[GetLayerGroupNumberByNumber(i)]) - global.print_layer[i] = 1; - - memcpy(saved_layer_stack, LayerStack, sizeof(LayerStack)); - qsort(LayerStack, max_copper_layer, sizeof(LayerStack[0]), layer_sort); - - global.linewidth = -1; - /* reset static vars */ - ps_set_layer(NULL, 0, -1); - use_gc(NULL); - - global.region.X1 = 0; - global.region.Y1 = 0; - global.region.X2 = PCB->MaxWidth; - global.region.Y2 = PCB->MaxHeight; - - if (!global.multi_file) { - /* %%Page DSC requires both a label and an ordinal */ - fprintf(the_file, "%%%%Page: TableOfContents 1\n"); - fprintf(the_file, "/Times-Roman findfont 24 scalefont setfont\n"); - fprintf(the_file, "/rightshow { /s exch def s stringwidth pop -1 mul 0 rmoveto s show } def\n"); - fprintf(the_file, "/y 72 9 mul def /toc { 100 y moveto show /y y 24 sub def } bind def\n"); - fprintf(the_file, "/tocp { /y y 12 sub def 90 y moveto rightshow } bind def\n"); - - global.doing_toc = 1; - global.pagecount = 1; /* 'pagecount' is modified by hid_expose_callback() call */ - hid_expose_callback(&ps_hid, &global.region, 0); - } - - global.pagecount = 1; /* Reset 'pagecount' if single file */ - global.doing_toc = 0; - ps_set_layer(NULL, 0, -1); /* reset static vars */ - hid_expose_callback(&ps_hid, &global.region, 0); - - if (the_file) - fprintf(the_file, "showpage\n"); - - memcpy(LayerStack, saved_layer_stack, sizeof(LayerStack)); - PCB->Flags = save_thindraw; -} - -static void ps_do_export(HID_Attr_Val * options) -{ - FILE *fh; - int save_ons[MAX_LAYER + 2]; - int i; - - if (!options) { - ps_get_export_options(0); - for (i = 0; i < NUM_OPTIONS; i++) - global.ps_values[i] = ps_attribute_list[i].default_val; - options = global.ps_values; - } - - global.filename = options[HA_psfile].str_value; - if (!global.filename) - global.filename = "pcb-out.ps"; - - global.multi_file = options[HA_multifile].int_value; - - if (global.multi_file) - fh = 0; - else { - fh = psopen(global.filename, "toc"); - if (!fh) { - perror(global.filename); - return; - } - } - - hid_save_and_show_layer_ons(save_ons); - ps_hid_export_to_file(fh, options); - hid_restore_layer_ons(save_ons); - - global.multi_file = 0; - if (fh) { - ps_end_file(fh); - fclose(fh); - } -} - -static void ps_parse_arguments(int *argc, char ***argv) -{ - hid_register_attributes(ps_attribute_list, NUM_OPTIONS, ps_cookie); - hid_parse_command_line(argc, argv); -} - -static void corner(FILE * fh, Coord x, Coord y, Coord dx, Coord dy) -{ - Coord len = MIL_TO_COORD(2000); - Coord len2 = MIL_TO_COORD(200); - Coord thick = 0; - /* - * Originally 'thick' used thicker lines. Currently is uses - * Postscript's "device thin" line - i.e. zero width means one - * device pixel. The code remains in case you want to make them - * thicker - it needs to offset everything so that the *edge* of the - * thick line lines up with the edge of the board, not the *center* - * of the thick line. - */ - - pcb_fprintf(fh, "gsave %mi setlinewidth %mi %mi translate %mi %mi scale\n", thick * 2, x, y, dx, dy); - pcb_fprintf(fh, "%mi %mi moveto %mi %mi %mi 0 90 arc %mi %mi lineto\n", len, thick, thick, thick, len2 + thick, thick, len); - if (dx < 0 && dy < 0) - pcb_fprintf(fh, "%mi %mi moveto 0 %mi rlineto\n", len2 * 2 + thick, thick, -len2); - fprintf(fh, "stroke grestore\n"); -} - -static int ps_set_layer(const char *name, int group, int empty) -{ - static int lastgroup = -1; - time_t currenttime; - int idx = (group >= 0 && group < max_group) - ? PCB->LayerGroups.Entries[group][0] - : group; - if (name == 0) - name = PCB->Data->Layer[idx].Name; - - if (empty == -1) - lastgroup = -1; - if (empty) - return 0; - - if (idx >= 0 && idx < max_copper_layer && !global.print_layer[idx]) - return 0; - - if (strcmp(name, "invisible") == 0) - return 0; - - global.is_drill = (SL_TYPE(idx) == SL_PDRILL || SL_TYPE(idx) == SL_UDRILL); - global.is_mask = (SL_TYPE(idx) == SL_MASK); - global.is_assy = (SL_TYPE(idx) == SL_ASSY); - global.is_copper = (SL_TYPE(idx) == 0); - global.is_paste = (SL_TYPE(idx) == SL_PASTE); -#if 0 - printf("Layer %s group %d drill %d mask %d\n", name, group, global.is_drill, global.is_mask); -#endif - - if (global.doing_toc) { - if (group < 0 || group != lastgroup) { - if (global.pagecount == 1) { - currenttime = time(NULL); - fprintf(global.f, "30 30 moveto (%s) show\n", PCB->Filename); - - fprintf(global.f, "(%d.) tocp\n", global.pagecount); - fprintf(global.f, "(Table of Contents \\(This Page\\)) toc\n"); - - fprintf(global.f, "(Created on %s) toc\n", asctime(localtime(¤ttime))); - fprintf(global.f, "( ) tocp\n"); - } - - global.pagecount++; - lastgroup = group; - fprintf(global.f, "(%d.) tocp\n", global.pagecount); - } - fprintf(global.f, "(%s) toc\n", name); - return 0; - } - - if (group < 0 || group != lastgroup) { - double boffset; - int mirror_this = 0; - lastgroup = group; - - if (global.pagecount != 0) { - pcb_fprintf(global.f, "showpage\n"); - } - global.pagecount++; - if (global.multi_file) { - if (global.f) { - ps_end_file(global.f); - fclose(global.f); - } - global.f = psopen(global.filename, layer_type_to_file_name(idx, FNS_fixed)); - if (!global.f) { - perror(global.filename); - return 0; - } - - ps_start_file(global.f); - } - - /* - * %%Page DSC comment marks the beginning of the PostScript - * language instructions that describe a particular - * page. %%Page: requires two arguments: a page label and a - * sequential page number. The label may be anything, but the - * ordinal page number must reflect the position of that page in - * the body of the PostScript file and must start with 1, not 0. - */ - fprintf(global.f, "%%%%Page: %s %d\n", layer_type_to_file_name(idx, FNS_fixed), global.pagecount); - - if (global.mirror) - mirror_this = !mirror_this; - if (global.automirror && ((idx >= 0 && group == GetLayerGroupNumberByNumber(solder_silk_layer)) - || (idx < 0 && SL_SIDE(idx) == SL_BOTTOM_SIDE))) - mirror_this = !mirror_this; - - fprintf(global.f, "/Helvetica findfont 10 scalefont setfont\n"); - if (global.legend) { - fprintf(global.f, "30 30 moveto (%s) show\n", PCB->Filename); - if (PCB->Name) - fprintf(global.f, "30 41 moveto (%s, %s) show\n", PCB->Name, layer_type_to_file_name(idx, FNS_fixed)); - else - fprintf(global.f, "30 41 moveto (%s) show\n", layer_type_to_file_name(idx, FNS_fixed)); - if (mirror_this) - fprintf(global.f, "( \\(mirrored\\)) show\n"); - - if (global.fillpage) - fprintf(global.f, "(, not to scale) show\n"); - else - fprintf(global.f, "(, scale = 1:%.3f) show\n", global.scale_factor); - } - fprintf(global.f, "newpath\n"); - - pcb_fprintf(global.f, "72 72 scale %mi %mi translate\n", global.media_width / 2, global.media_height / 2); - - boffset = global.media_height / 2; - if (PCB->MaxWidth > PCB->MaxHeight) { - fprintf(global.f, "90 rotate\n"); - boffset = global.media_width / 2; - fprintf(global.f, "%g %g scale %% calibration\n", global.calibration_y, global.calibration_x); - } - else - fprintf(global.f, "%g %g scale %% calibration\n", global.calibration_x, global.calibration_y); - - if (mirror_this) - fprintf(global.f, "1 -1 scale\n"); - - fprintf(global.f, "%g dup neg scale\n", (SL_TYPE(idx) == SL_FAB) ? 1.0 : global.scale_factor); - pcb_fprintf(global.f, "%mi %mi translate\n", -PCB->MaxWidth / 2, -PCB->MaxHeight / 2); - - /* Keep the drill list from falling off the left edge of the paper, - * even if it means some of the board falls off the right edge. - * If users don't want to make smaller boards, or use fewer drill - * sizes, they can always ignore this sheet. */ - if (SL_TYPE(idx) == SL_FAB) { - Coord natural = boffset - MIL_TO_COORD(500) - PCB->MaxHeight / 2; - Coord needed = PrintFab_overhang(); - pcb_fprintf(global.f, "%% PrintFab overhang natural %mi, needed %mi\n", natural, needed); - if (needed > natural) - pcb_fprintf(global.f, "0 %mi translate\n", needed - natural); - } - - if (global.invert) { - fprintf(global.f, "/gray { 1 exch sub setgray } bind def\n"); - fprintf(global.f, "/rgb { 1 1 3 { pop 1 exch sub 3 1 roll } for setrgbcolor } bind def\n"); - } - else { - fprintf(global.f, "/gray { setgray } bind def\n"); - fprintf(global.f, "/rgb { setrgbcolor } bind def\n"); - } - - if ((global.outline && !global.outline_layer) ||global.invert) { - pcb_fprintf(global.f, - "0 setgray 0 setlinewidth 0 0 moveto 0 " - "%mi lineto %mi %mi lineto %mi 0 lineto closepath %s\n", - PCB->MaxHeight, PCB->MaxWidth, PCB->MaxHeight, PCB->MaxWidth, global.invert ? "fill" : "stroke"); - } - - if (global.align_marks) { - corner(global.f, 0, 0, -1, -1); - corner(global.f, PCB->MaxWidth, 0, 1, -1); - corner(global.f, PCB->MaxWidth, PCB->MaxHeight, 1, 1); - corner(global.f, 0, PCB->MaxHeight, -1, 1); - } - - global.linewidth = -1; - use_gc(NULL); /* reset static vars */ - - fprintf(global.f, - "/ts 1 def\n" - "/ty ts neg def /tx 0 def /Helvetica findfont ts scalefont setfont\n" - "/t { moveto lineto stroke } bind def\n" - "/dr { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n" - " x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath stroke } bind def\n" - "/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n" - " x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def\n" - "/c { 0 360 arc fill } bind def\n" - "/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def\n"); - if (global.drill_helper) - pcb_fprintf(global.f, - "/dh { gsave %mi setlinewidth 0 gray %mi 0 360 arc stroke grestore} bind def\n", - (Coord) MIN_PINORVIAHOLE, (Coord) (MIN_PINORVIAHOLE * 3 / 2)); - } -#if 0 - /* Try to outsmart ps2pdf's heuristics for page rotation, by putting - * text on all pages -- even if that text is blank */ - if (SL_TYPE(idx) != SL_FAB) - fprintf(global.f, "gsave tx ty translate 1 -1 scale 0 0 moveto (Layer %s) show grestore newpath /ty ty ts sub def\n", name); - else - fprintf(global.f, "gsave tx ty translate 1 -1 scale 0 0 moveto ( ) show grestore newpath /ty ty ts sub def\n"); -#endif - - /* If we're printing a layer other than the outline layer, and - we want to "print outlines", and we have an outline layer, - print the outline layer on this layer also. */ - if (global.outline && - global.outline_layer != NULL && - global.outline_layer != PCB->Data->Layer + idx && strcmp(name, "outline") != 0 && strcmp(name, "route") != 0) { - DrawLayer(global.outline_layer, &global.region); - } - - return 1; -} - -static hidGC ps_make_gc(void) -{ - hidGC rv = (hidGC) calloc(1, sizeof(hid_gc_struct)); - rv->me_pointer = &ps_hid; - rv->cap = Trace_Cap; - return rv; -} - -static void ps_destroy_gc(hidGC gc) -{ - free(gc); -} - -static void ps_use_mask(int use_it) -{ - /* does nothing */ -} - -static void ps_set_color(hidGC gc, const char *name) -{ - if (strcmp(name, "erase") == 0 || strcmp(name, "drill") == 0) { - gc->r = gc->g = gc->b = 255; - gc->erase = 1; - } - else if (global.incolor) { - int r, g, b; - sscanf(name + 1, "%02x%02x%02x", &r, &g, &b); - gc->r = r; - gc->g = g; - gc->b = b; - gc->erase = 0; - } - else { - gc->r = gc->g = gc->b = 0; - gc->erase = 0; - } -} - -static void ps_set_line_cap(hidGC gc, EndCapStyle style) -{ - gc->cap = style; -} - -static void ps_set_line_width(hidGC gc, Coord width) -{ - gc->width = width; -} - -static void ps_set_draw_xor(hidGC gc, int xor_) -{ - ; -} - -static void ps_set_draw_faded(hidGC gc, int faded) -{ - gc->faded = faded; -} - -static void use_gc(hidGC gc) -{ - static int lastcap = -1; - static int lastcolor = -1; - - if (gc == NULL) { - lastcap = lastcolor = -1; - return; - } - if (gc->me_pointer != &ps_hid) { - fprintf(stderr, "Fatal: GC from another HID passed to ps HID\n"); - abort(); - } - if (global.linewidth != gc->width) { - pcb_fprintf(global.f, "%mi setlinewidth\n", gc->width + (gc->erase ? -2 : 2) * global.bloat); - global.linewidth = gc->width; - } - if (lastcap != gc->cap) { - int c; - switch (gc->cap) { - case Round_Cap: - case Trace_Cap: - c = 1; - break; - default: - case Square_Cap: - c = 2; - break; - } - fprintf(global.f, "%d setlinecap %d setlinejoin\n", c, c); - lastcap = gc->cap; - } -#define CBLEND(gc) (((gc->r)<<24)|((gc->g)<<16)|((gc->b)<<8)|(gc->faded)) - if (lastcolor != CBLEND(gc)) { - if (global.is_drill || global.is_mask) { - fprintf(global.f, "%d gray\n", gc->erase ? 0 : 1); - lastcolor = 0; - } - else { - double r, g, b; - r = gc->r; - g = gc->g; - b = gc->b; - if (gc->faded) { - r = (1 - global.fade_ratio) *255 + global.fade_ratio * r; - g = (1 - global.fade_ratio) *255 + global.fade_ratio * g; - b = (1 - global.fade_ratio) *255 + global.fade_ratio * b; - } - if (gc->r == gc->g && gc->g == gc->b) - fprintf(global.f, "%g gray\n", r / 255.0); - else - fprintf(global.f, "%g %g %g rgb\n", r / 255.0, g / 255.0, b / 255.0); - lastcolor = CBLEND(gc); - } - } -} - -static void ps_draw_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) -{ - use_gc(gc); - pcb_fprintf(global.f, "%mi %mi %mi %mi dr\n", x1, y1, x2, y2); -} - -static void ps_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); -static void ps_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius); - -static void ps_draw_line(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) -{ -#if 0 - /* If you're etching your own paste mask, this will reduce the - amount of brass you need to etch by drawing outlines for large - pads. See also ps_fill_rect. */ - if (is_paste && gc->width > 2500 && gc->cap == Square_Cap && (x1 == x2 || y1 == y2)) { - Coord t, w; - if (x1 > x2) { - t = x1; - x1 = x2; - x2 = t; - } - if (y1 > y2) { - t = y1; - y1 = y2; - y2 = t; - } - w = gc->width / 2; - ps_fill_rect(gc, x1 - w, y1 - w, x2 + w, y2 + w); - return; - } -#endif - if (x1 == x2 && y1 == y2) { - Coord w = gc->width / 2; - if (gc->cap == Square_Cap) - ps_fill_rect(gc, x1 - w, y1 - w, x1 + w, y1 + w); - else - ps_fill_circle(gc, x1, y1, w); - return; - } - use_gc(gc); - pcb_fprintf(global.f, "%mi %mi %mi %mi t\n", x1, y1, x2, y2); -} - -static void ps_draw_arc(hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle) -{ - Angle sa, ea; - if (delta_angle > 0) { - sa = start_angle; - ea = start_angle + delta_angle; - } - else { - sa = start_angle + delta_angle; - ea = start_angle; - } -#if 0 - printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n", cx, cy, width, height, start_angle, delta_angle, sa, ea); -#endif - use_gc(gc); - pcb_fprintf(global.f, "%ma %ma %mi %mi %mi %mi %g a\n", - sa, ea, -width, height, cx, cy, (double) (global.linewidth + 2 * global.bloat) /(double) width); -} - -static void ps_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius) -{ - use_gc(gc); - if (!gc->erase || !global.is_copper || global.drillcopper) { - if (gc->erase && global.is_copper && global.drill_helper && radius >= PCB->minDrill / 4) - radius = PCB->minDrill / 4; - pcb_fprintf(global.f, "%mi %mi %mi c\n", cx, cy, radius + (gc->erase ? -1 : 1) * global.bloat); - } -} - -static void ps_fill_polygon(hidGC gc, int n_coords, Coord * x, Coord * y) -{ - int i; - char *op = "moveto"; - use_gc(gc); - for (i = 0; i < n_coords; i++) { - pcb_fprintf(global.f, "%mi %mi %s\n", x[i], y[i], op); - op = "lineto"; - } - fprintf(global.f, "fill\n"); -} - -typedef struct { - Coord x1, y1, x2, y2; -} lseg_t; - -typedef struct { - Coord x, y; -} lpoint_t; - -#define minmax(val, min, max) \ -do { \ - if (val < min) min = val; \ - if (val > max) max = val; \ -} while(0) - -#define lsegs_append(x1_, y1_, x2_, y2_) \ -do { \ - if (y1_ < y2_) { \ - lsegs[lsegs_used].x1 = x1_; \ - lsegs[lsegs_used].y1 = y1_; \ - lsegs[lsegs_used].x2 = x2_; \ - lsegs[lsegs_used].y2 = y2_; \ - } \ - else { \ - lsegs[lsegs_used].x2 = x1_; \ - lsegs[lsegs_used].y2 = y1_; \ - lsegs[lsegs_used].x1 = x2_; \ - lsegs[lsegs_used].y1 = y2_; \ - } \ - lsegs_used++; \ - minmax(y1_, lsegs_ymin, lsegs_ymax); \ - minmax(y2_, lsegs_ymin, lsegs_ymax); \ - minmax(x1_, lsegs_xmin, lsegs_xmax); \ - minmax(x2_, lsegs_xmin, lsegs_xmax); \ -} while(0) - -#define lseg_line(x1_, y1_, x2_, y2_) \ - do { \ - fprintf(global.f, "newpath\n"); \ - pcb_fprintf(global.f, "%mi %mi moveto\n", x1_, y1_); \ - pcb_fprintf(global.f, "%mi %mi lineto\n", x2_, y2_); \ - fprintf (global.f, "stroke\n"); \ - } while(0) - -int coord_comp(const void *c1_, const void *c2_) -{ - const Coord *c1 = c1_, *c2 = c2_; - return *c1 < *c2; -} - -static void ps_fill_pcb_polygon(hidGC gc, PolygonType * poly, const BoxType * clip_box) -{ - /* Ignore clip_box, just draw everything */ - - VNODE *v; - PLINE *pl; - char *op; - int len; - double POLYGRID = ps_attribute_list[HA_polygrid].default_val.real_value; - - use_gc(gc); - - pl = poly->Clipped->contours; - len = 0; - if (POLYGRID > 0.1) - POLYGRID *= 1000000.0; - - do { - v = pl->head.next; - if (POLYGRID > 0.1) - fprintf(global.f, "closepath\n"); - op = "moveto"; - do { - pcb_fprintf(global.f, "%mi %mi %s\n", v->point[0], v->point[1], op); - op = "lineto"; - len++; - } - while ((v = v->next) != pl->head.next); - len++; - } - while ((pl = pl->next) != NULL); - - if (POLYGRID > 0.1) { - Coord y, x, lx, ly, fx, fy, lsegs_xmin, lsegs_xmax, lsegs_ymin, lsegs_ymax; - lseg_t *lsegs = alloca(sizeof(lseg_t) * len); - Coord *lpoints = alloca(sizeof(Coord) * len); - int lsegs_used = 0; - - lsegs_xmin = -1000000000; - lsegs_ymin = -1000000000; - lsegs_xmax = +1000000000; - lsegs_ymax = +1000000000; - - /* save all line segs in an array */ - pl = poly->Clipped->contours; - do { - v = pl->head.next; - fx = v->point[0]; - fy = v->point[1]; - goto start1; - do { - lsegs_append(lx, ly, v->point[0], v->point[1]); - start1:; - lx = v->point[0]; - ly = v->point[1]; - } while ((v = v->next) != pl->head.next); - lsegs_append(lx, ly, fx, fy); - } while ((pl = pl->next) != NULL); - - - - - fprintf(global.f, "%% POLYGRID2\n"); - fprintf(global.f, "gsave\n"); - fprintf(global.f, "0.0015 setlinewidth\n"); - fprintf(global.f, "closepath\n"); - fprintf(global.f, "stroke\n"); - - for (y = lsegs_ymin; y < lsegs_ymax; y += POLYGRID) { - int pts, n; -/* pcb_fprintf(global.f, "%% gridline at y %mi\n", y);*/ - retry1:; - if (y > lsegs_ymax) - break; - pts = 0; - for (n = 0; n < lsegs_used; n++) { - if ((lsegs[n].y1 <= y) && (lsegs[n].y2 >= y)) { - if ((lsegs[n].y2 == lsegs[n].y1) || (lsegs[n].y1 == y) || (lsegs[n].y2 == y)) { - y += POLYGRID / 100.0; - goto retry1; - } - x = lsegs[n].x1 + (lsegs[n].x2 - lsegs[n].x1) * (y - lsegs[n].y1) / (lsegs[n].y2 - lsegs[n].y1); - lpoints[pts] = x; - pts++; - } - } - if ((pts % 2) != 0) { - y += POLYGRID / 100.0; - goto retry1; - } - if (pts > 1) { - qsort(lpoints, pts, sizeof(Coord), coord_comp); - for (n = 0; n < pts; n += 2) - lseg_line(lpoints[n], y, lpoints[n + 1], y); - } - } - - for (x = lsegs_xmin; x < lsegs_xmax; x += POLYGRID) { - int pts, n; -/* pcb_fprintf(global.f, "%% gridline at y %mi\n", y); */ - retry2:; - if (x > lsegs_xmax) - break; - pts = 0; - for (n = 0; n < lsegs_used; n++) { - if (((lsegs[n].x1 <= x) && (lsegs[n].x2 >= x)) || ((lsegs[n].x1 >= x) && (lsegs[n].x2 <= x))) { - if ((lsegs[n].x2 == lsegs[n].x1) || (lsegs[n].x1 == x) || (lsegs[n].x2 == x)) { - x += POLYGRID / 100.0; - goto retry2; - } - y = lsegs[n].y1 + (lsegs[n].y2 - lsegs[n].y1) * (x - lsegs[n].x1) / (lsegs[n].x2 - lsegs[n].x1); - lpoints[pts] = y; - pts++; - } - } - if ((pts % 2) != 0) { - x += POLYGRID / 100.0; - goto retry2; - } - if ((pts > 1)) { - qsort(lpoints, pts, sizeof(Coord), coord_comp); - for (n = 0; n < pts; n += 2) - lseg_line(x, lpoints[n], x, lpoints[n + 1]); - } - } - - - fprintf(global.f, "grestore\nnewpath\n"); - } - else - fprintf(global.f, "fill\n"); -} - -static void ps_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) -{ - use_gc(gc); - if (x1 > x2) { - Coord t = x1; - x1 = x2; - x2 = t; - } - if (y1 > y2) { - Coord t = y1; - y1 = y2; - y2 = t; - } -#if 0 - /* See comment in ps_draw_line. */ - if (is_paste && (x2 - x1) > 2500 && (y2 - y1) > 2500) { - linewidth = 1000; - lastcap = Round_Cap; - fprintf(f, "1000 setlinewidth 1 setlinecap 1 setlinejoin\n"); - fprintf(f, "%d %d moveto %d %d lineto %d %d lineto %d %d lineto closepath stroke\n", - x1 + 500 - bloat, y1 + 500 - bloat, - x1 + 500 - bloat, y2 - 500 + bloat, x2 - 500 + bloat, y2 - 500 + bloat, x2 - 500 + bloat, y1 + 500 - bloat); - return; - } -#endif - pcb_fprintf(global.f, "%mi %mi %mi %mi r\n", x1 - global.bloat, y1 - global.bloat, x2 + global.bloat, y2 + global.bloat); -} - -HID_Attribute ps_calib_attribute_list[] = { - {"lprcommand", "Command to print", - HID_String, 0, 0, {0, 0, 0}, 0, 0}, -}; - -static const char *const calib_lines[] = { - "%!PS-Adobe-3.0\n", - "%%Title: Calibration Page\n", - "%%PageOrder: Ascend\n", - "%%Pages: 1\n", - "%%EndComments\n", - "\n", - "%%Page: Calibrate 1\n", - "72 72 scale\n", - "\n", - "0 setlinewidth\n", - "0.375 0.375 moveto\n", - "8.125 0.375 lineto\n", - "8.125 10.625 lineto\n", - "0.375 10.625 lineto\n", - "closepath stroke\n", - "\n", - "0.5 0.5 translate\n", - "0.001 setlinewidth\n", - "\n", - "/Times-Roman findfont 0.2 scalefont setfont\n", - "\n", - "/sign {\n", - " 0 lt { -1 } { 1 } ifelse\n", - "} def\n", - "\n", - "/cbar {\n", - " /units exch def\n", - " /x exch def\n", - " /y exch def \n", - "\n", - " /x x sign 0.5 mul def\n", - "\n", - " 0 setlinewidth\n", - " newpath x y 0.25 0 180 arc gsave 0.85 setgray fill grestore closepath stroke\n", - " newpath x 0 0.25 180 360 arc gsave 0.85 setgray fill grestore closepath stroke\n", - " 0.001 setlinewidth\n", - "\n", - " x 0 moveto\n", - " x y lineto\n", - "% -0.07 -0.2 rlineto 0.14 0 rmoveto -0.07 0.2 rlineto\n", - " x y lineto\n", - " -0.1 0 rlineto 0.2 0 rlineto\n", - " stroke\n", - " x 0 moveto\n", - "% -0.07 0.2 rlineto 0.14 0 rmoveto -0.07 -0.2 rlineto\n", - " x 0 moveto\n", - " -0.1 0 rlineto 0.2 0 rlineto\n", - " stroke\n", - "\n", - " x 0.1 add\n", - " y 0.2 sub moveto\n", - " units show\n", - "} bind def\n", - "\n", - "/y 9 def\n", - "/t {\n", - " /str exch def\n", - " 1.5 y moveto str show\n", - " /y y 0.25 sub def\n", - "} bind def\n", - "\n", - "(Please measure ONE of the horizontal lines, in the units indicated for)t\n", - "(that line, and enter that value as X. Similarly, measure ONE of the)t\n", - "(vertical lines and enter that value as Y. Measurements should be)t\n", - "(between the flat faces of the semicircles.)t\n", - "()t\n", - "(The large box is 10.25 by 7.75 inches)t\n", - "\n", - "/in { } bind def\n", - "/cm { 2.54 div } bind def\n", - "/mm { 25.4 div } bind def\n", - "\n", - 0 -}; - -static int guess(double val, double close_to, double *calib) -{ - if (val >= close_to * 0.9 && val <= close_to * 1.1) { - *calib = close_to / val; - return 0; - } - return 1; -} - -void ps_calibrate_1(double xval, double yval, int use_command) -{ - HID_Attr_Val vals[3]; - FILE *ps_cal_file; - int used_popen = 0, c; - - if (xval > 0 && yval > 0) { - if (guess(xval, 4, &global.calibration_x)) - if (guess(xval, 15, &global.calibration_x)) - if (guess(xval, 7.5, &global.calibration_x)) { - if (xval < 2) - ps_attribute_list[HA_xcalib].default_val.real_value = global.calibration_x = xval; - else - Message("X value of %g is too far off.\n" "Expecting it near: 1.0, 4.0, 15.0, 7.5\n", xval); - } - if (guess(yval, 4, &global.calibration_y)) - if (guess(yval, 20, &global.calibration_y)) - if (guess(yval, 10, &global.calibration_y)) { - if (yval < 2) - ps_attribute_list[HA_ycalib].default_val.real_value = global.calibration_y = yval; - else - Message("Y value of %g is too far off.\n" "Expecting it near: 1.0, 4.0, 20.0, 10.0\n", yval); - } - return; - } - - if (ps_calib_attribute_list[0].default_val.str_value == NULL) { - ps_calib_attribute_list[0].default_val.str_value = strdup("lpr"); - } - - if (gui-> - attribute_dialog(ps_calib_attribute_list, 1, vals, _("Print Calibration Page"), - _("Generates a printer calibration page"))) - return; - - if (use_command || strchr(vals[0].str_value, '|')) { - const char *cmd = vals[0].str_value; - while (*cmd == ' ' || *cmd == '|') - cmd++; - ps_cal_file = popen(cmd, "w"); - used_popen = 1; - } - else - ps_cal_file = fopen(vals[0].str_value, "w"); - - for (c = 0; calib_lines[c]; c++) - fputs(calib_lines[c], ps_cal_file); - - fprintf(ps_cal_file, "4 in 0.5 (Y in) cbar\n"); - fprintf(ps_cal_file, "20 cm 1.5 (Y cm) cbar\n"); - fprintf(ps_cal_file, "10 in 2.5 (Y in) cbar\n"); - fprintf(ps_cal_file, "-90 rotate\n"); - fprintf(ps_cal_file, "4 in -0.5 (X in) cbar\n"); - fprintf(ps_cal_file, "15 cm -1.5 (X cm) cbar\n"); - fprintf(ps_cal_file, "7.5 in -2.5 (X in) cbar\n"); - - fprintf(ps_cal_file, "showpage\n"); - - fprintf(ps_cal_file, "%%%%EOF\n"); - - if (used_popen) - pclose(ps_cal_file); - else - fclose(ps_cal_file); -} - -static void ps_calibrate(double xval, double yval) -{ - ps_calibrate_1(xval, yval, 0); -} - -static void ps_set_crosshair(int x, int y, int action) -{ -} - -static int ActionPSCalib(int argc, char **argv, Coord x, Coord y) -{ - ps_calibrate(0.0, 0.0); - return 0; -} - -HID_Action hidps_action_list[] = { - {"pscalib", 0, ActionPSCalib} -}; - -REGISTER_ACTIONS(hidps_action_list, ps_cookie) - - -#include "dolists.h" - -HID ps_hid; -void ps_ps_init(HID * hid) -{ - hid->get_export_options = ps_get_export_options; - hid->do_export = ps_do_export; - hid->parse_arguments = ps_parse_arguments; - hid->set_layer = ps_set_layer; - hid->make_gc = ps_make_gc; - hid->destroy_gc = ps_destroy_gc; - hid->use_mask = ps_use_mask; - hid->set_color = ps_set_color; - hid->set_line_cap = ps_set_line_cap; - hid->set_line_width = ps_set_line_width; - hid->set_draw_xor = ps_set_draw_xor; - hid->set_draw_faded = ps_set_draw_faded; - hid->draw_line = ps_draw_line; - hid->draw_arc = ps_draw_arc; - hid->draw_rect = ps_draw_rect; - hid->fill_circle = ps_fill_circle; - hid->fill_polygon = ps_fill_polygon; - hid->fill_pcb_polygon = ps_fill_pcb_polygon; - hid->fill_rect = ps_fill_rect; - hid->calibrate = ps_calibrate; - hid->set_crosshair = ps_set_crosshair; - - REGISTER_ACTIONS(hidps_action_list, ps_cookie) -} - -void hid_ps_init() -{ - memset(&ps_hid, 0, sizeof(HID)); - - common_nogui_init(&ps_hid); - common_draw_helpers_init(&ps_hid); - ps_ps_init(&ps_hid); - - ps_hid.struct_size = sizeof(HID); - ps_hid.name = "ps"; - ps_hid.description = "Postscript export"; - ps_hid.exporter = 1; - ps_hid.poly_before = 1; - - hid_register_hid(&ps_hid); - - hid_eps_init(); -} Index: trunk/src/hid/ps/eps.c =================================================================== --- trunk/src/hid/ps/eps.c (revision 1262) +++ trunk/src/hid/ps/eps.c (nonexistent) @@ -1,630 +0,0 @@ -/* $Id$ */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "global.h" -#include "data.h" -#include "misc.h" -#include "pcb-printf.h" - -#include "hid.h" -#include "../hidint.h" -#include "hid/common/hidnogui.h" -#include "hid/common/draw_helpers.h" -#include "../ps/ps.h" -#include "hid/common/hidinit.h" - - -RCSID("$Id$"); - -#define CRASH fprintf(stderr, "HID error: pcb called unimplemented EPS function %s.\n", __FUNCTION__); abort() - -/*----------------------------------------------------------------------------*/ -/* Function prototypes */ -/*----------------------------------------------------------------------------*/ -static HID_Attribute *eps_get_export_options(int *n); -static void eps_do_export(HID_Attr_Val * options); -static void eps_parse_arguments(int *argc, char ***argv); -static int eps_set_layer(const char *name, int group, int empty); -static hidGC eps_make_gc(void); -static void eps_destroy_gc(hidGC gc); -static void eps_use_mask(int use_it); -static void eps_set_color(hidGC gc, const char *name); -static void eps_set_line_cap(hidGC gc, EndCapStyle style); -static void eps_set_line_width(hidGC gc, Coord width); -static void eps_set_draw_xor(hidGC gc, int _xor); -static void eps_draw_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); -static void eps_draw_line(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); -static void eps_draw_arc(hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle); -static void eps_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); -static void eps_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius); -static void eps_fill_polygon(hidGC gc, int n_coords, Coord * x, Coord * y); -static void eps_calibrate(double xval, double yval); -static void eps_set_crosshair(int x, int y, int action); -/*----------------------------------------------------------------------------*/ - -typedef struct hid_gc_struct { - EndCapStyle cap; - Coord width; - int color; - int erase; -} hid_gc_struct; - -static HID eps_hid; - -static FILE *f = 0; -static Coord linewidth = -1; -static int lastcap = -1; -static int lastcolor = -1; -static int print_group[MAX_LAYER]; -static int print_layer[MAX_LAYER]; -static int fast_erase = -1; - -static HID_Attribute eps_attribute_list[] = { - /* other HIDs expect this to be first. */ - -/* %start-doc options "92 Encapsulated Postscript Export" -@ftable @code -@item --eps-file -Name of the encapsulated postscript output file. Can contain a path. -@end ftable -%end-doc -*/ - {"eps-file", "Encapsulated Postscript output file", - HID_String, 0, 0, {0, 0, 0}, 0, 0}, -#define HA_psfile 0 - -/* %start-doc options "92 Encapsulated Postscript Export" -@ftable @code -@item --eps-scale -Scale EPS output by the parameter @samp{num}. -@end ftable -%end-doc -*/ - {"eps-scale", "EPS scale", - HID_Real, 0, 100, {0, 0, 1.0}, 0, 0}, -#define HA_scale 1 - -/* %start-doc options "92 Encapsulated Postscript Export" -@ftable @code -@cindex as-shown (EPS) -@item --as-shown -Export layers as shown on screen. -@end ftable -%end-doc -*/ - {"as-shown", "Export layers as shown on screen", - HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, -#define HA_as_shown 2 - -/* %start-doc options "92 Encapsulated Postscript Export" -@ftable @code -@item --monochrome -Convert output to monochrome. -@end ftable -%end-doc -*/ - {"monochrome", "Convert to monochrome", - HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, -#define HA_mono 3 - -/* %start-doc options "92 Encapsulated Postscript Export" -@ftable @code -@cindex only-visible -@item --only-visible -Limit the bounds of the EPS file to the visible items. -@end ftable -%end-doc -*/ - {"only-visible", "Limit the bounds of the EPS file to the visible items", - HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, -#define HA_only_visible 4 -}; - -#define NUM_OPTIONS (sizeof(eps_attribute_list)/sizeof(eps_attribute_list[0])) - -REGISTER_ATTRIBUTES(eps_attribute_list, ps_cookie) - - static HID_Attr_Val eps_values[NUM_OPTIONS]; - - static HID_Attribute *eps_get_export_options(int *n) -{ - static char *last_made_filename = 0; - - if (PCB) - derive_default_filename(PCB->Filename, &eps_attribute_list[HA_psfile], ".eps", &last_made_filename); - - if (n) - *n = NUM_OPTIONS; - return eps_attribute_list; -} - -static int comp_layer, solder_layer; - -static int group_for_layer(int l) -{ - if (l < max_copper_layer + 2 && l >= 0) - return GetLayerGroupNumberByNumber(l); - /* else something unique */ - return max_group + 3 + l; -} - -static int layer_sort(const void *va, const void *vb) -{ - int a = *(int *) va; - int b = *(int *) vb; - int al = group_for_layer(a); - int bl = group_for_layer(b); - int d = bl - al; - - if (a >= 0 && a <= max_copper_layer + 1) { - int aside = (al == solder_layer ? 0 : al == comp_layer ? 2 : 1); - int bside = (bl == solder_layer ? 0 : bl == comp_layer ? 2 : 1); - if (bside != aside) - return bside - aside; - } - if (d) - return d; - return b - a; -} - -static const char *filename; -static BoxType *bounds; -static int in_mono, as_shown; - -void eps_hid_export_to_file(FILE * the_file, HID_Attr_Val * options) -{ - int i; - static int saved_layer_stack[MAX_LAYER]; - BoxType region; - FlagType save_thindraw; - - save_thindraw = PCB->Flags; - CLEAR_FLAG(THINDRAWFLAG, PCB); - CLEAR_FLAG(THINDRAWPOLYFLAG, PCB); - CLEAR_FLAG(CHECKPLANESFLAG, PCB); - - f = the_file; - - region.X1 = 0; - region.Y1 = 0; - region.X2 = PCB->MaxWidth; - region.Y2 = PCB->MaxHeight; - - if (options[HA_only_visible].int_value) - bounds = GetDataBoundingBox(PCB->Data); - else - bounds = ®ion; - - memset(print_group, 0, sizeof(print_group)); - memset(print_layer, 0, sizeof(print_layer)); - - /* Figure out which layers actually have stuff on them. */ - for (i = 0; i < max_copper_layer; i++) { - LayerType *layer = PCB->Data->Layer + i; - if (layer->On) - if (!LAYER_IS_EMPTY(layer)) - print_group[GetLayerGroupNumberByNumber(i)] = 1; - } - - /* Now, if only one layer has real stuff on it, we can use the fast - erase logic. Otherwise, we have to use the expensive multi-mask - erase. */ - fast_erase = 0; - for (i = 0; i < max_group; i++) - if (print_group[i]) - fast_erase++; - - /* If NO layers had anything on them, at least print the component - layer to get the pins. */ - if (fast_erase == 0) { - print_group[GetLayerGroupNumberByNumber(component_silk_layer)] = 1; - fast_erase = 1; - } - - /* "fast_erase" is 1 if we can just paint white to erase. */ - fast_erase = fast_erase == 1 ? 1 : 0; - - /* Now, for each group we're printing, mark its layers for - printing. */ - for (i = 0; i < max_copper_layer; i++) - if (print_group[GetLayerGroupNumberByNumber(i)]) - print_layer[i] = 1; - - if (fast_erase) { - eps_hid.poly_before = 1; - eps_hid.poly_after = 0; - } - else { - eps_hid.poly_before = 0; - eps_hid.poly_after = 1; - } - - memcpy(saved_layer_stack, LayerStack, sizeof(LayerStack)); - as_shown = options[HA_as_shown].int_value; - if (!options[HA_as_shown].int_value) { - comp_layer = GetLayerGroupNumberByNumber(component_silk_layer); - solder_layer = GetLayerGroupNumberByNumber(solder_silk_layer); - qsort(LayerStack, max_copper_layer, sizeof(LayerStack[0]), layer_sort); - } - fprintf(f, "%%!PS-Adobe-3.0 EPSF-3.0\n"); - linewidth = -1; - lastcap = -1; - lastcolor = -1; - - in_mono = options[HA_mono].int_value; - -#define pcb2em(x) 1 + COORD_TO_INCH (x) * 72.0 * options[HA_scale].real_value - fprintf(f, "%%%%BoundingBox: 0 0 %f %f\n", pcb2em(bounds->X2 - bounds->X1), pcb2em(bounds->Y2 - bounds->Y1)); -#undef pcb2em - fprintf(f, "%%%%Pages: 1\n"); - fprintf(f, "save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def\n"); - fprintf(f, "%%%%EndProlog\n"); - fprintf(f, "%%%%Page: 1 1\n"); - fprintf(f, "%%%%BeginDocument: %s\n\n", filename); - - fprintf(f, "72 72 scale\n"); - fprintf(f, "1 dup neg scale\n"); - fprintf(f, "%g dup scale\n", options[HA_scale].real_value); - pcb_fprintf(f, "%mi %mi translate\n", -bounds->X1, -bounds->Y2); - if (options[HA_as_shown].int_value && Settings.ShowSolderSide) - pcb_fprintf(f, "-1 1 scale %mi 0 translate\n", bounds->X1 - bounds->X2); - linewidth = -1; - lastcap = -1; - lastcolor = -1; -#define Q (Coord) MIL_TO_COORD(10) - pcb_fprintf(f, - "/nclip { %mi %mi moveto %mi %mi lineto %mi %mi lineto %mi %mi lineto %mi %mi lineto eoclip newpath } def\n", - bounds->X1 - Q, bounds->Y1 - Q, bounds->X1 - Q, bounds->Y2 + Q, - bounds->X2 + Q, bounds->Y2 + Q, bounds->X2 + Q, bounds->Y1 - Q, bounds->X1 - Q, bounds->Y1 - Q); -#undef Q - fprintf(f, "/t { moveto lineto stroke } bind def\n"); - fprintf(f, "/tc { moveto lineto strokepath nclip } bind def\n"); - fprintf(f, "/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n"); - fprintf(f, " x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def\n"); - fprintf(f, "/c { 0 360 arc fill } bind def\n"); - fprintf(f, "/cc { 0 360 arc nclip } bind def\n"); - fprintf(f, "/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def\n"); - - hid_expose_callback(&eps_hid, bounds, 0); - - fprintf(f, "showpage\n"); - - fprintf(f, "%%%%EndDocument\n"); - fprintf(f, "%%%%Trailer\n"); - fprintf(f, "cleartomark countdictstack exch sub { end } repeat restore\n"); - fprintf(f, "%%%%EOF\n"); - - memcpy(LayerStack, saved_layer_stack, sizeof(LayerStack)); - PCB->Flags = save_thindraw; -} - -static void eps_do_export(HID_Attr_Val * options) -{ - int i; - int save_ons[MAX_LAYER + 2]; - - if (!options) { - eps_get_export_options(0); - for (i = 0; i < NUM_OPTIONS; i++) - eps_values[i] = eps_attribute_list[i].default_val; - options = eps_values; - } - - filename = options[HA_psfile].str_value; - if (!filename) - filename = "pcb-out.eps"; - - f = fopen(filename, "w"); - if (!f) { - perror(filename); - return; - } - - if (!options[HA_as_shown].int_value) - hid_save_and_show_layer_ons(save_ons); - eps_hid_export_to_file(f, options); - if (!options[HA_as_shown].int_value) - hid_restore_layer_ons(save_ons); - - fclose(f); -} - -static void eps_parse_arguments(int *argc, char ***argv) -{ - hid_register_attributes(eps_attribute_list, sizeof(eps_attribute_list) / sizeof(eps_attribute_list[0]), ps_cookie); - hid_parse_command_line(argc, argv); -} - -static int is_mask; -static int is_paste; -static int is_drill; - -static int eps_set_layer(const char *name, int group, int empty) -{ - int idx = (group >= 0 && group < max_group) ? PCB->LayerGroups.Entries[group][0] : group; - if (name == 0) - name = PCB->Data->Layer[idx].Name; - - if (idx >= 0 && idx < max_copper_layer && !print_layer[idx]) - return 0; - if (SL_TYPE(idx) == SL_ASSY || SL_TYPE(idx) == SL_FAB) - return 0; - - if (strcmp(name, "invisible") == 0) - return 0; - - is_drill = (SL_TYPE(idx) == SL_PDRILL || SL_TYPE(idx) == SL_UDRILL); - is_mask = (SL_TYPE(idx) == SL_MASK); - is_paste = (SL_TYPE(idx) == SL_PASTE); - - if (is_mask || is_paste) - return 0; -#if 0 - printf("Layer %s group %d drill %d mask %d\n", name, group, is_drill, is_mask); -#endif - fprintf(f, "%% Layer %s group %d drill %d mask %d\n", name, group, is_drill, is_mask); - - if (as_shown) { - switch (idx) { - case SL(SILK, TOP): - case SL(SILK, BOTTOM): - if (SL_MYSIDE(idx)) - return PCB->ElementOn; - else - return 0; - } - } - else { - switch (idx) { - case SL(SILK, TOP): - return 1; - case SL(SILK, BOTTOM): - return 0; - } - } - - return 1; -} - -static hidGC eps_make_gc(void) -{ - hidGC rv = (hidGC) malloc(sizeof(hid_gc_struct)); - rv->cap = Trace_Cap; - rv->width = 0; - rv->color = 0; - return rv; -} - -static void eps_destroy_gc(hidGC gc) -{ - free(gc); -} - -static void eps_use_mask(int use_it) -{ - static int mask_pending = 0; - switch (use_it) { - case HID_MASK_CLEAR: - if (!mask_pending) { - mask_pending = 1; - fprintf(f, "gsave\n"); - } - break; - case HID_MASK_AFTER: - break; - case HID_MASK_OFF: - if (mask_pending) { - mask_pending = 0; - fprintf(f, "grestore\n"); - lastcolor = -1; - } - break; - } -} - -static void eps_set_color(hidGC gc, const char *name) -{ - static void *cache = 0; - hidval cval; - - if (strcmp(name, "erase") == 0) { - gc->color = 0xffffff; - gc->erase = fast_erase ? 0 : 1; - return; - } - if (strcmp(name, "drill") == 0) { - gc->color = 0xffffff; - gc->erase = 0; - return; - } - gc->erase = 0; - if (hid_cache_color(0, name, &cval, &cache)) { - gc->color = cval.lval; - } - else if (in_mono) { - gc->color = 0; - } - else if (name[0] == '#') { - unsigned int r, g, b; - sscanf(name + 1, "%2x%2x%2x", &r, &g, &b); - gc->color = (r << 16) + (g << 8) + b; - } - else - gc->color = 0; -} - -static void eps_set_line_cap(hidGC gc, EndCapStyle style) -{ - gc->cap = style; -} - -static void eps_set_line_width(hidGC gc, Coord width) -{ - gc->width = width; -} - -static void eps_set_draw_xor(hidGC gc, int xor_) -{ - ; -} - -static void use_gc(hidGC gc) -{ - if (linewidth != gc->width) { - pcb_fprintf(f, "%mi setlinewidth\n", gc->width); - linewidth = gc->width; - } - if (lastcap != gc->cap) { - int c; - switch (gc->cap) { - case Round_Cap: - case Trace_Cap: - c = 1; - break; - default: - case Square_Cap: - c = 2; - break; - } - fprintf(f, "%d setlinecap\n", c); - lastcap = gc->cap; - } - if (lastcolor != gc->color) { - int c = gc->color; -#define CV(x,b) (((x>>b)&0xff)/255.0) - fprintf(f, "%g %g %g setrgbcolor\n", CV(c, 16), CV(c, 8), CV(c, 0)); - lastcolor = gc->color; - } -} - -static void eps_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); -static void eps_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius); - -static void eps_draw_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) -{ - use_gc(gc); - pcb_fprintf(f, "%mi %mi %mi %mi r\n", x1, y1, x2, y2); -} - -static void eps_draw_line(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) -{ - Coord w = gc->width / 2; - if (x1 == x2 && y1 == y2) { - if (gc->cap == Square_Cap) - eps_fill_rect(gc, x1 - w, y1 - w, x1 + w, y1 + w); - else - eps_fill_circle(gc, x1, y1, w); - return; - } - use_gc(gc); - if (gc->erase && gc->cap != Square_Cap) { - double ang = atan2(y2 - y1, x2 - x1); - double dx = w * sin(ang); - double dy = -w * cos(ang); - double deg = ang * 180.0 / M_PI; - Coord vx1 = x1 + dx; - Coord vy1 = y1 + dy; - - pcb_fprintf(f, "%mi %mi moveto ", vx1, vy1); - pcb_fprintf(f, "%mi %mi %mi %g %g arc\n", x2, y2, w, deg - 90, deg + 90); - pcb_fprintf(f, "%mi %mi %mi %g %g arc\n", x1, y1, w, deg + 90, deg + 270); - fprintf(f, "nclip\n"); - - return; - } - pcb_fprintf(f, "%mi %mi %mi %mi %s\n", x1, y1, x2, y2, gc->erase ? "tc" : "t"); -} - -static void eps_draw_arc(hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle) -{ - Angle sa, ea; - if (delta_angle > 0) { - sa = start_angle; - ea = start_angle + delta_angle; - } - else { - sa = start_angle + delta_angle; - ea = start_angle; - } -#if 0 - printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n", cx, cy, width, height, start_angle, delta_angle, sa, ea); -#endif - use_gc(gc); - pcb_fprintf(f, "%ma %ma %mi %mi %mi %mi %g a\n", sa, ea, -width, height, cx, cy, (double) linewidth / width); -} - -static void eps_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius) -{ - use_gc(gc); - pcb_fprintf(f, "%mi %mi %mi %s\n", cx, cy, radius, gc->erase ? "cc" : "c"); -} - -static void eps_fill_polygon(hidGC gc, int n_coords, Coord * x, Coord * y) -{ - int i; - char *op = "moveto"; - use_gc(gc); - for (i = 0; i < n_coords; i++) { - pcb_fprintf(f, "%mi %mi %s\n", x[i], y[i], op); - op = "lineto"; - } - fprintf(f, "fill\n"); -} - -static void eps_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) -{ - use_gc(gc); - pcb_fprintf(f, "%mi %mi %mi %mi r\n", x1, y1, x2, y2); -} - -static void eps_calibrate(double xval, double yval) -{ - CRASH; -} - -static void eps_set_crosshair(int x, int y, int action) -{ -} - -void hid_eps_init() -{ - memset(&eps_hid, 0, sizeof(HID)); - - common_nogui_init(&eps_hid); - common_draw_helpers_init(&eps_hid); - - eps_hid.struct_size = sizeof(HID); - eps_hid.name = "eps"; - eps_hid.description = "Encapsulated Postscript"; - eps_hid.exporter = 1; - eps_hid.poly_after = 1; - - eps_hid.get_export_options = eps_get_export_options; - eps_hid.do_export = eps_do_export; - eps_hid.parse_arguments = eps_parse_arguments; - eps_hid.set_layer = eps_set_layer; - eps_hid.make_gc = eps_make_gc; - eps_hid.destroy_gc = eps_destroy_gc; - eps_hid.use_mask = eps_use_mask; - eps_hid.set_color = eps_set_color; - eps_hid.set_line_cap = eps_set_line_cap; - eps_hid.set_line_width = eps_set_line_width; - eps_hid.set_draw_xor = eps_set_draw_xor; - eps_hid.draw_line = eps_draw_line; - eps_hid.draw_arc = eps_draw_arc; - eps_hid.draw_rect = eps_draw_rect; - eps_hid.fill_circle = eps_fill_circle; - eps_hid.fill_polygon = eps_fill_polygon; - eps_hid.fill_rect = eps_fill_rect; - eps_hid.calibrate = eps_calibrate; - eps_hid.set_crosshair = eps_set_crosshair; - - hid_register_hid(&eps_hid); -} Index: trunk/src/hid/ps/hid.conf =================================================================== --- trunk/src/hid/ps/hid.conf (revision 1262) +++ trunk/src/hid/ps/hid.conf (nonexistent) @@ -1 +0,0 @@ -type=export Index: trunk/src/hid/ps/ps.h =================================================================== --- trunk/src/hid/ps/ps.h (revision 1262) +++ trunk/src/hid/ps/ps.h (nonexistent) @@ -1,9 +0,0 @@ -/* $Id$ */ - -extern const char *ps_cookie; -extern HID ps_hid; -extern void ps_hid_export_to_file(FILE *, HID_Attr_Val *); -extern void ps_start_file(FILE *); -extern void ps_calibrate_1(double, double, int); -extern void hid_eps_init(); -void ps_ps_init(HID * hid); Index: trunk/src/hid/lpr/hid.conf =================================================================== --- trunk/src/hid/lpr/hid.conf (revision 1262) +++ trunk/src/hid/lpr/hid.conf (nonexistent) @@ -1,2 +0,0 @@ -type=printer -deps=ps Index: trunk/src/hid/lpr/lpr.c =================================================================== --- trunk/src/hid/lpr/lpr.c (revision 1262) +++ trunk/src/hid/lpr/lpr.c (nonexistent) @@ -1,134 +0,0 @@ -/* $Id$ */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "global.h" -#include "data.h" -#include "misc.h" - -#include "hid.h" -#include "../hidint.h" -#include "../ps/ps.h" -#include "hid/common/hidnogui.h" -#include "hid/common/hidinit.h" - - -RCSID("$Id$"); - -#define CRASH fprintf(stderr, "HID error: pcb called unimplemented PS function %s.\n", __FUNCTION__); abort() - -const char *lpr_cookie = "lpr HID"; - -static HID_Attribute base_lpr_options[] = { - -/* %start-doc options "98 lpr Printing Options" -@ftable @code -@item --lprcommand -Command to use for printing. Defaults to @code{lpr}. This can be used to produce -PDF output with a virtual PDF printer. Example: @* -@code{--lprcommand "lp -d CUPS-PDF-Printer"}. -@end ftable -@noindent In addition, all @ref{Postscript Export} options are valid. -%end-doc -*/ - {"lprcommand", "Command to use for printing", - HID_String, 0, 0, {0, 0, 0}, 0, 0}, -#define HA_lprcommand 0 -}; - -#define NUM_OPTIONS (sizeof(lpr_options)/sizeof(lpr_options[0])) - -static HID_Attribute *lpr_options = 0; -static int num_lpr_options = 0; -static HID_Attr_Val *lpr_values; - -static HID_Attribute *lpr_get_export_options(int *n) -{ - /* - * We initialize the default value in this manner because the GUI - * HID's may want to free() this string value and replace it with a - * new one based on how a user fills out a print dialog. - */ - if (base_lpr_options[HA_lprcommand].default_val.str_value == NULL) { - base_lpr_options[HA_lprcommand].default_val.str_value = strdup("lpr"); - } - - if (lpr_options == 0) { - HID_Attribute *ps_opts = ps_hid.get_export_options(&num_lpr_options); - lpr_options = (HID_Attribute *) calloc(num_lpr_options, sizeof(HID_Attribute)); - memcpy(lpr_options, ps_opts, num_lpr_options * sizeof(HID_Attribute)); - memcpy(lpr_options, base_lpr_options, sizeof(base_lpr_options)); - lpr_values = (HID_Attr_Val *) calloc(num_lpr_options, sizeof(HID_Attr_Val)); - } - if (n) - *n = num_lpr_options; - return lpr_options; -} - -static void lpr_do_export(HID_Attr_Val * options) -{ - FILE *f; - int i; - const char *filename; - - if (!options) { - lpr_get_export_options(0); - for (i = 0; i < num_lpr_options; i++) - lpr_values[i] = lpr_options[i].default_val; - options = lpr_values; - } - - filename = options[HA_lprcommand].str_value; - - printf("LPR: open %s\n", filename); - f = popen(filename, "w"); - if (!f) { - perror(filename); - return; - } - - ps_hid_export_to_file(f, options); - - fclose(f); -} - -static void lpr_parse_arguments(int *argc, char ***argv) -{ - lpr_get_export_options(0); - hid_register_attributes(lpr_options, num_lpr_options, lpr_cookie); - hid_parse_command_line(argc, argv); -} - -static void lpr_calibrate(double xval, double yval) -{ - ps_calibrate_1(xval, yval, 1); -} - -static HID lpr_hid; - -void hid_lpr_init() -{ - memset(&lpr_hid, 0, sizeof(HID)); - - common_nogui_init(&lpr_hid); - ps_ps_init(&lpr_hid); - - lpr_hid.struct_size = sizeof(HID); - lpr_hid.name = "lpr"; - lpr_hid.description = "Postscript print"; - lpr_hid.printer = 1; - lpr_hid.poly_before = 1; - - lpr_hid.get_export_options = lpr_get_export_options; - lpr_hid.do_export = lpr_do_export; - lpr_hid.parse_arguments = lpr_parse_arguments; - lpr_hid.calibrate = lpr_calibrate; - - hid_register_hid(&lpr_hid); -} Index: trunk/src_plugins/export_lpr/lpr.c =================================================================== --- trunk/src_plugins/export_lpr/lpr.c (nonexistent) +++ trunk/src_plugins/export_lpr/lpr.c (revision 1263) @@ -0,0 +1,134 @@ +/* $Id$ */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "global.h" +#include "data.h" +#include "misc.h" + +#include "hid.h" +#include "hid/hidint.h" +#include "../export_ps/ps.h" +#include "hid/common/hidnogui.h" +#include "hid/common/hidinit.h" + + +RCSID("$Id$"); + +#define CRASH fprintf(stderr, "HID error: pcb called unimplemented PS function %s.\n", __FUNCTION__); abort() + +const char *lpr_cookie = "lpr HID"; + +static HID_Attribute base_lpr_options[] = { + +/* %start-doc options "98 lpr Printing Options" +@ftable @code +@item --lprcommand +Command to use for printing. Defaults to @code{lpr}. This can be used to produce +PDF output with a virtual PDF printer. Example: @* +@code{--lprcommand "lp -d CUPS-PDF-Printer"}. +@end ftable +@noindent In addition, all @ref{Postscript Export} options are valid. +%end-doc +*/ + {"lprcommand", "Command to use for printing", + HID_String, 0, 0, {0, 0, 0}, 0, 0}, +#define HA_lprcommand 0 +}; + +#define NUM_OPTIONS (sizeof(lpr_options)/sizeof(lpr_options[0])) + +static HID_Attribute *lpr_options = 0; +static int num_lpr_options = 0; +static HID_Attr_Val *lpr_values; + +static HID_Attribute *lpr_get_export_options(int *n) +{ + /* + * We initialize the default value in this manner because the GUI + * HID's may want to free() this string value and replace it with a + * new one based on how a user fills out a print dialog. + */ + if (base_lpr_options[HA_lprcommand].default_val.str_value == NULL) { + base_lpr_options[HA_lprcommand].default_val.str_value = strdup("lpr"); + } + + if (lpr_options == 0) { + HID_Attribute *ps_opts = ps_hid.get_export_options(&num_lpr_options); + lpr_options = (HID_Attribute *) calloc(num_lpr_options, sizeof(HID_Attribute)); + memcpy(lpr_options, ps_opts, num_lpr_options * sizeof(HID_Attribute)); + memcpy(lpr_options, base_lpr_options, sizeof(base_lpr_options)); + lpr_values = (HID_Attr_Val *) calloc(num_lpr_options, sizeof(HID_Attr_Val)); + } + if (n) + *n = num_lpr_options; + return lpr_options; +} + +static void lpr_do_export(HID_Attr_Val * options) +{ + FILE *f; + int i; + const char *filename; + + if (!options) { + lpr_get_export_options(0); + for (i = 0; i < num_lpr_options; i++) + lpr_values[i] = lpr_options[i].default_val; + options = lpr_values; + } + + filename = options[HA_lprcommand].str_value; + + printf("LPR: open %s\n", filename); + f = popen(filename, "w"); + if (!f) { + perror(filename); + return; + } + + ps_hid_export_to_file(f, options); + + fclose(f); +} + +static void lpr_parse_arguments(int *argc, char ***argv) +{ + lpr_get_export_options(0); + hid_register_attributes(lpr_options, num_lpr_options, lpr_cookie); + hid_parse_command_line(argc, argv); +} + +static void lpr_calibrate(double xval, double yval) +{ + ps_calibrate_1(xval, yval, 1); +} + +static HID lpr_hid; + +void hid_export_lpr_init() +{ + memset(&lpr_hid, 0, sizeof(HID)); + + common_nogui_init(&lpr_hid); + ps_ps_init(&lpr_hid); + + lpr_hid.struct_size = sizeof(HID); + lpr_hid.name = "lpr"; + lpr_hid.description = "Postscript print"; + lpr_hid.printer = 1; + lpr_hid.poly_before = 1; + + lpr_hid.get_export_options = lpr_get_export_options; + lpr_hid.do_export = lpr_do_export; + lpr_hid.parse_arguments = lpr_parse_arguments; + lpr_hid.calibrate = lpr_calibrate; + + hid_register_hid(&lpr_hid); +} Index: trunk/src_plugins/export_ps/eps.c =================================================================== --- trunk/src_plugins/export_ps/eps.c (nonexistent) +++ trunk/src_plugins/export_ps/eps.c (revision 1263) @@ -0,0 +1,630 @@ +/* $Id$ */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "global.h" +#include "data.h" +#include "misc.h" +#include "pcb-printf.h" + +#include "hid.h" +#include "hid/hidint.h" +#include "hid/common/hidnogui.h" +#include "hid/common/draw_helpers.h" +#include "ps.h" +#include "hid/common/hidinit.h" + + +RCSID("$Id$"); + +#define CRASH fprintf(stderr, "HID error: pcb called unimplemented EPS function %s.\n", __FUNCTION__); abort() + +/*----------------------------------------------------------------------------*/ +/* Function prototypes */ +/*----------------------------------------------------------------------------*/ +static HID_Attribute *eps_get_export_options(int *n); +static void eps_do_export(HID_Attr_Val * options); +static void eps_parse_arguments(int *argc, char ***argv); +static int eps_set_layer(const char *name, int group, int empty); +static hidGC eps_make_gc(void); +static void eps_destroy_gc(hidGC gc); +static void eps_use_mask(int use_it); +static void eps_set_color(hidGC gc, const char *name); +static void eps_set_line_cap(hidGC gc, EndCapStyle style); +static void eps_set_line_width(hidGC gc, Coord width); +static void eps_set_draw_xor(hidGC gc, int _xor); +static void eps_draw_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); +static void eps_draw_line(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); +static void eps_draw_arc(hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle); +static void eps_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); +static void eps_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius); +static void eps_fill_polygon(hidGC gc, int n_coords, Coord * x, Coord * y); +static void eps_calibrate(double xval, double yval); +static void eps_set_crosshair(int x, int y, int action); +/*----------------------------------------------------------------------------*/ + +typedef struct hid_gc_struct { + EndCapStyle cap; + Coord width; + int color; + int erase; +} hid_gc_struct; + +static HID eps_hid; + +static FILE *f = 0; +static Coord linewidth = -1; +static int lastcap = -1; +static int lastcolor = -1; +static int print_group[MAX_LAYER]; +static int print_layer[MAX_LAYER]; +static int fast_erase = -1; + +static HID_Attribute eps_attribute_list[] = { + /* other HIDs expect this to be first. */ + +/* %start-doc options "92 Encapsulated Postscript Export" +@ftable @code +@item --eps-file +Name of the encapsulated postscript output file. Can contain a path. +@end ftable +%end-doc +*/ + {"eps-file", "Encapsulated Postscript output file", + HID_String, 0, 0, {0, 0, 0}, 0, 0}, +#define HA_psfile 0 + +/* %start-doc options "92 Encapsulated Postscript Export" +@ftable @code +@item --eps-scale +Scale EPS output by the parameter @samp{num}. +@end ftable +%end-doc +*/ + {"eps-scale", "EPS scale", + HID_Real, 0, 100, {0, 0, 1.0}, 0, 0}, +#define HA_scale 1 + +/* %start-doc options "92 Encapsulated Postscript Export" +@ftable @code +@cindex as-shown (EPS) +@item --as-shown +Export layers as shown on screen. +@end ftable +%end-doc +*/ + {"as-shown", "Export layers as shown on screen", + HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, +#define HA_as_shown 2 + +/* %start-doc options "92 Encapsulated Postscript Export" +@ftable @code +@item --monochrome +Convert output to monochrome. +@end ftable +%end-doc +*/ + {"monochrome", "Convert to monochrome", + HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, +#define HA_mono 3 + +/* %start-doc options "92 Encapsulated Postscript Export" +@ftable @code +@cindex only-visible +@item --only-visible +Limit the bounds of the EPS file to the visible items. +@end ftable +%end-doc +*/ + {"only-visible", "Limit the bounds of the EPS file to the visible items", + HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, +#define HA_only_visible 4 +}; + +#define NUM_OPTIONS (sizeof(eps_attribute_list)/sizeof(eps_attribute_list[0])) + +REGISTER_ATTRIBUTES(eps_attribute_list, ps_cookie) + + static HID_Attr_Val eps_values[NUM_OPTIONS]; + + static HID_Attribute *eps_get_export_options(int *n) +{ + static char *last_made_filename = 0; + + if (PCB) + derive_default_filename(PCB->Filename, &eps_attribute_list[HA_psfile], ".eps", &last_made_filename); + + if (n) + *n = NUM_OPTIONS; + return eps_attribute_list; +} + +static int comp_layer, solder_layer; + +static int group_for_layer(int l) +{ + if (l < max_copper_layer + 2 && l >= 0) + return GetLayerGroupNumberByNumber(l); + /* else something unique */ + return max_group + 3 + l; +} + +static int layer_sort(const void *va, const void *vb) +{ + int a = *(int *) va; + int b = *(int *) vb; + int al = group_for_layer(a); + int bl = group_for_layer(b); + int d = bl - al; + + if (a >= 0 && a <= max_copper_layer + 1) { + int aside = (al == solder_layer ? 0 : al == comp_layer ? 2 : 1); + int bside = (bl == solder_layer ? 0 : bl == comp_layer ? 2 : 1); + if (bside != aside) + return bside - aside; + } + if (d) + return d; + return b - a; +} + +static const char *filename; +static BoxType *bounds; +static int in_mono, as_shown; + +void eps_hid_export_to_file(FILE * the_file, HID_Attr_Val * options) +{ + int i; + static int saved_layer_stack[MAX_LAYER]; + BoxType region; + FlagType save_thindraw; + + save_thindraw = PCB->Flags; + CLEAR_FLAG(THINDRAWFLAG, PCB); + CLEAR_FLAG(THINDRAWPOLYFLAG, PCB); + CLEAR_FLAG(CHECKPLANESFLAG, PCB); + + f = the_file; + + region.X1 = 0; + region.Y1 = 0; + region.X2 = PCB->MaxWidth; + region.Y2 = PCB->MaxHeight; + + if (options[HA_only_visible].int_value) + bounds = GetDataBoundingBox(PCB->Data); + else + bounds = ®ion; + + memset(print_group, 0, sizeof(print_group)); + memset(print_layer, 0, sizeof(print_layer)); + + /* Figure out which layers actually have stuff on them. */ + for (i = 0; i < max_copper_layer; i++) { + LayerType *layer = PCB->Data->Layer + i; + if (layer->On) + if (!LAYER_IS_EMPTY(layer)) + print_group[GetLayerGroupNumberByNumber(i)] = 1; + } + + /* Now, if only one layer has real stuff on it, we can use the fast + erase logic. Otherwise, we have to use the expensive multi-mask + erase. */ + fast_erase = 0; + for (i = 0; i < max_group; i++) + if (print_group[i]) + fast_erase++; + + /* If NO layers had anything on them, at least print the component + layer to get the pins. */ + if (fast_erase == 0) { + print_group[GetLayerGroupNumberByNumber(component_silk_layer)] = 1; + fast_erase = 1; + } + + /* "fast_erase" is 1 if we can just paint white to erase. */ + fast_erase = fast_erase == 1 ? 1 : 0; + + /* Now, for each group we're printing, mark its layers for + printing. */ + for (i = 0; i < max_copper_layer; i++) + if (print_group[GetLayerGroupNumberByNumber(i)]) + print_layer[i] = 1; + + if (fast_erase) { + eps_hid.poly_before = 1; + eps_hid.poly_after = 0; + } + else { + eps_hid.poly_before = 0; + eps_hid.poly_after = 1; + } + + memcpy(saved_layer_stack, LayerStack, sizeof(LayerStack)); + as_shown = options[HA_as_shown].int_value; + if (!options[HA_as_shown].int_value) { + comp_layer = GetLayerGroupNumberByNumber(component_silk_layer); + solder_layer = GetLayerGroupNumberByNumber(solder_silk_layer); + qsort(LayerStack, max_copper_layer, sizeof(LayerStack[0]), layer_sort); + } + fprintf(f, "%%!PS-Adobe-3.0 EPSF-3.0\n"); + linewidth = -1; + lastcap = -1; + lastcolor = -1; + + in_mono = options[HA_mono].int_value; + +#define pcb2em(x) 1 + COORD_TO_INCH (x) * 72.0 * options[HA_scale].real_value + fprintf(f, "%%%%BoundingBox: 0 0 %f %f\n", pcb2em(bounds->X2 - bounds->X1), pcb2em(bounds->Y2 - bounds->Y1)); +#undef pcb2em + fprintf(f, "%%%%Pages: 1\n"); + fprintf(f, "save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def\n"); + fprintf(f, "%%%%EndProlog\n"); + fprintf(f, "%%%%Page: 1 1\n"); + fprintf(f, "%%%%BeginDocument: %s\n\n", filename); + + fprintf(f, "72 72 scale\n"); + fprintf(f, "1 dup neg scale\n"); + fprintf(f, "%g dup scale\n", options[HA_scale].real_value); + pcb_fprintf(f, "%mi %mi translate\n", -bounds->X1, -bounds->Y2); + if (options[HA_as_shown].int_value && Settings.ShowSolderSide) + pcb_fprintf(f, "-1 1 scale %mi 0 translate\n", bounds->X1 - bounds->X2); + linewidth = -1; + lastcap = -1; + lastcolor = -1; +#define Q (Coord) MIL_TO_COORD(10) + pcb_fprintf(f, + "/nclip { %mi %mi moveto %mi %mi lineto %mi %mi lineto %mi %mi lineto %mi %mi lineto eoclip newpath } def\n", + bounds->X1 - Q, bounds->Y1 - Q, bounds->X1 - Q, bounds->Y2 + Q, + bounds->X2 + Q, bounds->Y2 + Q, bounds->X2 + Q, bounds->Y1 - Q, bounds->X1 - Q, bounds->Y1 - Q); +#undef Q + fprintf(f, "/t { moveto lineto stroke } bind def\n"); + fprintf(f, "/tc { moveto lineto strokepath nclip } bind def\n"); + fprintf(f, "/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n"); + fprintf(f, " x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def\n"); + fprintf(f, "/c { 0 360 arc fill } bind def\n"); + fprintf(f, "/cc { 0 360 arc nclip } bind def\n"); + fprintf(f, "/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def\n"); + + hid_expose_callback(&eps_hid, bounds, 0); + + fprintf(f, "showpage\n"); + + fprintf(f, "%%%%EndDocument\n"); + fprintf(f, "%%%%Trailer\n"); + fprintf(f, "cleartomark countdictstack exch sub { end } repeat restore\n"); + fprintf(f, "%%%%EOF\n"); + + memcpy(LayerStack, saved_layer_stack, sizeof(LayerStack)); + PCB->Flags = save_thindraw; +} + +static void eps_do_export(HID_Attr_Val * options) +{ + int i; + int save_ons[MAX_LAYER + 2]; + + if (!options) { + eps_get_export_options(0); + for (i = 0; i < NUM_OPTIONS; i++) + eps_values[i] = eps_attribute_list[i].default_val; + options = eps_values; + } + + filename = options[HA_psfile].str_value; + if (!filename) + filename = "pcb-out.eps"; + + f = fopen(filename, "w"); + if (!f) { + perror(filename); + return; + } + + if (!options[HA_as_shown].int_value) + hid_save_and_show_layer_ons(save_ons); + eps_hid_export_to_file(f, options); + if (!options[HA_as_shown].int_value) + hid_restore_layer_ons(save_ons); + + fclose(f); +} + +static void eps_parse_arguments(int *argc, char ***argv) +{ + hid_register_attributes(eps_attribute_list, sizeof(eps_attribute_list) / sizeof(eps_attribute_list[0]), ps_cookie); + hid_parse_command_line(argc, argv); +} + +static int is_mask; +static int is_paste; +static int is_drill; + +static int eps_set_layer(const char *name, int group, int empty) +{ + int idx = (group >= 0 && group < max_group) ? PCB->LayerGroups.Entries[group][0] : group; + if (name == 0) + name = PCB->Data->Layer[idx].Name; + + if (idx >= 0 && idx < max_copper_layer && !print_layer[idx]) + return 0; + if (SL_TYPE(idx) == SL_ASSY || SL_TYPE(idx) == SL_FAB) + return 0; + + if (strcmp(name, "invisible") == 0) + return 0; + + is_drill = (SL_TYPE(idx) == SL_PDRILL || SL_TYPE(idx) == SL_UDRILL); + is_mask = (SL_TYPE(idx) == SL_MASK); + is_paste = (SL_TYPE(idx) == SL_PASTE); + + if (is_mask || is_paste) + return 0; +#if 0 + printf("Layer %s group %d drill %d mask %d\n", name, group, is_drill, is_mask); +#endif + fprintf(f, "%% Layer %s group %d drill %d mask %d\n", name, group, is_drill, is_mask); + + if (as_shown) { + switch (idx) { + case SL(SILK, TOP): + case SL(SILK, BOTTOM): + if (SL_MYSIDE(idx)) + return PCB->ElementOn; + else + return 0; + } + } + else { + switch (idx) { + case SL(SILK, TOP): + return 1; + case SL(SILK, BOTTOM): + return 0; + } + } + + return 1; +} + +static hidGC eps_make_gc(void) +{ + hidGC rv = (hidGC) malloc(sizeof(hid_gc_struct)); + rv->cap = Trace_Cap; + rv->width = 0; + rv->color = 0; + return rv; +} + +static void eps_destroy_gc(hidGC gc) +{ + free(gc); +} + +static void eps_use_mask(int use_it) +{ + static int mask_pending = 0; + switch (use_it) { + case HID_MASK_CLEAR: + if (!mask_pending) { + mask_pending = 1; + fprintf(f, "gsave\n"); + } + break; + case HID_MASK_AFTER: + break; + case HID_MASK_OFF: + if (mask_pending) { + mask_pending = 0; + fprintf(f, "grestore\n"); + lastcolor = -1; + } + break; + } +} + +static void eps_set_color(hidGC gc, const char *name) +{ + static void *cache = 0; + hidval cval; + + if (strcmp(name, "erase") == 0) { + gc->color = 0xffffff; + gc->erase = fast_erase ? 0 : 1; + return; + } + if (strcmp(name, "drill") == 0) { + gc->color = 0xffffff; + gc->erase = 0; + return; + } + gc->erase = 0; + if (hid_cache_color(0, name, &cval, &cache)) { + gc->color = cval.lval; + } + else if (in_mono) { + gc->color = 0; + } + else if (name[0] == '#') { + unsigned int r, g, b; + sscanf(name + 1, "%2x%2x%2x", &r, &g, &b); + gc->color = (r << 16) + (g << 8) + b; + } + else + gc->color = 0; +} + +static void eps_set_line_cap(hidGC gc, EndCapStyle style) +{ + gc->cap = style; +} + +static void eps_set_line_width(hidGC gc, Coord width) +{ + gc->width = width; +} + +static void eps_set_draw_xor(hidGC gc, int xor_) +{ + ; +} + +static void use_gc(hidGC gc) +{ + if (linewidth != gc->width) { + pcb_fprintf(f, "%mi setlinewidth\n", gc->width); + linewidth = gc->width; + } + if (lastcap != gc->cap) { + int c; + switch (gc->cap) { + case Round_Cap: + case Trace_Cap: + c = 1; + break; + default: + case Square_Cap: + c = 2; + break; + } + fprintf(f, "%d setlinecap\n", c); + lastcap = gc->cap; + } + if (lastcolor != gc->color) { + int c = gc->color; +#define CV(x,b) (((x>>b)&0xff)/255.0) + fprintf(f, "%g %g %g setrgbcolor\n", CV(c, 16), CV(c, 8), CV(c, 0)); + lastcolor = gc->color; + } +} + +static void eps_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); +static void eps_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius); + +static void eps_draw_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) +{ + use_gc(gc); + pcb_fprintf(f, "%mi %mi %mi %mi r\n", x1, y1, x2, y2); +} + +static void eps_draw_line(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) +{ + Coord w = gc->width / 2; + if (x1 == x2 && y1 == y2) { + if (gc->cap == Square_Cap) + eps_fill_rect(gc, x1 - w, y1 - w, x1 + w, y1 + w); + else + eps_fill_circle(gc, x1, y1, w); + return; + } + use_gc(gc); + if (gc->erase && gc->cap != Square_Cap) { + double ang = atan2(y2 - y1, x2 - x1); + double dx = w * sin(ang); + double dy = -w * cos(ang); + double deg = ang * 180.0 / M_PI; + Coord vx1 = x1 + dx; + Coord vy1 = y1 + dy; + + pcb_fprintf(f, "%mi %mi moveto ", vx1, vy1); + pcb_fprintf(f, "%mi %mi %mi %g %g arc\n", x2, y2, w, deg - 90, deg + 90); + pcb_fprintf(f, "%mi %mi %mi %g %g arc\n", x1, y1, w, deg + 90, deg + 270); + fprintf(f, "nclip\n"); + + return; + } + pcb_fprintf(f, "%mi %mi %mi %mi %s\n", x1, y1, x2, y2, gc->erase ? "tc" : "t"); +} + +static void eps_draw_arc(hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle) +{ + Angle sa, ea; + if (delta_angle > 0) { + sa = start_angle; + ea = start_angle + delta_angle; + } + else { + sa = start_angle + delta_angle; + ea = start_angle; + } +#if 0 + printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n", cx, cy, width, height, start_angle, delta_angle, sa, ea); +#endif + use_gc(gc); + pcb_fprintf(f, "%ma %ma %mi %mi %mi %mi %g a\n", sa, ea, -width, height, cx, cy, (double) linewidth / width); +} + +static void eps_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius) +{ + use_gc(gc); + pcb_fprintf(f, "%mi %mi %mi %s\n", cx, cy, radius, gc->erase ? "cc" : "c"); +} + +static void eps_fill_polygon(hidGC gc, int n_coords, Coord * x, Coord * y) +{ + int i; + char *op = "moveto"; + use_gc(gc); + for (i = 0; i < n_coords; i++) { + pcb_fprintf(f, "%mi %mi %s\n", x[i], y[i], op); + op = "lineto"; + } + fprintf(f, "fill\n"); +} + +static void eps_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) +{ + use_gc(gc); + pcb_fprintf(f, "%mi %mi %mi %mi r\n", x1, y1, x2, y2); +} + +static void eps_calibrate(double xval, double yval) +{ + CRASH; +} + +static void eps_set_crosshair(int x, int y, int action) +{ +} + +void hid_eps_init() +{ + memset(&eps_hid, 0, sizeof(HID)); + + common_nogui_init(&eps_hid); + common_draw_helpers_init(&eps_hid); + + eps_hid.struct_size = sizeof(HID); + eps_hid.name = "eps"; + eps_hid.description = "Encapsulated Postscript"; + eps_hid.exporter = 1; + eps_hid.poly_after = 1; + + eps_hid.get_export_options = eps_get_export_options; + eps_hid.do_export = eps_do_export; + eps_hid.parse_arguments = eps_parse_arguments; + eps_hid.set_layer = eps_set_layer; + eps_hid.make_gc = eps_make_gc; + eps_hid.destroy_gc = eps_destroy_gc; + eps_hid.use_mask = eps_use_mask; + eps_hid.set_color = eps_set_color; + eps_hid.set_line_cap = eps_set_line_cap; + eps_hid.set_line_width = eps_set_line_width; + eps_hid.set_draw_xor = eps_set_draw_xor; + eps_hid.draw_line = eps_draw_line; + eps_hid.draw_arc = eps_draw_arc; + eps_hid.draw_rect = eps_draw_rect; + eps_hid.fill_circle = eps_fill_circle; + eps_hid.fill_polygon = eps_fill_polygon; + eps_hid.fill_rect = eps_fill_rect; + eps_hid.calibrate = eps_calibrate; + eps_hid.set_crosshair = eps_set_crosshair; + + hid_register_hid(&eps_hid); +} Index: trunk/src_plugins/export_ps/ps.c =================================================================== --- trunk/src_plugins/export_ps/ps.c (nonexistent) +++ trunk/src_plugins/export_ps/ps.c (revision 1263) @@ -0,0 +1,1602 @@ +/* $Id$ */ + +#include "config.h" + +#include +#include /* not used */ +#include +#include +#include /* not used */ +#include + +#include "global.h" +#include "data.h" +#include "misc.h" +#include "error.h" +#include "draw.h" +#include "pcb-printf.h" + +#include "hid.h" +#include "hid/hidint.h" +#include "hid/common/hidnogui.h" +#include "hid/common/draw_helpers.h" +#include "ps.h" +#include "print.h" +#include "hid/common/hidinit.h" + + +RCSID("$Id$"); + +#define CRASH fprintf(stderr, "HID error: pcb called unimplemented PS function %s.\n", __FUNCTION__); abort() + +const char *ps_cookie = "ps HID"; + +static int ps_set_layer(const char *name, int group, int empty); +static void use_gc(hidGC gc); + +typedef struct hid_gc_struct { + HID *me_pointer; + EndCapStyle cap; + Coord width; + unsigned char r, g, b; + int erase; + int faded; +} hid_gc_struct; + +static const char *medias[] = { + "A0", "A1", "A2", "A3", "A4", "A5", + "A6", "A7", "A8", "A9", "A10", + "B0", "B1", "B2", "B3", "B4", "B5", + "B6", "B7", "B8", "B9", "B10", + "Letter", "11x17", "Ledger", + "Legal", "Executive", + "A-Size", "B-size", + "C-Size", "D-size", "E-size", + "US-Business_Card", "Intl-Business_Card", + 0 +}; + +typedef struct { + char *name; + Coord Width, Height; + Coord MarginX, MarginY; +} MediaType, *MediaTypePtr; + +/* + * Metric ISO sizes in mm. See http://en.wikipedia.org/wiki/ISO_paper_sizes + * + * A0 841 x 1189 + * A1 594 x 841 + * A2 420 x 594 + * A3 297 x 420 + * A4 210 x 297 + * A5 148 x 210 + * A6 105 x 148 + * A7 74 x 105 + * A8 52 x 74 + * A9 37 x 52 + * A10 26 x 37 + * + * B0 1000 x 1414 + * B1 707 x 1000 + * B2 500 x 707 + * B3 353 x 500 + * B4 250 x 353 + * B5 176 x 250 + * B6 125 x 176 + * B7 88 x 125 + * B8 62 x 88 + * B9 44 x 62 + * B10 31 x 44 + * + * awk '{printf(" {\"%s\", %d, %d, MARGINX, MARGINY},\n", $2, $3*100000/25.4, $5*100000/25.4)}' + * + * See http://en.wikipedia.org/wiki/Paper_size#Loose_sizes for some of the other sizes. The + * {A,B,C,D,E}-Size here are the ANSI sizes and not the architectural sizes. + */ + +#define MARGINX MIL_TO_COORD(500) +#define MARGINY MIL_TO_COORD(500) + +static MediaType media_data[] = { + {"A0", MM_TO_COORD(841), MM_TO_COORD(1189), MARGINX, MARGINY}, + {"A1", MM_TO_COORD(594), MM_TO_COORD(841), MARGINX, MARGINY}, + {"A2", MM_TO_COORD(420), MM_TO_COORD(594), MARGINX, MARGINY}, + {"A3", MM_TO_COORD(297), MM_TO_COORD(420), MARGINX, MARGINY}, + {"A4", MM_TO_COORD(210), MM_TO_COORD(297), MARGINX, MARGINY}, + {"A5", MM_TO_COORD(148), MM_TO_COORD(210), MARGINX, MARGINY}, + {"A6", MM_TO_COORD(105), MM_TO_COORD(148), MARGINX, MARGINY}, + {"A7", MM_TO_COORD(74), MM_TO_COORD(105), MARGINX, MARGINY}, + {"A8", MM_TO_COORD(52), MM_TO_COORD(74), MARGINX, MARGINY}, + {"A9", MM_TO_COORD(37), MM_TO_COORD(52), MARGINX, MARGINY}, + {"A10", MM_TO_COORD(26), MM_TO_COORD(37), MARGINX, MARGINY}, + {"B0", MM_TO_COORD(1000), MM_TO_COORD(1414), MARGINX, MARGINY}, + {"B1", MM_TO_COORD(707), MM_TO_COORD(1000), MARGINX, MARGINY}, + {"B2", MM_TO_COORD(500), MM_TO_COORD(707), MARGINX, MARGINY}, + {"B3", MM_TO_COORD(353), MM_TO_COORD(500), MARGINX, MARGINY}, + {"B4", MM_TO_COORD(250), MM_TO_COORD(353), MARGINX, MARGINY}, + {"B5", MM_TO_COORD(176), MM_TO_COORD(250), MARGINX, MARGINY}, + {"B6", MM_TO_COORD(125), MM_TO_COORD(176), MARGINX, MARGINY}, + {"B7", MM_TO_COORD(88), MM_TO_COORD(125), MARGINX, MARGINY}, + {"B8", MM_TO_COORD(62), MM_TO_COORD(88), MARGINX, MARGINY}, + {"B9", MM_TO_COORD(44), MM_TO_COORD(62), MARGINX, MARGINY}, + {"B10", MM_TO_COORD(31), MM_TO_COORD(44), MARGINX, MARGINY}, + {"Letter", INCH_TO_COORD(8.5), INCH_TO_COORD(11), MARGINX, MARGINY}, + {"11x17", INCH_TO_COORD(11), INCH_TO_COORD(17), MARGINX, MARGINY}, + {"Ledger", INCH_TO_COORD(17), INCH_TO_COORD(11), MARGINX, MARGINY}, + {"Legal", INCH_TO_COORD(8.5), INCH_TO_COORD(14), MARGINX, MARGINY}, + {"Executive", INCH_TO_COORD(7.5), INCH_TO_COORD(10), MARGINX, MARGINY}, + {"A-size", INCH_TO_COORD(8.5), INCH_TO_COORD(11), MARGINX, MARGINY}, + {"B-size", INCH_TO_COORD(11), INCH_TO_COORD(17), MARGINX, MARGINY}, + {"C-size", INCH_TO_COORD(17), INCH_TO_COORD(22), MARGINX, MARGINY}, + {"D-size", INCH_TO_COORD(22), INCH_TO_COORD(34), MARGINX, MARGINY}, + {"E-size", INCH_TO_COORD(34), INCH_TO_COORD(44), MARGINX, MARGINY}, + {"US-Business_Card", INCH_TO_COORD(3.5), INCH_TO_COORD(2.0), 0, 0}, + {"Intl-Business_Card", INCH_TO_COORD(3.375), INCH_TO_COORD(2.125), 0, 0} +}; + +#undef MARGINX +#undef MARGINY + +HID_Attribute ps_attribute_list[] = { + /* other HIDs expect this to be first. */ + +/* %start-doc options "91 Postscript Export" +@ftable @code +@item --psfile +Name of the postscript output file. Can contain a path. +@end ftable +%end-doc +*/ + {"psfile", "Postscript output file", + HID_String, 0, 0, {0, 0, 0}, 0, 0}, +#define HA_psfile 0 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@cindex drill-helper +@item --drill-helper +Print a centering target in large drill holes. +@end ftable +%end-doc +*/ + {"drill-helper", "Print a centering target in large drill holes", + HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, +#define HA_drillhelper 1 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@cindex align-marks +@item --align-marks +Print alignment marks on each sheet. This is meant to ease alignment during exposure. +@end ftable +%end-doc +*/ + {"align-marks", "Print alignment marks on each sheet", + HID_Boolean, 0, 0, {1, 0, 0}, 0, 0}, +#define HA_alignmarks 2 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@item --outline +Print the contents of the outline layer on each sheet. +@end ftable +%end-doc +*/ + {"outline", "Print outline on each sheet", + HID_Boolean, 0, 0, {1, 0, 0}, 0, 0}, +#define HA_outline 3 +/* %start-doc options "91 Postscript Export" +@ftable @code +@item --mirror +Print mirror image. +@end ftable +%end-doc +*/ + {"mirror", "Print mirror image of every page", + HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, +#define HA_mirror 4 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@item --fill-page +Scale output to make the board fit the page. +@end ftable +%end-doc +*/ + {"fill-page", "Scale board to fill page", + HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, +#define HA_fillpage 5 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@item --auto-mirror +Print mirror image of appropriate layers. +@end ftable +%end-doc +*/ + {"auto-mirror", "Print mirror image of appropriate layers", + HID_Boolean, 0, 0, {1, 0, 0}, 0, 0}, +#define HA_automirror 6 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@item --ps-color +Postscript output in color. +@end ftable +%end-doc +*/ + {"ps-color", "Prints in color", + HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, +#define HA_color 7 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@cindex ps-bloat +@item --ps-bloat +Amount to add to trace/pad/pin edges. +@end ftable +%end-doc +*/ + {"ps-bloat", "Amount to add to trace/pad/pin edges", + HID_Coord, -MIL_TO_COORD(100), MIL_TO_COORD(100), {0, 0, 0}, 0, 0}, +#define HA_psbloat 8 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@cindex ps-invert +@item --ps-invert +Draw objects as white-on-black. +@end ftable +%end-doc +*/ + {"ps-invert", "Draw objects as white-on-black", + HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, +#define HA_psinvert 9 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@item --media +Size of the media, the postscript is fitted to. The parameter +@code{} can be any of the standard names for paper size: @samp{A0} +to @samp{A10}, @samp{B0} to @samp{B10}, @samp{Letter}, @samp{11x17}, +@samp{Ledger}, @samp{Legal}, @samp{Executive}, @samp{A-Size}, @samp{B-size}, +@samp{C-Size}, @samp{D-size}, @samp{E-size}, @samp{US-Business_Card}, +@samp{Intl-Business_Card}. +@end ftable +%end-doc +*/ + {"media", "media type", + HID_Enum, 0, 0, {22, 0, 0}, medias, 0}, +#define HA_media 10 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@cindex psfade +@item --psfade +Fade amount for assembly drawings (0.0=missing, 1.0=solid). +@end ftable +%end-doc +*/ + {"psfade", "Fade amount for assembly drawings (0.0=missing, 1.0=solid)", + HID_Real, 0, 1, {0, 0, 0.40}, 0, 0}, +#define HA_psfade 11 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@item --scale +Scale value to compensate for printer sizing errors (1.0 = full scale). +@end ftable +%end-doc +*/ + {"scale", "Scale value to compensate for printer sizing errors (1.0 = full scale)", + HID_Real, 0.01, 4, {0, 0, 1.00}, 0, 0}, +#define HA_scale 12 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@cindex multi-file +@item --multi-file +Produce multiple files, one per page, instead of a single multi page file. +@end ftable +%end-doc +*/ + {"multi-file", "Produce multiple files, one per page, instead of a single file", + HID_Boolean, 0, 0, {0, 0, 0.40}, 0, 0}, +#define HA_multifile 13 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@item --xcalib +Paper width. Used for x-Axis calibration. +@end ftable +%end-doc +*/ + {"xcalib", "Paper width. Used for x-Axis calibration", + HID_Real, 0, 0, {0, 0, 1.0}, 0, 0}, +#define HA_xcalib 14 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@item --ycalib +Paper height. Used for y-Axis calibration. +@end ftable +%end-doc +*/ + {"ycalib", "Paper height. Used for y-Axis calibration", + HID_Real, 0, 0, {0, 0, 1.0}, 0, 0}, +#define HA_ycalib 15 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@item --drill-copper +Draw drill holes in pins / vias, instead of leaving solid copper. +@end ftable +%end-doc +*/ + {"drill-copper", "Draw drill holes in pins / vias, instead of leaving solid copper", + HID_Boolean, 0, 0, {1, 0, 0}, 0, 0}, +#define HA_drillcopper 16 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@cindex show-legend +@item --show-legend +Print file name and scale on printout. +@end ftable +%end-doc +*/ + {"show-legend", "Print file name and scale on printout", + HID_Boolean, 0, 0, {1, 0, 0}, 0, 0}, +#define HA_legend 17 + +/* %start-doc options "91 Postscript Export" +@ftable @code +@item --polygrid +If non-zero grid polygons instead of filling them with gridlines spaced as specified. +@end ftable +%end-doc +*/ + {"polygrid", "When non-zero: grid polygons instead of filling with gridlines spaced as specified", + HID_Real, 0, 10, {0, 0, 0.0}, 0, 0}, +#define HA_polygrid 18 + +}; + +#define NUM_OPTIONS (sizeof(ps_attribute_list)/sizeof(ps_attribute_list[0])) + +REGISTER_ATTRIBUTES(ps_attribute_list, ps_cookie) + +/* All file-scope data is in global struct */ + static struct { + double calibration_x, calibration_y; + + FILE *f; + int pagecount; + Coord linewidth; + bool print_group[MAX_LAYER]; + bool print_layer[MAX_LAYER]; + double fade_ratio; + bool multi_file; + Coord media_width, media_height, ps_width, ps_height; + + const char *filename; + bool drill_helper; + bool align_marks; + bool outline; + bool mirror; + bool fillpage; + bool automirror; + bool incolor; + bool doing_toc; + Coord bloat; + bool invert; + int media_idx; + bool drillcopper; + bool legend; + + LayerTypePtr outline_layer; + + double scale_factor; + + BoxType region; + + HID_Attr_Val ps_values[NUM_OPTIONS]; + + bool is_mask; + bool is_drill; + bool is_assy; + bool is_copper; + bool is_paste; + + double polygrid; + } global; + + static HID_Attribute *ps_get_export_options(int *n) +{ + static char *last_made_filename = 0; + if (PCB) + derive_default_filename(PCB->Filename, &ps_attribute_list[HA_psfile], ".ps", &last_made_filename); + + if (n) + *n = NUM_OPTIONS; + return ps_attribute_list; +} + +static int group_for_layer(int l) +{ + if (l < max_copper_layer + 2 && l >= 0) + return GetLayerGroupNumberByNumber(l); + /* else something unique */ + return max_group + 3 + l; +} + +static int layer_sort(const void *va, const void *vb) +{ + int a = *(int *) va; + int b = *(int *) vb; + int d = group_for_layer(b) - group_for_layer(a); + if (d) + return d; + return b - a; +} + +void ps_start_file(FILE * f) +{ + time_t currenttime = time(NULL); + + fprintf(f, "%%!PS-Adobe-3.0\n"); + + /* Document Structuring Conventions (DCS): */ + + /* Start General Header Comments: */ + + /* + * %%Title DCS provides text title for the document that is useful + * for printing banner pages. + */ + fprintf(f, "%%%%Title: %s\n", PCB->Filename); + + /* + * %%CreationDate DCS indicates the date and time the document was + * created. Neither the date nor time need be in any standard + * format. This comment is meant to be used purely for informational + * purposes, such as printing on banner pages. + */ + fprintf(f, "%%%%CreationDate: %s", asctime(localtime(¤ttime))); + + /* + * %%Creator DCS indicates the document creator, usually the name of + * the document composition software. + */ + fprintf(f, "%%%%Creator: PCB release: %s " VERSION "\n", Progname); + + /* + * %%Version DCS comment can be used to note the version and + * revision number of a document or resource. A document manager may + * wish to provide version control services, or allow substitution + * of compatible versions/revisions of a resource or document. + * + * The format should be in the form of 'procname': + * ::= < name> < version> < revision> + * < name> ::= < text> + * < version> ::= < real> + * < revision> ::= < uint> + * + * If a version numbering scheme is not used, these fields should + * still be filled with a dummy value of 0. + * + * There is currently no code in PCB to manage this revision number. + * + */ + fprintf(f, "%%%%Version: (PCB %s " VERSION ") 0.0 0\n", Progname); + + + /* + * %%PageOrder DCS is intended to help document managers determine + * the order of pages in the document file, which in turn enables a + * document manager optionally to reorder the pages. 'Ascend'-The + * pages are in ascending order for example, 1-2-3-4-5-6. + */ + fprintf(f, "%%%%PageOrder: Ascend\n"); + + /* + * %%Pages: < numpages> | (atend) < numpages> ::= < uint> (Total + * %%number of pages) + * + * %%Pages DCS defines the number of virtual pages that a document + * will image. (atend) defers the count until the end of the file, + * which is useful for dynamically generated contents. + */ + fprintf(f, "%%%%Pages: (atend)\n"); + + /* + * %%DocumentMedia: + * + * Substitute 0 or "" for N/A. Width and height are in points + * (1/72"). + * + * Media sizes are in PCB units + */ + pcb_fprintf(f, "%%%%DocumentMedia: %s %mi %mi 0 \"\" \"\"\n", + media_data[global.media_idx].name, + 72 * media_data[global.media_idx].Width, 72 * media_data[global.media_idx].Height); + pcb_fprintf(f, "%%%%DocumentPaperSizes: %s\n", media_data[global.media_idx].name); + + /* End General Header Comments. */ + + /* General Body Comments go here. Currently there are none. */ + + /* + * %%EndComments DCS indicates an explicit end to the header + * comments of the document. All global DCS's must preceded + * this. A blank line gives an implicit end to the comments. + */ + fprintf(f, "%%%%EndComments\n\n"); +} + +static void ps_end_file(FILE * f) +{ + /* + * %%Trailer DCS must only occur once at the end of the document + * script. Any post-processing or cleanup should be contained in + * the trailer of the document, which is anything that follows the + * %%Trailer comment. Any of the document level structure comments + * that were deferred by using the (atend) convention must be + * mentioned in the trailer of the document after the %%Trailer + * comment. + */ + fprintf(f, "%%%%Trailer\n"); + + /* + * %%Pages was deferred until the end of the document via the + * (atend) mentioned, in the General Header section. + */ + fprintf(f, "%%%%Pages: %d\n", global.pagecount); + + /* + * %%EOF DCS signifies the end of the document. When the document + * manager sees this comment, it issues an end-of-file signal to the + * PostScript interpreter. This is done so system-dependent file + * endings, such as Control-D and end-of-file packets, do not + * confuse the PostScript interpreter. + */ + fprintf(f, "%%%%EOF\n"); +} + +static FILE *psopen(const char *base, const char *which) +{ + FILE *ps_open_file; + char *buf, *suff, *buf2; + + if (!global.multi_file) + return fopen(base, "w"); + + buf = (char *) malloc(strlen(base) + strlen(which) + 5); + + suff = (char *) strrchr(base, '.'); + if (suff) { + strcpy(buf, base); + buf2 = strrchr(buf, '.'); + sprintf(buf2, ".%s.%s", which, suff + 1); + } + else { + sprintf(buf, "%s.%s.ps", base, which); + } + printf("PS: open %s\n", buf); + ps_open_file = fopen(buf, "w"); + free(buf); + return ps_open_file; +} + +/* This is used by other HIDs that use a postscript format, like lpr + or eps. */ +void ps_hid_export_to_file(FILE * the_file, HID_Attr_Val * options) +{ + int i; + static int saved_layer_stack[MAX_LAYER]; + FlagType save_thindraw; + + save_thindraw = PCB->Flags; + CLEAR_FLAG(THINDRAWFLAG, PCB); + CLEAR_FLAG(THINDRAWPOLYFLAG, PCB); + CLEAR_FLAG(CHECKPLANESFLAG, PCB); + + global.f = the_file; + global.drill_helper = options[HA_drillhelper].int_value; + global.align_marks = options[HA_alignmarks].int_value; + global.outline = options[HA_outline].int_value; + global.mirror = options[HA_mirror].int_value; + global.fillpage = options[HA_fillpage].int_value; + global.automirror = options[HA_automirror].int_value; + global.incolor = options[HA_color].int_value; + global.bloat = options[HA_psbloat].int_value; + global.invert = options[HA_psinvert].int_value; + global.fade_ratio = PCB_CLAMP(options[HA_psfade].real_value, 0, 1); + global.media_idx = options[HA_media].int_value; + global.media_width = media_data[global.media_idx].Width; + global.media_height = media_data[global.media_idx].Height; + global.ps_width = global.media_width - 2.0 * media_data[global.media_idx].MarginX; + global.ps_height = global.media_height - 2.0 * media_data[global.media_idx].MarginY; + global.scale_factor = options[HA_scale].real_value; + global.calibration_x = options[HA_xcalib].real_value; + global.calibration_y = options[HA_ycalib].real_value; + global.drillcopper = options[HA_drillcopper].int_value; + global.legend = options[HA_legend].int_value; + global.polygrid = options[HA_polygrid].real_value; + + if (the_file) + ps_start_file(the_file); + + if (global.fillpage) { + double zx, zy; + if (PCB->MaxWidth > PCB->MaxHeight) { + zx = global.ps_height / PCB->MaxWidth; + zy = global.ps_width / PCB->MaxHeight; + } + else { + zx = global.ps_height / PCB->MaxHeight; + zy = global.ps_width / PCB->MaxWidth; + } + global.scale_factor *= MIN(zx, zy); + } + + memset(global.print_group, 0, sizeof(global.print_group)); + memset(global.print_layer, 0, sizeof(global.print_layer)); + + global.outline_layer = NULL; + + for (i = 0; i < max_copper_layer; i++) { + LayerType *layer = PCB->Data->Layer + i; + if (!LAYER_IS_EMPTY(layer)) + global.print_group[GetLayerGroupNumberByNumber(i)] = 1; + + if (strcmp(layer->Name, "outline") == 0 || strcmp(layer->Name, "route") == 0) { + global.outline_layer = layer; + } + } + global.print_group[GetLayerGroupNumberByNumber(solder_silk_layer)] = 1; + global.print_group[GetLayerGroupNumberByNumber(component_silk_layer)] = 1; + for (i = 0; i < max_copper_layer; i++) + if (global.print_group[GetLayerGroupNumberByNumber(i)]) + global.print_layer[i] = 1; + + memcpy(saved_layer_stack, LayerStack, sizeof(LayerStack)); + qsort(LayerStack, max_copper_layer, sizeof(LayerStack[0]), layer_sort); + + global.linewidth = -1; + /* reset static vars */ + ps_set_layer(NULL, 0, -1); + use_gc(NULL); + + global.region.X1 = 0; + global.region.Y1 = 0; + global.region.X2 = PCB->MaxWidth; + global.region.Y2 = PCB->MaxHeight; + + if (!global.multi_file) { + /* %%Page DSC requires both a label and an ordinal */ + fprintf(the_file, "%%%%Page: TableOfContents 1\n"); + fprintf(the_file, "/Times-Roman findfont 24 scalefont setfont\n"); + fprintf(the_file, "/rightshow { /s exch def s stringwidth pop -1 mul 0 rmoveto s show } def\n"); + fprintf(the_file, "/y 72 9 mul def /toc { 100 y moveto show /y y 24 sub def } bind def\n"); + fprintf(the_file, "/tocp { /y y 12 sub def 90 y moveto rightshow } bind def\n"); + + global.doing_toc = 1; + global.pagecount = 1; /* 'pagecount' is modified by hid_expose_callback() call */ + hid_expose_callback(&ps_hid, &global.region, 0); + } + + global.pagecount = 1; /* Reset 'pagecount' if single file */ + global.doing_toc = 0; + ps_set_layer(NULL, 0, -1); /* reset static vars */ + hid_expose_callback(&ps_hid, &global.region, 0); + + if (the_file) + fprintf(the_file, "showpage\n"); + + memcpy(LayerStack, saved_layer_stack, sizeof(LayerStack)); + PCB->Flags = save_thindraw; +} + +static void ps_do_export(HID_Attr_Val * options) +{ + FILE *fh; + int save_ons[MAX_LAYER + 2]; + int i; + + if (!options) { + ps_get_export_options(0); + for (i = 0; i < NUM_OPTIONS; i++) + global.ps_values[i] = ps_attribute_list[i].default_val; + options = global.ps_values; + } + + global.filename = options[HA_psfile].str_value; + if (!global.filename) + global.filename = "pcb-out.ps"; + + global.multi_file = options[HA_multifile].int_value; + + if (global.multi_file) + fh = 0; + else { + fh = psopen(global.filename, "toc"); + if (!fh) { + perror(global.filename); + return; + } + } + + hid_save_and_show_layer_ons(save_ons); + ps_hid_export_to_file(fh, options); + hid_restore_layer_ons(save_ons); + + global.multi_file = 0; + if (fh) { + ps_end_file(fh); + fclose(fh); + } +} + +static void ps_parse_arguments(int *argc, char ***argv) +{ + hid_register_attributes(ps_attribute_list, NUM_OPTIONS, ps_cookie); + hid_parse_command_line(argc, argv); +} + +static void corner(FILE * fh, Coord x, Coord y, Coord dx, Coord dy) +{ + Coord len = MIL_TO_COORD(2000); + Coord len2 = MIL_TO_COORD(200); + Coord thick = 0; + /* + * Originally 'thick' used thicker lines. Currently is uses + * Postscript's "device thin" line - i.e. zero width means one + * device pixel. The code remains in case you want to make them + * thicker - it needs to offset everything so that the *edge* of the + * thick line lines up with the edge of the board, not the *center* + * of the thick line. + */ + + pcb_fprintf(fh, "gsave %mi setlinewidth %mi %mi translate %mi %mi scale\n", thick * 2, x, y, dx, dy); + pcb_fprintf(fh, "%mi %mi moveto %mi %mi %mi 0 90 arc %mi %mi lineto\n", len, thick, thick, thick, len2 + thick, thick, len); + if (dx < 0 && dy < 0) + pcb_fprintf(fh, "%mi %mi moveto 0 %mi rlineto\n", len2 * 2 + thick, thick, -len2); + fprintf(fh, "stroke grestore\n"); +} + +static int ps_set_layer(const char *name, int group, int empty) +{ + static int lastgroup = -1; + time_t currenttime; + int idx = (group >= 0 && group < max_group) + ? PCB->LayerGroups.Entries[group][0] + : group; + if (name == 0) + name = PCB->Data->Layer[idx].Name; + + if (empty == -1) + lastgroup = -1; + if (empty) + return 0; + + if (idx >= 0 && idx < max_copper_layer && !global.print_layer[idx]) + return 0; + + if (strcmp(name, "invisible") == 0) + return 0; + + global.is_drill = (SL_TYPE(idx) == SL_PDRILL || SL_TYPE(idx) == SL_UDRILL); + global.is_mask = (SL_TYPE(idx) == SL_MASK); + global.is_assy = (SL_TYPE(idx) == SL_ASSY); + global.is_copper = (SL_TYPE(idx) == 0); + global.is_paste = (SL_TYPE(idx) == SL_PASTE); +#if 0 + printf("Layer %s group %d drill %d mask %d\n", name, group, global.is_drill, global.is_mask); +#endif + + if (global.doing_toc) { + if (group < 0 || group != lastgroup) { + if (global.pagecount == 1) { + currenttime = time(NULL); + fprintf(global.f, "30 30 moveto (%s) show\n", PCB->Filename); + + fprintf(global.f, "(%d.) tocp\n", global.pagecount); + fprintf(global.f, "(Table of Contents \\(This Page\\)) toc\n"); + + fprintf(global.f, "(Created on %s) toc\n", asctime(localtime(¤ttime))); + fprintf(global.f, "( ) tocp\n"); + } + + global.pagecount++; + lastgroup = group; + fprintf(global.f, "(%d.) tocp\n", global.pagecount); + } + fprintf(global.f, "(%s) toc\n", name); + return 0; + } + + if (group < 0 || group != lastgroup) { + double boffset; + int mirror_this = 0; + lastgroup = group; + + if (global.pagecount != 0) { + pcb_fprintf(global.f, "showpage\n"); + } + global.pagecount++; + if (global.multi_file) { + if (global.f) { + ps_end_file(global.f); + fclose(global.f); + } + global.f = psopen(global.filename, layer_type_to_file_name(idx, FNS_fixed)); + if (!global.f) { + perror(global.filename); + return 0; + } + + ps_start_file(global.f); + } + + /* + * %%Page DSC comment marks the beginning of the PostScript + * language instructions that describe a particular + * page. %%Page: requires two arguments: a page label and a + * sequential page number. The label may be anything, but the + * ordinal page number must reflect the position of that page in + * the body of the PostScript file and must start with 1, not 0. + */ + fprintf(global.f, "%%%%Page: %s %d\n", layer_type_to_file_name(idx, FNS_fixed), global.pagecount); + + if (global.mirror) + mirror_this = !mirror_this; + if (global.automirror && ((idx >= 0 && group == GetLayerGroupNumberByNumber(solder_silk_layer)) + || (idx < 0 && SL_SIDE(idx) == SL_BOTTOM_SIDE))) + mirror_this = !mirror_this; + + fprintf(global.f, "/Helvetica findfont 10 scalefont setfont\n"); + if (global.legend) { + fprintf(global.f, "30 30 moveto (%s) show\n", PCB->Filename); + if (PCB->Name) + fprintf(global.f, "30 41 moveto (%s, %s) show\n", PCB->Name, layer_type_to_file_name(idx, FNS_fixed)); + else + fprintf(global.f, "30 41 moveto (%s) show\n", layer_type_to_file_name(idx, FNS_fixed)); + if (mirror_this) + fprintf(global.f, "( \\(mirrored\\)) show\n"); + + if (global.fillpage) + fprintf(global.f, "(, not to scale) show\n"); + else + fprintf(global.f, "(, scale = 1:%.3f) show\n", global.scale_factor); + } + fprintf(global.f, "newpath\n"); + + pcb_fprintf(global.f, "72 72 scale %mi %mi translate\n", global.media_width / 2, global.media_height / 2); + + boffset = global.media_height / 2; + if (PCB->MaxWidth > PCB->MaxHeight) { + fprintf(global.f, "90 rotate\n"); + boffset = global.media_width / 2; + fprintf(global.f, "%g %g scale %% calibration\n", global.calibration_y, global.calibration_x); + } + else + fprintf(global.f, "%g %g scale %% calibration\n", global.calibration_x, global.calibration_y); + + if (mirror_this) + fprintf(global.f, "1 -1 scale\n"); + + fprintf(global.f, "%g dup neg scale\n", (SL_TYPE(idx) == SL_FAB) ? 1.0 : global.scale_factor); + pcb_fprintf(global.f, "%mi %mi translate\n", -PCB->MaxWidth / 2, -PCB->MaxHeight / 2); + + /* Keep the drill list from falling off the left edge of the paper, + * even if it means some of the board falls off the right edge. + * If users don't want to make smaller boards, or use fewer drill + * sizes, they can always ignore this sheet. */ + if (SL_TYPE(idx) == SL_FAB) { + Coord natural = boffset - MIL_TO_COORD(500) - PCB->MaxHeight / 2; + Coord needed = PrintFab_overhang(); + pcb_fprintf(global.f, "%% PrintFab overhang natural %mi, needed %mi\n", natural, needed); + if (needed > natural) + pcb_fprintf(global.f, "0 %mi translate\n", needed - natural); + } + + if (global.invert) { + fprintf(global.f, "/gray { 1 exch sub setgray } bind def\n"); + fprintf(global.f, "/rgb { 1 1 3 { pop 1 exch sub 3 1 roll } for setrgbcolor } bind def\n"); + } + else { + fprintf(global.f, "/gray { setgray } bind def\n"); + fprintf(global.f, "/rgb { setrgbcolor } bind def\n"); + } + + if ((global.outline && !global.outline_layer) ||global.invert) { + pcb_fprintf(global.f, + "0 setgray 0 setlinewidth 0 0 moveto 0 " + "%mi lineto %mi %mi lineto %mi 0 lineto closepath %s\n", + PCB->MaxHeight, PCB->MaxWidth, PCB->MaxHeight, PCB->MaxWidth, global.invert ? "fill" : "stroke"); + } + + if (global.align_marks) { + corner(global.f, 0, 0, -1, -1); + corner(global.f, PCB->MaxWidth, 0, 1, -1); + corner(global.f, PCB->MaxWidth, PCB->MaxHeight, 1, 1); + corner(global.f, 0, PCB->MaxHeight, -1, 1); + } + + global.linewidth = -1; + use_gc(NULL); /* reset static vars */ + + fprintf(global.f, + "/ts 1 def\n" + "/ty ts neg def /tx 0 def /Helvetica findfont ts scalefont setfont\n" + "/t { moveto lineto stroke } bind def\n" + "/dr { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n" + " x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath stroke } bind def\n" + "/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n" + " x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def\n" + "/c { 0 360 arc fill } bind def\n" + "/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def\n"); + if (global.drill_helper) + pcb_fprintf(global.f, + "/dh { gsave %mi setlinewidth 0 gray %mi 0 360 arc stroke grestore} bind def\n", + (Coord) MIN_PINORVIAHOLE, (Coord) (MIN_PINORVIAHOLE * 3 / 2)); + } +#if 0 + /* Try to outsmart ps2pdf's heuristics for page rotation, by putting + * text on all pages -- even if that text is blank */ + if (SL_TYPE(idx) != SL_FAB) + fprintf(global.f, "gsave tx ty translate 1 -1 scale 0 0 moveto (Layer %s) show grestore newpath /ty ty ts sub def\n", name); + else + fprintf(global.f, "gsave tx ty translate 1 -1 scale 0 0 moveto ( ) show grestore newpath /ty ty ts sub def\n"); +#endif + + /* If we're printing a layer other than the outline layer, and + we want to "print outlines", and we have an outline layer, + print the outline layer on this layer also. */ + if (global.outline && + global.outline_layer != NULL && + global.outline_layer != PCB->Data->Layer + idx && strcmp(name, "outline") != 0 && strcmp(name, "route") != 0) { + DrawLayer(global.outline_layer, &global.region); + } + + return 1; +} + +static hidGC ps_make_gc(void) +{ + hidGC rv = (hidGC) calloc(1, sizeof(hid_gc_struct)); + rv->me_pointer = &ps_hid; + rv->cap = Trace_Cap; + return rv; +} + +static void ps_destroy_gc(hidGC gc) +{ + free(gc); +} + +static void ps_use_mask(int use_it) +{ + /* does nothing */ +} + +static void ps_set_color(hidGC gc, const char *name) +{ + if (strcmp(name, "erase") == 0 || strcmp(name, "drill") == 0) { + gc->r = gc->g = gc->b = 255; + gc->erase = 1; + } + else if (global.incolor) { + int r, g, b; + sscanf(name + 1, "%02x%02x%02x", &r, &g, &b); + gc->r = r; + gc->g = g; + gc->b = b; + gc->erase = 0; + } + else { + gc->r = gc->g = gc->b = 0; + gc->erase = 0; + } +} + +static void ps_set_line_cap(hidGC gc, EndCapStyle style) +{ + gc->cap = style; +} + +static void ps_set_line_width(hidGC gc, Coord width) +{ + gc->width = width; +} + +static void ps_set_draw_xor(hidGC gc, int xor_) +{ + ; +} + +static void ps_set_draw_faded(hidGC gc, int faded) +{ + gc->faded = faded; +} + +static void use_gc(hidGC gc) +{ + static int lastcap = -1; + static int lastcolor = -1; + + if (gc == NULL) { + lastcap = lastcolor = -1; + return; + } + if (gc->me_pointer != &ps_hid) { + fprintf(stderr, "Fatal: GC from another HID passed to ps HID\n"); + abort(); + } + if (global.linewidth != gc->width) { + pcb_fprintf(global.f, "%mi setlinewidth\n", gc->width + (gc->erase ? -2 : 2) * global.bloat); + global.linewidth = gc->width; + } + if (lastcap != gc->cap) { + int c; + switch (gc->cap) { + case Round_Cap: + case Trace_Cap: + c = 1; + break; + default: + case Square_Cap: + c = 2; + break; + } + fprintf(global.f, "%d setlinecap %d setlinejoin\n", c, c); + lastcap = gc->cap; + } +#define CBLEND(gc) (((gc->r)<<24)|((gc->g)<<16)|((gc->b)<<8)|(gc->faded)) + if (lastcolor != CBLEND(gc)) { + if (global.is_drill || global.is_mask) { + fprintf(global.f, "%d gray\n", gc->erase ? 0 : 1); + lastcolor = 0; + } + else { + double r, g, b; + r = gc->r; + g = gc->g; + b = gc->b; + if (gc->faded) { + r = (1 - global.fade_ratio) *255 + global.fade_ratio * r; + g = (1 - global.fade_ratio) *255 + global.fade_ratio * g; + b = (1 - global.fade_ratio) *255 + global.fade_ratio * b; + } + if (gc->r == gc->g && gc->g == gc->b) + fprintf(global.f, "%g gray\n", r / 255.0); + else + fprintf(global.f, "%g %g %g rgb\n", r / 255.0, g / 255.0, b / 255.0); + lastcolor = CBLEND(gc); + } + } +} + +static void ps_draw_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) +{ + use_gc(gc); + pcb_fprintf(global.f, "%mi %mi %mi %mi dr\n", x1, y1, x2, y2); +} + +static void ps_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); +static void ps_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius); + +static void ps_draw_line(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) +{ +#if 0 + /* If you're etching your own paste mask, this will reduce the + amount of brass you need to etch by drawing outlines for large + pads. See also ps_fill_rect. */ + if (is_paste && gc->width > 2500 && gc->cap == Square_Cap && (x1 == x2 || y1 == y2)) { + Coord t, w; + if (x1 > x2) { + t = x1; + x1 = x2; + x2 = t; + } + if (y1 > y2) { + t = y1; + y1 = y2; + y2 = t; + } + w = gc->width / 2; + ps_fill_rect(gc, x1 - w, y1 - w, x2 + w, y2 + w); + return; + } +#endif + if (x1 == x2 && y1 == y2) { + Coord w = gc->width / 2; + if (gc->cap == Square_Cap) + ps_fill_rect(gc, x1 - w, y1 - w, x1 + w, y1 + w); + else + ps_fill_circle(gc, x1, y1, w); + return; + } + use_gc(gc); + pcb_fprintf(global.f, "%mi %mi %mi %mi t\n", x1, y1, x2, y2); +} + +static void ps_draw_arc(hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle) +{ + Angle sa, ea; + if (delta_angle > 0) { + sa = start_angle; + ea = start_angle + delta_angle; + } + else { + sa = start_angle + delta_angle; + ea = start_angle; + } +#if 0 + printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n", cx, cy, width, height, start_angle, delta_angle, sa, ea); +#endif + use_gc(gc); + pcb_fprintf(global.f, "%ma %ma %mi %mi %mi %mi %g a\n", + sa, ea, -width, height, cx, cy, (double) (global.linewidth + 2 * global.bloat) /(double) width); +} + +static void ps_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius) +{ + use_gc(gc); + if (!gc->erase || !global.is_copper || global.drillcopper) { + if (gc->erase && global.is_copper && global.drill_helper && radius >= PCB->minDrill / 4) + radius = PCB->minDrill / 4; + pcb_fprintf(global.f, "%mi %mi %mi c\n", cx, cy, radius + (gc->erase ? -1 : 1) * global.bloat); + } +} + +static void ps_fill_polygon(hidGC gc, int n_coords, Coord * x, Coord * y) +{ + int i; + char *op = "moveto"; + use_gc(gc); + for (i = 0; i < n_coords; i++) { + pcb_fprintf(global.f, "%mi %mi %s\n", x[i], y[i], op); + op = "lineto"; + } + fprintf(global.f, "fill\n"); +} + +typedef struct { + Coord x1, y1, x2, y2; +} lseg_t; + +typedef struct { + Coord x, y; +} lpoint_t; + +#define minmax(val, min, max) \ +do { \ + if (val < min) min = val; \ + if (val > max) max = val; \ +} while(0) + +#define lsegs_append(x1_, y1_, x2_, y2_) \ +do { \ + if (y1_ < y2_) { \ + lsegs[lsegs_used].x1 = x1_; \ + lsegs[lsegs_used].y1 = y1_; \ + lsegs[lsegs_used].x2 = x2_; \ + lsegs[lsegs_used].y2 = y2_; \ + } \ + else { \ + lsegs[lsegs_used].x2 = x1_; \ + lsegs[lsegs_used].y2 = y1_; \ + lsegs[lsegs_used].x1 = x2_; \ + lsegs[lsegs_used].y1 = y2_; \ + } \ + lsegs_used++; \ + minmax(y1_, lsegs_ymin, lsegs_ymax); \ + minmax(y2_, lsegs_ymin, lsegs_ymax); \ + minmax(x1_, lsegs_xmin, lsegs_xmax); \ + minmax(x2_, lsegs_xmin, lsegs_xmax); \ +} while(0) + +#define lseg_line(x1_, y1_, x2_, y2_) \ + do { \ + fprintf(global.f, "newpath\n"); \ + pcb_fprintf(global.f, "%mi %mi moveto\n", x1_, y1_); \ + pcb_fprintf(global.f, "%mi %mi lineto\n", x2_, y2_); \ + fprintf (global.f, "stroke\n"); \ + } while(0) + +int coord_comp(const void *c1_, const void *c2_) +{ + const Coord *c1 = c1_, *c2 = c2_; + return *c1 < *c2; +} + +static void ps_fill_pcb_polygon(hidGC gc, PolygonType * poly, const BoxType * clip_box) +{ + /* Ignore clip_box, just draw everything */ + + VNODE *v; + PLINE *pl; + char *op; + int len; + double POLYGRID = ps_attribute_list[HA_polygrid].default_val.real_value; + + use_gc(gc); + + pl = poly->Clipped->contours; + len = 0; + if (POLYGRID > 0.1) + POLYGRID *= 1000000.0; + + do { + v = pl->head.next; + if (POLYGRID > 0.1) + fprintf(global.f, "closepath\n"); + op = "moveto"; + do { + pcb_fprintf(global.f, "%mi %mi %s\n", v->point[0], v->point[1], op); + op = "lineto"; + len++; + } + while ((v = v->next) != pl->head.next); + len++; + } + while ((pl = pl->next) != NULL); + + if (POLYGRID > 0.1) { + Coord y, x, lx, ly, fx, fy, lsegs_xmin, lsegs_xmax, lsegs_ymin, lsegs_ymax; + lseg_t *lsegs = alloca(sizeof(lseg_t) * len); + Coord *lpoints = alloca(sizeof(Coord) * len); + int lsegs_used = 0; + + lsegs_xmin = -1000000000; + lsegs_ymin = -1000000000; + lsegs_xmax = +1000000000; + lsegs_ymax = +1000000000; + + /* save all line segs in an array */ + pl = poly->Clipped->contours; + do { + v = pl->head.next; + fx = v->point[0]; + fy = v->point[1]; + goto start1; + do { + lsegs_append(lx, ly, v->point[0], v->point[1]); + start1:; + lx = v->point[0]; + ly = v->point[1]; + } while ((v = v->next) != pl->head.next); + lsegs_append(lx, ly, fx, fy); + } while ((pl = pl->next) != NULL); + + + + + fprintf(global.f, "%% POLYGRID2\n"); + fprintf(global.f, "gsave\n"); + fprintf(global.f, "0.0015 setlinewidth\n"); + fprintf(global.f, "closepath\n"); + fprintf(global.f, "stroke\n"); + + for (y = lsegs_ymin; y < lsegs_ymax; y += POLYGRID) { + int pts, n; +/* pcb_fprintf(global.f, "%% gridline at y %mi\n", y);*/ + retry1:; + if (y > lsegs_ymax) + break; + pts = 0; + for (n = 0; n < lsegs_used; n++) { + if ((lsegs[n].y1 <= y) && (lsegs[n].y2 >= y)) { + if ((lsegs[n].y2 == lsegs[n].y1) || (lsegs[n].y1 == y) || (lsegs[n].y2 == y)) { + y += POLYGRID / 100.0; + goto retry1; + } + x = lsegs[n].x1 + (lsegs[n].x2 - lsegs[n].x1) * (y - lsegs[n].y1) / (lsegs[n].y2 - lsegs[n].y1); + lpoints[pts] = x; + pts++; + } + } + if ((pts % 2) != 0) { + y += POLYGRID / 100.0; + goto retry1; + } + if (pts > 1) { + qsort(lpoints, pts, sizeof(Coord), coord_comp); + for (n = 0; n < pts; n += 2) + lseg_line(lpoints[n], y, lpoints[n + 1], y); + } + } + + for (x = lsegs_xmin; x < lsegs_xmax; x += POLYGRID) { + int pts, n; +/* pcb_fprintf(global.f, "%% gridline at y %mi\n", y); */ + retry2:; + if (x > lsegs_xmax) + break; + pts = 0; + for (n = 0; n < lsegs_used; n++) { + if (((lsegs[n].x1 <= x) && (lsegs[n].x2 >= x)) || ((lsegs[n].x1 >= x) && (lsegs[n].x2 <= x))) { + if ((lsegs[n].x2 == lsegs[n].x1) || (lsegs[n].x1 == x) || (lsegs[n].x2 == x)) { + x += POLYGRID / 100.0; + goto retry2; + } + y = lsegs[n].y1 + (lsegs[n].y2 - lsegs[n].y1) * (x - lsegs[n].x1) / (lsegs[n].x2 - lsegs[n].x1); + lpoints[pts] = y; + pts++; + } + } + if ((pts % 2) != 0) { + x += POLYGRID / 100.0; + goto retry2; + } + if ((pts > 1)) { + qsort(lpoints, pts, sizeof(Coord), coord_comp); + for (n = 0; n < pts; n += 2) + lseg_line(x, lpoints[n], x, lpoints[n + 1]); + } + } + + + fprintf(global.f, "grestore\nnewpath\n"); + } + else + fprintf(global.f, "fill\n"); +} + +static void ps_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) +{ + use_gc(gc); + if (x1 > x2) { + Coord t = x1; + x1 = x2; + x2 = t; + } + if (y1 > y2) { + Coord t = y1; + y1 = y2; + y2 = t; + } +#if 0 + /* See comment in ps_draw_line. */ + if (is_paste && (x2 - x1) > 2500 && (y2 - y1) > 2500) { + linewidth = 1000; + lastcap = Round_Cap; + fprintf(f, "1000 setlinewidth 1 setlinecap 1 setlinejoin\n"); + fprintf(f, "%d %d moveto %d %d lineto %d %d lineto %d %d lineto closepath stroke\n", + x1 + 500 - bloat, y1 + 500 - bloat, + x1 + 500 - bloat, y2 - 500 + bloat, x2 - 500 + bloat, y2 - 500 + bloat, x2 - 500 + bloat, y1 + 500 - bloat); + return; + } +#endif + pcb_fprintf(global.f, "%mi %mi %mi %mi r\n", x1 - global.bloat, y1 - global.bloat, x2 + global.bloat, y2 + global.bloat); +} + +HID_Attribute ps_calib_attribute_list[] = { + {"lprcommand", "Command to print", + HID_String, 0, 0, {0, 0, 0}, 0, 0}, +}; + +static const char *const calib_lines[] = { + "%!PS-Adobe-3.0\n", + "%%Title: Calibration Page\n", + "%%PageOrder: Ascend\n", + "%%Pages: 1\n", + "%%EndComments\n", + "\n", + "%%Page: Calibrate 1\n", + "72 72 scale\n", + "\n", + "0 setlinewidth\n", + "0.375 0.375 moveto\n", + "8.125 0.375 lineto\n", + "8.125 10.625 lineto\n", + "0.375 10.625 lineto\n", + "closepath stroke\n", + "\n", + "0.5 0.5 translate\n", + "0.001 setlinewidth\n", + "\n", + "/Times-Roman findfont 0.2 scalefont setfont\n", + "\n", + "/sign {\n", + " 0 lt { -1 } { 1 } ifelse\n", + "} def\n", + "\n", + "/cbar {\n", + " /units exch def\n", + " /x exch def\n", + " /y exch def \n", + "\n", + " /x x sign 0.5 mul def\n", + "\n", + " 0 setlinewidth\n", + " newpath x y 0.25 0 180 arc gsave 0.85 setgray fill grestore closepath stroke\n", + " newpath x 0 0.25 180 360 arc gsave 0.85 setgray fill grestore closepath stroke\n", + " 0.001 setlinewidth\n", + "\n", + " x 0 moveto\n", + " x y lineto\n", + "% -0.07 -0.2 rlineto 0.14 0 rmoveto -0.07 0.2 rlineto\n", + " x y lineto\n", + " -0.1 0 rlineto 0.2 0 rlineto\n", + " stroke\n", + " x 0 moveto\n", + "% -0.07 0.2 rlineto 0.14 0 rmoveto -0.07 -0.2 rlineto\n", + " x 0 moveto\n", + " -0.1 0 rlineto 0.2 0 rlineto\n", + " stroke\n", + "\n", + " x 0.1 add\n", + " y 0.2 sub moveto\n", + " units show\n", + "} bind def\n", + "\n", + "/y 9 def\n", + "/t {\n", + " /str exch def\n", + " 1.5 y moveto str show\n", + " /y y 0.25 sub def\n", + "} bind def\n", + "\n", + "(Please measure ONE of the horizontal lines, in the units indicated for)t\n", + "(that line, and enter that value as X. Similarly, measure ONE of the)t\n", + "(vertical lines and enter that value as Y. Measurements should be)t\n", + "(between the flat faces of the semicircles.)t\n", + "()t\n", + "(The large box is 10.25 by 7.75 inches)t\n", + "\n", + "/in { } bind def\n", + "/cm { 2.54 div } bind def\n", + "/mm { 25.4 div } bind def\n", + "\n", + 0 +}; + +static int guess(double val, double close_to, double *calib) +{ + if (val >= close_to * 0.9 && val <= close_to * 1.1) { + *calib = close_to / val; + return 0; + } + return 1; +} + +void ps_calibrate_1(double xval, double yval, int use_command) +{ + HID_Attr_Val vals[3]; + FILE *ps_cal_file; + int used_popen = 0, c; + + if (xval > 0 && yval > 0) { + if (guess(xval, 4, &global.calibration_x)) + if (guess(xval, 15, &global.calibration_x)) + if (guess(xval, 7.5, &global.calibration_x)) { + if (xval < 2) + ps_attribute_list[HA_xcalib].default_val.real_value = global.calibration_x = xval; + else + Message("X value of %g is too far off.\n" "Expecting it near: 1.0, 4.0, 15.0, 7.5\n", xval); + } + if (guess(yval, 4, &global.calibration_y)) + if (guess(yval, 20, &global.calibration_y)) + if (guess(yval, 10, &global.calibration_y)) { + if (yval < 2) + ps_attribute_list[HA_ycalib].default_val.real_value = global.calibration_y = yval; + else + Message("Y value of %g is too far off.\n" "Expecting it near: 1.0, 4.0, 20.0, 10.0\n", yval); + } + return; + } + + if (ps_calib_attribute_list[0].default_val.str_value == NULL) { + ps_calib_attribute_list[0].default_val.str_value = strdup("lpr"); + } + + if (gui-> + attribute_dialog(ps_calib_attribute_list, 1, vals, _("Print Calibration Page"), + _("Generates a printer calibration page"))) + return; + + if (use_command || strchr(vals[0].str_value, '|')) { + const char *cmd = vals[0].str_value; + while (*cmd == ' ' || *cmd == '|') + cmd++; + ps_cal_file = popen(cmd, "w"); + used_popen = 1; + } + else + ps_cal_file = fopen(vals[0].str_value, "w"); + + for (c = 0; calib_lines[c]; c++) + fputs(calib_lines[c], ps_cal_file); + + fprintf(ps_cal_file, "4 in 0.5 (Y in) cbar\n"); + fprintf(ps_cal_file, "20 cm 1.5 (Y cm) cbar\n"); + fprintf(ps_cal_file, "10 in 2.5 (Y in) cbar\n"); + fprintf(ps_cal_file, "-90 rotate\n"); + fprintf(ps_cal_file, "4 in -0.5 (X in) cbar\n"); + fprintf(ps_cal_file, "15 cm -1.5 (X cm) cbar\n"); + fprintf(ps_cal_file, "7.5 in -2.5 (X in) cbar\n"); + + fprintf(ps_cal_file, "showpage\n"); + + fprintf(ps_cal_file, "%%%%EOF\n"); + + if (used_popen) + pclose(ps_cal_file); + else + fclose(ps_cal_file); +} + +static void ps_calibrate(double xval, double yval) +{ + ps_calibrate_1(xval, yval, 0); +} + +static void ps_set_crosshair(int x, int y, int action) +{ +} + +static int ActionPSCalib(int argc, char **argv, Coord x, Coord y) +{ + ps_calibrate(0.0, 0.0); + return 0; +} + +HID_Action hidps_action_list[] = { + {"pscalib", 0, ActionPSCalib} +}; + +REGISTER_ACTIONS(hidps_action_list, ps_cookie) + + +#include "dolists.h" + +HID ps_hid; +void ps_ps_init(HID * hid) +{ + hid->get_export_options = ps_get_export_options; + hid->do_export = ps_do_export; + hid->parse_arguments = ps_parse_arguments; + hid->set_layer = ps_set_layer; + hid->make_gc = ps_make_gc; + hid->destroy_gc = ps_destroy_gc; + hid->use_mask = ps_use_mask; + hid->set_color = ps_set_color; + hid->set_line_cap = ps_set_line_cap; + hid->set_line_width = ps_set_line_width; + hid->set_draw_xor = ps_set_draw_xor; + hid->set_draw_faded = ps_set_draw_faded; + hid->draw_line = ps_draw_line; + hid->draw_arc = ps_draw_arc; + hid->draw_rect = ps_draw_rect; + hid->fill_circle = ps_fill_circle; + hid->fill_polygon = ps_fill_polygon; + hid->fill_pcb_polygon = ps_fill_pcb_polygon; + hid->fill_rect = ps_fill_rect; + hid->calibrate = ps_calibrate; + hid->set_crosshair = ps_set_crosshair; + + REGISTER_ACTIONS(hidps_action_list, ps_cookie) +} + +void hid_export_ps_init() +{ + memset(&ps_hid, 0, sizeof(HID)); + + common_nogui_init(&ps_hid); + common_draw_helpers_init(&ps_hid); + ps_ps_init(&ps_hid); + + ps_hid.struct_size = sizeof(HID); + ps_hid.name = "ps"; + ps_hid.description = "Postscript export"; + ps_hid.exporter = 1; + ps_hid.poly_before = 1; + + hid_register_hid(&ps_hid); + + hid_eps_init(); +} Index: trunk/src_plugins/export_ps/ps.h =================================================================== --- trunk/src_plugins/export_ps/ps.h (nonexistent) +++ trunk/src_plugins/export_ps/ps.h (revision 1263) @@ -0,0 +1,9 @@ +/* $Id$ */ + +extern const char *ps_cookie; +extern HID ps_hid; +extern void ps_hid_export_to_file(FILE *, HID_Attr_Val *); +extern void ps_start_file(FILE *); +extern void ps_calibrate_1(double, double, int); +extern void hid_eps_init(); +void ps_ps_init(HID * hid);