diff --git a/doc/xschem_man/developer_info.html b/doc/xschem_man/developer_info.html index 30cbbf37..98023453 100644 --- a/doc/xschem_man/developer_info.html +++ b/doc/xschem_man/developer_info.html @@ -543,7 +543,6 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns" -
@@ -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
Highlight net name 'net'
+ + 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.
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"
+
+
diff --git a/src/draw.c b/src/draw.c
index 2f01c267..e52a290a 100644
--- a/src/draw.c
+++ b/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);
diff --git a/src/scheduler.c b/src/scheduler.c
index 0a4dec67..7d1c3628 100644
--- a/src/scheduler.c
+++ b/src/scheduler.c
@@ -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);
}
}
diff --git a/src/xschem.h b/src/xschem.h
index 5c568284..76ce8f0d 100644
--- a/src/xschem.h
+++ b/src/xschem.h
@@ -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);