graphs are now rendered (as detailed png bitmaps) in svg exports

This commit is contained in:
Stefan Frederik 2022-09-15 19:39:16 +02:00
parent 87937a5add
commit f644ce58a6
6 changed files with 126 additions and 40 deletions

View File

@ -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, "<image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" %s "
"xlink:href=\"data:image/png;base64,%s\"/>\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;i<xctx->rects[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)

View File

@ -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',

View File

@ -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();
}

View File

@ -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;c<cadlayers;c++)
{
for(i=0;i<xctx->rects[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;c<cadlayers;c++)
{
for(i=0;i<xctx->lines[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;i<xctx->rects[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);
}

View File

@ -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;
}

View File

@ -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);