diff options
Diffstat (limited to 'xps/xpscommon.c')
-rw-r--r-- | xps/xpscommon.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/xps/xpscommon.c b/xps/xpscommon.c index 77aec58c..7e489ef7 100644 --- a/xps/xpscommon.c +++ b/xps/xpscommon.c @@ -1,6 +1,14 @@ #include "fitz.h" #include "muxps.h" +static inline int unhex(int a) +{ + if (a >= 'A' && a <= 'F') return a - 'A' + 0xA; + if (a >= 'a' && a <= 'f') return a - 'a' + 0xA; + if (a >= '0' && a <= '9') return a - '0'; + return 0; +} + void xps_parse_brush(xps_context *ctx, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *node) { @@ -30,6 +38,67 @@ xps_parse_element(xps_context *ctx, fz_matrix ctm, char *base_uri, xps_resource } void +xps_begin_opacity(xps_context *ctx, fz_matrix ctm, fz_rect area, + char *base_uri, xps_resource *dict, + char *opacity_att, xml_element *opacity_mask_tag) +{ + float opacity; + + if (!opacity_att && !opacity_mask_tag) + return; + + opacity = 1.0; + if (opacity_att) + opacity = atof(opacity_att); + + if (opacity_mask_tag && !strcmp(xml_tag(opacity_mask_tag), "SolidColorBrush")) + { + char *scb_opacity_att = xml_att(opacity_mask_tag, "Opacity"); + char *scb_color_att = xml_att(opacity_mask_tag, "Color"); + if (scb_opacity_att) + opacity = opacity * atof(scb_opacity_att); + if (scb_color_att) + { + fz_colorspace *colorspace; + float samples[32]; + xps_parse_color(ctx, base_uri, scb_color_att, &colorspace, samples); + opacity = opacity * samples[0]; + } + opacity_mask_tag = NULL; + } + + if (ctx->opacity_top + 1 < nelem(ctx->opacity)) + { + ctx->opacity[ctx->opacity_top + 1] = ctx->opacity[ctx->opacity_top] * opacity; + ctx->opacity_top++; + } + + if (opacity_mask_tag) + { + ctx->dev->beginmask(ctx->dev->user, area, 0, NULL, NULL); + xps_parse_brush(ctx, ctm, area, base_uri, dict, opacity_mask_tag); + ctx->dev->endmask(ctx->dev->user); + } +} + +void +xps_end_opacity(xps_context *ctx, char *base_uri, xps_resource *dict, + char *opacity_att, xml_element *opacity_mask_tag) +{ + if (!opacity_att && !opacity_mask_tag) + return; + + if (ctx->opacity_top > 0) + ctx->opacity_top--; + + if (opacity_mask_tag) + { + if (strcmp(xml_tag(opacity_mask_tag), "SolidColorBrush")) + ctx->dev->popclip(ctx->dev->user); + } +} + +void xps_parse_render_transform(xps_context *ctx, char *transform, fz_matrix *matrix) { float args[6]; @@ -93,3 +162,121 @@ xps_parse_rectangle(xps_context *ctx, char *text, fz_rect *rect) rect->x1 = args[0] + args[2]; rect->y1 = args[1] + args[3]; } + +static int count_commas(char *s) +{ + int n = 0; + while (*s) + { + if (*s == ',') + n ++; + s ++; + } + return n; +} + +void +xps_parse_color(xps_context *ctx, char *base_uri, char *string, + fz_colorspace **csp, float *samples) +{ + char *p; + int i, n; + char buf[1024]; + char *profile; + + *csp = fz_devicergb; + + samples[0] = 1.0; + samples[1] = 0.0; + samples[2] = 0.0; + samples[3] = 0.0; + + if (string[0] == '#') + { + if (strlen(string) == 9) + { + samples[0] = unhex(string[1]) * 16 + unhex(string[2]); + samples[1] = unhex(string[3]) * 16 + unhex(string[4]); + samples[2] = unhex(string[5]) * 16 + unhex(string[6]); + samples[3] = unhex(string[7]) * 16 + unhex(string[8]); + } + else + { + samples[0] = 255.0; + samples[1] = unhex(string[1]) * 16 + unhex(string[2]); + samples[2] = unhex(string[3]) * 16 + unhex(string[4]); + samples[3] = unhex(string[5]) * 16 + unhex(string[6]); + } + + samples[0] /= 255.0; + samples[1] /= 255.0; + samples[2] /= 255.0; + samples[3] /= 255.0; + } + + else if (string[0] == 's' && string[1] == 'c' && string[2] == '#') + { + if (count_commas(string) == 2) + sscanf(string, "sc#%g,%g,%g", samples + 1, samples + 2, samples + 3); + if (count_commas(string) == 3) + sscanf(string, "sc#%g,%g,%g,%g", samples, samples + 1, samples + 2, samples + 3); + } + + else if (strstr(string, "ContextColor ") == string) + { + /* Crack the string for profile name and sample values */ + strcpy(buf, string); + + profile = strchr(buf, ' '); + if (!profile) + { + fz_warn("cannot find icc profile uri in '%s'", string); + return; + } + + *profile++ = 0; + p = strchr(profile, ' '); + if (!p) + { + fz_warn("cannot find component values in '%s'", profile); + return; + } + + *p++ = 0; + n = count_commas(p) + 1; + i = 0; + while (i < n) + { + samples[i++] = atof(p); + p = strchr(p, ','); + if (!p) + break; + p ++; + if (*p == ' ') + p ++; + } + while (i < n) + { + samples[i++] = 0.0; + } + + /* TODO: load ICC profile */ + switch (n) + { + case 2: *csp = fz_devicegray; break; + case 4: *csp = fz_devicergb; break; + case 5: *csp = fz_devicecmyk; break; + default: *csp = fz_devicegray; break; + } + } +} + +void +xps_set_color(xps_context *ctx, fz_colorspace *colorspace, float *samples) +{ + int i; + ctx->colorspace = colorspace; + for (i = 0; i < colorspace->n; i++) + ctx->color[i] = samples[i + 1]; + ctx->alpha = samples[0] * ctx->opacity[ctx->opacity_top]; +} |