From f644ce58a6424dac0955409cf5cc9ceb14ca96f2 Mon Sep 17 00:00:00 2001 From: Stefan Frederik Date: Thu, 15 Sep 2022 19:39:16 +0200 Subject: [PATCH] graphs are now rendered (as detailed png bitmaps) in svg exports --- src/draw.c | 121 +++++++++++++++++++++++++++++++++++++----------- src/save.c | 1 + src/scheduler.c | 4 +- src/svgdraw.c | 29 ++++++++---- src/xinit.c | 1 + src/xschem.h | 10 +++- 6 files changed, 126 insertions(+), 40 deletions(-) diff --git a/src/draw.c b/src/draw.c index 14e67fa1..4674ec34 100644 --- a/src/draw.c +++ b/src/draw.c @@ -81,7 +81,7 @@ void print_image() #if HAS_CAIRO == 0 char cmd[PATH_MAX+100]; #endif - int save_draw_grid; + int save_draw_grid, save_draw_window; static char lastdir[PATH_MAX] = ""; const char *r; @@ -107,7 +107,10 @@ void print_image() #endif save_draw_grid = tclgetboolvar("draw_grid"); tclsetvar("draw_grid", "0"); + save_draw_window = xctx->draw_window; + xctx->draw_window=0; xctx->draw_pixmap=1; + xctx->do_copy_area=0; draw(); @@ -115,29 +118,31 @@ void print_image() * XPM and handles Xrender extensions for transparent embedded images */ { cairo_surface_t *png_sfc; -#ifdef __unix__ + #ifdef __unix__ png_sfc = cairo_xlib_surface_create(display, xctx->save_pixmap, visual, xctx->xrect[0].width, xctx->xrect[0].height); -#else + #else HWND hwnd = Tk_GetHWND(xctx->window); HDC dc = GetDC(hwnd); png_sfc = cairo_win32_surface_create(dc); -#endif + #endif if(xctx->plotfile[0]) cairo_surface_write_to_png(png_sfc, xctx->plotfile); else cairo_surface_write_to_png(png_sfc, "plot.png"); + + cairo_surface_destroy(png_sfc); } #else /* no cairo */ -#ifdef __unix__ + #ifdef __unix__ XpmWriteFileFromPixmap(display, "plot.xpm", xctx->save_pixmap,0, NULL ); /* .gz ???? */ dbg(1, "print_image(): Window image saved\n"); if(xctx->plotfile[0]) { my_snprintf(cmd, S(cmd), "convert_to_png plot.xpm {%s}", xctx->plotfile); tcleval(cmd); } else tcleval( "convert_to_png plot.xpm plot.png"); -#else + #else char *psfile = NULL; create_ps(&psfile, 7); if (xctx->plotfile[0]) { @@ -145,11 +150,13 @@ void print_image() tcleval(cmd); } else tcleval("convert_to_png {%s} plot.png", psfile); -#endif + #endif #endif my_strncpy(xctx->plotfile,"", S(xctx->plotfile)); tclsetboolvar("draw_grid", save_draw_grid); xctx->draw_pixmap=1; + xctx->draw_window=save_draw_window; + xctx->do_copy_area=1; } #if HAS_CAIRO==1 @@ -2943,10 +2950,10 @@ static cairo_status_t png_writer(void *in_closure, const unsigned char *in_data, /* rot and flip for rotated / flipped symbols - * draw: 1 draw image + * dr: 1 draw image * 0 only load image and build base64 */ -void draw_image(int draw, xRect *r, double *x1, double *y1, double *x2, double *y2, int rot, int flip) +void draw_image(int dr, xRect *r, double *x1, double *y1, double *x2, double *y2, int rot, int flip) { #if HAS_CAIRO == 1 const char *ptr; @@ -2973,7 +2980,7 @@ void draw_image(int draw, xRect *r, double *x1, double *y1, double *x2, double * xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2)) return; set_rect_extraptr(1, r); /* create r->extraptr pointing to a xEmb_image struct */ emb_ptr = r->extraptr; - if(draw) { + if(dr) { cairo_save(xctx->cairo_ctx); cairo_save(xctx->cairo_save_ctx); } @@ -3074,7 +3081,7 @@ void draw_image(int draw, xRect *r, double *x1, double *y1, double *x2, double * scalex = rw/w * xctx->mooz; scaley = rh/h * xctx->mooz; } - if(draw && xctx->draw_pixmap) { + if(dr && xctx->draw_pixmap) { cairo_translate(xctx->cairo_save_ctx, x, y); if(flip && (rot == 0 || rot == 2)) cairo_scale(xctx->cairo_save_ctx, -scalex, scaley); else if(flip && (rot == 1 || rot == 3)) cairo_scale(xctx->cairo_save_ctx, scalex, -scaley); @@ -3087,7 +3094,7 @@ void draw_image(int draw, xRect *r, double *x1, double *y1, double *x2, double * cairo_clip(xctx->cairo_save_ctx); cairo_paint_with_alpha(xctx->cairo_save_ctx, alpha); } - if(draw && xctx->draw_window) { + if(dr && xctx->draw_window) { cairo_translate(xctx->cairo_ctx, x, y); if(flip && (rot == 0 || rot == 2)) cairo_scale(xctx->cairo_ctx, -scalex, scaley); else if(flip && (rot == 1 || rot == 3)) cairo_scale(xctx->cairo_ctx, scalex, -scaley); @@ -3100,7 +3107,7 @@ void draw_image(int draw, xRect *r, double *x1, double *y1, double *x2, double * cairo_clip(xctx->cairo_ctx); cairo_paint_with_alpha(xctx->cairo_ctx, alpha); } - if(draw) { + if(dr) { cairo_restore(xctx->cairo_ctx); cairo_restore(xctx->cairo_save_ctx); } @@ -3122,6 +3129,64 @@ static void draw_images_all(void) #endif } +void svg_embedded_graph(FILE *fd, xRect *r, double rx1, double ry1, double rx2, double ry2) +{ + char *ptr = NULL; + double x1, y1, x2, y2, w, h; + int rw, rh; + char transform[150]; + png_to_byte_closure_t closure; + cairo_surface_t *png_sfc; + int save_draw_window, save_draw_grid; + size_t olength; + + rw = (int) fabs(rx2 -rx1); + rh = (int) fabs(ry2 - ry1); + save_restore_zoom(1); + set_viewport_size(rw, rh, 0.8); + zoom_box(rx1, ry1, rx2, ry2, 1.0); + resetwin(1, 1, 1, rw, rh); + save_draw_grid = tclgetboolvar("draw_grid"); + tclsetvar("draw_grid", "0"); + save_draw_window = xctx->draw_window; + xctx->draw_window=0; + xctx->draw_pixmap=1; + xctx->do_copy_area=0; + draw(); + png_sfc = cairo_xlib_surface_create(display, xctx->save_pixmap, visual, + xctx->xrect[0].width, xctx->xrect[0].height); + closure.buffer = NULL; + closure.size = 0; + closure.pos = 0; + cairo_surface_write_to_png_stream(png_sfc, png_writer, &closure); + ptr = base64_encode(closure.buffer, closure.pos, &olength, 1); + my_free(1547, &closure.buffer); + cairo_surface_destroy(png_sfc); + xctx->draw_pixmap=1; + xctx->draw_window=save_draw_window; + xctx->do_copy_area=1; + tclsetboolvar("draw_grid", save_draw_grid); + save_restore_zoom(0); + resetwin(1, 1, 1, 0, 0); + change_linewidth(-1.); + + x1=X_TO_SVG(rx1); + y1=Y_TO_SVG(ry1); + x2=X_TO_SVG(rx2); + y2=Y_TO_SVG(ry2); + h = fabs(y2 - y1); + w = fabs(x2 - x1); + + my_snprintf(transform, S(transform), "transform=\"translate(%g,%g)\"", x1, y1); + if(ptr[0]) { + fprintf(fd, "\n", + 0.0, 0.0, w, h, transform, ptr); + } + my_free(1546, &ptr); +} + + void draw(void) { /* inst_ptr and wire hash iterator 20171224 */ @@ -3133,15 +3198,15 @@ void draw(void) xSymbol *symptr; int textlayer; int show_hidden_texts = tclgetboolvar("show_hidden_texts"); - + #if HAS_CAIRO==1 const char *textfont; -#ifndef __unix__ + #ifndef __unix__ clear_cairo_surface(xctx->cairo_save_ctx, xctx->xrect[0].x, xctx->xrect[0].y, xctx->xrect[0].width, xctx->xrect[0].height); clear_cairo_surface(xctx->cairo_ctx, xctx->xrect[0].x, xctx->xrect[0].y, xctx->xrect[0].width, xctx->xrect[0].height); -#endif + #endif #endif if(xctx->no_draw) return; rebuild_selected_array(); @@ -3179,10 +3244,11 @@ void draw(void) if(xctx->enable_layer[c]) for(i=0;irects[c];i++) { xRect *r = &xctx->rect[c][i]; #if HAS_CAIRO==1 - if(c != GRIDLAYER || !(r->flags & (1 + 1024)) ) { + if(c != GRIDLAYER || !(r->flags & (1 + 1024))) #else - if(c != GRIDLAYER || !(r->flags & 1) ) { + if(c != GRIDLAYER || !(r->flags & 1) ) #endif + { drawrect(c, ADD, r->x1, r->y1, r->x2, r->y2, r->dash); filledrect(c, ADD, r->x1, r->y1, r->x2, r->y2); } @@ -3294,14 +3360,16 @@ void draw(void) } } /* !xctx->only_probes, 20110112 */ draw_hilight_net(xctx->draw_window); - if(!xctx->draw_window) { - MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gctiled, xctx->xrect[0].x, xctx->xrect[0].y, - xctx->xrect[0].width, xctx->xrect[0].height, xctx->xrect[0].x, xctx->xrect[0].y); + if(xctx->do_copy_area) { /* this is zero only when doing png hardcopy to avoid video flickering */ + if(!xctx->draw_window) { + MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gctiled, xctx->xrect[0].x, xctx->xrect[0].y, + xctx->xrect[0].width, xctx->xrect[0].height, xctx->xrect[0].x, xctx->xrect[0].y); + } + #if !defined(__unix__) && defined(HAS_CAIRO) + else + my_cairo_fill(xctx->cairo_sfc, xctx->xrect[0].x, xctx->xrect[0].y, xctx->xrect[0].width, xctx->xrect[0].height); + #endif } -#if !defined(__unix__) && defined(HAS_CAIRO) - else - my_cairo_fill(xctx->cairo_sfc, xctx->xrect[0].x, xctx->xrect[0].y, xctx->xrect[0].width, xctx->xrect[0].height); -#endif draw_selection(xctx->gc[SELLAYER], 0); /* 20181009 moved outside of cadlayers loop */ } /* if(has_x) */ } @@ -3319,7 +3387,8 @@ int XSetTile(Display* display, GC gc, Pixmap s_pixmap) } #endif -void MyXCopyArea(Display* display, Drawable src, Drawable dest, GC gc, int src_x, int src_y, unsigned int width, unsigned int height, int dest_x, int dest_y) +void MyXCopyArea(Display* display, Drawable src, Drawable dest, GC gc, int src_x, int src_y, + unsigned int width, unsigned int height, int dest_x, int dest_y) { XCopyArea(display, src, dest, gc, src_x, src_y, width, height, dest_x, dest_y); #if !defined(__unix__) && defined(HAS_CAIRO) diff --git a/src/save.c b/src/save.c index b735bb5f..c2e17948 100644 --- a/src/save.c +++ b/src/save.c @@ -115,6 +115,7 @@ int filter_data(const char* din, const size_t ilen, #endif /* Caller should free returned buffer */ +/* set brk to 1 if you want newlines added */ char *base64_encode(const unsigned char *data, const size_t input_length, size_t *output_length, int brk) { static const char b64_enc[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', diff --git a/src/scheduler.c b/src/scheduler.c index 3078e224..dc964b6d 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -1998,7 +1998,6 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg save_restore_zoom(0); resetwin(1, 1, 1, 0, 0); change_linewidth(-1.); - draw(); } else if( argc == 10) { w = atoi(argv[4]); h = atoi(argv[5]); @@ -2007,14 +2006,13 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg x2 = atof(argv[8]); y2 = atof(argv[9]); save_restore_zoom(1); - set_viewport_size(w, h, 0.8); + set_viewport_size(w, h, 0.8); zoom_box(x1, y1, x2, y2, 1.0); resetwin(1, 1, 1, w, h); print_image(); save_restore_zoom(0); resetwin(1, 1, 1, 0, 0); change_linewidth(-1.); - draw(); } else { print_image(); } diff --git a/src/svgdraw.c b/src/svgdraw.c index 3a313671..11e3d991 100644 --- a/src/svgdraw.c +++ b/src/svgdraw.c @@ -21,8 +21,6 @@ */ #include "xschem.h" -#define X_TO_SVG(x) ( (x+xctx->xorigin)* xctx->mooz ) -#define Y_TO_SVG(y) ( (y+xctx->yorigin)* xctx->mooz ) static FILE *fd; @@ -391,7 +389,6 @@ static void svg_drawgrid() } } - static void svg_embedded_image(xRect *r, double rx1, double ry1, double rx2, double ry2, int rot, int flip) { const char *ptr; @@ -431,7 +428,6 @@ static void svg_embedded_image(xRect *r, double rx1, double ry1, double rx2, dou } } - static void svg_draw_symbol(int c, int n,int layer,short tmp_flip, short rot, double xoffset, double yoffset) /* draws current layer only, should be called within */ @@ -467,10 +463,11 @@ static void svg_draw_symbol(int c, int n,int layer,short tmp_flip, short rot, xctx->inst[n].flags|=1; return; } - else xctx->inst[n].flags&=~1; + else { + xctx->inst[n].flags&=~1; + } } else if(xctx->inst[n].flags&1) { - dbg(1, "draw_symbol(): skipping inst %d\n", n); return; } flip = xctx->inst[n].flip; @@ -521,7 +518,6 @@ static void svg_draw_symbol(int c, int n,int layer,short tmp_flip, short rot, 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); - if(layer == GRIDLAYER && rect->flags & 1024) { double xx1 = x0 + x1; double yy1 = y0 + y1; @@ -795,6 +791,19 @@ void svg_draw(void) xctx->text[i].x0,xctx->text[i].y0, xctx->text[i].xscale, xctx->text[i].yscale); } + + + /* do first graphs as these require draw() which clobbers xctx->inst[n].flags bit 0 */ + for(c=0;crects[c];i++) + { + if(c == GRIDLAYER && (xctx->rect[c][i].flags & 1) ) { /* graph */ + xRect *r = &xctx->rect[c][i]; + svg_embedded_graph(fd, r, r->x1, r->y1, r->x2, r->y2); + } + } + } for(c=0;clines[c];i++) @@ -802,10 +811,12 @@ void svg_draw(void) 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) ) { + if(c == GRIDLAYER && (xctx->rect[c][i].flags & 1) ) { /* graph */ + /* do nothing, done above */ + } else if(c == GRIDLAYER && (xctx->rect[c][i].flags & 1024) ) { /* image */ xRect *r = &xctx->rect[c][i]; svg_embedded_image(r, r->x1, r->y1, r->x2, r->y2, 0, 0); - } else if(c != GRIDLAYER || !(xctx->rect[c][i].flags & 1) ) { + } else { svg_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); } diff --git a/src/xinit.c b/src/xinit.c index f7b1ff57..37bb976f 100644 --- a/src/xinit.c +++ b/src/xinit.c @@ -633,6 +633,7 @@ static void alloc_xschem_data(const char *top_path, const char *win_path) xctx->x_strcmp = strcmp; xctx->fill_pattern = 1; xctx->draw_window = 0; + xctx->do_copy_area = 1; xctx->time_last_modify = 0; } diff --git a/src/xschem.h b/src/xschem.h index df7445a4..6a630f8f 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -327,6 +327,10 @@ extern char win_temp_dir[PATH_MAX]; #define X_TO_XSCHEM(x) ( (x) * xctx->zoom - xctx->xorigin ) #define Y_TO_XSCHEM(y) ( (y) * xctx->zoom - xctx->yorigin ) +#define X_TO_SVG(x) ( (x+xctx->xorigin)* xctx->mooz ) +#define Y_TO_SVG(y) ( (y+xctx->yorigin)* xctx->mooz ) + + /* coordinate transformations graph to xschem */ #define W_X(x) (gr->cx * (x) + gr->dx) #define W_Y(y) (gr->cy * (y) + gr->dy) @@ -924,7 +928,6 @@ typedef struct { int menu_removed; /* fullscreen previous setting */ double save_lw; /* used to save linewidth when selecting 'only_probes' view */ int no_draw; - int draw_pixmap; /* pixmap used as 2nd buffer */ int netlist_count; /* netlist counter incremented at any cell being netlisted */ int hide_symbols; int netlist_type; @@ -941,7 +944,9 @@ typedef struct { char *current_win_path; /* .drw or .x1.drw, .... ; always .drw in tabbed interface */ int *fill_type; /* for every layer: 0: no fill, 1, solid fill, 2: stipple fill */ int fill_pattern; + int draw_pixmap; /* pixmap used as 2nd buffer */ int draw_window; + int do_copy_area; time_t time_last_modify; int undo_type; /* 0: on disk, 1: in memory */ void (*push_undo)(void); @@ -1021,7 +1026,7 @@ extern int cli_opt_load_initfile; extern Xschem_ctx *xctx; /* FUNCTIONS */ -extern void draw_image(int draw, xRect *r, double *x1, double *y1, double *x2, double *y2, int rot, int flip); +extern void draw_image(int dr, xRect *r, double *x1, double *y1, double *x2, double *y2, int rot, int flip); extern int filter_data(const char *din, const size_t ilen, char **dout, size_t *olen, const char *cmd); extern int embed_rawfile(const char *rawfile); @@ -1073,6 +1078,7 @@ extern int process_options(int argc, char **argv); extern void calc_drawing_bbox(xRect *boundbox, int selected); extern int ps_draw(int what); extern void svg_draw(void); +extern void svg_embedded_graph(FILE *fd, xRect *r, double rx1, double ry1, double rx2, double ry2); extern void set_viewport_size(int w, int h, double lw); extern void print_image(); extern const char *get_trailing_path(const char *str, int no_of_dir, int skip_ext);