cleanups in draw_image(), added command `xschem image` for various operations on images
This commit is contained in:
parent
6416df9733
commit
d5f7c5c88c
|
|
@ -543,7 +543,6 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li><kbd> abort_operation</kbd></li><pre>
|
||||
|
|
@ -862,6 +861,13 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
|
|||
'inst' can be an instance name or number </pre>
|
||||
<li><kbd> hilight_netname net</kbd></li><pre>
|
||||
Highlight net name 'net' </pre>
|
||||
<li><kbd> image [invert|white_transp|black_transp|transp_white|transp_black|write_back]</kbd></li><pre>
|
||||
Apply required changes to selected images
|
||||
invert: invert colors
|
||||
white_transp: transform white to transparent color (alpha=0) after invert.
|
||||
black_transp: transform black to transparent color (alpha=0) after invert.
|
||||
transp_white: transform white to transparent color (alpha=0) after invert.
|
||||
transp_black: transform black to transparent color (alpha=0) after invert.</pre>
|
||||
<li><kbd> instance sym_name x y rot flip [prop] [n]</kbd></li><pre>
|
||||
Place a new instance of symbol 'sym_name' at position x,y,
|
||||
rotation and flip set to 'rot', 'flip'
|
||||
|
|
@ -1592,6 +1598,8 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
214
src/draw.c
214
src/draw.c
|
|
@ -3880,15 +3880,34 @@ cairo_status_t png_writer(void *in_closure, const unsigned char *in_data, unsign
|
|||
#endif
|
||||
|
||||
#if HAS_CAIRO==1
|
||||
void inspect_image(cairo_surface_t **surface)
|
||||
/* what:
|
||||
* 1: invert colors
|
||||
* 2: set white to transparent
|
||||
* 4: set black to transparent
|
||||
* 8: set transparent to white
|
||||
* 16: set transparent to black
|
||||
* 256: write back into `image_data` attribute
|
||||
*/
|
||||
int edit_image(int what, xRect *r)
|
||||
{
|
||||
cairo_t *ct;
|
||||
unsigned char *data;
|
||||
cairo_surface_t *newsfc;
|
||||
cairo_format_t format;
|
||||
int size_x, size_y, stride, x, y;
|
||||
int jpg, size_x, size_y, stride, x, y;
|
||||
xEmb_image *emb_ptr = r->extraptr;
|
||||
cairo_surface_t **surface = &emb_ptr->image;
|
||||
const char *attr = get_tok_value(r->prop_ptr, "image_data", 0);
|
||||
|
||||
cairo_surface_flush(*surface);
|
||||
|
||||
if(attr[0]) {
|
||||
if(!strncmp(attr, "/9j/", 4)) jpg = 1;
|
||||
else if(!strncmp(attr, "iVBOR", 5)) jpg = 0;
|
||||
else jpg = -1; /* some invalid data */
|
||||
} else {
|
||||
jpg = -1;
|
||||
}
|
||||
if(jpg == -1) return 0;
|
||||
format = cairo_image_surface_get_format(*surface);
|
||||
size_x = cairo_image_surface_get_width(*surface);
|
||||
size_y = cairo_image_surface_get_height(*surface);
|
||||
|
|
@ -3908,43 +3927,121 @@ void inspect_image(cairo_surface_t **surface)
|
|||
for(x = 0; x < size_x; x++) {
|
||||
for(y = 0; y < size_y; y++) {
|
||||
unsigned char *ptr = data + y * stride + x * 4;
|
||||
unsigned int a = ptr[3];
|
||||
unsigned int r = ptr[2];
|
||||
unsigned int g = ptr[1];
|
||||
unsigned int b = ptr[0];
|
||||
unsigned char a = ptr[3];
|
||||
unsigned char r = ptr[2];
|
||||
unsigned char g = ptr[1];
|
||||
unsigned char b = ptr[0];
|
||||
|
||||
if(0 && x == 100) {
|
||||
dbg(0, "R=%d G=%d B=%d A=%d\n", r, g, b, a);
|
||||
/* invert colors */
|
||||
if(what & 1) {
|
||||
r = a - r;
|
||||
g = a - g;
|
||||
b = a - b;
|
||||
}
|
||||
|
||||
#if 1 /* premultiplied data invert*/
|
||||
r = a - r;
|
||||
g = a - g;
|
||||
b = a - b;
|
||||
#endif
|
||||
/* set white to transparent */
|
||||
if(what & 2) {
|
||||
if(r > 242 && g > 242 && b >242) {r = g = b = a = 0;}
|
||||
}
|
||||
|
||||
#if 1 /* set (almost) white to transparent */
|
||||
if(r > 245 && g > 245 && b >245) {r = g = b = a = 0;}
|
||||
#endif
|
||||
/* set black to transparent */
|
||||
if(what & 4) {
|
||||
if(r < 13 && g < 13 && b < 13) {r = g = b = a = 0;}
|
||||
}
|
||||
|
||||
#if 0 /* set (almost) black to transparent */
|
||||
if(r < 10 && g < 10 && b < 10) {r = g = b = a = 0;}
|
||||
#endif
|
||||
/* set transparent to white */
|
||||
if(what & 8) {
|
||||
if(a == 0) {r = g = b = a = 0xff;}
|
||||
}
|
||||
|
||||
/* set transparent to black */
|
||||
if(what & 16) {
|
||||
if(a == 0) {r = g = b = 0x00; a = 0xff;}
|
||||
}
|
||||
|
||||
/* write result back */
|
||||
#if 1
|
||||
ptr[3] = (unsigned char) a;
|
||||
ptr[2] = (unsigned char) r;
|
||||
ptr[1] = (unsigned char) g;
|
||||
ptr[0] = (unsigned char) b;
|
||||
#endif
|
||||
ptr[3] = a;
|
||||
ptr[2] = r;
|
||||
ptr[1] = g;
|
||||
ptr[0] = b;
|
||||
}
|
||||
}
|
||||
cairo_surface_mark_dirty(*surface);
|
||||
|
||||
|
||||
/* write back modified image to image_data attribute */
|
||||
if(what & 256) {
|
||||
char *encoded_data = NULL;
|
||||
size_t olength;
|
||||
png_to_byte_closure_t closure;
|
||||
if(jpg == 0) {
|
||||
/* write PNG to in-memory buffer */
|
||||
closure.buffer = NULL;
|
||||
closure.size = 0;
|
||||
closure.pos = 0;
|
||||
cairo_surface_write_to_png_stream(emb_ptr->image, png_writer, &closure);
|
||||
closure.size = closure.pos;
|
||||
} else if(jpg == 1) {
|
||||
/* write JPG to in-memory buffer */
|
||||
#if defined(HAS_LIBJPEG)
|
||||
int jpeg_quality;
|
||||
const char *ptr;
|
||||
ptr = get_tok_value(r->prop_ptr, "jpeg_quality", 0);
|
||||
jpeg_quality = 75;
|
||||
if(ptr[0]) jpeg_quality = atoi(ptr);
|
||||
closure.buffer = NULL;
|
||||
closure.size = 0;
|
||||
closure.pos = 0;
|
||||
cairo_image_surface_write_to_jpeg_mem(emb_ptr->image, &closure.buffer, &closure.pos, jpeg_quality);
|
||||
closure.size = closure.pos;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* put base64 encoded data to rect image_data attribute */
|
||||
encoded_data = base64_encode((unsigned char *)closure.buffer, closure.size, &olength, 0);
|
||||
my_strdup2(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "image_data", encoded_data));
|
||||
my_free(_ALLOC_ID_, &closure.buffer);
|
||||
my_free(_ALLOC_ID_, &encoded_data);
|
||||
}
|
||||
dbg(1, "size_x = %d, size_y = %d, stride = %d\n", size_x, size_y, stride);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static cairo_surface_t *get_surface_from_b64data(const char *attr)
|
||||
{
|
||||
int jpg = -1;
|
||||
png_to_byte_closure_t closure;
|
||||
size_t data_size;
|
||||
cairo_surface_t *surface = NULL;
|
||||
|
||||
if(!strncmp(attr, "/9j/", 4)) jpg = 1;
|
||||
else if(!strncmp(attr, "iVBOR", 5)) jpg = 0;
|
||||
else jpg = -1; /* some invalid data */
|
||||
closure.buffer = base64_decode(attr, strlen(attr), &data_size);
|
||||
closure.pos = 0;
|
||||
closure.size = data_size; /* should not be necessary */
|
||||
if(closure.buffer == NULL) {
|
||||
dbg(0, "draw_image(): image creation failed\n");
|
||||
return NULL;
|
||||
}
|
||||
if(jpg == 0) {
|
||||
surface = cairo_image_surface_create_from_png_stream(png_reader, &closure);
|
||||
} else if(jpg == 1) {
|
||||
#if defined(HAS_LIBJPEG)
|
||||
surface = cairo_image_surface_create_from_jpeg_mem(closure.buffer, closure.size);
|
||||
#endif
|
||||
}
|
||||
if(!surface || cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
|
||||
if(jpg != 1)
|
||||
dbg(0, "draw_image(): failure creating image surface from \"image_data\" attribute\n");
|
||||
if(surface) cairo_surface_destroy(surface);
|
||||
surface = NULL;
|
||||
}
|
||||
my_free(_ALLOC_ID_, &closure.buffer);
|
||||
return surface;
|
||||
}
|
||||
|
||||
/* rot and flip for rotated / flipped symbols
|
||||
* dr: 1 draw image
|
||||
* 0 only load image and build base64
|
||||
|
|
@ -3953,9 +4050,6 @@ int draw_image(int dr, xRect *r, double *x1, double *y1, double *x2, double *y2,
|
|||
{
|
||||
#if HAS_CAIRO==1
|
||||
#if defined(HAS_LIBJPEG)
|
||||
#ifdef INSPECT_IMAGE
|
||||
int jpeg_quality=75;
|
||||
#endif
|
||||
#endif
|
||||
const char *ptr;
|
||||
int w,h;
|
||||
|
|
@ -3986,46 +4080,17 @@ int draw_image(int dr, xRect *r, double *x1, double *y1, double *x2, double *y2,
|
|||
cairo_save(xctx->cairo_save_ctx);
|
||||
}
|
||||
my_strncpy(filename, get_tok_value(r->prop_ptr, "image", 0), S(filename));
|
||||
#if defined(HAS_LIBJPEG)
|
||||
#ifdef INSPECT_IMAGE
|
||||
ptr = get_tok_value(r->prop_ptr, "quality", 0);
|
||||
jpeg_quality = 75;
|
||||
if(ptr[0]) jpeg_quality = atoi(ptr);
|
||||
#endif
|
||||
#endif
|
||||
/******* read image from in-memory buffer ... *******/
|
||||
if(emb_ptr && emb_ptr->image) {
|
||||
/* nothing to do, image is already created */
|
||||
/******* ... or read PNG from image_data attribute *******/
|
||||
} else if( (attr = get_tok_value(r->prop_ptr, "image_data", 0))[0] ) {
|
||||
png_to_byte_closure_t closure;
|
||||
size_t data_size;
|
||||
|
||||
if(!strncmp(attr, "/9j/", 4)) jpg = 1;
|
||||
else if(!strncmp(attr, "iVBOR", 5)) jpg = 0;
|
||||
else jpg = -1; /* some invalid data */
|
||||
closure.buffer = base64_decode(attr, strlen(attr), &data_size);
|
||||
closure.pos = 0;
|
||||
closure.size = data_size; /* should not be necessary */
|
||||
if(closure.buffer == NULL) {
|
||||
dbg(0, "draw_image(): image creation failed\n");
|
||||
return 0;
|
||||
}
|
||||
if(jpg == 0) {
|
||||
emb_ptr->image = cairo_image_surface_create_from_png_stream(png_reader, &closure);
|
||||
} else if(jpg == 1) {
|
||||
#if defined(HAS_LIBJPEG)
|
||||
emb_ptr->image = cairo_image_surface_create_from_jpeg_mem(closure.buffer, closure.size);
|
||||
#endif
|
||||
}
|
||||
if(!emb_ptr->image || cairo_surface_status(emb_ptr->image) != CAIRO_STATUS_SUCCESS) {
|
||||
} else if( (attr = get_tok_value(r->prop_ptr, "image_data", 0))[0] && strlen(attr) > 5) {
|
||||
emb_ptr->image = get_surface_from_b64data(attr);
|
||||
if(!emb_ptr->image) {
|
||||
if(jpg != 1)
|
||||
dbg(0, "draw_image(): failure creating image surface from \"image_data\" attribute\n");
|
||||
my_free(_ALLOC_ID_, &closure.buffer);
|
||||
return 0;
|
||||
}
|
||||
my_free(_ALLOC_ID_, &closure.buffer);
|
||||
dbg(1, "draw_image(): length2 = %d\n", closure.pos);
|
||||
/******* ... or read PNG from file (image attribute) *******/
|
||||
} else if(filename[0] && !stat(filename, &buf)) {
|
||||
png_to_byte_closure_t closure;
|
||||
|
|
@ -4090,37 +4155,12 @@ int draw_image(int dr, xRect *r, double *x1, double *y1, double *x2, double *y2,
|
|||
my_free(_ALLOC_ID_, &closure.buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this code can be used to transfer an image surface back to a memory buffer
|
||||
* closure.buffer will hold the data, closure.pos wil be set to the size */
|
||||
#ifdef INSPECT_IMAGE
|
||||
inspect_image(&emb_ptr->image);
|
||||
|
||||
if(jpg == 0) {
|
||||
/* write PNG to in-memory buffer */
|
||||
my_free(_ALLOC_ID_, &closure.buffer);
|
||||
closure.size = 0;
|
||||
closure.pos = 0;
|
||||
cairo_surface_write_to_png_stream(emb_ptr->image, png_writer, &closure);
|
||||
closure.size = closure.pos;
|
||||
} else if(jpg == 1) {
|
||||
/* write JPG to in-memory buffer */
|
||||
#if defined(HAS_LIBJPEG)
|
||||
my_free(_ALLOC_ID_, &closure.buffer);
|
||||
closure.size = 0;
|
||||
closure.pos = 0;
|
||||
cairo_image_surface_write_to_jpeg_mem(emb_ptr->image, &closure.buffer, &closure.pos, jpeg_quality);
|
||||
closure.size = closure.pos;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* put base64 encoded data to rect image_data attribute */
|
||||
encoded_data = base64_encode((unsigned char *)closure.buffer, closure.size, &olength, 0);
|
||||
my_strdup2(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "image_data", encoded_data));
|
||||
my_free(_ALLOC_ID_, &encoded_data);
|
||||
my_free(_ALLOC_ID_, &closure.buffer);
|
||||
} else {
|
||||
} else { /* no emb_ptr->image and no "image_data" attribute */
|
||||
return 0;
|
||||
}
|
||||
ptr = get_tok_value(r->prop_ptr, "alpha", 0);
|
||||
|
|
|
|||
|
|
@ -2032,6 +2032,53 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
|
|||
else { cmd_found = 0;}
|
||||
break;
|
||||
case 'i': /*----------------------------------------------*/
|
||||
/* image [invert|white_transp|black_transp|transp_white|transp_black|write_back]
|
||||
* Apply required changes to selected images
|
||||
* invert: invert colors
|
||||
* white_transp: transform white to transparent color (alpha=0) after invert.
|
||||
* black_transp: transform black to transparent color (alpha=0) after invert.
|
||||
* transp_white: transform white to transparent color (alpha=0) after invert.
|
||||
* transp_black: transform black to transparent color (alpha=0) after invert.
|
||||
*/
|
||||
if(!strcmp(argv[1], "image"))
|
||||
{
|
||||
int n, i, c;
|
||||
int what = 0;
|
||||
xRect *r;
|
||||
if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
|
||||
if(argc < 3) {
|
||||
Tcl_SetResult(interp, "Missing arguments", TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if(!strcmp(argv[2], "help")) {
|
||||
Tcl_SetResult(interp,
|
||||
"xschem image [invert|white_transp|black_transp|transp_white|transp_black|write_back]",
|
||||
TCL_STATIC);
|
||||
return TCL_OK;
|
||||
}
|
||||
for(i = 2; i < argc; i++) {
|
||||
if(!strcmp(argv[i], "invert")) what |= 1;
|
||||
if(!strcmp(argv[i], "white_transp")) what |= 2;
|
||||
if(!strcmp(argv[i], "black_transp")) what |= 4;
|
||||
if(!strcmp(argv[i], "transp_white")) what |= 8;
|
||||
if(!strcmp(argv[i], "transp_black")) what |= 16;
|
||||
if(!strcmp(argv[i], "write_back")) what |= 256;
|
||||
}
|
||||
rebuild_selected_array();
|
||||
for(n=0; n < xctx->lastsel; ++n) {
|
||||
if(xctx->sel_array[n].type == xRECT) {
|
||||
i = xctx->sel_array[n].n;
|
||||
c = xctx->sel_array[n].col;
|
||||
r = &xctx->rect[c][i];
|
||||
if(c == GRIDLAYER && r->flags & 1024) {
|
||||
edit_image(what, &xctx->rect[c][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
draw();
|
||||
Tcl_ResetResult(interp);
|
||||
}
|
||||
|
||||
/* instance sym_name x y rot flip [prop] [n]
|
||||
* Place a new instance of symbol 'sym_name' at position x,y,
|
||||
* rotation and flip set to 'rot', 'flip'
|
||||
|
|
@ -2040,7 +2087,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
|
|||
* if 'n' is given it must be 0 on first call
|
||||
* and non zero on following calls
|
||||
* It is used only for efficiency reasons if placing multiple instances */
|
||||
if(!strcmp(argv[1], "instance"))
|
||||
else if(!strcmp(argv[1], "instance"))
|
||||
{
|
||||
if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
|
||||
if(argc==7) {
|
||||
|
|
@ -5330,13 +5377,11 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
|
|||
del_object_table();
|
||||
Tcl_ResetResult(interp);
|
||||
}
|
||||
/* test 2 inst text_n */
|
||||
else if(argc > 2 && atoi(argv[2]) == 2) {
|
||||
dbg(0, "graph_flags=%d\n", xctx->graph_flags);
|
||||
Tcl_ResetResult(interp);
|
||||
}
|
||||
else if(argc > 2 && atoi(argv[2]) == 3) {
|
||||
|
||||
else if(argc > 3 && atoi(argv[2]) == 3) {
|
||||
Tcl_ResetResult(interp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1227,6 +1227,7 @@ extern int cli_opt_load_initfile;
|
|||
extern Xschem_ctx *xctx;
|
||||
|
||||
/* FUNCTIONS */
|
||||
extern int edit_image(int what, xRect *r);
|
||||
extern int 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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue