simplified alpha removal and inversion in ps_embedded_image()

This commit is contained in:
stefan schippers 2024-03-18 11:53:51 +01:00
parent 197379989a
commit 6405ac4c09
3 changed files with 52 additions and 32 deletions

View File

@ -82,7 +82,7 @@ int ps_embedded_image(xRect* r, double x1, double y1, double x2, double y2, int
#if defined(HAS_LIBJPEG) && HAS_CAIRO==1
int i, jpg;
int size_x, size_y;
unsigned char *img_data = NULL, BG_r, BG_g, BG_b;
unsigned char *ptr = NULL;
int invertImage;
unsigned char* ascii85EncodedJpeg;
const char* attr;
@ -129,29 +129,30 @@ int ps_embedded_image(xRect* r, double x1, double y1, double x2, double y2, int
cairo_paint(ct);
cairo_destroy(ct);
img_data = cairo_image_surface_get_data(surface);
ptr = cairo_image_surface_get_data(surface);
/* jpeg has no alpha channel so blend transparency with white */
BG_r = 0xFF; BG_g = 0xFF; BG_b = 0xFF;
for (i = 0; i < (size_x * size_y * 4); i += 4)
{
unsigned char png_r = img_data[i + 0];
unsigned char png_g = img_data[i + 1];
unsigned char png_b = img_data[i + 2];
unsigned char png_a = img_data[i + 3];
double ainv=((double)(0xFF - png_a)) / ((double)(0xFF));
unsigned char a = ptr[i + 3];
unsigned char r = ptr[i + 2];
unsigned char g = ptr[i + 1];
unsigned char b = ptr[i + 0];
/* invert colors */
if(invertImage) {
img_data[i + 0] = (unsigned char)(0xFF-png_r) + (unsigned char)((double)BG_r * ainv);
img_data[i + 1] = (unsigned char)(0xFF-png_g) + (unsigned char)((double)BG_g * ainv);
img_data[i + 2] = (unsigned char)(0xFF-png_b) + (unsigned char)((double)BG_b * ainv);
img_data[i + 3] = 0xFF;
} else {
img_data[i + 0] = png_r + (unsigned char)((double)BG_r * ainv);
img_data[i + 1] = png_g + (unsigned char)((double)BG_g * ainv);
img_data[i + 2] = png_b + (unsigned char)((double)BG_b * ainv);
img_data[i + 3] = 0xFF;
r = a - r;
g = a - g;
b = a - b;
}
/* blend with white, remove alpha */
r += (unsigned char)(0xff - a);
g += (unsigned char)(0xff - a);
b += (unsigned char)(0xff - a);
a = (unsigned char) 0xff;
/* write result back */
ptr[i + 3] = a;
ptr[i + 2] = r;
ptr[i + 1] = g;
ptr[i + 0] = b;
}
cairo_surface_mark_dirty(surface);
if(invertImage || jpg == 0) {

View File

@ -2033,13 +2033,17 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
break;
case 'i': /*----------------------------------------------*/
#if HAS_CAIRO==1
/* image [invert|white_transp|black_transp|transp_white|transp_black|write_back]
/* image [invert|white_transp|black_transp|transp_white|transp_black|write_back|
* blend_white|blend_black]
* 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.
* blend_white: blend with white background and remove alpha
* blend_black: blend with black background and remove alpha
* write_back: write resulting image back into `image_data` attribute
*/
if(!strcmp(argv[1], "image"))
{
@ -2053,10 +2057,15 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
}
if(!strcmp(argv[2], "help")) {
Tcl_SetResult(interp,
"xschem image [invert|white_transp|black_transp|transp_white|transp_black|write_back]",
"xschem image [invert|white_transp|black_transp|transp_white|transp_black|\n"
" blend_white|blend_black|write_back]",
TCL_STATIC);
return TCL_OK;
}
if(xctx->lastsel == 0) {
Tcl_SetResult(interp, "No images selected", TCL_STATIC);
return TCL_ERROR;
}
for(i = 2; i < argc; i++) {
if(!strcmp(argv[i], "invert")) what |= 1;
if(!strcmp(argv[i], "white_transp")) what |= 2;

View File

@ -456,9 +456,10 @@ static void svg_drawgrid()
}
}
static void svg_embedded_image(xRect *r, double rx1, double ry1, double rx2, double ry2, int rot, int flip)
static int svg_embedded_image(xRect *r, double rx1, double ry1, double rx2, double ry2, int rot, int flip)
{
const char *ptr;
const char *attr;
size_t attr_len;
double x1, y1, x2, y2, w, h, scalex = 1.0, scaley = 1.0;
int jpg = 0;
char opacity[100];
@ -479,20 +480,29 @@ static void svg_embedded_image(xRect *r, double rx1, double ry1, double rx2, dou
if(flip && (rot == 0 || rot == 2)) scalex = -1.0;
else if(flip && (rot == 1 || rot == 3)) scaley = -1.0;
ptr = get_tok_value(r->prop_ptr, "alpha", 0);
if(ptr[0]) alpha = atof(ptr);
ptr = get_tok_value(r->prop_ptr, "image_data", 0);
attr = get_tok_value(r->prop_ptr, "alpha", 0);
if(attr[0]) alpha = atof(attr);
attr = get_tok_value(r->prop_ptr, "image_data", 0);
attr_len = strlen(attr);
if(attr_len > 5) {
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;
}
my_snprintf(transform, S(transform),
"transform=\"translate(%g,%g) scale(%g,%g) rotate(%d)\"", x1, y1, scalex, scaley, rot * 90);
if(alpha == 1.0) strcpy(opacity, "");
else my_snprintf(opacity, S(opacity), "style=\"opacity:%g;\"", alpha);
if(ptr[0]) {
if(!strncmp(ptr, "/9j/", 4)) jpg = 1; /* jpeg base64 header (24 bits checked) */
fprintf(fd, "<image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" %s %s "
"xlink:href=\"data:image/%s;base64,%s\"/>\n",
0.0, 0.0, w, h, transform, opacity, jpg ? "jpeg" : "png", ptr);
}
fprintf(fd, "<image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" %s %s "
"xlink:href=\"data:image/%s;base64,%s\"/>\n",
0.0, 0.0, w, h, transform, opacity, jpg ? "jpeg" : "png", attr);
return 1;
}
static void svg_draw_symbol(int c, int n,int layer,short tmp_flip, short rot,