/* File: psprint.c * * This file is part of XSCHEM, * a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit * simulation. * Copyright (C) 1998-2024 Stefan Frederik Schippers * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "xschem.h" #define X_TO_PS(x) ( (x+xctx->xorigin)* xctx->mooz ) #define Y_TO_PS(y) ( (y+xctx->yorigin)* xctx->mooz ) char *utf8_enc[]={ "/recodedict 24 dict def\n", "/recode {recodedict begin /nco&na exch def\n", "/nfnam exch def /basefontname exch def /basefontdict basefontname findfont def\n", "/newfont basefontdict maxlength dict def basefontdict {exch dup /FID ne\n", "{dup /Encoding eq {exch dup length array copy newfont 3 1 roll put} {exch\n", "newfont 3 1 roll put} ifelse} {pop pop} ifelse } forall newfont\n", "/FontName nfnam put nco&na aload pop nco&na length 2 idiv {newfont\n", "/Encoding get 3 1 roll put} repeat nfnam newfont definefont pop end } def\n", }; char *utf8[]={ "/chararr [\n", /* 0xC2 2-byte characters */ " 161 /exclamdown\n", " 162 /cent\n", " 163 /sterling\n", " 164 /currency\n", " 165 /yen\n", " 166 /bar\n", " 167 /section\n", " 168 /dieresis\n", " 169 /copyright\n", " 170 /ordfeminine\n", " 171 /guillemotleft\n", " 172 /logicalnot\n", " 173 /emdash\n", " 174 /registered\n", " 175 /macron\n", " 176 /degree\n", " 177 /plusminus\n", " 178 /twosuperior\n", " 179 /threesuperior\n", " 180 /acute\n", " 181 /mu\n", " 182 /paragraph\n", " 183 /periodcentered\n", " 184 /cedilla\n", " 185 /onesuperior\n", " 186 /ordmasculine\n", " 187 /guillemotright\n", " 188 /onequarter\n", " 189 /onehalf\n", " 190 /threequarters\n", " 191 /questiondown\n", /* 0xC3 2-byte characters */ " 192 /Agrave\n", " 193 /Aacute\n", " 194 /Acircumflex\n", " 195 /Atilde\n", " 196 /Adieresis\n", " 197 /Aring\n", " 198 /AE\n", " 199 /Ccedilla\n", " 200 /Egrave\n", " 201 /Eacute\n", " 202 /Ecircumflex\n", " 203 /Edieresis\n", " 204 /Igrave\n", " 205 /Iacute\n", " 206 /Icircumflex\n", " 207 /Idieresis\n", " 208 /Eth\n", " 209 /Ntilde\n", " 210 /Ograve\n", " 211 /Oacute\n", " 212 /Ocircumflex\n", " 213 /Otilde\n", " 214 /Odieresis\n", " 215 /multiply\n", " 216 /Oslash\n", " 217 /Ugrave\n", " 218 /Uacute\n", " 219 /Ucircumflex\n", " 220 /Udieresis\n", " 221 /Yacute\n", " 222 /Thorn\n", " 223 /germandbls\n", " 224 /agrave\n", " 225 /aacute\n", " 226 /acircumflex\n", " 227 /atilde\n", " 228 /adieresis\n", " 229 /aring\n", " 230 /ae\n", " 231 /ccedilla\n", " 232 /egrave\n", " 233 /eacute\n", " 234 /ecircumflex\n", " 235 /edieresis\n", " 236 /igrave\n", " 237 /iacute\n", " 238 /icircumflex\n", " 239 /idieresis\n", " 240 /eth\n", " 241 /ntilde\n", " 242 /ograve\n", " 243 /oacute\n", " 244 /ocircumflex\n", " 245 /otilde\n", " 246 /odieresis\n", " 247 /divide\n", " 248 /oslash\n", " 249 /ugrave\n", " 250 /uacute\n", " 251 /ucircumflex\n", " 252 /udieresis\n", " 253 /yacute\n", " 254 /thorn\n", " 255 /ydieresis\n", " ] def\n"}; static FILE *fd; typedef struct { unsigned int red; unsigned int green; unsigned int blue; } Ps_color; static Ps_color *ps_colors; static char ps_font_name[80] = "Helvetica"; /* Courier Times Helvetica Symbol */ static char ps_font_family[80] = "Helvetica"; /* Courier Times Helvetica Symbol */ static int ps_embedded_image(xRect* r, double x1, double y1, double x2, double y2, int rot, int flip) { #if defined(HAS_LIBJPEG) && HAS_CAIRO==1 int i, jpg; int size_x, size_y; unsigned char *ptr = NULL; int invertImage; unsigned char* ascii85EncodedJpeg; char *attr = NULL; unsigned char *buffer = NULL; cairo_surface_t *surface = NULL, *orig_sfc = NULL; xEmb_image *emb_ptr; unsigned char* jpgData = NULL; size_t fileSize = 0; int quality=40; const char *quality_attr, *filter; size_t oLength, attr_len, buffer_size; cairo_t *ct; double sx1, sy1, sx2, sy2; /* screen position */ sx1=X_TO_SCREEN(x1); sy1=Y_TO_SCREEN(y1); sx2=X_TO_SCREEN(x2); sy2=Y_TO_SCREEN(y2); if(RECT_OUTSIDE(sx1, sy1, sx2, sy2, xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2)) return 0; invertImage = !strboolcmp(get_tok_value(r->prop_ptr, "InvertOnExport", 0), "true"); if(!invertImage) invertImage = !strboolcmp(get_tok_value(r->prop_ptr, "ps_invert", 0), "true"); quality_attr = get_tok_value(r->prop_ptr, "jpeg_quality", 0); if(quality_attr[0]) quality = atoi(quality_attr); else { quality_attr = get_tok_value(r->prop_ptr, "jpg_quality", 0); if(quality_attr[0]) quality = atoi(quality_attr); } attr_len = my_strdup2(_ALLOC_ID_, &attr, get_tok_value(r->prop_ptr, "image_data", 0)); filter = get_tok_value(r->prop_ptr, "filter", 0); buffer = base64_decode(attr, attr_len, &buffer_size); if(attr_len > 5) { if(!strncmp(attr, "/9j/", 4)) jpg = 1; /* jpg */ else if(!strncmp(attr, "iVBOR", 5)) jpg = 0; /* png */ else if(my_memmem(buffer, buffer_size, "extraptr; if(jpg == -1 || !(emb_ptr && emb_ptr->image)) { my_free(_ALLOC_ID_, &buffer); my_free(_ALLOC_ID_, &attr); return 0; } orig_sfc = emb_ptr->image; cairo_surface_flush(orig_sfc); /* create a copy of image surface with no alpha */ size_x = cairo_image_surface_get_width(orig_sfc); size_y = cairo_image_surface_get_height(orig_sfc); surface = cairo_surface_create_similar_image(orig_sfc, CAIRO_FORMAT_RGB24, size_x, size_y); ct = cairo_create(surface); cairo_set_source_surface(ct, orig_sfc, 0, 0); cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); cairo_paint(ct); cairo_destroy(ct); ptr = cairo_image_surface_get_data(surface); for (i = 0; i < (size_x * size_y * 4); i += 4) { unsigned char a = ptr[i + 3]; unsigned char r = ptr[i + 2]; unsigned char g = ptr[i + 1]; unsigned char b = ptr[i + 0]; /* invert colors */ if(invertImage) { r = a - r; g = a - g; b = a - b; } /* blend with white, remove alpha */ r += (unsigned char)(0xff - a); g += (unsigned char)(0xff - a); b += (unsigned char)(0xff - a); a = (unsigned char) 0xff; /* write result back */ ptr[i + 3] = a; ptr[i + 2] = r; ptr[i + 1] = g; ptr[i + 0] = b; } cairo_surface_mark_dirty(surface); if(invertImage || jpg != 1) { cairo_image_surface_write_to_jpeg_mem(surface, &jpgData, &fileSize, quality); } else { jpgData = base64_decode(attr, attr_len, &fileSize); } cairo_surface_destroy(surface); ascii85EncodedJpeg = ascii85_encode(jpgData, fileSize, &oLength); fprintf(fd, "gsave\n"); fprintf(fd, "save\n"); fprintf(fd, "/RawData currentfile /ASCII85Decode filter def\n"); fprintf(fd, "/Data RawData << >> /DCTDecode filter def\n"); fprintf(fd, "%g %g translate\n", X_TO_PS(x1), Y_TO_PS(y1)); if(rot==1) fprintf(fd, "90 rotate\n"); if(rot==2) fprintf(fd, "180 rotate\n"); if(rot==3) fprintf(fd, "270 rotate\n"); fprintf(fd, "%g %g scale\n", (X_TO_PS(x2) - X_TO_PS(x1))*1., (Y_TO_PS(y2) - Y_TO_PS(y1))*1.); fprintf(fd, "/DeviceRGB setcolorspace\n"); fprintf(fd, "{ << /ImageType 1\n"); fprintf(fd, " /Width %g\n", (double)size_x); fprintf(fd, " /Height %g\n", (double)size_y); if(!flip) { if(rot==1) fprintf(fd, " /ImageMatrix [%g 0 0 %g 0 %g]\n", (double)size_y, (double)size_x, (double)size_y); else if(rot==2) fprintf(fd, " /ImageMatrix [%g 0 0 %g %g %g]\n", (double)size_x, (double)size_y, (double)size_x, (double)size_y); else if(rot==3) fprintf(fd, " /ImageMatrix [%g 0 0 %g %g 0]\n", (double)size_y, (double)size_x, (double)size_x); else fprintf(fd, " /ImageMatrix [%g 0 0 %g 0 0]\n", (double)size_x, (double)size_y); } else { if(rot==1) fprintf(fd, " /ImageMatrix [%g 0 0 %g %g %g]\n", -(double)size_y, (double)size_x, (double)size_x, (double)size_y); else if(rot==2) fprintf(fd, " /ImageMatrix [%g 0 0 %g 0 %g]\n", -(double)size_x, (double)size_y, (double)size_y); else if(rot==3) fprintf(fd, " /ImageMatrix [%g 0 0 %g 0 0]\n", -(double)size_y, (double)size_x); else fprintf(fd, " /ImageMatrix [%g 0 0 %g %g 0]\n", -(double)size_x, (double)size_y, (double)size_x); } fprintf(fd, " /DataSource Data\n"); fprintf(fd, " /BitsPerComponent 8\n"); fprintf(fd, " /Decode [0 1 0 1 0 1]\n"); fprintf(fd, " >> image\n"); fprintf(fd, " Data closefile\n"); fprintf(fd, " RawData flushfile\n"); fprintf(fd, " restore\n"); fprintf(fd, "} exec\n"); #if 1 /* break lines */ for (i = 0; i < oLength; ++i) { fputc(ascii85EncodedJpeg[i],fd); if(i > 0 && (i % 64) == 0) { fputc('\n',fd); /* if (ascii85Encode[i+1]=='%') idx=63; imageMagic does this for some reason?! * Doesn't seem to be necesary. */ } } #else fprintf(fd, "%s", ascii85EncodedJpeg); #endif fprintf(fd, "~>\n"); fprintf(fd, "grestore\n"); my_free(_ALLOC_ID_, &ascii85EncodedJpeg); free(jpgData); my_free(_ALLOC_ID_, &buffer); my_free(_ALLOC_ID_, &attr); #endif return 1; } static int ps_embedded_graph(xRect* r, double rx1, double ry1, double rx2, double ry2) { #if defined(HAS_LIBJPEG) && HAS_CAIRO==1 Zoom_info zi; double rw, rh, scale; cairo_surface_t* png_sfc; int save, save_draw_window, save_draw_grid, rwi, rhi; const double max_size = 3000.0; int d_c; unsigned char* jpgData = NULL; size_t fileSize = 0; /* * FILE* fp; * static char str[PATH_MAX]; */ unsigned char *ascii85EncodedJpeg; int quality=40; const char *quality_attr; size_t oLength; int i; double sx1, sy1, sx2, sy2; /* screen position */ sx1=X_TO_SCREEN(rx1); sy1=Y_TO_SCREEN(ry1); sx2=X_TO_SCREEN(rx2); sy2=Y_TO_SCREEN(ry2); if(RECT_OUTSIDE(sx1, sy1, sx2, sy2, xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2)) return 0; quality_attr = get_tok_value(r->prop_ptr, "jpeg_quality", 0); if(quality_attr[0]) quality = atoi(quality_attr); else { quality_attr = get_tok_value(r->prop_ptr, "jpg_quality", 0); if(quality_attr[0]) quality = atoi(quality_attr); } if(quality_attr[0]) quality = atoi(quality_attr); if (!has_x) return 0; rw = fabs(rx2 - rx1); rh = fabs(ry2 - ry1); scale = 3.0; if (rw > rh && rw > max_size) { scale = max_size / rw; } else if (rh > max_size) { scale = max_size / rh; } rwi = (int)(rw * scale + 1.0); rhi = (int)(rh * scale + 1.0); dbg(1, "graph size: %dx%d\n", rwi, rhi); save_restore_zoom(1, &zi); set_viewport_size(rwi, rhi, xctx->lw); /* zoom_box(rx1 - xctx->lw, ry1 - xctx->lw, rx2 + xctx->lw, ry2 + xctx->lw, 1.0); */ xctx->xorigin = -rx1; xctx->yorigin = -ry1; xctx->zoom=(rx2-rx1)/(rwi - 1); xctx->mooz = 1 / xctx->zoom; resetwin(1, 1, 1, rwi, rhi); dbg(1, "lw=%g\n", xctx->lw); save_draw_grid = tclgetboolvar("draw_grid"); tclsetvar("draw_grid", "0"); save_draw_window = xctx->draw_window; xctx->draw_window = 0; xctx->draw_pixmap = 1; save = xctx->do_copy_area; xctx->do_copy_area = 0; d_c = tclgetboolvar("dark_colorscheme"); tclsetboolvar("dark_colorscheme", 0); build_colors(0, 0); draw(); dbg(1, "width=%d, rwi=%d height=%d rhi=%d\n", xctx->xrect[0].width, rwi, xctx->xrect[0].height, rhi); #ifdef __unix__ png_sfc = cairo_xlib_surface_create(display, xctx->save_pixmap, visual, xctx->xrect[0].width, xctx->xrect[0].height); #else /* pixmap doesn't work on windows Copy from cairo_save_sfc and use cairo to draw in the data points to embed the graph */ png_sfc = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, xctx->xrect[0].width, xctx->xrect[0].height); cairo_t* ct = cairo_create(png_sfc); cairo_set_source_surface(ct, xctx->cairo_save_sfc, 0, 0); cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); cairo_paint(ct); for (i = 0; i < xctx->rects[GRIDLAYER]; ++i) { xRect* r2 = &xctx->rect[GRIDLAYER][i]; if (r2->flags & 1) { setup_graph_data(i, 0, &xctx->graph_struct); draw_graph(i, 8 + (xctx->graph_flags & (4 | 2 | 128 | 256)), &xctx->graph_struct, (void *)ct); } } #endif cairo_image_surface_write_to_jpeg_mem(png_sfc, &jpgData, &fileSize, quality); ascii85EncodedJpeg = ascii85_encode(jpgData, fileSize, &oLength); free(jpgData); cairo_surface_destroy(png_sfc); xctx->draw_pixmap = 1; tclsetboolvar("draw_grid", save_draw_grid); save_restore_zoom(0, &zi); resetwin(1, 1, 1, xctx->xrect[0].width, xctx->xrect[0].height); change_linewidth(xctx->lw); tclsetboolvar("dark_colorscheme", d_c); build_colors(0, 0); draw(); xctx->do_copy_area = save; xctx->draw_window = save_draw_window; fprintf(fd, "gsave\n"); fprintf(fd, "save\n"); fprintf(fd, "/RawData currentfile /ASCII85Decode filter def\n"); fprintf(fd, "/Data RawData << >> /DCTDecode filter def\n"); fprintf(fd, "%f %f translate\n", X_TO_PS(rx1), Y_TO_PS(ry1)); fprintf(fd, "%f %f scale\n", X_TO_PS(rx2) - X_TO_PS(rx1), Y_TO_PS(ry2) - Y_TO_PS(ry1)); fprintf(fd, "/DeviceRGB setcolorspace\n"); fprintf(fd, "{ << /ImageType 1\n"); fprintf(fd, " /Width %d\n", rwi); fprintf(fd, " /Height %d\n", rhi); fprintf(fd, " /ImageMatrix [%d 0 0 %d 0 0]\n", rwi, rhi); fprintf(fd, " /DataSource Data\n"); fprintf(fd, " /BitsPerComponent 8\n"); fprintf(fd, " /Decode [0 1 0 1 0 1]\n"); fprintf(fd, " >> image\n"); fprintf(fd, " Data closefile\n"); fprintf(fd, " RawData flushfile\n"); fprintf(fd, " restore\n"); fprintf(fd, "} exec\n"); #if 1 /* break lines */ for (i = 0; i < oLength; ++i) { fputc(ascii85EncodedJpeg[i],fd); if(i > 0 && (i % 64) == 0) { fputc('\n',fd); /* if (ascii85Encode[i+1]=='%') idx=63; imageMagic does this for some reason?! * Doesn't seem to be necesary. */ } } #else fprintf(fd, "%s", ascii85EncodedJpeg); #endif fprintf(fd, "~>\n"); fprintf(fd, "grestore\n"); my_free(_ALLOC_ID_, &ascii85EncodedJpeg); #endif return 1; } static void set_lw(void) { if(xctx->lw==0.0) fprintf(fd, "%g setlinewidth\n",0.5); else fprintf(fd, "%g setlinewidth\n",xctx->lw/1.2); } static void set_ps_colors(unsigned int pixel) { dbg(1, "set_ps_colors(): setting color %u\n", pixel); if(color_ps) fprintf(fd, "%g %g %g RGB\n", (double)ps_colors[pixel].red/256.0, (double)ps_colors[pixel].green/256.0, (double)ps_colors[pixel].blue/256.0); } static void ps_xdrawarc(int layer, int fillarc, double x, double y, double r, double a, double b) { if(xctx->fill_pattern && xctx->fill_type[layer] && fillarc) fprintf(fd, "%g %g MT %g %g %g %g %g A %g %g LT C F S\n", x, y, x, y, r, -a, -a-b, x, y); else fprintf(fd, "%g %g %g %g %g A S\n", x, y, r, -a, -a-b); } static void ps_xdrawline(int layer, double x1, double y1, double x2, double y2) { fprintf(fd, "%.6g %.6g %.6g %.6g L\n", x2, y2, x1, y1); } static void ps_xdrawpoint(int layer, double x1, double y1) { fprintf(fd, "%g %g %g %g L\n", x1, y1,x1,y1); } static void ps_xfillrectange(int layer, double x1, double y1, double x2, double y2, int fill) { fprintf(fd, "%g %g %g %g R\n", x1,y1,x2-x1,y2-y1); if(fill && (xctx->fill_type[layer] == 1) && xctx->fill_pattern) { fprintf(fd, "%g %g %g %g RF\n", x1,y1,x2-x1,y2-y1); /* fprintf(fd,"fill\n"); */ } /*fprintf(fd,"stroke\n"); */ } static void ps_drawbezier(double *x, double *y, int points) { const double bez_steps = 1.0/32.0; /* divide the t = [0,1] interval into 32 steps */ int b, i; double t; double xp, yp; double x0, x1, x2, y0, y1, y2; i = 0; for(b = 0; b < points - 2; b++) { if(points == 3) { /* 3 points: only one bezier */ x0 = x[0]; y0 = y[0]; x1 = x[1]; y1 = y[1]; x2 = x[2]; y2 = y[2]; } else if(b == points - 3) { /* last bezier */ x0 = (x[points - 3] + x[points - 2]) / 2.0; y0 = (y[points - 3] + y[points - 2]) / 2.0; x1 = x[points - 2]; y1 = y[points - 2]; x2 = x[points - 1]; y2 = y[points - 1]; } else if(b == 0) { /* first bezier */ x0 = x[0]; y0 = y[0]; x1 = x[1]; y1 = y[1]; x2 = (x[1] + x[2]) / 2.0; y2 = (y[1] + y[2]) / 2.0; } else { /* beziers in the middle */ x0 = (x[b] + x[b + 1]) / 2.0; y0 = (y[b] + y[b + 1]) / 2.0; x1 = x[b + 1]; y1 = y[b + 1]; x2 = (x[b + 1] + x[b + 2]) / 2.0; y2 = (y[b + 1] + y[b + 2]) / 2.0; } for(t = 0; t <= 1.0; t += bez_steps) { xp = (1 - t) * (1 - t) * x0 + 2 * (1 - t) * t * x1 + t * t * x2; yp = (1 - t) * (1 - t) * y0 + 2 * (1 - t) * t * y1 + t * t * y2; if(i==0) fprintf(fd, "NP\n%g %g MT\n", X_TO_PS(xp), Y_TO_PS(yp)); else fprintf(fd, "%g %g LT\n", X_TO_PS(xp), Y_TO_PS(yp)); i++; } } } /* Convex Nonconvex Complex */ #define Polygontype Nonconvex static void ps_drawpolygon(int c, int what, double *x, double *y, int points, int poly_fill, int dash, int flags) { double x1,y1,x2,y2; double xx, yy; double psdash; int i, bezier; polygon_bbox(x, y, points, &x1,&y1,&x2,&y2); x1=X_TO_PS(x1); y1=Y_TO_PS(y1); x2=X_TO_PS(x2); y2=Y_TO_PS(y2); if( !rectclip(xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2,&x1,&y1,&x2,&y2) ) { return; } psdash = dash / xctx->zoom; if(dash) { fprintf(fd, "[%g %g] 0 setdash\n", psdash, psdash); } bezier = flags && (points > 2); if(bezier) { ps_drawbezier(x, y, points); } else { for(i=0;ifill_pattern && xctx->fill_type[c] && poly_fill) { fprintf(fd, "GS C F GR S\n"); } else { fprintf(fd, "S\n"); } if(dash) { fprintf(fd, "[] 0 setdash\n"); } } static void ps_filledrect(int gc, double rectx1,double recty1,double rectx2,double recty2, int dash, int fill) { double x1,y1,x2,y2, tmp; double psdash; x1=X_TO_PS(rectx1); y1=Y_TO_PS(recty1); x2=X_TO_PS(rectx2); y2=Y_TO_PS(recty2); if( rectclip(xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2,&tmp,&tmp,&tmp,&tmp) ) { psdash = dash / xctx->zoom; if(dash) { fprintf(fd, "[%g %g] 0 setdash\n", psdash, psdash); } ps_xfillrectange(gc, x1,y1,x2,y2, fill); if(dash) { fprintf(fd, "[] 0 setdash\n"); } } } static void ps_drawarc(int gc, int fillarc, double x,double y,double r,double a, double b, int dash) { double xx,yy,rr; double x1, y1, x2, y2; double psdash; xx=X_TO_PS(x); yy=Y_TO_PS(y); rr=r*xctx->mooz; arc_bbox(x, y, r, a, b, &x1,&y1,&x2,&y2); x1=X_TO_PS(x1); y1=Y_TO_PS(y1); x2=X_TO_PS(x2); y2=Y_TO_PS(y2); if( rectclip(xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2,&x1,&y1,&x2,&y2) ) { psdash = dash / xctx->zoom; if(dash) { fprintf(fd, "[%g %g] 0 setdash\n", psdash, psdash); } ps_xdrawarc(gc, fillarc, xx, yy, rr, a, b); if(dash) { fprintf(fd, "[] 0 setdash\n"); } } } static void ps_drawline(int gc, double linex1,double liney1,double linex2,double liney2, int dash) { double x1,y1,x2,y2; double psdash; x1=X_TO_PS(linex1); y1=Y_TO_PS(liney1); x2=X_TO_PS(linex2); y2=Y_TO_PS(liney2); if( clip(&x1,&y1,&x2,&y2) ) { psdash = dash / xctx->zoom; if(dash) { fprintf(fd, "[%g %g] 0 setdash\n", psdash, psdash); } ps_xdrawline(gc, x1, y1, x2, y2); if(dash) { fprintf(fd, "[] 0 setdash\n"); } } } static void ps_draw_string_line(int layer, char *s, double x, double y, double size, short rot, short flip, int lineno, double fontheight, double fontascent, double fontdescent, int llength, int no_of_lines, double longest_line) { double ix, iy; short rot1; unsigned char c, offset; double line_delta; double lines; dbg(1, "ps_draw_string_line(): drawing |%s| on layer %d\n", s, layer); if(s==NULL) return; if(llength==0) return; fprintf(fd, "GS\n"); set_ps_colors(layer); line_delta = lineno*fontheight; lines = (no_of_lines-1)*fontheight; ix=X_TO_PS(x); iy=Y_TO_PS(y); if(rot&1) { rot1=3; } else rot1=0; if( rot==0 && flip==0) {iy+=line_delta+fontascent;} else if(rot==1 && flip==0) {ix=ix-fontheight+fontascent-lines+line_delta;} else if(rot==2 && flip==0) {iy=iy-fontheight-lines+line_delta+fontascent;} else if(rot==3 && flip==0) {ix+=line_delta+fontascent;} else if(rot==0 && flip==1) {iy+=line_delta+fontascent;} else if(rot==1 && flip==1) {ix=ix-fontheight+line_delta-lines+fontascent;} else if(rot==2 && flip==1) {iy=iy-fontheight-lines+line_delta+fontascent;} else if(rot==3 && flip==1) {ix+=line_delta+fontascent;} fprintf(fd, "/%s", ps_font_family); fprintf(fd, " FF\n"); fprintf(fd, "%g SCF\n", size * xctx->mooz); fprintf(fd, "SF\n"); fprintf(fd, "NP\n"); fprintf(fd, "%g %g MT\n", ix, iy); if(rot1) fprintf(fd, "%d rotate\n", rot1*90); fprintf(fd, "1 -1 scale\n"); fprintf(fd, "("); offset = 0; while( (c = (unsigned char) *s) ) { if(c > 127) { if(c == 195) {offset = 64;s++; continue;} if(c == 194) {s++; continue;} fprintf(fd, "\\%03o", c + offset); offset = 0; } else switch(c) { case '(': fputs("\\(", fd); break; case ')': fputs("\\)", fd); break; default: fputc(c, fd); } ++s; } fprintf(fd, ")\n"); if (rot==1 && flip==0) {fprintf(fd, "dup SW pop neg 0 RMT\n");} else if(rot==2 && flip==0) {fprintf(fd, "dup SW pop neg 0 RMT\n");} else if(rot==0 && flip==1) {fprintf(fd, "dup SW pop neg 0 RMT\n");} else if(rot==3 && flip==1) {fprintf(fd, "dup SW pop neg 0 RMT\n");} fprintf(fd, "show\n"); fprintf(fd, "GR\n"); } static void ps_draw_string(int layer, const char *str, short rot, short flip, int hcenter, int vcenter, double x,double y, double xscale, double yscale) { char *tt, *ss, *sss=NULL; double textx1,textx2,texty1,texty2; char c; char *estr = NULL; /* expanded string: TABs replaced with spaces */ int lineno=0; double size, height, ascent, descent; int llength=0, no_of_lines; double longest_line; if(str==NULL) return; size = xscale*53. * cairo_font_scale; height = size*xctx->mooz * 1.147; /* was 1.147 */ ascent = size*xctx->mooz * 0.808; /* was 0.908 */ descent = size*xctx->mooz * 0.219; /* was 0.219 */ estr = my_expand(str, tclgetintvar("tabstop")); text_bbox(estr, xscale, yscale, rot, flip, hcenter, vcenter, x,y, &textx1,&texty1,&textx2,&texty2, &no_of_lines, &longest_line); if(!textclip(xctx->areax1,xctx->areay1,xctx->areax2, xctx->areay2,textx1,texty1,textx2,texty2)) { my_free(_ALLOC_ID_, &estr); return; } if(hcenter) { if(rot == 0 && flip == 0 ) { x=textx1;} if(rot == 1 && flip == 0 ) { y=texty1;} if(rot == 2 && flip == 0 ) { x=textx2;} if(rot == 3 && flip == 0 ) { y=texty2;} if(rot == 0 && flip == 1 ) { x=textx2;} if(rot == 1 && flip == 1 ) { y=texty2;} if(rot == 2 && flip == 1 ) { x=textx1;} if(rot == 3 && flip == 1 ) { y=texty1;} } if(vcenter) { if(rot == 0 && flip == 0 ) { y=texty1;} if(rot == 1 && flip == 0 ) { x=textx2;} if(rot == 2 && flip == 0 ) { y=texty2;} if(rot == 3 && flip == 0 ) { x=textx1;} if(rot == 0 && flip == 1 ) { y=texty1;} if(rot == 1 && flip == 1 ) { x=textx2;} if(rot == 2 && flip == 1 ) { y=texty2;} if(rot == 3 && flip == 1 ) { x=textx1;} } llength=0; my_strdup2(_ALLOC_ID_, &sss, estr); tt=ss=sss; for(;;) { c=*ss; if(c=='\n' || c==0) { *ss='\0'; ps_draw_string_line(layer, tt, x, y, size, rot, flip, lineno, height, ascent, descent, llength, no_of_lines, longest_line); ++lineno; if(c==0) break; *ss='\n'; tt=ss+1; llength=0; } else { ++llength; } ++ss; } my_free(_ALLOC_ID_, &sss); my_free(_ALLOC_ID_, &estr); } static void old_ps_draw_string(int gctext, const char *str, short rot, short flip, int hcenter, int vcenter, double x1,double y1, double xscale, double yscale) { double a,yy,curr_x1,curr_y1,curr_x2,curr_y2,rx1,rx2,ry1,ry2; int pos=0,cc,pos2=0; int i, no_of_lines; double longest_line; char *estr = NULL; if(str==NULL) return; estr = my_expand(str, tclgetintvar("tabstop")); xscale*=tclgetdoublevar("nocairo_font_xscale") * cairo_font_scale; yscale*=tclgetdoublevar("nocairo_font_yscale") * cairo_font_scale; #if HAS_CAIRO==1 text_bbox_nocairo(estr, xscale, yscale, rot, flip, hcenter, vcenter, x1,y1, &rx1,&ry1,&rx2,&ry2, &no_of_lines, &longest_line); #else text_bbox(estr, xscale, yscale, rot, flip, hcenter, vcenter, x1,y1, &rx1,&ry1,&rx2,&ry2, &no_of_lines, &longest_line); #endif if(!textclip(xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2,rx1,ry1,rx2,ry2)) { my_free(_ALLOC_ID_, &estr); return; } set_ps_colors(gctext); x1=rx1;y1=ry1; if(rot&1) {y1=ry2;rot=3;} else rot=0; flip = 0; yy=y1; while(estr[pos2]) { cc = (unsigned char)estr[pos2++]; if(cc>127) cc= '?'; if(cc=='\n') { yy+=(FONTHEIGHT+FONTDESCENT+FONTWHITESPACE)* yscale; pos=0; continue; } a = pos*(FONTWIDTH+FONTWHITESPACE); for(i=0;imooz; while(deltaxorigin* xctx->mooz;y = xctx->yorigin* xctx->mooz; set_ps_colors(GRIDLAYER); if(y>xctx->areay1 && yareay2) { ps_xdrawline(GRIDLAYER,xctx->areax1+1,(int)y, xctx->areax2-1, (int)y); } if(x>xctx->areax1 && xareax2) { ps_xdrawline(GRIDLAYER,(int)x,xctx->areay1+1, (int)x, xctx->areay2-1); } set_ps_colors(GRIDLAYER); tmp = floor((xctx->areay1+1)/delta)*delta-fmod(-xctx->yorigin* xctx->mooz,delta); for(x=floor((xctx->areax1+1)/delta)*delta-fmod(-xctx->xorigin* xctx->mooz,delta);xareax2;x+=delta) { for(y=tmp;yareay2;y+=delta) { ps_xdrawpoint(GRIDLAYER,(int)(x), (int)(y)); } } } static void ps_draw_symbol(int c, int n,int layer, int what, short tmp_flip, short rot, double xoffset, double yoffset) /* draws current layer only, should be called within */ { /* a "for(i=0;iinst[n].ptr == -1) return; if( (layer != PINLAYER && !xctx->enable_layer[layer]) ) return; if( (xctx->hide_symbols==1 && (xctx->inst[n].ptr+ xctx->sym)->prop_ptr && !strcmp( (xctx->inst[n].ptr+ xctx->sym)->type, "subcircuit") ) || (xctx->hide_symbols == 2) ) { hide = 1; } else { hide = 0; } if(layer==0) { x1=X_TO_PS(xctx->inst[n].x1); x2=X_TO_PS(xctx->inst[n].x2); y1=Y_TO_PS(xctx->inst[n].y1); y2=Y_TO_PS(xctx->inst[n].y2); if(RECT_OUTSIDE(x1,y1,x2,y2,xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2)) { xctx->inst[n].flags|=1; return; } else xctx->inst[n].flags&=~1; /* pdfmarks, only if doing hierarchy print and if symbol has a subcircuit */ if(what != 7) { char fname[PATH_MAX]; if(!strcmp(xctx->sym[xctx->inst[n].ptr].type, "subcircuit")) { get_sch_from_sym(fname, xctx->inst[n].ptr+ xctx->sym, n, 0); fprintf(fd, "[ " "/Rect [ %g %g %g %g ] " "/Border [0 0 0] " "/Dest /%s " "/Subtype /Link " "/ANN pdfmark\n", x1, y1, x2, y2, get_cell_w_ext(sanitize(fname), 0)); } } } else if(xctx->inst[n].flags&1) { dbg(1, "draw_symbol(): skippinginst %d\n", n); return; } flip = xctx->inst[n].flip; if(tmp_flip) flip = !flip; rot = (xctx->inst[n].rot + rot ) & 0x3; x0=xctx->inst[n].x0 + xoffset; y0=xctx->inst[n].y0 + yoffset; symptr = (xctx->inst[n].ptr+ xctx->sym); for(j=0;j< (xctx->inst[n].ptr+ xctx->sym)->lines[layer]; ++j) { line = ((xctx->inst[n].ptr+ xctx->sym)->line[layer])[j]; ROTATION(rot, flip, 0.0,0.0,line.x1,line.y1,x1,y1); ROTATION(rot, flip, 0.0,0.0,line.x2,line.y2,x2,y2); ORDER(x1,y1,x2,y2); ps_drawline(c, x0+x1, y0+y1, x0+x2, y0+y2, line.dash); } for(j=0;j< (xctx->inst[n].ptr+ xctx->sym)->polygons[layer]; ++j) { polygon = &((xctx->inst[n].ptr+ xctx->sym)->poly[layer])[j]; { /* scope block so we declare some auxiliary arrays for coord transforms. 20171115 */ int k, bezier; double *x = my_malloc(_ALLOC_ID_, sizeof(double) * polygon->points); double *y = my_malloc(_ALLOC_ID_, sizeof(double) * polygon->points); for(k=0;kpoints; ++k) { ROTATION(rot, flip, 0.0,0.0,polygon->x[k],polygon->y[k],x[k],y[k]); x[k]+= x0; y[k] += y0; } bezier = !strboolcmp(get_tok_value(polygon->prop_ptr, "bezier", 0), "true"); ps_drawpolygon(c, NOW, x, y, polygon->points, polygon->fill, polygon->dash, bezier); my_free(_ALLOC_ID_, &x); my_free(_ALLOC_ID_, &y); } } if((xctx->inst[n].ptr+ xctx->sym)->arcs[layer]) fprintf(fd, "NP\n"); /* newpath */ for(j=0;j< (xctx->inst[n].ptr+ xctx->sym)->arcs[layer]; ++j) { double angle; arc = ((xctx->inst[n].ptr+ xctx->sym)->arc[layer])[j]; if(flip) { angle = 270.*rot+180.-arc.b-arc.a; } else { angle = arc.a+rot*270.; } angle = fmod(angle, 360.); if(angle<0.) angle+=360.; ROTATION(rot, flip, 0.0,0.0,arc.x,arc.y,x1,y1); ps_drawarc(c, arc.fill, x0+x1, y0+y1, arc.r, angle, arc.b, arc.dash); } if( xctx->enable_layer[layer] ) for(j=0;j< (xctx->inst[n].ptr+ xctx->sym)->rects[layer]; ++j) { rect = ((xctx->inst[n].ptr+ xctx->sym)->rect[layer])[j]; ROTATION(rot, flip, 0.0,0.0,rect.x1,rect.y1,x1,y1); ROTATION(rot, flip, 0.0,0.0,rect.x2,rect.y2,x2,y2); RECTORDER(x1,y1,x2,y2); if (rect.flags & 1024) /* image */ { ps_embedded_image(&rect, x0 + x1, y0 + y1, x0 + x2, y0 + y2, rot, flip); continue; } ps_filledrect(c, x0+x1, y0+y1, x0+x2, y0+y2, rect.dash, rect.fill); } if( !(xctx->inst[n].flags & HIDE_SYMBOL_TEXTS) && ( (layer==TEXTWIRELAYER && (xctx->inst[n].flags & PIN_OR_LABEL) ) || (xctx->sym_txt && (layer==TEXTLAYER) && !(xctx->inst[n].flags & PIN_OR_LABEL)) ) ) { const char *txtptr; for(j=0;j< (xctx->inst[n].ptr+ xctx->sym)->texts; ++j) { double xscale, yscale; get_sym_text_size(n, j, &xscale, &yscale); text = (xctx->inst[n].ptr+ xctx->sym)->text[j]; /* if(xscale*FONTWIDTH* xctx->mooz<1) continue; */ if(!xctx->show_hidden_texts && (text.flags & (HIDE_TEXT | HIDE_TEXT_INSTANTIATED))) continue; if( hide && text.txt_ptr && strcmp(text.txt_ptr, "@symname") && strcmp(text.txt_ptr, "@name") ) continue; txtptr= translate(n, text.txt_ptr); ROTATION(rot, flip, 0.0,0.0,text.x0,text.y0,x1,y1); textlayer = c; /* do not allow custom text color on PINLAYER hilighted instances */ if( !(xctx->inst[n].color == -PINLAYER)) { textlayer = (xctx->inst[n].ptr+ xctx->sym)->text[j].layer; if(textlayer < 0 || textlayer >= cadlayers) textlayer = c; } /* display PINLAYER colored instance texts even if PINLAYER disabled */ if(xctx->inst[n].color == -PINLAYER || xctx->enable_layer[textlayer]) { my_snprintf(ps_font_family, S(ps_font_name), "Helvetica"); my_snprintf(ps_font_name, S(ps_font_name), "Helvetica"); textfont = symptr->text[j].font; if( (textfont && textfont[0])) { my_snprintf(ps_font_family, S(ps_font_family), textfont); my_snprintf(ps_font_name, S(ps_font_name), textfont); } if( symptr->text[j].flags & TEXT_BOLD) { if( (symptr->text[j].flags & TEXT_ITALIC) || (symptr->text[j].flags & TEXT_OBLIQUE) ) { my_snprintf(ps_font_family, S(ps_font_family), "%s-BoldOblique", ps_font_name); } else { my_snprintf(ps_font_family, S(ps_font_family), "%s-Bold", ps_font_name); } } else if( symptr->text[j].flags & TEXT_ITALIC) my_snprintf(ps_font_family, S(ps_font_family), "%s-Oblique", ps_font_name); else if( symptr->text[j].flags & TEXT_OBLIQUE) my_snprintf(ps_font_family, S(ps_font_family), "%s-Oblique", ps_font_name); if(text_ps) { ps_draw_string(textlayer, txtptr, (text.rot + ( (flip && (text.rot & 1) ) ? rot+2 : rot) ) & 0x3, flip^text.flip, text.hcenter, text.vcenter, x0+x1, y0+y1, xscale, yscale); } else { old_ps_draw_string(textlayer, txtptr, (text.rot + ( (flip && (text.rot & 1) ) ? rot+2 : rot) ) & 0x3, flip^text.flip, text.hcenter, text.vcenter, x0+x1, y0+y1, xscale, yscale); } } } } } static void fill_ps_colors() { char s[200]; /* overflow safe 20161122 */ unsigned int i,c; /* if(debug_var>=1) { * tcleval( "puts $ps_colors"); * } */ for(i=0;i> 16; ps_colors[i].green = (c & 0x00ff00) >> 8; ps_colors[i].blue = (c & 0x0000ff); } } /* fullzoom: * 0: Print area displayed in window * 1: Do a full zoom before generating ps/pdf * 2: set paper size to bounding box instead of a4/letter */ void create_ps(char **psfile, int what, int fullzoom, int eps) { double dx, dy, scale, scaley; int landscape=1; static int numpages = 0; double margin=10; /* in postscript points, (1/72)". No need to add margin as xschem zoom full already has margins.*/ char papername[80] = "a4"; double pagex = 842; double pagey = 595; xRect boundbox; int c,i, textlayer; int old_grid; const char *textfont; static Zoom_info zi; Hilight_hashentry *entry; dbg(1, "create_ps(): what = %d, fullzoom=%d\n", what, fullzoom); if(tcleval("info exists ps_paper_size")[0] == '1') { double tmp; my_strncpy(papername, tcleval("lindex $ps_paper_size 0"), S(papername)); pagex = my_atod(tcleval("lindex $ps_paper_size 1")); pagey = my_atod(tcleval("lindex $ps_paper_size 2")); if(pagex < pagey) { /* start with landscape; later we decide paper orientation */ tmp = pagex; pagex = pagey; pagey = tmp; } } if(what & 1) { /* prolog */ numpages = 0; if(!(fd = open_tmpfile("psplot_", ".ps", psfile)) ) { fprintf(errfp, "ps_draw(): can not create tmpfile %s\n", *psfile); return; } } setbuf(fd, NULL); /*To prevent buffer errors, still investigating cause. */ ps_colors=my_calloc(_ALLOC_ID_, cadlayers, sizeof(Ps_color)); if(ps_colors==NULL){ fprintf(errfp, "create_ps(): calloc error\n"); return; } fill_ps_colors(); old_grid=tclgetboolvar("draw_grid"); tclsetvar("draw_grid", "0"); /* xschem window aspect ratio decides if portrait or landscape */ boundbox.x1 = xctx->areax1; boundbox.x2 = xctx->areax2; boundbox.y1 = xctx->areay1; boundbox.y2 = xctx->areay2; dx=boundbox.x2-boundbox.x1; dy=boundbox.y2-boundbox.y1; /* xschem drawing bbox decides if portrait or landscape */ if(fullzoom == 1) { calc_drawing_bbox(&boundbox, 0); dx=boundbox.x2-boundbox.x1; dy=boundbox.y2-boundbox.y1; } if(dx >= dy) { landscape = 1; } else { landscape = 0; } dbg(1, "dx=%g, dy=%g\n", dx, dy); if(fullzoom == 1) { /* save size and zoom factor */ save_restore_zoom(1, &zi); /* this zoom only done to reset lw */ zoom_full(0, 0, 1 + 2 * tclgetboolvar("zoom_full_center"), 0.97); /* adjust aspect ratio to paper size */ if(landscape) xctx->xrect[0].height = (short unsigned int) (xctx->xrect[0].width * pagey / pagex); else xctx->xrect[0].width = (short unsigned int) (xctx->xrect[0].height * pagey / pagex); dbg(1, "xrect.width=%d, xrect.height=%d\n", xctx->xrect[0].width, xctx->xrect[0].height); xctx->areax1 = -2*INT_WIDTH(xctx->lw); xctx->areay1 = -2*INT_WIDTH(xctx->lw); xctx->areax2 = xctx->xrect[0].width+2*INT_WIDTH(xctx->lw); xctx->areay2 = xctx->xrect[0].height+2*INT_WIDTH(xctx->lw); xctx->areaw = xctx->areax2-xctx->areax1; xctx->areah = xctx->areay2 - xctx->areay1; dbg(1, "dx=%g, dy=%g\n", dx, dy); /* fit schematic into adjusted size */ zoom_full(0, 0, 0 + 2 * tclgetboolvar("zoom_full_center"), 0.97); boundbox.x1 = xctx->areax1; boundbox.x2 = xctx->areax2; boundbox.y1 = xctx->areay1; boundbox.y2 = xctx->areay2; dx=boundbox.x2-boundbox.x1; dy=boundbox.y2-boundbox.y1; } if(!landscape) { /* decide paper orientation for best schematic fit */ double tmp; tmp = pagex; pagex = pagey; pagey = tmp; } if(fullzoom == 2) { /* set media size to bbox */ double sc; my_strncpy(papername, "bbox", S(papername)); pagex = xctx->xrect[0].width; pagey = xctx->xrect[0].height; if(pagex > pagey) { sc = 842. / pagex; pagex = my_round(pagex * sc); pagey = my_round(pagey * sc); } else { sc = 842. / pagey; pagex = my_round(pagex * sc); pagey = my_round(pagey * sc); } margin = 0.0; } if(what & 1) {/* prolog */ dbg(1, "ps_draw(): bbox: x1=%g y1=%g x2=%g y2=%g\n", boundbox.x1, boundbox.y1, boundbox.x2, boundbox.y2); if(!eps) { fprintf(fd, "%%!PS-Adobe-3.0\n"); } else { fprintf(fd, "%%!PS-Adobe-2.0 EPSF-2.0\n"); fprintf(fd, "%%%%BoundingBox: 0 0 %g %g\n", pagex, pagey); } /* fprintf(fd, "%%%%DocumentMedia: %s %g %g 80 () ()\n", landscape ? "a4land" : "a4", pagex, pagey); */ fprintf(fd, "%%%%DocumentMedia: %s %g %g 80 () ()\n", papername, pagex, pagey); fprintf(fd, "%%%%PageOrientation: %s\n", landscape ? "Landscape" : "Portrait"); fprintf(fd, "%%%%Title: xschem plot\n"); fprintf(fd, "%%%%Creator: xschem\n"); if(!eps) fprintf(fd, "%%%%Pages: (atend)\n"); fprintf(fd, "%%%%EndComments\n"); if(eps) { fprintf(fd, "%%%%BeginProlog\n"); fprintf(fd, "save\n"); fprintf(fd, "countdictstack\n"); fprintf(fd, "mark\n"); fprintf(fd, "newpath\n"); fprintf(fd, "/showpage {} def\n"); fprintf(fd, "/setpagedevice {pop} def\n"); fprintf(fd, "%%%%EndProlog\n"); fprintf(fd, "%%%%Page 1 1\n"); } fprintf(fd, "%%%%BeginProlog\n\n"); for(i = 0; i < sizeof(utf8_enc)/sizeof(char *); ++i) { fprintf(fd, "%s", utf8_enc[i]); } for(i = 0; i < sizeof(utf8)/sizeof(char *); ++i) { fprintf(fd, "%s", utf8[i]); } fprintf(fd, "/Times /Times chararr recode\n"); fprintf(fd, "/Times-Bold /Times-Bold chararr recode\n"); fprintf(fd, "/Times-Oblique /Times-Oblique chararr recode\n"); fprintf(fd, "/Times-BoldOblique /Times-BoldOblique chararr recode\n"); fprintf(fd, "/Helvetica /Helvetica chararr recode\n"); fprintf(fd, "/Helvetica-Bold /Helvetica-Bold chararr recode\n"); fprintf(fd, "/Helvetica-Oblique /Helvetica-Oblique chararr recode\n"); fprintf(fd, "/Helvetica-BoldOblique /Helvetica-BoldOblique chararr recode\n"); fprintf(fd, "/Courier /Courier chararr recode\n"); fprintf(fd, "/Courier-Bold /Courier-Bold chararr recode\n"); fprintf(fd, "/Courier-Oblique /Courier-Oblique chararr recode\n"); fprintf(fd, "/Courier-BoldOblique /Courier-BoldOblique chararr recode\n"); fprintf(fd,"/cm {28.346457 mul} bind def\n"); fprintf(fd,"/LT {lineto} bind def\n"); fprintf(fd,"/MT {moveto} bind def\n"); fprintf(fd,"/RMT {rmoveto} bind def\n"); fprintf(fd,"/L {moveto lineto stroke} bind def\n"); fprintf(fd,"/RGB {setrgbcolor} bind def\n"); fprintf(fd,"/FF {findfont} bind def\n"); fprintf(fd,"/SF {setfont} bind def\n"); fprintf(fd,"/SCF {scalefont} bind def\n"); fprintf(fd,"/SW {stringwidth} bind def\n"); fprintf(fd,"/GS {gsave} bind def\n"); fprintf(fd,"/GR {grestore} bind def\n"); fprintf(fd,"/NP {newpath} bind def\n"); fprintf(fd,"/A {arcn} bind def\n"); fprintf(fd,"/R {rectstroke} bind def\n"); fprintf(fd,"/S {stroke} bind def\n"); fprintf(fd,"/C {closepath} bind def\n"); fprintf(fd,"/F {fill} bind def\n"); fprintf(fd,"/RF {rectfill} bind def\n"); fprintf(fd, "%%%%EndProlog\n"); } if(what & 2) { /* page */ ++numpages; if(!eps) { fprintf(fd, "%%%%BeginSetup\n"); fprintf(fd, "<< /PageSize [%g %g] /Orientation 0 >> setpagedevice\n", pagex, pagey); fprintf(fd, "%%%%EndSetup\n"); fprintf(fd, "%%%%Page: %d %d\n\n", numpages, numpages); fprintf(fd, "%%%%BeginPageSetup\n"); fprintf(fd, "%%%%EndPageSetup\n"); } /* add small page title */ if(tclgetboolvar("ps_page_title") && fullzoom != 2) fprintf(fd, "/Helvetica FF 10 SCF SF NP 20 %g MT (%s) show\n", pagey - 20, xctx->current_name); /* Add anchor for pdfmarks */ fprintf(fd, "[ " "/Dest /%s " "/DEST pdfmark\n", get_cell_w_ext(sanitize(xctx->current_name), 0)); scaley = scale = (pagey-2 * margin) / dy; dbg(1, "scale=%g pagex=%g pagey=%g dx=%g dy=%g\n", scale, pagex, pagey, dx, dy); if(dx * scale > (pagex - 2 * margin)) { scale = (pagex - 2 * margin) / dx; dbg(1, "scale=%g\n", scale); } fprintf(fd, "%g %g translate\n", -scale * boundbox.x1 + margin, pagey - (scaley - scale) * dy - margin + scale * boundbox.y1); fprintf(fd, "%g %g scale\n", scale, -scale); fprintf(fd, "1 setlinejoin 1 setlinecap\n"); set_lw(); ps_drawgrid(); for(c=0;clines[c]; ++i) ps_drawline(c, xctx->line[c][i].x1, xctx->line[c][i].y1, xctx->line[c][i].x2, xctx->line[c][i].y2, xctx->line[c][i].dash); for(i=0;irects[c]; ++i) { if (c == GRIDLAYER && (xctx->rect[c][i].flags & 1024)) { /* image */ xRect* r = &xctx->rect[c][i]; /* PNG Code Here */ ps_embedded_image(r, r->x1, r->y1, r->x2, r->y2,0 ,0); continue; } if (c == GRIDLAYER && (xctx->rect[c][i].flags & 1)) { /* graph */ xRect* r = &xctx->rect[c][i]; ps_embedded_graph(r, r->x1, r->y1, r->x2, r->y2); } if(c != GRIDLAYER || !(xctx->rect[c][i].flags & 1) ) { ps_filledrect(c, xctx->rect[c][i].x1, xctx->rect[c][i].y1, xctx->rect[c][i].x2, xctx->rect[c][i].y2, xctx->rect[c][i].dash, xctx->rect[c][i].fill); } } if(xctx->arcs[c]) fprintf(fd, "NP\n"); /* newpath */ for(i=0;iarcs[c]; ++i) { ps_drawarc(c, xctx->arc[c][i].fill, xctx->arc[c][i].x, xctx->arc[c][i].y, xctx->arc[c][i].r, xctx->arc[c][i].a, xctx->arc[c][i].b, xctx->arc[c][i].dash); } for(i=0;ipolygons[c]; ++i) { int bezier = !strboolcmp(get_tok_value(xctx->poly[c][i].prop_ptr, "bezier", 0), "true"); ps_drawpolygon(c, NOW, xctx->poly[c][i].x, xctx->poly[c][i].y, xctx->poly[c][i].points, xctx->poly[c][i].fill, xctx->poly[c][i].dash, bezier); } dbg(1, "create_ps(): starting drawing symbols on layer %d\n", c); } /* for(c=0;cinstances; ++i) { int color = c; if(xctx->inst[i].color != -10000) color = get_color(xctx->inst[i].color); set_ps_colors(color); ps_draw_symbol(color, i,c,what,0,0,0.0,0.0); } } prepare_netlist_structs(0); /* NEEDED: data was cleared by trim_wires() */ for(i=0;iwires; ++i) { int color = WIRELAYER; if(xctx->hilight_nets && (entry=bus_hilight_hash_lookup( xctx->wire[i].node, 0, XLOOKUP))) { color = get_color(entry->value); } set_ps_colors(color); ps_drawline(color, xctx->wire[i].x1,xctx->wire[i].y1,xctx->wire[i].x2,xctx->wire[i].y2, 0); } { double x1, y1, x2, y2; Wireentry *wireptr; int i; int first = 1; Iterator_ctx ctx; update_conn_cues(WIRELAYER, 0, 0); /* draw connecting dots */ x1 = X_TO_XSCHEM(xctx->areax1); y1 = Y_TO_XSCHEM(xctx->areay1); x2 = X_TO_XSCHEM(xctx->areax2); y2 = Y_TO_XSCHEM(xctx->areay2); for(init_wire_iterator(&ctx, x1, y1, x2, y2); ( wireptr = wire_iterator_next(&ctx) ) ;) { if(first) { fprintf(fd, "NP\n"); /* newpath */ first = 0; } i = wireptr->n; if( xctx->wire[i].end1 >1 ) { ps_drawarc(WIRELAYER, 1, xctx->wire[i].x1, xctx->wire[i].y1, xctx->cadhalfdotsize, 0, 360, 0); } if( xctx->wire[i].end2 >1 ) { ps_drawarc(WIRELAYER, 1, xctx->wire[i].x2, xctx->wire[i].y2, xctx->cadhalfdotsize, 0, 360, 0); } } } for(i=0;itexts; ++i) { textlayer = xctx->text[i].layer; if(!xctx->show_hidden_texts && (xctx->text[i].flags & HIDE_TEXT)) continue; if(textlayer < 0 || textlayer >= cadlayers) textlayer = TEXTLAYER; my_snprintf(ps_font_family, S(ps_font_name), "Helvetica"); my_snprintf(ps_font_name, S(ps_font_name), "Helvetica"); textfont = xctx->text[i].font; if( (textfont && textfont[0])) { my_snprintf(ps_font_family, S(ps_font_family), textfont); my_snprintf(ps_font_name, S(ps_font_name), textfont); } if( xctx->text[i].flags & TEXT_BOLD) { if( (xctx->text[i].flags & TEXT_ITALIC) || (xctx->text[i].flags & TEXT_OBLIQUE) ) { my_snprintf(ps_font_family, S(ps_font_family), "%s-BoldOblique", ps_font_name); } else { my_snprintf(ps_font_family, S(ps_font_family), "%s-Bold", ps_font_name); } } else if( xctx->text[i].flags & TEXT_ITALIC) my_snprintf(ps_font_family, S(ps_font_family), "%s-Oblique", ps_font_name); else if( xctx->text[i].flags & TEXT_OBLIQUE) my_snprintf(ps_font_family, S(ps_font_family), "%s-Oblique", ps_font_name); if(text_ps) { ps_draw_string(textlayer, get_text_floater(i), xctx->text[i].rot, xctx->text[i].flip, xctx->text[i].hcenter, xctx->text[i].vcenter, xctx->text[i].x0,xctx->text[i].y0, xctx->text[i].xscale, xctx->text[i].yscale); } else { old_ps_draw_string(textlayer, get_text_floater(i), xctx->text[i].rot, xctx->text[i].flip, xctx->text[i].hcenter, xctx->text[i].vcenter, xctx->text[i].x0,xctx->text[i].y0, xctx->text[i].xscale, xctx->text[i].yscale); } } dbg(1, "ps_draw(): INT_WIDTH(lw)=%d plotfile=%s\n",INT_WIDTH(xctx->lw), xctx->plotfile); fprintf(fd, "showpage\n\n"); } if(what & 4) { /* trailer */ fprintf(fd, "%%%%trailer\n"); fprintf(fd, "%%%%Pages: %d\n", numpages); if(eps) { fprintf(fd, "cleartomark\n"); fprintf(fd, "countdictstack\n"); fprintf(fd, "exch sub { end } repeat\n"); fprintf(fd, "restore\n"); } fprintf(fd, "%%%%EOF\n"); fclose(fd); } tclsetboolvar("draw_grid", old_grid); my_free(_ALLOC_ID_, &ps_colors); /* restore original size and zoom factor */ if(fullzoom == 1) { save_restore_zoom(0, &zi); } } int ps_draw(int what, int fullzoom, int eps) { char tmp[2*PATH_MAX+40]; static char lastdir[PATH_MAX] = ""; const char *r; static char *psfile; if(what & 1) { /* prolog */ if(!lastdir[0]) my_strncpy(lastdir, pwd_dir, S(lastdir)); if(has_x && !xctx->plotfile[0]) { /* tclvareval("tk_getSaveFile -title {Select destination file} -initialfile {", * get_cell(xctx->sch[xctx->currsch], 0) , ".pdf} -initialdir {", lastdir, "}", NULL); */ tclvareval("save_file_dialog {Select destination file} *.{ps,pdf} INITIALLOADDIR {", pwd_dir, "/", get_cell(xctx->sch[xctx->currsch], 0), eps ? ".eps}": ".pdf}", NULL); r = tclresult(); if(r[0]) { my_strncpy(xctx->plotfile, r, S(xctx->plotfile)); tclvareval("file dirname {", xctx->plotfile, "}", NULL); my_strncpy(lastdir, tclresult(), S(lastdir)); } else return 0; } } create_ps(&psfile, what, fullzoom, eps); if(what & 4) { /* trailer */ if(xctx->plotfile[0]) { my_snprintf(tmp, S(tmp), "convert_to_pdf {%s} {%s}", psfile, xctx->plotfile); } else { my_snprintf(tmp, S(tmp), "convert_to_pdf {%s} plot.pdf", psfile); } my_strncpy(xctx->plotfile,"", S(xctx->plotfile)); tcleval( tmp); Tcl_SetResult(interp,"",TCL_STATIC); } return 1; }