refactored draw_image() into smaller functions

This commit is contained in:
stefan schippers 2024-03-17 10:11:57 +01:00
parent 9670368f9d
commit bf027bc4f8
1 changed files with 126 additions and 91 deletions

View File

@ -4009,94 +4009,30 @@ int edit_image(int what, xRect *r)
#endif
#if HAS_CAIRO==1
static cairo_surface_t *get_surface_from_b64data(const char *attr)
/* returns a cairo surface.
* `filename` should be a png or jpeg image or anything else that can be converted to png
* or jpeg via a `filter` pipeline. (example: filter="gm convert - png:-")
* buffer returns the content of filename or the filtered result if filter is given.
* `size` is set to the size of the returned data */
static cairo_surface_t *get_surface_from_file(const char *filename, const char *filter,
unsigned char **buffer, size_t *size)
{
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;
}
#endif
/* rot and flip for rotated / flipped symbols
* dr: 1 draw image
* 0 only load image and build base64
*/
int draw_image(int dr, xRect *r, double *x1, double *y1, double *x2, double *y2, int rot, int flip)
{
#if HAS_CAIRO==1
#if defined(HAS_LIBJPEG)
#endif
const char *ptr;
int w,h;
double x, y, rw, rh;
double sx1, sy1, sx2, sy2, alpha;
char filename[PATH_MAX];
struct stat buf;
const char *attr ;
double xx1, yy1, scalex, scaley;
xEmb_image *emb_ptr;
int jpg = 0; /* set to 1 if image_data attribute contains base64 encoded JPEG */
if(xctx->only_probes) return 0;
xx1 = *x1; yy1 = *y1; /* image anchor point */
RECTORDER(*x1, *y1, *x2, *y2);
/* screen position */
sx1=X_TO_SCREEN(*x1);
sy1=Y_TO_SCREEN(*y1);
sx2=X_TO_SCREEN(*x2);
sy2=Y_TO_SCREEN(*y2);
if(RECT_OUTSIDE(sx1, sy1, sx2, sy2,
xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2)) return 0;
set_rect_extraptr(1, r); /* create r->extraptr pointing to a xEmb_image struct */
emb_ptr = r->extraptr;
my_strncpy(filename, get_tok_value(r->prop_ptr, "image", 0), S(filename));
/******* 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] && strlen(attr) > 5) {
emb_ptr->image = get_surface_from_b64data(attr);
if(!emb_ptr->image) {
return 0;
}
/******* ... or read PNG from file (image attribute) *******/
} else if(filename[0] && !stat(filename, &buf)) {
int jpg = 0;
png_to_byte_closure_t closure;
char *encoded_data = NULL;
size_t olength;
size_t filesize = 0;
char *filedata = NULL;
FILE *fd;
char *filter = NULL;
struct stat buf;
cairo_surface_t *surface = NULL;
if(stat(filename, &buf)) {
dbg(0, "get_surface_from_file(): file %s not found.\n", filename);
*buffer = NULL;
*size = 0;
return NULL;
}
filesize = (size_t)buf.st_size;
if(filesize > 0) {
fd = fopen(filename, "r");
@ -4105,15 +4041,17 @@ int draw_image(int dr, xRect *r, double *x1, double *y1, double *x2, double *y2,
filedata = my_malloc(_ALLOC_ID_, filesize);
if((bytes_read = fread(filedata, 1, filesize, fd)) < filesize) {
filesize = bytes_read;
dbg(0, "draw_image(): less bytes read than expected from %s, got %ld bytes\n", filename, bytes_read);
dbg(0, "get_surface_from_file(): less bytes read than expected from %s, got %ld bytes\n",
filename, bytes_read);
}
fclose(fd);
}
} else {
dbg(0, "draw_image(): file %s has zero size\n", filename);
return 0;
dbg(0, "get_surface_from_file(): file %s has zero size\n", filename);
*buffer = NULL;
*size = 0;
return NULL;
}
my_strdup(_ALLOC_ID_, &filter, get_tok_value(r->prop_ptr, "filter", 0));
if(filter) {
size_t filtered_img_size = 0;
char *filtered_img_data = NULL;
@ -4139,23 +4077,120 @@ int draw_image(int dr, xRect *r, double *x1, double *y1, double *x2, double *y2,
}
if(jpg == 0) {
emb_ptr->image = cairo_image_surface_create_from_png_stream(png_reader, &closure);
surface = 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);
surface = 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) {
if(!surface || cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
if(jpg != 1) dbg(0, "draw_image(): failure creating image surface from %s\n", filename);
if(surface) cairo_surface_destroy(surface);
my_free(_ALLOC_ID_, &closure.buffer);
*buffer = NULL;
*size = 0;
return NULL;
}
*buffer = closure.buffer;
*size = closure.size;
return surface;
}
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, "get_surface_from_b64data(): decoding base64 data for image 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, "get_surface_from_b64data(): 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;
}
#endif
/* rot and flip for rotated / flipped symbols
* dr: 1 draw image
* 0 only load image and build base64
*/
int draw_image(int dr, xRect *r, double *x1, double *y1, double *x2, double *y2, int rot, int flip)
{
#if HAS_CAIRO==1
#if defined(HAS_LIBJPEG)
#endif
const char *ptr;
int w,h;
double x, y, rw, rh;
double sx1, sy1, sx2, sy2, alpha;
char filename[PATH_MAX];
const char *attr ;
double xx1, yy1, scalex, scaley;
xEmb_image *emb_ptr;
if(xctx->only_probes) return 0;
xx1 = *x1; yy1 = *y1; /* image anchor point */
RECTORDER(*x1, *y1, *x2, *y2);
/* screen position */
sx1=X_TO_SCREEN(*x1);
sy1=Y_TO_SCREEN(*y1);
sx2=X_TO_SCREEN(*x2);
sy2=Y_TO_SCREEN(*y2);
if(RECT_OUTSIDE(sx1, sy1, sx2, sy2,
xctx->areax1,xctx->areay1,xctx->areax2,xctx->areay2)) return 0;
set_rect_extraptr(1, r); /* create r->extraptr pointing to a xEmb_image struct */
emb_ptr = r->extraptr;
my_strncpy(filename, get_tok_value(r->prop_ptr, "image", 0), S(filename));
/******* 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] && strlen(attr) > 5) {
emb_ptr->image = get_surface_from_b64data(attr);
if(!emb_ptr->image) {
return 0;
}
/******* ... or read PNG from file (image attribute) *******/
} else if(filename[0]) {
unsigned char *buffer = NULL;
size_t size = 0;
char *filter = NULL;
char *encoded_data = NULL;
size_t olength;
my_strdup(_ALLOC_ID_, &filter, get_tok_value(r->prop_ptr, "filter", 0));
emb_ptr->image = get_surface_from_file(filename, filter, &buffer, &size);
if(!emb_ptr->image) {
return 0;
}
/* put base64 encoded data to rect image_data attribute */
encoded_data = base64_encode((unsigned char *)closure.buffer, closure.size, &olength, 0);
encoded_data = base64_encode((unsigned char *)buffer, 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);
my_free(_ALLOC_ID_, &buffer);
} else { /* no emb_ptr->image and no "image_data" attribute */
return 0;
}