diff --git a/doc/xschem_man/developer_info.html b/doc/xschem_man/developer_info.html
index 705444af..a9976ff0 100644
--- a/doc/xschem_man/developer_info.html
+++ b/doc/xschem_man/developer_info.html
@@ -553,7 +553,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
add_graph
Start a GUI placement of a graph object
add_png
- Ask user to choose a png file and start a GUI placement of the image
+ Ask user to choose a png/jpg file and start a GUI placement of the image
align
Align currently selected objects to current snap setting
annotate_op [raw_file] [level]
@@ -720,11 +720,13 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
Get C variable/constant 'var'
- backlayer number of background layer
+ - bbox bounding box schematic
- bbox_hilighted bounding box of highlinhted objects
- bbox_selected bounding box of selected objects
- cadlayers number of layers
- case_insensitive case_insensitive symbol matching
- color_ps color postscript flag
+ - constr_mv color postscript flag
- current_dirname directory name of current design
- current_name name of current design (no library path)
- current_win_path path of current tab/window (.drw, .x1.drw, ...)
@@ -1341,7 +1343,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
- cadgrid set cad grid (default: 20)
- cadsnap set mouse snap (default: 10)
- color_ps set color psoscript (1 or 0)
- - constrained_move set constrained move (1=horiz, 2=vert, 0=none)
+ - constr_mv set constrained move (1=horiz, 2=vert, 0=none)
- cursor1_x set graph cursor1 position
- cursor2_x set graph cursor2 position
- draw_window set drawing to window (1 or 0)
diff --git a/src/actions.c b/src/actions.c
index 0f27163f..1ff48a57 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -933,7 +933,9 @@ int set_rect_extraptr(int what, xRect *drptr)
if(drptr->flags & 1024) { /* embedded image */
if(drptr->extraptr) {
xEmb_image *d = drptr->extraptr;
- if(d->image) cairo_surface_destroy(d->image);
+ if(d->image) {
+ cairo_surface_destroy(d->image);
+ }
my_free(_ALLOC_ID_, &drptr->extraptr);
}
}
diff --git a/src/cairo_jpg.c b/src/cairo_jpg.c
index 81e0ad46..a4a49d82 100644
--- a/src/cairo_jpg.c
+++ b/src/cairo_jpg.c
@@ -375,8 +375,10 @@ cairo_surface_t *cairo_image_surface_create_from_jpeg_mem(void *data, size_t len
(void) jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
+ /* Stefan: commented out since this assumes static lifetime of 'data' buffer
+ * that I don't assume. I consider this a bug */
/* set jpeg mime data */
- cairo_surface_set_mime_data(sfc, CAIRO_MIME_TYPE_JPEG, data, len, free, data);
+ /* cairo_surface_set_mime_data(sfc, CAIRO_MIME_TYPE_JPEG, data, len, free, data);*/
return sfc;
}
diff --git a/src/callback.c b/src/callback.c
index 8a496c25..09b07449 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -3529,7 +3529,7 @@ int rstate; /* (reduced state, without ShiftMask) */
move_objects(START,0,0,0);
}
else if(state == ShiftMask) copy_objects(START);
- else move_objects(START,0,0,0);
+ else if( !(state & ControlMask) ) move_objects(START,0,0,0);
}
#ifndef __unix__
diff --git a/src/draw.c b/src/draw.c
index 03d721e8..905fcbfa 100644
--- a/src/draw.c
+++ b/src/draw.c
@@ -3865,7 +3865,7 @@ cairo_status_t png_reader(void *in_closure, unsigned char *out_data, unsigned in
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t png_writer(void *in_closure, const unsigned char *in_data, unsigned int length)
+cairo_status_t png_writer(void *in_closure, const unsigned char *in_data, unsigned int length)
{
png_to_byte_closure_t *closure = (png_to_byte_closure_t *) in_closure;
if(!in_data) return CAIRO_STATUS_WRITE_ERROR;
@@ -3898,6 +3898,7 @@ void draw_image(int dr, xRect *r, double *x1, double *y1, double *x2, double *y2
double xx1, yy1, scalex, scaley;
png_to_byte_closure_t closure;
xEmb_image *emb_ptr;
+ int jpg = 0; /* set to 1 if image_data attribute contains base64 encoded JPEG */
if(xctx->only_probes) return;
xx1 = *x1; yy1 = *y1; /* image anchor point */
@@ -3934,11 +3935,24 @@ void draw_image(int dr, xRect *r, double *x1, double *y1, double *x2, double *y2
filter_data(filterdata, filtersize, (char **)&closure.buffer, &data_size, filter);
my_free(_ALLOC_ID_, &filterdata);
} else {
+ if(!strncmp(attr, "/9j/4", 5)) 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 */
- emb_ptr->image = cairo_image_surface_create_from_png_stream(png_reader, &closure);
+ if(jpg == 0) {
+ emb_ptr->image = cairo_image_surface_create_from_png_stream(png_reader, &closure);
+ } else {
+ emb_ptr->image = cairo_image_surface_create_from_jpeg_mem(closure.buffer, closure.size);
+ }
+ if(cairo_surface_status(emb_ptr->image) != CAIRO_STATUS_SUCCESS) {
+ my_free(_ALLOC_ID_, &filter);
+ my_free(_ALLOC_ID_, &closure.buffer);
+ return;
+ }
+
if(closure.buffer == NULL) dbg(0, "draw_image(): image creation failed\n");
my_free(_ALLOC_ID_, &closure.buffer);
dbg(1, "draw_image(): length2 = %d\n", closure.pos);
@@ -3969,12 +3983,33 @@ void draw_image(int dr, xRect *r, double *x1, double *y1, double *x2, double *y2
image_data = base64_encode((unsigned char *)filterdata, filtersize, &olength, 0);
my_free(_ALLOC_ID_, &filterdata);
} else {
+ FILE *fd;
+ size_t size = (size_t)buf.st_size >= 5 ? 5 : (size_t)buf.st_size;
+ char header[5];
+
+ header[0] = '\0';
+ fd = fopen(filename, "r");
+ if(fd) {
+ fread(header, size, 1, fd);
+ fclose(fd);
+ }
+ if(!strncmp(header, "\x89PNG", 4)) jpg = 0;
+ else if(!strncmp(header, "\xFF\xD8\xFF", 3)) jpg = 1;
+ else jpg = -1;
+
+
closure.buffer = NULL;
closure.size = 0;
closure.pos = 0;
- emb_ptr->image = cairo_image_surface_create_from_png(filename);
- /* write PNG to in-memory buffer */
- cairo_surface_write_to_png_stream(emb_ptr->image, png_writer, &closure);
+ if(jpg == 0) {
+ emb_ptr->image = cairo_image_surface_create_from_png(filename);
+ /* write PNG to in-memory buffer */
+ cairo_surface_write_to_png_stream(emb_ptr->image, png_writer, &closure);
+ } else {
+ emb_ptr->image = cairo_image_surface_create_from_jpeg(filename);
+ /* write JPG to in-memory buffer */
+ cairo_image_surface_write_to_jpeg_mem(emb_ptr->image, &closure.buffer, &closure.pos, 75);
+ }
image_data = base64_encode(closure.buffer, closure.pos, &olength, 0);
my_free(_ALLOC_ID_, &closure.buffer);
}
diff --git a/src/scheduler.c b/src/scheduler.c
index d95dda80..e1e1bcd7 100644
--- a/src/scheduler.c
+++ b/src/scheduler.c
@@ -220,13 +220,13 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
}
/* add_png
- * Ask user to choose a png file and start a GUI placement of the image */
+ * Ask user to choose a png/jpg file and start a GUI placement of the image */
else if(!strcmp(argv[1], "add_png"))
{
char str[PATH_MAX+100];
if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
unselect_all(1);
- tcleval("tk_getOpenFile -filetypes { {{Png} {.png}} {{All files} *} }");
+ tcleval("tk_getOpenFile -filetypes {{{Png} {.png}} {{Jpg} {.jpg .jpeg}} {{All files} *} }");
if(tclresult()[0]) {
my_snprintf(str, S(str), "flags=image,unscaled\nalpha=0.8\nimage=%s\n", tclresult());
storeobject(-1, xctx->mousex_snap-100, xctx->mousey_snap-100, xctx->mousex_snap+100, xctx->mousey_snap+100,
diff --git a/src/xschem.h b/src/xschem.h
index 44141a92..e77060fa 100644
--- a/src/xschem.h
+++ b/src/xschem.h
@@ -1349,6 +1349,7 @@ extern void hash_objects(void); /* hash all objects */
#if HAS_CAIRO==1
extern cairo_status_t png_reader(void* in_closure, unsigned char* out_data, unsigned int length);
+extern cairo_status_t png_writer(void *in_closure, const unsigned char *in_data, unsigned int length);
extern int text_bbox_nocairo(const char * str,double xscale, double yscale,
short rot, short flip, int hcenter, int vcenter,
double x1,double y1, double *rx1, double *ry1,
diff --git a/src/xschem.tcl b/src/xschem.tcl
index 93387c95..2b0b921f 100644
--- a/src/xschem.tcl
+++ b/src/xschem.tcl
@@ -7735,7 +7735,7 @@ proc build_widgets { {topwin {} } } {
toolbar_add ToolInsertArc "xschem arc" "Insert Arc" $topwin
$topwin.menubar.tools.menu add command -label "Insert circle" -command "xschem circle" -accelerator Ctrl+Shift+C
toolbar_add ToolInsertCircle "xschem circle" "Insert Circle" $topwin
- $topwin.menubar.tools.menu add command -label "Insert PNG image" -command "xschem add_png"
+ $topwin.menubar.tools.menu add command -label "Insert JPG/PNG image" -command "xschem add_png"
$topwin.menubar.tools.menu add command -label "Search" -accelerator Ctrl+F -command property_search
toolbar_add ToolSearch property_search "Search" $topwin
$topwin.menubar.tools.menu add command -label "Align to Grid" -accelerator Alt+U -command "xschem align"