pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 #ifdef HAVE_CONFIG_H 00002 #include "config.h" 00003 #endif 00004 00005 #include <stdio.h> 00006 #include <stdarg.h> /* not used */ 00007 #include <stdlib.h> 00008 #include <string.h> 00009 #include <assert.h> /* not used */ 00010 #include <time.h> 00011 00012 #include "global.h" 00013 #include "data.h" 00014 #include "misc.h" 00015 #include "error.h" 00016 #include "draw.h" 00017 #include "pcb-printf.h" 00018 00019 #include "hid.h" 00020 #include "hid_draw.h" 00021 #include "../hidint.h" 00022 #include "hid/common/hidnogui.h" 00023 #include "hid/common/draw_helpers.h" 00024 #include "../ps/ps.h" 00025 #include "../../print.h" 00026 #include "hid/common/hidinit.h" 00027 00028 #ifdef HAVE_LIBDMALLOC 00029 #include <dmalloc.h> 00030 #endif 00031 00032 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented PS function %s.\n", __FUNCTION__); abort() 00033 00034 static int ps_set_layer (const char *name, int group, int empty); 00035 static void use_gc (hidGC gc); 00036 00037 typedef struct hid_gc_struct 00038 { 00039 HID *me_pointer; 00040 EndCapStyle cap; 00041 Coord width; 00042 unsigned char r, g, b; 00043 int erase; 00044 int faded; 00045 } hid_gc_struct; 00046 00047 static const char *medias[] = { 00048 "A0", "A1", "A2", "A3", "A4", "A5", 00049 "A6", "A7", "A8", "A9", "A10", 00050 "B0", "B1", "B2", "B3", "B4", "B5", 00051 "B6", "B7", "B8", "B9", "B10", 00052 "Letter", "11x17", "Ledger", 00053 "Legal", "Executive", 00054 "A-Size", "B-size", 00055 "C-Size", "D-size", "E-size", 00056 "US-Business_Card", "Intl-Business_Card", 00057 0 00058 }; 00059 00060 typedef struct 00061 { 00062 char *name; 00063 Coord Width, Height; 00064 Coord MarginX, MarginY; 00065 } MediaType; 00066 00067 /* 00068 * Metric ISO sizes in mm. See http://en.wikipedia.org/wiki/ISO_paper_sizes 00069 * 00070 * A0 841 x 1189 00071 * A1 594 x 841 00072 * A2 420 x 594 00073 * A3 297 x 420 00074 * A4 210 x 297 00075 * A5 148 x 210 00076 * A6 105 x 148 00077 * A7 74 x 105 00078 * A8 52 x 74 00079 * A9 37 x 52 00080 * A10 26 x 37 00081 * 00082 * B0 1000 x 1414 00083 * B1 707 x 1000 00084 * B2 500 x 707 00085 * B3 353 x 500 00086 * B4 250 x 353 00087 * B5 176 x 250 00088 * B6 125 x 176 00089 * B7 88 x 125 00090 * B8 62 x 88 00091 * B9 44 x 62 00092 * B10 31 x 44 00093 * 00094 * awk '{printf(" {\"%s\", %d, %d, MARGINX, MARGINY},\n", $2, $3*100000/25.4, $5*100000/25.4)}' 00095 * 00096 * See http://en.wikipedia.org/wiki/Paper_size#Loose_sizes for some of the other sizes. The 00097 * {A,B,C,D,E}-Size here are the ANSI sizes and not the architectural sizes. 00098 */ 00099 00100 #define MARGINX MIL_TO_COORD(500) 00101 #define MARGINY MIL_TO_COORD(500) 00102 00103 static MediaType media_data[] = { 00104 {"A0", MM_TO_COORD(841), MM_TO_COORD(1189), MARGINX, MARGINY}, 00105 {"A1", MM_TO_COORD(594), MM_TO_COORD(841), MARGINX, MARGINY}, 00106 {"A2", MM_TO_COORD(420), MM_TO_COORD(594), MARGINX, MARGINY}, 00107 {"A3", MM_TO_COORD(297), MM_TO_COORD(420), MARGINX, MARGINY}, 00108 {"A4", MM_TO_COORD(210), MM_TO_COORD(297), MARGINX, MARGINY}, 00109 {"A5", MM_TO_COORD(148), MM_TO_COORD(210), MARGINX, MARGINY}, 00110 {"A6", MM_TO_COORD(105), MM_TO_COORD(148), MARGINX, MARGINY}, 00111 {"A7", MM_TO_COORD(74), MM_TO_COORD(105), MARGINX, MARGINY}, 00112 {"A8", MM_TO_COORD(52), MM_TO_COORD(74), MARGINX, MARGINY}, 00113 {"A9", MM_TO_COORD(37), MM_TO_COORD(52), MARGINX, MARGINY}, 00114 {"A10", MM_TO_COORD(26), MM_TO_COORD(37), MARGINX, MARGINY}, 00115 {"B0", MM_TO_COORD(1000), MM_TO_COORD(1414), MARGINX, MARGINY}, 00116 {"B1", MM_TO_COORD(707), MM_TO_COORD(1000), MARGINX, MARGINY}, 00117 {"B2", MM_TO_COORD(500), MM_TO_COORD(707), MARGINX, MARGINY}, 00118 {"B3", MM_TO_COORD(353), MM_TO_COORD(500), MARGINX, MARGINY}, 00119 {"B4", MM_TO_COORD(250), MM_TO_COORD(353), MARGINX, MARGINY}, 00120 {"B5", MM_TO_COORD(176), MM_TO_COORD(250), MARGINX, MARGINY}, 00121 {"B6", MM_TO_COORD(125), MM_TO_COORD(176), MARGINX, MARGINY}, 00122 {"B7", MM_TO_COORD(88), MM_TO_COORD(125), MARGINX, MARGINY}, 00123 {"B8", MM_TO_COORD(62), MM_TO_COORD(88), MARGINX, MARGINY}, 00124 {"B9", MM_TO_COORD(44), MM_TO_COORD(62), MARGINX, MARGINY}, 00125 {"B10", MM_TO_COORD(31), MM_TO_COORD(44), MARGINX, MARGINY}, 00126 {"Letter", INCH_TO_COORD(8.5), INCH_TO_COORD(11), MARGINX, MARGINY}, 00127 {"11x17", INCH_TO_COORD(11), INCH_TO_COORD(17), MARGINX, MARGINY}, 00128 {"Ledger", INCH_TO_COORD(17), INCH_TO_COORD(11), MARGINX, MARGINY}, 00129 {"Legal", INCH_TO_COORD(8.5), INCH_TO_COORD(14), MARGINX, MARGINY}, 00130 {"Executive", INCH_TO_COORD(7.5), INCH_TO_COORD(10), MARGINX, MARGINY}, 00131 {"A-size", INCH_TO_COORD(8.5), INCH_TO_COORD(11), MARGINX, MARGINY}, 00132 {"B-size", INCH_TO_COORD(11), INCH_TO_COORD(17), MARGINX, MARGINY}, 00133 {"C-size", INCH_TO_COORD(17), INCH_TO_COORD(22), MARGINX, MARGINY}, 00134 {"D-size", INCH_TO_COORD(22), INCH_TO_COORD(34), MARGINX, MARGINY}, 00135 {"E-size", INCH_TO_COORD(34), INCH_TO_COORD(44), MARGINX, MARGINY}, 00136 {"US-Business_Card", INCH_TO_COORD(3.5), INCH_TO_COORD(2.0), 0, 0}, 00137 {"Intl-Business_Card", INCH_TO_COORD(3.375), INCH_TO_COORD(2.125), 0, 0} 00138 }; 00139 00140 #undef MARGINX 00141 #undef MARGINY 00142 00143 HID_Attribute ps_attribute_list[] = { 00144 /* other HIDs expect this to be first. */ 00145 00146 /* %start-doc options "91 Postscript Export" 00147 @ftable @code 00148 @item --psfile <string> 00149 Name of the postscript output file. Can contain a path. 00150 @end ftable 00151 %end-doc 00152 */ 00153 {N_("psfile"), N_("Postscript output file"), 00154 HID_String, 0, 0, {0, 0, 0}, 0, 0}, 00155 #define HA_psfile 0 00156 00157 /* %start-doc options "91 Postscript Export" 00158 @ftable @code 00159 @cindex drill-helper 00160 @item --drill-helper 00161 Print a centering target in large drill holes. 00162 @end ftable 00163 %end-doc 00164 */ 00165 {N_("drill-helper"), N_("Print a centering target in large drill holes"), 00166 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, 00167 #define HA_drillhelper 1 00168 00169 /* %start-doc options "91 Postscript Export" 00170 @ftable @code 00171 @cindex align-marks 00172 @item --align-marks 00173 Print alignment marks on each sheet. This is meant to ease alignment during exposure. 00174 @end ftable 00175 %end-doc 00176 */ 00177 {N_("align-marks"), N_("Print alignment marks on each sheet"), 00178 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0}, 00179 #define HA_alignmarks 2 00180 00181 /* %start-doc options "91 Postscript Export" 00182 @ftable @code 00183 @item --outline 00184 Print the contents of the outline layer on each sheet. 00185 @end ftable 00186 %end-doc 00187 */ 00188 {N_("outline"), N_("Print outline on each sheet"), 00189 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0}, 00190 #define HA_outline 3 00191 /* %start-doc options "91 Postscript Export" 00192 @ftable @code 00193 @item --mirror 00194 Print mirror image. 00195 @end ftable 00196 %end-doc 00197 */ 00198 {N_("mirror"), N_("Print mirror image of every page"), 00199 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, 00200 #define HA_mirror 4 00201 00202 /* %start-doc options "91 Postscript Export" 00203 @ftable @code 00204 @item --fill-page 00205 Scale output to make the board fit the page. 00206 @end ftable 00207 %end-doc 00208 */ 00209 {N_("fill-page"), N_("Scale board to fill page"), 00210 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, 00211 #define HA_fillpage 5 00212 00213 /* %start-doc options "91 Postscript Export" 00214 @ftable @code 00215 @item --auto-mirror 00216 Print mirror image of appropriate layers. 00217 @end ftable 00218 %end-doc 00219 */ 00220 {N_("auto-mirror"), N_("Print mirror image of appropriate layers"), 00221 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0}, 00222 #define HA_automirror 6 00223 00224 /* %start-doc options "91 Postscript Export" 00225 @ftable @code 00226 @item --ps-color 00227 Postscript output in color. 00228 @end ftable 00229 %end-doc 00230 */ 00231 {N_("ps-color"), N_("Prints in color"), 00232 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, 00233 #define HA_color 7 00234 00235 /* %start-doc options "91 Postscript Export" 00236 @ftable @code 00237 @cindex ps-bloat 00238 @item --ps-bloat <num> 00239 Amount to add to trace/pad/pin edges. 00240 @end ftable 00241 %end-doc 00242 */ 00243 {N_("ps-bloat"), N_("Amount to add to trace/pad/pin edges"), 00244 HID_Coord, -MIL_TO_COORD (100), MIL_TO_COORD (100), {0, 0, 0}, 0, 0}, 00245 #define HA_psbloat 8 00246 00247 /* %start-doc options "91 Postscript Export" 00248 @ftable @code 00249 @cindex ps-invert 00250 @item --ps-invert 00251 Draw objects as white-on-black. 00252 @end ftable 00253 %end-doc 00254 */ 00255 {N_("ps-invert"), N_("Draw objects as white-on-black"), 00256 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, 00257 #define HA_psinvert 9 00258 00259 /* %start-doc options "91 Postscript Export" 00260 @ftable @code 00261 @item --media <media-name> 00262 Size of the media, the postscript is fitted to. The parameter 00263 @code{<media-name>} can be any of the standard names for paper size: @samp{A0} 00264 to @samp{A10}, @samp{B0} to @samp{B10}, @samp{Letter}, @samp{11x17}, 00265 @samp{Ledger}, @samp{Legal}, @samp{Executive}, @samp{A-Size}, @samp{B-size}, 00266 @samp{C-Size}, @samp{D-size}, @samp{E-size}, @samp{US-Business_Card}, 00267 @samp{Intl-Business_Card}. 00268 @end ftable 00269 %end-doc 00270 */ 00271 {N_("media"), N_("Media type"), 00272 HID_Enum, 0, 0, {22, 0, 0}, medias, 0}, 00273 #define HA_media 10 00274 00275 /* %start-doc options "91 Postscript Export" 00276 @ftable @code 00277 @cindex psfade 00278 @item --psfade <num> 00279 Fade amount for assembly drawings (0.0=missing, 1.0=solid). 00280 @end ftable 00281 %end-doc 00282 */ 00283 {N_("psfade"), 00284 N_("Fade amount for assembly drawings (0.0=missing, 1.0=solid)"), 00285 HID_Real, 0, 1, {0, 0, 0.40}, 0, 0}, 00286 #define HA_psfade 11 00287 00288 /* %start-doc options "91 Postscript Export" 00289 @ftable @code 00290 @item --scale <num> 00291 Scale value to compensate for printer sizing errors (1.0 = full scale). 00292 @end ftable 00293 %end-doc 00294 */ 00295 {N_("scale"), 00296 N_("Scale value to compensate for printer sizing errors (1.0 = full scale)"), 00297 HID_Real, 0.01, 4, {0, 0, 1.00}, 0, 0}, 00298 #define HA_scale 12 00299 00300 /* %start-doc options "91 Postscript Export" 00301 @ftable @code 00302 @cindex multi-file 00303 @item --multi-file 00304 Produce multiple files, one per page, instead of a single multi page file. 00305 @end ftable 00306 %end-doc 00307 */ 00308 {N_("multi-file"), 00309 N_("Produce multiple files, one per page, instead of a single file"), 00310 HID_Boolean, 0, 0, {0, 0, 0.40}, 0, 0}, 00311 #define HA_multifile 13 00312 00313 /* %start-doc options "91 Postscript Export" 00314 @ftable @code 00315 @item --xcalib <num> 00316 Paper width. Used for x-Axis calibration. 00317 @end ftable 00318 %end-doc 00319 */ 00320 {N_("xcalib"), N_("Paper width. Used for x-Axis calibration"), 00321 HID_Real, 0, 0, {0, 0, 1.0}, 0, 0}, 00322 #define HA_xcalib 14 00323 00324 /* %start-doc options "91 Postscript Export" 00325 @ftable @code 00326 @item --ycalib <num> 00327 Paper height. Used for y-Axis calibration. 00328 @end ftable 00329 %end-doc 00330 */ 00331 {N_("ycalib"), N_("Paper height. Used for y-Axis calibration"), 00332 HID_Real, 0, 0, {0, 0, 1.0}, 0, 0}, 00333 #define HA_ycalib 15 00334 00335 /* %start-doc options "91 Postscript Export" 00336 @ftable @code 00337 @item --drill-copper 00338 Draw drill holes in pins / vias, instead of leaving solid copper. 00339 @end ftable 00340 %end-doc 00341 */ 00342 {N_("drill-copper"), 00343 N_("Draw drill holes in pins / vias, instead of leaving solid copper"), 00344 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0}, 00345 #define HA_drillcopper 16 00346 00347 /* %start-doc options "91 Postscript Export" 00348 @ftable @code 00349 @cindex show-legend 00350 @item --show-legend 00351 Print file name and scale on printout. 00352 @end ftable 00353 %end-doc 00354 */ 00355 {N_("show-legend"), N_("Print file name and scale on printout"), 00356 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0}, 00357 #define HA_legend 17 00358 }; 00359 00360 #define NUM_OPTIONS (sizeof(ps_attribute_list)/sizeof(ps_attribute_list[0])) 00361 00362 REGISTER_ATTRIBUTES (ps_attribute_list) 00363 00364 /* All file-scope data is in global struct */ 00365 static struct { 00366 double calibration_x, calibration_y; 00367 00368 FILE *f; 00369 int pagecount; 00370 Coord linewidth; 00371 bool print_group[MAX_GROUP]; 00372 bool print_layer[MAX_ALL_LAYER]; 00373 double fade_ratio; 00374 bool multi_file; 00375 Coord media_width, media_height, ps_width, ps_height; 00376 00377 const char *filename; 00378 bool drill_helper; 00379 bool align_marks; 00380 bool outline; 00381 bool mirror; 00382 bool fillpage; 00383 bool automirror; 00384 bool incolor; 00385 bool doing_toc; 00386 Coord bloat; 00387 bool invert; 00388 int media_idx; 00389 bool drillcopper; 00390 bool legend; 00391 00392 LayerType *outline_layer; 00393 00394 double scale_factor; 00395 00396 BoxType region; 00397 00398 HID_Attr_Val ps_values[NUM_OPTIONS]; 00399 00400 bool is_mask; 00401 bool is_drill; 00402 bool is_assy; 00403 bool is_copper; 00404 bool is_paste; 00405 } global; 00406 00407 static HID_Attribute * 00408 ps_get_export_options (int *n) 00409 { 00410 static char *last_made_filename = 0; 00411 if (PCB) 00412 derive_default_filename(PCB->Filename, &ps_attribute_list[HA_psfile], ".ps", &last_made_filename); 00413 00414 if (n) 00415 *n = NUM_OPTIONS; 00416 return ps_attribute_list; 00417 } 00418 00419 static int 00420 layer_stack_sort (const void *va, const void *vb) 00421 { 00422 int a_layer = *(int *) va; 00423 int b_layer = *(int *) vb; 00424 int a_group = GetLayerGroupNumberByNumber (a_layer); 00425 int b_group = GetLayerGroupNumberByNumber (b_layer); 00426 00427 if (b_group != a_group) 00428 return b_group - a_group; 00429 00430 return b_layer - a_layer; 00431 } 00432 00433 void 00434 ps_start_file (FILE *f) 00435 { 00436 time_t currenttime = time( NULL ); 00437 00438 fprintf (f, "%%!PS-Adobe-3.0\n"); 00439 00440 /* Document Structuring Conventions (DCS): */ 00441 00442 /* Start General Header Comments: */ 00443 00444 /* 00445 * %%Title DCS provides text title for the document that is useful 00446 * for printing banner pages. 00447 */ 00448 fprintf (f, "%%%%Title: %s\n", PCB->Filename); 00449 00450 /* 00451 * %%CreationDate DCS indicates the date and time the document was 00452 * created. Neither the date nor time need be in any standard 00453 * format. This comment is meant to be used purely for informational 00454 * purposes, such as printing on banner pages. 00455 */ 00456 fprintf (f, "%%%%CreationDate: %s", asctime (localtime (¤ttime))); 00457 00458 /* 00459 * %%Creator DCS indicates the document creator, usually the name of 00460 * the document composition software. 00461 */ 00462 fprintf (f, "%%%%Creator: PCB release: %s " VERSION "\n", Progname); 00463 00464 /* 00465 * %%Version DCS comment can be used to note the version and 00466 * revision number of a document or resource. A document manager may 00467 * wish to provide version control services, or allow substitution 00468 * of compatible versions/revisions of a resource or document. 00469 * 00470 * The format should be in the form of 'procname': 00471 * <procname>::= < name> < version> < revision> 00472 * < name> ::= < text> 00473 * < version> ::= < real> 00474 * < revision> ::= < uint> 00475 * 00476 * If a version numbering scheme is not used, these fields should 00477 * still be filled with a dummy value of 0. 00478 * 00479 * There is currently no code in PCB to manage this revision number. 00480 * 00481 */ 00482 fprintf (f, "%%%%Version: (PCB %s " VERSION ") 0.0 0\n", Progname ); 00483 00484 00485 /* 00486 * %%PageOrder DCS is intended to help document managers determine 00487 * the order of pages in the document file, which in turn enables a 00488 * document manager optionally to reorder the pages. 'Ascend'-The 00489 * pages are in ascending order for example, 1-2-3-4-5-6. 00490 */ 00491 fprintf (f, "%%%%PageOrder: Ascend\n" ); 00492 00493 /* 00494 * %%Pages: < numpages> | (atend) < numpages> ::= < uint> (Total 00495 * %%number of pages) 00496 * 00497 * %%Pages DCS defines the number of virtual pages that a document 00498 * will image. (atend) defers the count until the end of the file, 00499 * which is useful for dynamically generated contents. 00500 */ 00501 fprintf (f, "%%%%Pages: (atend)\n" ); 00502 00503 /* 00504 * %%DocumentMedia: <name> <width> <height> <weight> <color> <type> 00505 * 00506 * Substitute 0 or "" for N/A. Width and height are in points 00507 * (1/72"). 00508 * 00509 * Media sizes are in PCB units 00510 */ 00511 pcb_fprintf (f, "%%%%DocumentMedia: %s %mi %mi 0 \"\" \"\"\n", 00512 media_data[global.media_idx].name, 00513 72 * media_data[global.media_idx].Width, 00514 72 * media_data[global.media_idx].Height); 00515 pcb_fprintf (f, "%%%%DocumentPaperSizes: %s\n", media_data[global.media_idx].name); 00516 00517 /* End General Header Comments. */ 00518 00519 /* General Body Comments go here. Currently there are none. */ 00520 00521 /* 00522 * %%EndComments DCS indicates an explicit end to the header 00523 * comments of the document. All global DCS's must preceded 00524 * this. A blank line gives an implicit end to the comments. 00525 */ 00526 fprintf (f, "%%%%EndComments\n\n" ); 00527 } 00528 00529 static void 00530 ps_end_file (FILE *f) 00531 { 00532 /* 00533 * %%Trailer DCS must only occur once at the end of the document 00534 * script. Any post-processing or cleanup should be contained in 00535 * the trailer of the document, which is anything that follows the 00536 * %%Trailer comment. Any of the document level structure comments 00537 * that were deferred by using the (atend) convention must be 00538 * mentioned in the trailer of the document after the %%Trailer 00539 * comment. 00540 */ 00541 fprintf (f, "%%%%Trailer\n" ); 00542 00543 /* 00544 * %%Pages was deferred until the end of the document via the 00545 * (atend) mentioned, in the General Header section. 00546 */ 00547 fprintf (f, "%%%%Pages: %d\n", global.pagecount); 00548 00549 /* 00550 * %%EOF DCS signifies the end of the document. When the document 00551 * manager sees this comment, it issues an end-of-file signal to the 00552 * PostScript interpreter. This is done so system-dependent file 00553 * endings, such as Control-D and end-of-file packets, do not 00554 * confuse the PostScript interpreter. 00555 */ 00556 fprintf (f, "%%%%EOF\n" ); 00557 } 00558 00559 static FILE * 00560 psopen (const char *base, const char *which) 00561 { 00562 FILE *ps_open_file; 00563 char *buf, *suff, *buf2; 00564 00565 if (!global.multi_file) 00566 return fopen (base, "w"); 00567 00568 buf = (char *)malloc (strlen (base) + strlen (which) + 5); 00569 00570 suff = (char *)strrchr (base, '.'); 00571 if (suff) 00572 { 00573 strcpy (buf, base); 00574 buf2 = strrchr (buf, '.'); 00575 sprintf(buf2, ".%s.%s", which, suff+1); 00576 } 00577 else 00578 { 00579 sprintf(buf, "%s.%s.ps", base, which); 00580 } 00581 printf("PS: open %s\n", buf); 00582 ps_open_file = fopen(buf, "w"); 00583 free (buf); 00584 return ps_open_file; 00585 } 00586 00587 /* This is used by other HIDs that use a postscript format, like lpr 00588 or eps. */ 00589 void 00590 ps_hid_export_to_file (FILE * the_file, HID_Attr_Val * options) 00591 { 00592 int i; 00593 static int saved_layer_stack[MAX_LAYER]; 00594 FlagType save_thindraw; 00595 00596 save_thindraw = PCB->Flags; 00597 CLEAR_FLAG(THINDRAWFLAG, PCB); 00598 CLEAR_FLAG(THINDRAWPOLYFLAG, PCB); 00599 CLEAR_FLAG(CHECKPLANESFLAG, PCB); 00600 00601 global.f = the_file; 00602 global.drill_helper = options[HA_drillhelper].int_value; 00603 global.align_marks = options[HA_alignmarks].int_value; 00604 global.outline = options[HA_outline].int_value; 00605 global.mirror = options[HA_mirror].int_value; 00606 global.fillpage = options[HA_fillpage].int_value; 00607 global.automirror = options[HA_automirror].int_value; 00608 global.incolor = options[HA_color].int_value; 00609 global.bloat = options[HA_psbloat].coord_value; 00610 global.invert = options[HA_psinvert].int_value; 00611 global.fade_ratio = CLAMP (options[HA_psfade].real_value, 0, 1); 00612 global.media_idx = options[HA_media].int_value; 00613 global.media_width = media_data[global.media_idx].Width; 00614 global.media_height = media_data[global.media_idx].Height; 00615 global.ps_width = global.media_width 00616 - 2.0 * media_data[global.media_idx].MarginX; 00617 global.ps_height = global.media_height 00618 - 2.0 * media_data[global.media_idx].MarginY; 00619 global.scale_factor = options[HA_scale].real_value; 00620 global.calibration_x = options[HA_xcalib].real_value; 00621 global.calibration_y = options[HA_ycalib].real_value; 00622 global.drillcopper = options[HA_drillcopper].int_value; 00623 global.legend = options[HA_legend].int_value; 00624 00625 if (the_file) 00626 ps_start_file (the_file); 00627 00628 if (global.fillpage) 00629 { 00630 double zx, zy; 00631 if (PCB->MaxWidth > PCB->MaxHeight) 00632 { 00633 zx = global.ps_height / PCB->MaxWidth; 00634 zy = global.ps_width / PCB->MaxHeight; 00635 } 00636 else 00637 { 00638 zx = global.ps_height / PCB->MaxHeight; 00639 zy = global.ps_width / PCB->MaxWidth; 00640 } 00641 global.scale_factor *= MIN (zx, zy); 00642 } 00643 00644 memset (global.print_group, 0, sizeof (global.print_group)); 00645 memset (global.print_layer, 0, sizeof (global.print_layer)); 00646 00647 global.outline_layer = NULL; 00648 00649 for (i = 0; i < max_copper_layer; i++) 00650 { 00651 LayerType *layer = PCB->Data->Layer + i; 00652 if (layer->LineN || layer->TextN || layer->ArcN || layer->PolygonN) 00653 global.print_group[GetLayerGroupNumberByNumber (i)] = 1; 00654 00655 if (strcmp (layer->Name, "outline") == 0 || 00656 strcmp (layer->Name, "route") == 0) 00657 { 00658 global.outline_layer = layer; 00659 } 00660 } 00661 global.print_group[GetLayerGroupNumberBySide (BOTTOM_SIDE)] = 1; 00662 global.print_group[GetLayerGroupNumberBySide (TOP_SIDE)] = 1; 00663 for (i = 0; i < max_copper_layer; i++) 00664 if (global.print_group[GetLayerGroupNumberByNumber (i)]) 00665 global.print_layer[i] = 1; 00666 00667 memcpy (saved_layer_stack, LayerStack, sizeof (LayerStack)); 00668 qsort (LayerStack, max_copper_layer, sizeof (LayerStack[0]), layer_stack_sort); 00669 00670 global.linewidth = -1; 00671 /* reset static vars */ 00672 ps_set_layer (NULL, 0, -1); 00673 use_gc (NULL); 00674 00675 global.region.X1 = 0; 00676 global.region.Y1 = 0; 00677 global.region.X2 = PCB->MaxWidth; 00678 global.region.Y2 = PCB->MaxHeight; 00679 00680 if (!global.multi_file) 00681 { 00682 /* %%Page DSC requires both a label and an ordinal */ 00683 fprintf (the_file, "%%%%Page: TableOfContents 1\n"); 00684 fprintf (the_file, "/Times-Roman findfont 14 scalefont setfont\n"); 00685 fprintf (the_file, "/rightshow { /s exch def s stringwidth pop -1 mul 0 rmoveto s show } def\n"); 00686 fprintf (the_file, "/y 72 9 mul def /toc { 100 y moveto show /y y 24 sub def } bind def\n"); 00687 fprintf (the_file, "/tocp { /y y 0 sub def 90 y moveto rightshow } bind def\n"); 00688 00689 global.doing_toc = 1; 00690 global.pagecount = 1; /* 'pagecount' is modified by hid_expose_callback() call */ 00691 hid_expose_callback (&ps_hid, &global.region, 0); 00692 } 00693 00694 global.pagecount = 1; /* Reset 'pagecount' if single file */ 00695 global.doing_toc = 0; 00696 ps_set_layer (NULL, 0, -1); /* reset static vars */ 00697 hid_expose_callback (&ps_hid, &global.region, 0); 00698 00699 if (the_file) 00700 fprintf (the_file, "showpage\n"); 00701 00702 memcpy (LayerStack, saved_layer_stack, sizeof (LayerStack)); 00703 PCB->Flags = save_thindraw; 00704 } 00705 00706 static void 00707 ps_do_export (HID_Attr_Val * options) 00708 { 00709 FILE *fh; 00710 int save_ons[MAX_ALL_LAYER]; 00711 int i; 00712 00713 if (!options) 00714 { 00715 ps_get_export_options (0); 00716 for (i = 0; i < NUM_OPTIONS; i++) 00717 global.ps_values[i] = ps_attribute_list[i].default_val; 00718 options = global.ps_values; 00719 } 00720 00721 global.filename = options[HA_psfile].str_value; 00722 if (!global.filename) 00723 global.filename = "pcb-out.ps"; 00724 00725 global.multi_file = options[HA_multifile].int_value; 00726 00727 if (global.multi_file) 00728 fh = 0; 00729 else 00730 { 00731 fh = psopen (global.filename, "toc"); 00732 if (!fh) 00733 { 00734 perror (global.filename); 00735 return; 00736 } 00737 } 00738 00739 hid_save_and_show_layer_ons (save_ons); 00740 ps_hid_export_to_file (fh, options); 00741 hid_restore_layer_ons (save_ons); 00742 00743 global.multi_file = 0; 00744 if (fh) 00745 { 00746 ps_end_file (fh); 00747 fclose (fh); 00748 } 00749 } 00750 00751 static void 00752 ps_parse_arguments (int *argc, char ***argv) 00753 { 00754 hid_register_attributes (ps_attribute_list, NUM_OPTIONS); 00755 hid_parse_command_line (argc, argv); 00756 } 00757 00758 static void 00759 corner (FILE *fh, Coord x, Coord y, int dx, int dy) 00760 { 00761 Coord len = MIL_TO_COORD (2000); 00762 Coord len2 = MIL_TO_COORD (200); 00763 Coord thick = 0; 00764 /* 00765 * Originally 'thick' used thicker lines. Currently is uses 00766 * Postscript's "device thin" line - i.e. zero width means one 00767 * device pixel. The code remains in case you want to make them 00768 * thicker - it needs to offset everything so that the *edge* of the 00769 * thick line lines up with the edge of the board, not the *center* 00770 * of the thick line. 00771 */ 00772 00773 pcb_fprintf (fh, "gsave %mi setlinewidth %mi %mi translate %d %d scale\n", 00774 thick * 2, x, y, dx, dy); 00775 pcb_fprintf (fh, "%mi %mi moveto %mi %mi %mi 0 90 arc %mi %mi lineto\n", 00776 len, thick, thick, thick, len2 + thick, thick, len); 00777 if (dx < 0 && dy < 0) 00778 pcb_fprintf (fh, "%mi %mi moveto 0 %mi rlineto\n", len2 * 2 + thick, thick, -len2); 00779 fprintf (fh, "stroke grestore\n"); 00780 } 00781 00782 static int 00783 ps_set_layer (const char *name, int group, int empty) 00784 { 00785 static int lastgroup = -1; 00786 time_t currenttime; 00787 int idx = (group >= 0 && group < max_group) 00788 ? PCB->LayerGroups.Entries[group][0] 00789 : group; 00790 if (name == 0) 00791 name = PCB->Data->Layer[idx].Name; 00792 00793 if (empty == -1) 00794 lastgroup = -1; 00795 if (empty) 00796 return 0; 00797 00798 if (idx >= 0 && idx < max_copper_layer && !global.print_layer[idx]) 00799 return 0; 00800 00801 if (strcmp (name, "invisible") == 0) 00802 return 0; 00803 00804 global.is_drill = (SL_TYPE (idx) == SL_PDRILL || SL_TYPE (idx) == SL_UDRILL); 00805 global.is_mask = (SL_TYPE (idx) == SL_MASK); 00806 global.is_assy = (SL_TYPE (idx) == SL_ASSY); 00807 global.is_copper = (SL_TYPE (idx) == 0); 00808 global.is_paste = (SL_TYPE (idx) == SL_PASTE); 00809 #if 0 00810 printf ("Layer %s group %d drill %d mask %d\n", name, group, global.is_drill, 00811 global.is_mask); 00812 #endif 00813 00814 if (global.doing_toc) 00815 { 00816 if (group < 0 || group != lastgroup) 00817 { 00818 if (global.pagecount == 1) 00819 { 00820 currenttime = time (NULL); 00821 fprintf (global.f, "30 30 moveto (%s) show\n", PCB->Filename); 00822 00823 fprintf (global.f, "(%d.) tocp\n", global.pagecount); 00824 fprintf (global.f, "(Table of Contents \\(This Page\\)) toc\n" ); 00825 00826 fprintf (global.f, "(Created on %s) toc\n", asctime (localtime (¤ttime))); 00827 fprintf (global.f, "( ) tocp\n" ); 00828 } 00829 00830 global.pagecount++; 00831 lastgroup = group; 00832 fprintf (global.f, "(%d.) tocp\n", global.pagecount); 00833 } 00834 fprintf (global.f, "(%s) toc\n", name); 00835 return 0; 00836 } 00837 00838 if (group < 0 || group != lastgroup) 00839 { 00840 double boffset; 00841 int mirror_this = 0; 00842 lastgroup = group; 00843 00844 if (global.pagecount != 0) 00845 { 00846 pcb_fprintf (global.f, "showpage\n"); 00847 } 00848 global.pagecount++; 00849 if (global.multi_file) 00850 { 00851 if (global.f) 00852 { 00853 ps_end_file (global.f); 00854 fclose (global.f); 00855 } 00856 global.f = psopen (global.filename, layer_type_to_file_name_ex (idx, FNS_fixed, name)); 00857 if (!global.f) 00858 { 00859 perror (global.filename); 00860 return 0; 00861 } 00862 00863 ps_start_file (global.f); 00864 } 00865 00866 /* 00867 * %%Page DSC comment marks the beginning of the PostScript 00868 * language instructions that describe a particular 00869 * page. %%Page: requires two arguments: a page label and a 00870 * sequential page number. The label may be anything, but the 00871 * ordinal page number must reflect the position of that page in 00872 * the body of the PostScript file and must start with 1, not 0. 00873 */ 00874 fprintf (global.f, "%%%%Page: %s %d\n", layer_type_to_file_name_ex (idx, FNS_fixed, name), global.pagecount); 00875 00876 if (global.mirror) 00877 mirror_this = !mirror_this; 00878 if (global.automirror 00879 && 00880 ((idx >= 0 && group == GetLayerGroupNumberBySide (BOTTOM_SIDE)) 00881 || (idx < 0 && SL_SIDE (idx) == SL_BOTTOM_SIDE))) 00882 mirror_this = !mirror_this; 00883 00884 fprintf (global.f, "/Helvetica findfont 10 scalefont setfont\n"); 00885 if (global.legend) 00886 { 00887 fprintf (global.f, "30 30 moveto (%s) show\n", PCB->Filename); 00888 if (PCB->Name) 00889 fprintf (global.f, "30 41 moveto (%s, %s) show\n", 00890 PCB->Name, layer_type_to_file_name_ex (idx, FNS_fixed, name)); 00891 else 00892 fprintf (global.f, "30 41 moveto (%s) show\n", 00893 layer_type_to_file_name_ex (idx, FNS_fixed, name)); 00894 if (mirror_this) 00895 fprintf (global.f, "( \\(mirrored\\)) show\n"); 00896 00897 if (global.fillpage) 00898 fprintf (global.f, "(, not to scale) show\n"); 00899 else 00900 fprintf (global.f, "(, scale = 1:%.3f) show\n", global.scale_factor); 00901 } 00902 fprintf (global.f, "newpath\n"); 00903 00904 pcb_fprintf (global.f, "72 72 scale %mi %mi translate\n", 00905 global.media_width / 2, global.media_height / 2); 00906 00907 boffset = global.media_height / 2; 00908 if (PCB->MaxWidth > PCB->MaxHeight) 00909 { 00910 fprintf (global.f, "90 rotate\n"); 00911 boffset = global.media_width / 2; 00912 fprintf (global.f, "%g %g scale %% calibration\n", global.calibration_y, global.calibration_x); 00913 } 00914 else 00915 fprintf (global.f, "%g %g scale %% calibration\n", global.calibration_x, global.calibration_y); 00916 00917 if (mirror_this) 00918 fprintf (global.f, "1 -1 scale\n"); 00919 00920 fprintf (global.f, "%g dup neg scale\n", 00921 (SL_TYPE (idx) == SL_FAB) ? 1.0 : global.scale_factor); 00922 pcb_fprintf (global.f, "%mi %mi translate\n", -PCB->MaxWidth / 2, -PCB->MaxHeight / 2); 00923 00924 /* Keep the drill list from falling off the left edge of the paper, 00925 * even if it means some of the board falls off the right edge. 00926 * If users don't want to make smaller boards, or use fewer drill 00927 * sizes, they can always ignore this sheet. */ 00928 if (SL_TYPE (idx) == SL_FAB) { 00929 Coord natural = boffset - MIL_TO_COORD(500) - PCB->MaxHeight / 2; 00930 Coord needed = PrintFab_overhang (); 00931 pcb_fprintf (global.f, "%% PrintFab overhang natural %mi, needed %mi\n", natural, needed); 00932 if (needed > natural) 00933 pcb_fprintf (global.f, "0 %mi translate\n", needed - natural); 00934 } 00935 00936 if (global.invert) 00937 { 00938 fprintf (global.f, "/gray { 1 exch sub setgray } bind def\n"); 00939 fprintf (global.f, 00940 "/rgb { 1 1 3 { pop 1 exch sub 3 1 roll } for setrgbcolor } bind def\n"); 00941 } 00942 else 00943 { 00944 fprintf (global.f, "/gray { setgray } bind def\n"); 00945 fprintf (global.f, "/rgb { setrgbcolor } bind def\n"); 00946 } 00947 00948 if ((global.outline && !global.outline_layer) || global.invert) 00949 { 00950 pcb_fprintf (global.f, 00951 "0 setgray 0 setlinewidth 0 0 moveto 0 " 00952 "%mi lineto %mi %mi lineto %mi 0 lineto closepath %s\n", 00953 PCB->MaxHeight, PCB->MaxWidth, PCB->MaxHeight, PCB->MaxWidth, 00954 global.invert ? "fill" : "stroke"); 00955 } 00956 00957 if (global.align_marks) 00958 { 00959 corner (global.f, 0, 0, -1, -1); 00960 corner (global.f, PCB->MaxWidth, 0, 1, -1); 00961 corner (global.f, PCB->MaxWidth, PCB->MaxHeight, 1, 1); 00962 corner (global.f, 0, PCB->MaxHeight, -1, 1); 00963 } 00964 00965 global.linewidth = -1; 00966 use_gc (NULL); /* reset static vars */ 00967 00968 fprintf (global.f, 00969 "/ts 1 def\n" 00970 "/ty ts neg def /tx 0 def /Helvetica findfont ts scalefont setfont\n" 00971 "/t { moveto lineto stroke } bind def\n" 00972 "/dr { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n" 00973 " x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath stroke } bind def\n" 00974 "/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n" 00975 " x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def\n" 00976 "/c { 0 360 arc fill } bind def\n" 00977 "/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def\n"); 00978 if (global.drill_helper) 00979 pcb_fprintf (global.f, 00980 "/dh { gsave %mi setlinewidth 0 gray %mi 0 360 arc stroke grestore} bind def\n", 00981 (Coord) MIN_PINORVIAHOLE, (Coord) (MIN_PINORVIAHOLE * 3 / 2)); 00982 } 00983 #if 0 00984 /* Try to outsmart ps2pdf's heuristics for page rotation, by putting 00985 * text on all pages -- even if that text is blank */ 00986 if (SL_TYPE (idx) != SL_FAB) 00987 fprintf (global.f, 00988 "gsave tx ty translate 1 -1 scale 0 0 moveto (Layer %s) show grestore newpath /ty ty ts sub def\n", 00989 name); 00990 else 00991 fprintf (global.f, "gsave tx ty translate 1 -1 scale 0 0 moveto ( ) show grestore newpath /ty ty ts sub def\n"); 00992 #endif 00993 00994 /* If we're printing a copper layer other than the outline layer, 00995 and we want to "print outlines", and we have an outline layer, 00996 print the outline layer on this layer also. */ 00997 if (global.outline && 00998 (global.is_copper || (strcmp(name, "topassembly") == 0) || (strcmp(name, "bottomassembly") == 0)) && 00999 global.outline_layer != NULL && 01000 global.outline_layer != PCB->Data->Layer+idx && 01001 strcmp (name, "outline") != 0 && 01002 strcmp (name, "route") != 0 01003 ) 01004 { 01005 DrawLayer (global.outline_layer, &global.region); 01006 } 01007 01008 return 1; 01009 } 01010 01011 static hidGC 01012 ps_make_gc (void) 01013 { 01014 hidGC rv = (hidGC) calloc (1, sizeof (hid_gc_struct)); 01015 rv->me_pointer = &ps_hid; 01016 rv->cap = Trace_Cap; 01017 return rv; 01018 } 01019 01020 static void 01021 ps_destroy_gc (hidGC gc) 01022 { 01023 free (gc); 01024 } 01025 01026 static void 01027 ps_use_mask (enum mask_mode mode) 01028 { 01029 /* does nothing */ 01030 } 01031 01032 static void 01033 ps_set_color (hidGC gc, const char *name) 01034 { 01035 if (strcmp (name, "erase") == 0 || strcmp (name, "drill") == 0) 01036 { 01037 gc->r = gc->g = gc->b = 255; 01038 gc->erase = 1; 01039 } 01040 else if (global.incolor) 01041 { 01042 int r, g, b; 01043 sscanf (name + 1, "%02x%02x%02x", &r, &g, &b); 01044 gc->r = r; 01045 gc->g = g; 01046 gc->b = b; 01047 gc->erase = 0; 01048 } 01049 else 01050 { 01051 gc->r = gc->g = gc->b = 0; 01052 gc->erase = 0; 01053 } 01054 } 01055 01056 static void 01057 ps_set_line_cap (hidGC gc, EndCapStyle style) 01058 { 01059 gc->cap = style; 01060 } 01061 01062 static void 01063 ps_set_line_width (hidGC gc, Coord width) 01064 { 01065 gc->width = width; 01066 } 01067 01068 static void 01069 ps_set_draw_xor (hidGC gc, int xor_) 01070 { 01071 ; 01072 } 01073 01074 static void 01075 ps_set_draw_faded (hidGC gc, int faded) 01076 { 01077 gc->faded = faded; 01078 } 01079 01080 static void 01081 use_gc (hidGC gc) 01082 { 01083 static int lastcap = -1; 01084 static int lastcolor = -1; 01085 01086 if (gc == NULL) 01087 { 01088 lastcap = lastcolor = -1; 01089 return; 01090 } 01091 if (gc->me_pointer != &ps_hid) 01092 { 01093 fprintf (stderr, "Fatal: GC from another HID passed to ps HID\n"); 01094 abort (); 01095 } 01096 if (global.linewidth != gc->width) 01097 { 01098 pcb_fprintf (global.f, "%mi setlinewidth\n", 01099 gc->width + (gc->erase ? -2 : 2) * global.bloat); 01100 global.linewidth = gc->width; 01101 } 01102 if (lastcap != gc->cap) 01103 { 01104 int c; 01105 switch (gc->cap) 01106 { 01107 case Round_Cap: 01108 case Trace_Cap: 01109 c = 1; 01110 break; 01111 default: 01112 case Square_Cap: 01113 c = 2; 01114 break; 01115 } 01116 fprintf (global.f, "%d setlinecap %d setlinejoin\n", c, c); 01117 lastcap = gc->cap; 01118 } 01119 #define CBLEND(gc) (((gc->r)<<24)|((gc->g)<<16)|((gc->b)<<8)|(gc->faded)) 01120 if (lastcolor != CBLEND (gc)) 01121 { 01122 if (global.is_drill || global.is_mask) 01123 { 01124 fprintf (global.f, "%d gray\n", gc->erase ? 0 : 1); 01125 lastcolor = 0; 01126 } 01127 else 01128 { 01129 double r, g, b; 01130 r = gc->r; 01131 g = gc->g; 01132 b = gc->b; 01133 if (gc->faded) 01134 { 01135 r = (1 - global.fade_ratio) * 255 + global.fade_ratio * r; 01136 g = (1 - global.fade_ratio) * 255 + global.fade_ratio * g; 01137 b = (1 - global.fade_ratio) * 255 + global.fade_ratio * b; 01138 } 01139 if (gc->r == gc->g && gc->g == gc->b) 01140 fprintf (global.f, "%g gray\n", r / 255.0); 01141 else 01142 fprintf (global.f, "%g %g %g rgb\n", r / 255.0, g / 255.0, b / 255.0); 01143 lastcolor = CBLEND (gc); 01144 } 01145 } 01146 } 01147 01148 static void 01149 ps_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 01150 { 01151 use_gc (gc); 01152 pcb_fprintf (global.f, "%mi %mi %mi %mi dr\n", x1, y1, x2, y2); 01153 } 01154 01155 static void ps_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); 01156 static void ps_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius); 01157 01158 static void 01159 ps_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 01160 { 01161 #if 0 01162 /* If you're etching your own paste mask, this will reduce the 01163 amount of brass you need to etch by drawing outlines for large 01164 pads. See also ps_fill_rect. */ 01165 if (is_paste && gc->width > 2500 && gc->cap == Square_Cap 01166 && (x1 == x2 || y1 == y2)) 01167 { 01168 Coord t, w; 01169 if (x1 > x2) 01170 { t = x1; x1 = x2; x2 = t; } 01171 if (y1 > y2) 01172 { t = y1; y1 = y2; y2 = t; } 01173 w = gc->width/2; 01174 ps_fill_rect (gc, x1-w, y1-w, x2+w, y2+w); 01175 return; 01176 } 01177 #endif 01178 if (x1 == x2 && y1 == y2) 01179 { 01180 Coord w = gc->width / 2; 01181 if (gc->cap == Square_Cap) 01182 ps_fill_rect (gc, x1 - w, y1 - w, x1 + w, y1 + w); 01183 else 01184 ps_fill_circle (gc, x1, y1, w); 01185 return; 01186 } 01187 use_gc (gc); 01188 pcb_fprintf (global.f, "%mi %mi %mi %mi t\n", x1, y1, x2, y2); 01189 } 01190 01191 static void 01192 ps_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height, 01193 Angle start_angle, Angle delta_angle) 01194 { 01195 Angle sa, ea; 01196 double linewidth; 01197 01198 if (delta_angle > 0) 01199 { 01200 sa = start_angle; 01201 ea = start_angle + delta_angle; 01202 } 01203 else 01204 { 01205 sa = start_angle + delta_angle; 01206 ea = start_angle; 01207 } 01208 01209 use_gc (gc); 01210 01211 /* Other than pcb's screen renderer, PostScript (at least GhostScript) 01212 internally limits linewidth to (diameter / 2), so no drawing of a dot with 01213 a circle of zero diameter. Compensate for this by making diameter larger 01214 and line width thinner. 01215 01216 Handling of this case currently has only circles in mind, no ellipses. 01217 The regular case works with ellipses, too. */ 01218 if (width < global.linewidth) 01219 { 01220 Coord outer_radius; 01221 01222 outer_radius = width + global.linewidth / 2 + global.bloat; 01223 width = height = outer_radius / 2; 01224 linewidth = 2.0; 01225 } 01226 else 01227 linewidth = (double) (global.linewidth + 2 * global.bloat) / (double) width; 01228 01229 /* The line of PostScript written here is a bit odd; linewidth isn't 01230 absolute, but relative to circle diameter. This is neccessary for 01231 ellipses, which are drawn by streching (transforming) a circle. */ 01232 pcb_fprintf (global.f, "%ma %ma %mi %mi %mi %mi %`g a\n", 01233 sa, ea, -width, height, cx, cy, linewidth); 01234 01235 } 01236 01237 static void 01238 ps_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius) 01239 { 01240 use_gc (gc); 01241 if (!gc->erase || !global.is_copper || global.drillcopper) 01242 { 01243 if (gc->erase && global.is_copper && global.drill_helper 01244 && radius >= PCB->minDrill / 4) 01245 radius = PCB->minDrill / 4; 01246 pcb_fprintf (global.f, "%mi %mi %mi c\n", 01247 cx, cy, radius + (gc->erase ? -1 : 1) * global.bloat); 01248 } 01249 } 01250 01251 static void 01252 ps_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y) 01253 { 01254 int i; 01255 char *op = "moveto"; 01256 use_gc (gc); 01257 for (i = 0; i < n_coords; i++) 01258 { 01259 pcb_fprintf (global.f, "%mi %mi %s\n", x[i], y[i], op); 01260 op = "lineto"; 01261 } 01262 fprintf (global.f, "fill\n"); 01263 } 01264 01265 static void 01266 fill_polyarea (hidGC gc, POLYAREA * pa, const BoxType * clip_box) 01267 { 01268 /* Ignore clip_box, just draw everything */ 01269 01270 VNODE *v; 01271 PLINE *pl; 01272 char *op; 01273 01274 use_gc (gc); 01275 01276 pl = pa->contours; 01277 01278 do 01279 { 01280 v = pl->head.next; 01281 op = "moveto"; 01282 do 01283 { 01284 pcb_fprintf (global.f, "%mi %mi %s\n", v->point[0], v->point[1], op); 01285 op = "lineto"; 01286 } 01287 while ((v = v->next) != pl->head.next); 01288 } 01289 while ((pl = pl->next) != NULL); 01290 01291 fprintf (global.f, "fill\n"); 01292 } 01293 01294 static void 01295 ps_draw_pcb_polygon (hidGC gc, PolygonType * poly, const BoxType * clip_box) 01296 { 01297 if (!poly->Clipped) 01298 return; 01299 fill_polyarea (gc, poly->Clipped, clip_box); 01300 if (TEST_FLAG (FULLPOLYFLAG, poly)) 01301 { 01302 POLYAREA *pa; 01303 01304 for (pa = poly->Clipped->f; pa != poly->Clipped; pa = pa->f) 01305 fill_polyarea (gc, pa, clip_box); 01306 } 01307 } 01308 01309 static void 01310 ps_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 01311 { 01312 use_gc (gc); 01313 if (x1 > x2) 01314 { 01315 Coord t = x1; 01316 x1 = x2; 01317 x2 = t; 01318 } 01319 if (y1 > y2) 01320 { 01321 Coord t = y1; 01322 y1 = y2; 01323 y2 = t; 01324 } 01325 #if 0 01326 /* See comment in ps_draw_line. */ 01327 if (is_paste && (x2-x1)>2500 && (y2-y1)>2500) 01328 { 01329 linewidth = 1000; 01330 lastcap = Round_Cap; 01331 fprintf(f, "1000 setlinewidth 1 setlinecap 1 setlinejoin\n"); 01332 fprintf(f, "%d %d moveto %d %d lineto %d %d lineto %d %d lineto closepath stroke\n", 01333 x1+500-bloat, y1+500-bloat, 01334 x1+500-bloat, y2-500+bloat, 01335 x2-500+bloat, y2-500+bloat, 01336 x2-500+bloat, y1+500-bloat); 01337 return; 01338 } 01339 #endif 01340 pcb_fprintf (global.f, "%mi %mi %mi %mi r\n", 01341 x1 - global.bloat, y1 - global.bloat, 01342 x2 + global.bloat, y2 + global.bloat); 01343 } 01344 01345 HID_Attribute ps_calib_attribute_list[] = { 01346 {N_("lprcommand"), N_("Command to print"), 01347 HID_String, 0, 0, {0, 0, 0}, 0, 0}, 01348 }; 01349 01350 static const char * const calib_lines[] = { 01351 "%!PS-Adobe-3.0\n", 01352 "%%Title: Calibration Page\n", 01353 "%%PageOrder: Ascend\n", 01354 "%%Pages: 1\n", 01355 "%%EndComments\n", 01356 "\n", 01357 "%%Page: Calibrate 1\n", 01358 "72 72 scale\n", 01359 "\n", 01360 "0 setlinewidth\n", 01361 "0.375 0.375 moveto\n", 01362 "8.125 0.375 lineto\n", 01363 "8.125 10.625 lineto\n", 01364 "0.375 10.625 lineto\n", 01365 "closepath stroke\n", 01366 "\n", 01367 "0.5 0.5 translate\n", 01368 "0.001 setlinewidth\n", 01369 "\n", 01370 "/Times-Roman findfont 0.2 scalefont setfont\n", 01371 "\n", 01372 "/sign {\n", 01373 " 0 lt { -1 } { 1 } ifelse\n", 01374 "} def\n", 01375 "\n", 01376 "/cbar {\n", 01377 " /units exch def\n", 01378 " /x exch def\n", 01379 " /y exch def \n", 01380 "\n", 01381 " /x x sign 0.5 mul def\n", 01382 "\n", 01383 " 0 setlinewidth\n", 01384 " newpath x y 0.25 0 180 arc gsave 0.85 setgray fill grestore closepath stroke\n", 01385 " newpath x 0 0.25 180 360 arc gsave 0.85 setgray fill grestore closepath stroke\n", 01386 " 0.001 setlinewidth\n", 01387 "\n", 01388 " x 0 moveto\n", 01389 " x y lineto\n", 01390 "% -0.07 -0.2 rlineto 0.14 0 rmoveto -0.07 0.2 rlineto\n", 01391 " x y lineto\n", 01392 " -0.1 0 rlineto 0.2 0 rlineto\n", 01393 " stroke\n", 01394 " x 0 moveto\n", 01395 "% -0.07 0.2 rlineto 0.14 0 rmoveto -0.07 -0.2 rlineto\n", 01396 " x 0 moveto\n", 01397 " -0.1 0 rlineto 0.2 0 rlineto\n", 01398 " stroke\n", 01399 "\n", 01400 " x 0.1 add\n", 01401 " y 0.2 sub moveto\n", 01402 " units show\n", 01403 "} bind def\n", 01404 "\n", 01405 "/y 9 def\n", 01406 "/t {\n", 01407 " /str exch def\n", 01408 " 1.5 y moveto str show\n", 01409 " /y y 0.25 sub def\n", 01410 "} bind def\n", 01411 "\n", 01412 "(Please measure between the flat faces of ONE pair of semi-circles on)t\n", 01413 "(both X and Y in the indicated units. Enter these values as X and Y)t\n", 01414 "(respectively. One member of each pair must be one of the semicircles)t\n", 01415 "(in the lower left corner. Nominal lengths on X are 4 in, 15 cm and 7.5 in.)t\n", 01416 "(Nominal lengths on Y are 4 in, 20 cm and 10 in.)t\n", 01417 "()t\n", 01418 "(The large box is 10.25 by 7.75 inches and is not used for calibration.)t\n", "\n", 01419 "/in { } bind def\n", 01420 "/cm { 2.54 div } bind def\n", 01421 "/mm { 25.4 div } bind def\n", 01422 "\n", 01423 0 01424 }; 01425 01426 static int 01427 guess(double val, double close_to, double *calib) 01428 { 01429 if (val >= close_to * 0.9 01430 && val <= close_to * 1.1) 01431 { 01432 *calib = close_to / val; 01433 return 0; 01434 } 01435 return 1; 01436 } 01437 01438 void 01439 ps_calibrate_1 (double xval, double yval, int use_command) 01440 { 01441 HID_Attr_Val vals[3]; 01442 FILE *ps_cal_file; 01443 int used_popen = 0, c; 01444 01445 if (xval > 0 && yval > 0) 01446 { 01447 if (guess (xval, 4, &global.calibration_x)) 01448 if (guess (xval, 15, &global.calibration_x)) 01449 if (guess (xval, 7.5, &global.calibration_x)) 01450 { 01451 if (xval < 2) 01452 ps_attribute_list[HA_xcalib].default_val.real_value = 01453 global.calibration_x = xval; 01454 else 01455 Message(_("X value of %g is too far off.\n" 01456 "Expecting it near: %.1f, %.1f, %.1f, %.1f\n"), 01457 xval, 1.0, 4.0, 15.0, 7.5); 01458 } 01459 if (guess (yval, 4, &global.calibration_y)) 01460 if (guess (yval, 20, &global.calibration_y)) 01461 if (guess (yval, 10, &global.calibration_y)) 01462 { 01463 if (yval < 2) 01464 ps_attribute_list[HA_ycalib].default_val.real_value = 01465 global.calibration_y = yval; 01466 else 01467 Message(_("Y value of %g is too far off.\n" 01468 "Expecting it near: %.1f, %.1f, %.1f, %.1f\n"), 01469 yval, 1.0, 4.0, 20.0, 10.0); 01470 } 01471 return; 01472 } 01473 01474 if (ps_calib_attribute_list[0].default_val.str_value == NULL) 01475 { 01476 ps_calib_attribute_list[0].default_val.str_value = strdup ("lpr"); 01477 } 01478 01479 if (gui->attribute_dialog (ps_calib_attribute_list, 1, vals, _("Print Calibration Page"), _("Generates a printer calibration page"))) 01480 return; 01481 01482 if (use_command || strchr (vals[0].str_value, '|')) 01483 { 01484 const char *cmd = vals[0].str_value; 01485 while (*cmd == ' ' || *cmd == '|') 01486 cmd ++; 01487 ps_cal_file = popen (cmd, "w"); 01488 used_popen = 1; 01489 } 01490 else 01491 ps_cal_file = fopen (vals[0].str_value, "w"); 01492 01493 for (c=0; calib_lines[c]; c++) 01494 fputs(calib_lines[c], ps_cal_file); 01495 01496 fprintf (ps_cal_file, "4 in 0.5 (Y in nom=4) cbar\n"); 01497 fprintf (ps_cal_file, "20 cm 1.5 (Y cm nom=20) cbar\n"); 01498 fprintf (ps_cal_file, "10 in 2.5 (Y in nom=10) cbar\n"); 01499 fprintf (ps_cal_file, "-90 rotate\n"); 01500 fprintf (ps_cal_file, "4 in -0.5 (X in nom=4) cbar\n"); 01501 fprintf (ps_cal_file, "15 cm -1.5 (X cm nom=15) cbar\n"); 01502 fprintf (ps_cal_file, "7.5 in -2.5 (X in nom=7.5) cbar\n"); 01503 fprintf (ps_cal_file, "showpage\n"); 01504 01505 fprintf (ps_cal_file, "%%%%EOF\n"); 01506 01507 if (used_popen) 01508 pclose (ps_cal_file); 01509 else 01510 fclose (ps_cal_file); 01511 } 01512 01513 static void 01514 ps_calibrate (double xval, double yval) 01515 { 01516 ps_calibrate_1 (xval, yval, 0); 01517 } 01518 01519 static void 01520 ps_set_crosshair (int x, int y, int action) 01521 { 01522 } 01523 01524 #include "dolists.h" 01525 01526 HID ps_hid; 01527 static HID_DRAW ps_graphics; 01528 01529 void ps_ps_init (HID *hid) 01530 { 01531 hid->get_export_options = ps_get_export_options; 01532 hid->do_export = ps_do_export; 01533 hid->parse_arguments = ps_parse_arguments; 01534 hid->set_layer = ps_set_layer; 01535 hid->calibrate = ps_calibrate; 01536 hid->set_crosshair = ps_set_crosshair; 01537 } 01538 01539 void ps_ps_graphics_init (HID_DRAW *graphics) 01540 { 01541 graphics->make_gc = ps_make_gc; 01542 graphics->destroy_gc = ps_destroy_gc; 01543 graphics->use_mask = ps_use_mask; 01544 graphics->set_color = ps_set_color; 01545 graphics->set_line_cap = ps_set_line_cap; 01546 graphics->set_line_width = ps_set_line_width; 01547 graphics->set_draw_xor = ps_set_draw_xor; 01548 graphics->set_draw_faded = ps_set_draw_faded; 01549 graphics->draw_line = ps_draw_line; 01550 graphics->draw_arc = ps_draw_arc; 01551 graphics->draw_rect = ps_draw_rect; 01552 graphics->fill_circle = ps_fill_circle; 01553 graphics->fill_polygon = ps_fill_polygon; 01554 graphics->fill_rect = ps_fill_rect; 01555 01556 graphics->draw_pcb_polygon = ps_draw_pcb_polygon; 01557 } 01558 01559 void 01560 hid_ps_init () 01561 { 01562 memset (&ps_hid, 0, sizeof (HID)); 01563 memset (&ps_graphics, 0, sizeof (HID_DRAW)); 01564 01565 common_nogui_init (&ps_hid); 01566 common_draw_helpers_init (&ps_graphics); 01567 ps_ps_init (&ps_hid); 01568 ps_ps_graphics_init (&ps_graphics); 01569 01570 ps_hid.struct_size = sizeof (HID); 01571 ps_hid.name = "ps"; 01572 ps_hid.description = N_("Postscript export"); 01573 ps_hid.exporter = 1; 01574 ps_hid.poly_before = 1; 01575 01576 ps_hid.graphics = &ps_graphics; 01577 01578 hid_register_hid (&ps_hid); 01579 01580 hid_eps_init (); 01581 #include "ps_lists.h" 01582 }