show and store embedded (png) images in schematics
This commit is contained in:
parent
03c5330c94
commit
d22245b33a
|
|
@ -612,6 +612,10 @@ void clear_drawing(void)
|
|||
for(j=0;j<xctx->rects[i];j++)
|
||||
{
|
||||
my_free(700, &xctx->rect[i][j].prop_ptr);
|
||||
if(xctx->rect[i][j].data) {
|
||||
my_free(1467, &xctx->rect[i][j].data);
|
||||
xctx->rect[i][j].data_size = 0;
|
||||
}
|
||||
}
|
||||
for(j=0;j<xctx->arcs[i];j++)
|
||||
{
|
||||
|
|
|
|||
105
src/draw.c
105
src/draw.c
|
|
@ -2561,11 +2561,42 @@ void draw_graph_all(int flags)
|
|||
}
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char *buffer;
|
||||
size_t pos;
|
||||
size_t size;
|
||||
} png_to_byte_closure_t;
|
||||
|
||||
|
||||
static cairo_status_t png_reader(void *in_closure, unsigned char *out_data, unsigned int length)
|
||||
{
|
||||
png_to_byte_closure_t *closure = (png_to_byte_closure_t *) in_closure;
|
||||
memcpy(out_data, closure->buffer + closure->pos, length);
|
||||
closure->pos += length;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static 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(closure->pos + length > closure->size) {
|
||||
my_realloc(1472, &closure->buffer, closure->pos + length + 65536);
|
||||
closure->size = closure->pos + length + 65536;
|
||||
}
|
||||
memcpy(closure->buffer + closure->pos, in_data, length);
|
||||
closure->pos += length;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int draw_images_all(void)
|
||||
{
|
||||
#if HAS_CAIRO==1
|
||||
int i, bbox_set = 0;
|
||||
int i, bbox_set = 0, w, h;
|
||||
double x, y, rw, rh;
|
||||
int save_bbx1, save_bby1, save_bbx2, save_bby2;
|
||||
cairo_surface_t *image;
|
||||
|
||||
if(xctx->sem) {
|
||||
bbox_set = 1;
|
||||
|
|
@ -2576,21 +2607,76 @@ int draw_images_all(void)
|
|||
bbox(END, 0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
cairo_save(xctx->cairo_ctx);
|
||||
cairo_save(xctx->cairo_save_ctx);
|
||||
if(xctx->draw_single_layer==-1 || GRIDLAYER == xctx->draw_single_layer) {
|
||||
if(xctx->enable_layer[GRIDLAYER]) for(i = 0; i < xctx->rects[GRIDLAYER]; i++) {
|
||||
xRect *r = &xctx->rect[GRIDLAYER][i];
|
||||
if(r->flags & 1024) {
|
||||
/* const char *filename = get_tok_value(r->prop_ptr, "image", 0); */
|
||||
struct stat buf;
|
||||
const char *attr;
|
||||
const char *filename;
|
||||
double scalex, scaley;
|
||||
png_to_byte_closure_t closure;
|
||||
|
||||
cairo_save(xctx->cairo_ctx);
|
||||
cairo_save(xctx->cairo_save_ctx);
|
||||
|
||||
if(r->data && r->data_size) {
|
||||
/* read PNG from in-memory buffer */
|
||||
closure.buffer = r->data;
|
||||
closure.pos = 0;
|
||||
closure.size = r->data_size; /* should not be necessary */
|
||||
image = cairo_image_surface_create_from_png_stream(png_reader, &closure);
|
||||
dbg(1, "draw_images_all(): length1 = %d\n", closure.pos);
|
||||
} else if( (attr = get_tok_value(r->prop_ptr, "image_data", 0))[0] ) {
|
||||
r->data = base64_decode(attr, strlen(attr), &r->data_size);
|
||||
closure.buffer = r->data;
|
||||
closure.pos = 0;
|
||||
closure.size = r->data_size; /* should not be necessary */
|
||||
image = cairo_image_surface_create_from_png_stream(png_reader, &closure);
|
||||
dbg(1, "draw_images_all(): length2 = %d\n", closure.pos);
|
||||
} else if( (filename = get_tok_value(r->prop_ptr, "image", 0))[0] && !stat(filename, &buf)) {
|
||||
char *image_data = NULL;
|
||||
size_t olength;
|
||||
image = cairo_image_surface_create_from_png(filename);
|
||||
if(cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) return 1;
|
||||
/* write PNG to in-memory buffer */
|
||||
closure.buffer = NULL;
|
||||
closure.size = 0;
|
||||
closure.pos = 0;
|
||||
cairo_surface_write_to_png_stream(image, png_writer, &closure);
|
||||
dbg(1, "draw_images_all(): length3 = %d\n", closure.pos);
|
||||
r->data = closure.buffer;
|
||||
r->data_size = closure.pos;
|
||||
/* put base64 encoded data to rect image_data attrinute */
|
||||
image_data = base64_encode(r->data, r->data_size, &olength);
|
||||
my_realloc(1466, &image_data, olength + 1);
|
||||
image_data[olength] = '\0';
|
||||
my_strdup2(1473, &r->prop_ptr, subst_token(r->prop_ptr, "image_data", image_data));
|
||||
my_free(1474, &image_data);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
if(cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) return 1;
|
||||
w = cairo_image_surface_get_width (image);
|
||||
h = cairo_image_surface_get_height (image);
|
||||
dbg(1, "draw_images_all() w=%d, h=%d\n", w, h);
|
||||
x = X_TO_SCREEN(r->x1);
|
||||
y = Y_TO_SCREEN(r->y1);
|
||||
rw = abs(r->x2 - r->x1);
|
||||
rh = abs(r->y2 - r->y1);
|
||||
cairo_translate(xctx->cairo_save_ctx, x, y);
|
||||
scalex = rw/w * xctx->mooz;
|
||||
scaley = rh/h * xctx->mooz;
|
||||
cairo_scale(xctx->cairo_save_ctx, scalex, scaley);
|
||||
cairo_set_source_surface(xctx->cairo_save_ctx, image, 0. , 0.);
|
||||
cairo_paint(xctx->cairo_save_ctx);
|
||||
|
||||
cairo_surface_destroy(image);
|
||||
cairo_restore(xctx->cairo_ctx);
|
||||
cairo_restore(xctx->cairo_save_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
cairo_restore(xctx->cairo_ctx);
|
||||
cairo_restore(xctx->cairo_save_ctx);
|
||||
|
||||
if(bbox_set) {
|
||||
xctx->bbx1 = save_bbx1;
|
||||
xctx->bby1 = save_bby1;
|
||||
|
|
@ -2599,10 +2685,10 @@ int draw_images_all(void)
|
|||
xctx->sem = 1;
|
||||
bbox(SET, 0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void draw(void)
|
||||
{
|
||||
/* inst_ptr and wire hash iterator 20171224 */
|
||||
|
|
@ -2629,6 +2715,7 @@ void draw(void)
|
|||
dbg(1, "draw(): window: %d %d %d %d\n",xctx->areax1, xctx->areay1, xctx->areax2, xctx->areay2);
|
||||
drawgrid();
|
||||
draw_graph_all((xctx->graph_flags & 6) + 8); /* xctx->graph_flags for cursors */
|
||||
draw_images_all();
|
||||
x1 = X_TO_XSCHEM(xctx->areax1);
|
||||
y1 = Y_TO_XSCHEM(xctx->areay1);
|
||||
x2 = X_TO_XSCHEM(xctx->areax2);
|
||||
|
|
@ -2651,7 +2738,7 @@ void draw(void)
|
|||
}
|
||||
if(xctx->enable_layer[c]) for(i=0;i<xctx->rects[c];i++) {
|
||||
xRect *r = &xctx->rect[c][i];
|
||||
if(c != GRIDLAYER || !(r->flags & 1) ) {
|
||||
if(c != GRIDLAYER || !(r->flags & (1 + 1024)) ) {
|
||||
drawrect(c, ADD, r->x1, r->y1, r->x2, r->y2, r->dash);
|
||||
filledrect(c, ADD, r->x1, r->y1, r->x2, r->y2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -434,6 +434,10 @@ static void edit_rect_property(int x)
|
|||
(char *) tclgetvar("retval"));
|
||||
}
|
||||
|
||||
if(xctx->rect[c][n].data) { /* used for images, clear so will be recreated from image attr */
|
||||
my_free(1465, &xctx->rect[c][n].data);
|
||||
xctx->rect[c][n].data_size = 0;
|
||||
}
|
||||
flags = get_tok_value(xctx->rect[c][n].prop_ptr,"flags",0);
|
||||
if( strcmp(flags, "") ) {
|
||||
int d = atoi(flags);
|
||||
|
|
|
|||
|
|
@ -307,6 +307,11 @@ void mem_push_undo(void)
|
|||
xctx->uslot[slot].bptr[c][i] = xctx->rect[c][i];
|
||||
xctx->uslot[slot].bptr[c][i].prop_ptr = NULL;
|
||||
my_strdup(185, &xctx->uslot[slot].bptr[c][i].prop_ptr, xctx->rect[c][i].prop_ptr);
|
||||
if(xctx->rect[c][i].data && xctx->rect[c][i].data_size) {
|
||||
xctx->uslot[slot].bptr[c][i].data_size = xctx->rect[c][i].data_size;
|
||||
xctx->uslot[slot].bptr[c][i].data = my_malloc(1469, xctx->rect[c][i].data_size);
|
||||
memcpy(xctx->uslot[slot].bptr[c][i].data, xctx->rect[c][i].data, xctx->rect[c][i].data_size);
|
||||
}
|
||||
}
|
||||
/* arcs */
|
||||
for(i = 0;i<xctx->arcs[c];i++) {
|
||||
|
|
@ -529,6 +534,11 @@ void mem_pop_undo(int redo, int set_modify_status)
|
|||
xctx->rect[c][i] = xctx->uslot[slot].bptr[c][i];
|
||||
xctx->rect[c][i].prop_ptr = NULL;
|
||||
my_strdup(205, &xctx->rect[c][i].prop_ptr, xctx->uslot[slot].bptr[c][i].prop_ptr);
|
||||
if(xctx->uslot[slot].bptr[c][i].data && xctx->uslot[slot].bptr[c][i].data_size) {
|
||||
xctx->rect[c][i].data_size = xctx->uslot[slot].bptr[c][i].data_size;
|
||||
xctx->rect[c][i].data = my_malloc(1468, xctx->uslot[slot].bptr[c][i].data_size);
|
||||
memcpy(xctx->rect[c][i].data, xctx->uslot[slot].bptr[c][i].data, xctx->uslot[slot].bptr[c][i].data_size);
|
||||
}
|
||||
}
|
||||
/* arcs */
|
||||
xctx->maxa[c] = xctx->arcs[c] = xctx->uslot[slot].arcs[c];
|
||||
|
|
|
|||
|
|
@ -145,6 +145,10 @@ void check_collapsing_objects()
|
|||
if(xctx->rect[c][i].x1==xctx->rect[c][i].x2 || xctx->rect[c][i].y1 == xctx->rect[c][i].y2)
|
||||
{
|
||||
my_free(815, &xctx->rect[c][i].prop_ptr);
|
||||
if(xctx->rect[c][i].data) {
|
||||
my_free(1471, &xctx->rect[c][i].data);
|
||||
xctx->rect[c][i].data_size = 0;
|
||||
}
|
||||
found=1;
|
||||
j++;
|
||||
continue;
|
||||
|
|
@ -872,6 +876,11 @@ void copy_objects(int what)
|
|||
storeobject(-1, xctx->rx1+xctx->deltax, xctx->ry1+xctx->deltay,
|
||||
xctx->rx2+xctx->deltax, xctx->ry2+xctx->deltay,xRECT, c, SELECTED, xctx->rect[c][n].prop_ptr);
|
||||
l = xctx->rects[c] - 1;
|
||||
if(xctx->rect[c][n].data && xctx->rect[c][n].data_size) {
|
||||
xctx->rect[c][l].data_size = xctx->rect[c][n].data_size;
|
||||
xctx->rect[c][l].data = my_malloc(1470, xctx->rect[c][n].data_size);
|
||||
memcpy(xctx->rect[c][l].data, xctx->rect[c][n].data, xctx->rect[c][n].data_size);
|
||||
}
|
||||
bbox(ADD, xctx->rect[c][l].x1, xctx->rect[c][l].y1, xctx->rect[c][l].x2, xctx->rect[c][l].y2);
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@ void merge_box(FILE *fd)
|
|||
return;
|
||||
}
|
||||
ptr[i].prop_ptr=NULL;
|
||||
ptr[i].data=NULL;
|
||||
ptr[i].data_size=0;
|
||||
RECTORDER(ptr[i].x1, ptr[i].y1, ptr[i].x2, ptr[i].y2);
|
||||
ptr[i].sel=0;
|
||||
load_ascii_string( &ptr[i].prop_ptr, fd);
|
||||
|
|
|
|||
82
src/save.c
82
src/save.c
|
|
@ -25,6 +25,86 @@
|
|||
#include <sys/wait.h> /* waitpid */
|
||||
#endif
|
||||
|
||||
/* Caller should free returned buffer */
|
||||
char *base64_encode(const unsigned char *data, size_t input_length, size_t *output_length) {
|
||||
static char b64_enc[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||
'4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
static int mod_table[] = {0, 2, 1};
|
||||
int i, j;
|
||||
char *encoded_data;
|
||||
|
||||
*output_length = 4 * ((input_length + 2) / 3);
|
||||
encoded_data = malloc(*output_length);
|
||||
if (encoded_data == NULL) return NULL;
|
||||
for (i = 0, j = 0; i < input_length;) {
|
||||
int octet_a = i < input_length ? (unsigned char)data[i++] : 0;
|
||||
int octet_b = i < input_length ? (unsigned char)data[i++] : 0;
|
||||
int octet_c = i < input_length ? (unsigned char)data[i++] : 0;
|
||||
int triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
|
||||
encoded_data[j++] = b64_enc[(triple >> 3 * 6) & 0x3F];
|
||||
encoded_data[j++] = b64_enc[(triple >> 2 * 6) & 0x3F];
|
||||
encoded_data[j++] = b64_enc[(triple >> 1 * 6) & 0x3F];
|
||||
encoded_data[j++] = b64_enc[(triple >> 0 * 6) & 0x3F];
|
||||
}
|
||||
for (i = 0; i < mod_table[input_length % 3]; i++)
|
||||
encoded_data[*output_length - 1 - i] = '=';
|
||||
return encoded_data;
|
||||
}
|
||||
|
||||
/* Caller should free returned buffer */
|
||||
unsigned char *base64_decode(const char *data, size_t input_length, size_t *output_length) {
|
||||
static unsigned char b64_dec[256] = {
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
||||
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
||||
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f
|
||||
};
|
||||
unsigned char *decoded_data;
|
||||
int i, j;
|
||||
|
||||
if (input_length % 4 != 0) return NULL;
|
||||
*output_length = input_length / 4 * 3;
|
||||
if (data[input_length - 1] == '=') (*output_length)--;
|
||||
if (data[input_length - 2] == '=') (*output_length)--;
|
||||
decoded_data = malloc(*output_length);
|
||||
if (decoded_data == NULL) return NULL;
|
||||
for (i = 0, j = 0; i < input_length;) {
|
||||
int sextet_a = data[i] == '=' ? 0 & i++ : b64_dec[(int)data[i++]];
|
||||
int sextet_b = data[i] == '=' ? 0 & i++ : b64_dec[(int)data[i++]];
|
||||
int sextet_c = data[i] == '=' ? 0 & i++ : b64_dec[(int)data[i++]];
|
||||
int sextet_d = data[i] == '=' ? 0 & i++ : b64_dec[(int)data[i++]];
|
||||
int triple = (sextet_a << 3 * 6)
|
||||
+ (sextet_b << 2 * 6)
|
||||
+ (sextet_c << 1 * 6)
|
||||
+ (sextet_d << 0 * 6);
|
||||
if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
|
||||
if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
|
||||
if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
|
||||
}
|
||||
|
||||
return decoded_data;
|
||||
}
|
||||
|
||||
/*
|
||||
read an unknown xschem record usually like:
|
||||
text {string} text {string}....
|
||||
|
|
@ -699,6 +779,8 @@ static void load_box(FILE *fd)
|
|||
return;
|
||||
}
|
||||
RECTORDER(ptr[i].x1, ptr[i].y1, ptr[i].x2, ptr[i].y2);
|
||||
ptr[i].data=NULL;
|
||||
ptr[i].data_size=0;
|
||||
ptr[i].prop_ptr=NULL;
|
||||
ptr[i].sel=0;
|
||||
load_ascii_string( &ptr[i].prop_ptr, fd);
|
||||
|
|
|
|||
|
|
@ -308,6 +308,8 @@ void storeobject(int pos, double x1,double y1,double x2,double y2,
|
|||
xctx->rect[rectc][n].y1=y1;
|
||||
xctx->rect[rectc][n].y2=y2;
|
||||
xctx->rect[rectc][n].prop_ptr=NULL;
|
||||
xctx->rect[rectc][n].data=NULL;
|
||||
xctx->rect[rectc][n].data_size=0;
|
||||
my_strdup(413, &xctx->rect[rectc][n].prop_ptr, prop_ptr);
|
||||
xctx->rect[rectc][n].sel=sel;
|
||||
if(prop_ptr && (dash = get_tok_value(prop_ptr,"dash",0))[0]) {
|
||||
|
|
|
|||
|
|
@ -403,6 +403,8 @@ typedef struct
|
|||
double y2;
|
||||
unsigned short sel;
|
||||
char *prop_ptr;
|
||||
void *data; /* generic data pointer (images) */
|
||||
size_t data_size; /* generic data pointer (images) */
|
||||
short dash;
|
||||
/* bit0=1 for graph function, bit1=1 for unlocked x axis
|
||||
* bit10: image embedding (png)
|
||||
|
|
@ -992,6 +994,8 @@ extern int cli_opt_load_initfile;
|
|||
extern Xschem_ctx *xctx;
|
||||
|
||||
/* FUNCTIONS */
|
||||
extern unsigned char *base64_decode(const char *data, size_t input_length, size_t *output_length);
|
||||
extern char *base64_encode(const unsigned char *data, size_t input_length, size_t *output_length);
|
||||
extern int get_raw_index(const char *node);
|
||||
extern double get_raw_value(int dataset, int idx, int point);
|
||||
extern int schematic_waves_loaded(void);
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue