diff options
author | Michael Vrhel <michael.vrhel@artifex.com> | 2010-06-15 17:24:45 +0000 |
---|---|---|
committer | Michael Vrhel <michael.vrhel@artifex.com> | 2010-06-15 17:24:45 +0000 |
commit | 37b58b80d018f877ead71c90462a804997bdb98f (patch) | |
tree | 6cb222f50cf39e4895997da0f65db9333cb98187 | |
parent | 2c498847e1354f9c5c3b36003693d8ac4a431378 (diff) |
Addition of code to use new icc color architecture in xps rendering. Tor to provide minor fixes to this, primarily to remove the ctx->icc object. There will be xps differences with this commit since icc profiles were previously ignored.
git-svn-id: http://svn.ghostscript.com/ghostscript/trunk@11379 a1074d23-0009-0410-80fe-cf8c14f379e6
-rw-r--r-- | xps/ghostxps.h | 21 | ||||
-rw-r--r-- | xps/xpscolor.c | 86 | ||||
-rw-r--r-- | xps/xpsgradient.c | 46 | ||||
-rw-r--r-- | xps/xpshdp.c | 4 | ||||
-rw-r--r-- | xps/xpsimage.c | 195 | ||||
-rw-r--r-- | xps/xpsjpeg.c | 30 | ||||
-rw-r--r-- | xps/xpspage.c | 8 | ||||
-rw-r--r-- | xps/xpspng.c | 17 | ||||
-rw-r--r-- | xps/xpstiff.c | 43 | ||||
-rw-r--r-- | xps/xpstop.c | 13 |
10 files changed, 382 insertions, 81 deletions
diff --git a/xps/ghostxps.h b/xps/ghostxps.h index d95a9bccb..256b1ac1f 100644 --- a/xps/ghostxps.h +++ b/xps/ghostxps.h @@ -64,6 +64,8 @@ #include "gzpath.h" #include "gsicc_manage.h" +#include "gscms.h" +#include "gsicc_cache.h" #include "zlib.h" @@ -196,6 +198,7 @@ struct xps_context_s gs_color_space *srgb; gs_color_space *scrgb; gs_color_space *cmyk; + gs_color_space *icc; char *directory; FILE *file; @@ -249,7 +252,8 @@ xps_part_t *xps_read_part(xps_context_t *ctx, char *partname); /* type for the information derived directly from the raster file format */ -enum { XPS_GRAY, XPS_GRAY_A, XPS_RGB, XPS_RGB_A, XPS_CMYK, XPS_CMYK_A }; +enum { XPS_GRAY, XPS_GRAY_A, XPS_RGB, XPS_RGB_A, XPS_CMYK, XPS_CMYK_A, + XPS_ICC, XPS_ICC_A, XPS_NOTICC }; struct xps_image_s { @@ -263,12 +267,18 @@ struct xps_image_s int yres; byte *samples; byte *alpha; /* isolated alpha plane */ + bool embeddedprofile; }; -int xps_decode_jpeg(gs_memory_t *mem, byte *rbuf, int rlen, xps_image_t *image); -int xps_decode_png(gs_memory_t *mem, byte *rbuf, int rlen, xps_image_t *image); -int xps_decode_tiff(gs_memory_t *mem, byte *rbuf, int rlen, xps_image_t *image); -int xps_decode_hdphoto(gs_memory_t *mem, byte *buf, int len, xps_image_t *image); +/* Probably need to clean this up to make different proc types */ +int xps_decode_jpeg(gs_memory_t *mem, byte *rbuf, int rlen, xps_image_t *image, + unsigned char **profile, int *profile_size); +int xps_decode_png(gs_memory_t *mem, byte *rbuf, int rlen, xps_image_t *image, + unsigned char **profile, int *profile_size); +int xps_decode_tiff(gs_memory_t *mem, byte *rbuf, int rlen, xps_image_t *image, + unsigned char **profile, int *profile_size); +int xps_decode_hdphoto(gs_memory_t *mem, byte *buf, int len, xps_image_t *image, + unsigned char **profile, int *profile_size); int xps_hasalpha_png(gs_memory_t *mem, byte *rbuf, int rlen); int xps_hasalpha_tiff(gs_memory_t *mem, byte *rbuf, int rlen); int xps_hasalpha_hdphoto(gs_memory_t *mem, byte *buf, int len); @@ -333,6 +343,7 @@ void xps_debug_path(xps_context_t *ctx); int xps_parse_color(xps_context_t *ctx, char *base_uri, char *hexstring, gs_color_space **csp, float *samples); int xps_set_color(xps_context_t *ctx, gs_color_space *colorspace, float *samples); int xps_parse_icc_profile(xps_context_t *ctx, gs_color_space **csp, byte *data, int length, int ncomp); +int xps_set_icc(xps_context_t *ctx, char *base_uri, char *profile, gs_color_space **csp); /* * XML document model diff --git a/xps/xpscolor.c b/xps/xpscolor.c index d4ffbc3af..5c4451841 100644 --- a/xps/xpscolor.c +++ b/xps/xpscolor.c @@ -60,16 +60,15 @@ static int count_commas(char *s) } return n; } - + int xps_parse_color(xps_context_t *ctx, char *base_uri, char *string, gs_color_space **csp, float *samples) { - xps_part_t *part; - char *profile, *p; + char *p; int i, n; - - char partname[1024]; char buf[1024]; + int code; + char *profile; samples[0] = 1.0; samples[1] = 0.0; @@ -145,34 +144,14 @@ xps_parse_color(xps_context_t *ctx, char *base_uri, char *string, gs_color_space } /* Default fallbacks if the ICC stuff fails */ - if (n == 2) /* alpha + tint */ *csp = ctx->gray; - if (n == 5) /* alpha + CMYK */ + if (n >= 5) /* alpha + CMYK */ *csp = ctx->cmyk; -#if 0 /* disable ICC profiles until gsicc_manager is available */ - /* Find ICC colorspace part */ - xps_absolute_path(partname, base_uri, profile, sizeof partname); - - colorspace = xps_hash_lookup(ctx->colorspace_table, partname); - if (!colorspace) - { - part = xps_read_part(ctx, partname); - if (!part) - return gs_throw1(-1, "cannot find icc profile part '%s'", partname); - code = xps_parse_icc_profile(ctx, &colorspace, part, n - 1); - if (code < 0) - return gs_rethrow1(code, "cannot parse icc profile part '%s'", partname); - xps_hash_insert(ctx->colorspace_table, xps_strdup(ctx, partname), colorspace); - xps_free_part(ctx, part); - } - - *csp = colorspace; -#endif - - return 0; + code = xps_set_icc(ctx, base_uri, profile, csp); + return code; } else @@ -182,6 +161,57 @@ xps_parse_color(xps_context_t *ctx, char *base_uri, char *string, gs_color_space } int +xps_set_icc(xps_context_t *ctx, char *base_uri, char *profile, gs_color_space **csp) +{ + cmm_profile_t *iccprofile; + xps_part_t *part; + char partname[1024]; + + /* Find ICC colorspace part */ + xps_absolute_path(partname, base_uri, profile, sizeof partname); + + /* See if we cached the profile */ + iccprofile = (cmm_profile_t*) xps_hash_lookup(ctx->colorspace_table, partname); + if (!iccprofile) + { + part = xps_read_part(ctx, partname); + /* Problem finding profile. Don't fail, just use default */ + if (!part) + return 0; + + /* Create the profile */ + iccprofile = gsicc_profile_new(NULL, ctx->memory, NULL, 0); + /* Set buffer */ + iccprofile->buffer = part->data; + iccprofile->buffer_size = part->size; + /* Parse */ + gsicc_init_profile_info(iccprofile); + /* Problem with profile. Don't fail, just use the default */ + if (iccprofile->profile_handle == NULL) + { + gsicc_profile_reference(iccprofile, -1); + return 0; + } + + /* Done with the buffer */ + xps_free_part(ctx, part); + iccprofile->buffer = NULL; + iccprofile->buffer_size = 0; + + /* Add profile to xps color cache. It appears never to remove + these except at the end of processing */ + xps_hash_insert(ctx, ctx->colorspace_table, xps_strdup(ctx, partname), + (void*) iccprofile); + } + + /* Associate icc color space with the profile */ + ctx->icc->cmm_icc_profile_data = iccprofile; + *csp = ctx->icc; + + return 0; +} + +int xps_parse_solid_color_brush(xps_context_t *ctx, char *base_uri, xps_resource_t *dict, xps_item_t *node) { char *opacity_att; diff --git a/xps/xpsgradient.c b/xps/xpsgradient.c index a51c65a68..c333decef 100644 --- a/xps/xpsgradient.c +++ b/xps/xpsgradient.c @@ -32,7 +32,11 @@ xps_parse_gradient_stops(xps_context_t *ctx, char *base_uri, xps_item_t *node, int count = 0; gs_color_space *colorspace; float sample[32], f; + unsigned short sample_in[8], sample_out[8]; /* XPS allows up to 8 bands */ int i, done; + gsicc_link_t *icclink = NULL; + gsicc_rendering_param_t rendering_params; + int num_colors; while (node && count < maxcount) { @@ -46,17 +50,49 @@ xps_parse_gradient_stops(xps_context_t *ctx, char *base_uri, xps_item_t *node, xps_parse_color(ctx, base_uri, color, &colorspace, sample); - /* TODO: Convert colors to sRGB using icc_work branch */ + /* Set the rendering parameters */ + rendering_params.black_point_comp = BP_ON; + rendering_params.object_type = GS_PATH_TAG; + rendering_params.rendering_intent = gsPERCEPTUAL; + + /* Get link to map from source to sRGB */ + icclink = gsicc_get_link((gs_imager_state*) ctx->pgs, colorspace, + ctx->srgb, &rendering_params, + ctx->memory, false); + + if (icclink != NULL && !icclink->is_identity) + { + /* Transform the color */ + num_colors = gsicc_getsrc_channel_count(colorspace->cmm_icc_profile_data); + for (i = 0; i < num_colors; i++) + { + sample_in[i] = sample[i+1]*65535; + } + gscms_transform_color(icclink, sample_in, sample_out, 2, NULL); + + colors[count * 4 + 0] = sample[0]; /* Alpha */ + colors[count * 4 + 1] = (float) sample_out[0] / 65535.0; /* sRGB */ + colors[count * 4 + 2] = (float) sample_out[1] / 65535.0; + colors[count * 4 + 3] = (float) sample_out[2] / 65535.0; + + } + else + { + colors[count * 4 + 0] = sample[0]; + colors[count * 4 + 1] = sample[1]; + colors[count * 4 + 2] = sample[2]; + colors[count * 4 + 3] = sample[3]; + } - colors[count * 4 + 0] = sample[0]; - colors[count * 4 + 1] = sample[1]; - colors[count * 4 + 2] = sample[2]; - colors[count * 4 + 3] = sample[3]; count ++; } } + if (icclink != NULL) + gsicc_release_link(icclink); + icclink = NULL; node = xps_next(node); + } if (count == maxcount) diff --git a/xps/xpshdp.c b/xps/xpshdp.c index a83ac7833..e637a8292 100644 --- a/xps/xpshdp.c +++ b/xps/xpshdp.c @@ -18,8 +18,10 @@ /* HD-Photo decoder should go here. */ int -xps_decode_hdphoto(gs_memory_t *mem, byte *buf, int len, xps_image_t *image) +xps_decode_hdphoto(gs_memory_t *mem, byte *buf, int len, xps_image_t *image, + unsigned char **profile, int *profile_size) { + *profile = NULL; return gs_throw(-1, "HD-Photo codec is not available"); } diff --git a/xps/xpsimage.c b/xps/xpsimage.c index 08a5d63fb..1f0ae5fe1 100644 --- a/xps/xpsimage.c +++ b/xps/xpsimage.c @@ -33,7 +33,8 @@ xps_isolate_alpha_channel_8(xps_context_t *ctx, xps_image_t *image) if ((image->colorspace != XPS_GRAY_A) && (image->colorspace != XPS_RGB_A) && - (image->colorspace != XPS_CMYK_A)) + (image->colorspace != XPS_CMYK_A) && + (image->colorspace != XPS_ICC_A)) return 0; image->alpha = xps_alloc(ctx, image->width * image->height); @@ -59,6 +60,8 @@ xps_isolate_alpha_channel_8(xps_context_t *ctx, xps_image_t *image) image->colorspace = XPS_RGB; if (image->colorspace == XPS_CMYK_A) image->colorspace = XPS_CMYK; + if (image->colorspace == XPS_ICC_A) + image->colorspace = XPS_ICC; image->comps --; image->stride = image->width * image->comps; @@ -75,7 +78,8 @@ xps_isolate_alpha_channel_16(xps_context_t *ctx, xps_image_t *image) if ((image->colorspace != XPS_GRAY_A) && (image->colorspace != XPS_RGB_A) && - (image->colorspace != XPS_CMYK_A)) + (image->colorspace != XPS_CMYK_A) && + (image->colorspace != XPS_ICC_A)) return 0; image->alpha = xps_alloc(ctx, image->width * image->height * 2); @@ -101,6 +105,8 @@ xps_isolate_alpha_channel_16(xps_context_t *ctx, xps_image_t *image) image->colorspace = XPS_RGB; if (image->colorspace == XPS_CMYK_A) image->colorspace = XPS_CMYK; + if (image->colorspace == XPS_ICC_A) + image->colorspace = XPS_ICC; image->comps --; image->stride = image->width * image->comps * 2; @@ -137,13 +143,18 @@ xps_image_has_alpha(xps_context_t *ctx, xps_part_t *part) return code; } - static int -xps_decode_image(xps_context_t *ctx, xps_part_t *part, xps_image_t *image) +xps_decode_image(xps_context_t *ctx, char *profilename, int profile_comp, + xps_part_t *imagepart, xps_image_t *image) { - byte *buf = (byte*)part->data; - int len = part->size; + byte *buf = (byte*)imagepart->data; + int len = imagepart->size; int error; + int iccinfo = image->colorspace; /* So that we know if external profile was valid */ + unsigned char *embedded_profile; + int profile_size; + cmm_profile_t *iccprofile; + bool has_alpha; if (len < 2) error = gs_throw(-1, "unknown image file format"); @@ -153,24 +164,107 @@ xps_decode_image(xps_context_t *ctx, xps_part_t *part, xps_image_t *image) image->alpha = NULL; if (buf[0] == 0xff && buf[1] == 0xd8) - error = xps_decode_jpeg(ctx->memory, buf, len, image); + error = xps_decode_jpeg(ctx->memory, buf, len, image, + &embedded_profile, &profile_size); else if (memcmp(buf, "\211PNG\r\n\032\n", 8) == 0) - error = xps_decode_png(ctx->memory, buf, len, image); + error = xps_decode_png(ctx->memory, buf, len, image, + &embedded_profile, &profile_size); else if (memcmp(buf, "II", 2) == 0 && buf[2] == 0xBC) - error = xps_decode_hdphoto(ctx->memory, buf, len, image); + error = xps_decode_hdphoto(ctx->memory, buf, len, image, + &embedded_profile, &profile_size); else if (memcmp(buf, "MM", 2) == 0) - error = xps_decode_tiff(ctx->memory, buf, len, image); + error = xps_decode_tiff(ctx->memory, buf, len, image, + &embedded_profile, &profile_size); else if (memcmp(buf, "II", 2) == 0) - error = xps_decode_tiff(ctx->memory, buf, len, image); + error = xps_decode_tiff(ctx->memory, buf, len, image, + &embedded_profile, &profile_size); else error = gs_throw(-1, "unknown image file format"); if (error) return gs_rethrow(error, "could not decode image"); - if (image->colorspace == XPS_GRAY_A || - image->colorspace == XPS_RGB_A || - image->colorspace == XPS_CMYK_A) + has_alpha = (image->colorspace == XPS_GRAY_A || + image->colorspace == XPS_RGB_A || + image->colorspace == XPS_CMYK_A); + + /* Make sure profile matches data type */ + if (iccinfo == XPS_ICC) + { + if (profile_comp == image->comps) + { + /* Profile is OK for this image. Change color space type. */ + if (has_alpha) + { + image->colorspace = XPS_ICC_A; + } + else + { + image->colorspace = XPS_ICC; + } + } + } + + /* See if we need to use the embedded profile. Only used if we + have one and a valid external profile was not specified */ + image->embeddedprofile = false; + if (image->colorspace != XPS_ICC_A && image->colorspace != XPS_ICC && + embedded_profile != NULL) + { + /* See if we can set up to use the embedded profile. Note + these profiles are NOT added to the xps color cache. + As such, they must be destroyed when the image brush ends. + Hence we need to make a note that we are using an embedded + profile. */ + + /* Create the profile */ + iccprofile = gsicc_profile_new(NULL, ctx->memory, NULL, 0); + /* Set buffer */ + iccprofile->buffer = embedded_profile; + iccprofile->buffer_size = profile_size; + /* Parse */ + gsicc_init_profile_info(iccprofile); + + /* Free up the buffer */ + gs_free_object(ctx->memory, embedded_profile, "Embedded Profile"); + iccprofile->buffer = NULL; + iccprofile->buffer_size = 0; + + if (iccprofile->profile_handle == NULL) + { + /* Problem with profile. Just ignore it */ + gsicc_profile_reference(iccprofile, -1); + } + else + { + /* Check the profile is OK for channel data count. + Need to be careful here since alpha is put into + comps */ + if ((image->comps - has_alpha) == gsicc_getsrc_channel_count(iccprofile)) + { + /* Use the embedded profile */ + image->embeddedprofile = true; + ctx->icc->cmm_icc_profile_data = iccprofile; + if (has_alpha) + { + image->colorspace = XPS_ICC_A; + } + else + { + image->colorspace = XPS_ICC; + } + } + else + { + /* Problem with profile. Just ignore it */ + gsicc_profile_reference(iccprofile, -1); + } + + } + } + + /* XPS_ICC_A potentially not set when has_alpha evaluated */ + if (has_alpha || image->colorspace == XPS_ICC_A ) { if (image->bits < 8) dprintf1("cannot isolate alpha channel in %d bpc images\n", image->bits); @@ -209,6 +303,7 @@ xps_paint_image_brush_imp(xps_context_t *ctx, xps_image_t *image, int alpha) case XPS_GRAY: colorspace = ctx->gray; break; case XPS_RGB: colorspace = ctx->srgb; break; case XPS_CMYK: colorspace = ctx->cmyk; break; + case XPS_ICC: colorspace = ctx->icc; break; default: return gs_throw(-1, "cannot draw images with interleaved alpha"); } @@ -290,14 +385,14 @@ xps_paint_image_brush(xps_context_t *ctx, char *base_uri, xps_resource_t *dict, } static int -xps_find_image_brush_source_part(xps_context_t *ctx, char *base_uri, xps_item_t *root, xps_part_t **partp) +xps_find_image_brush_source_part(xps_context_t *ctx, char *base_uri, xps_item_t *root, + xps_part_t **imagepartp, char **profile_name) { - xps_part_t *part; + xps_part_t *imagepart, *iccpart; char *image_source_att; char buf[1024]; char partname[1024]; char *image_name; - char *profile_name; char *p; image_source_att = xps_att(root, "ImageSource"); @@ -308,7 +403,7 @@ xps_find_image_brush_source_part(xps_context_t *ctx, char *base_uri, xps_item_t if (strstr(image_source_att, "{ColorConvertedBitmap") == image_source_att) { image_name = NULL; - profile_name = NULL; + *profile_name = NULL; strcpy(buf, image_source_att); p = strchr(buf, ' '); @@ -319,7 +414,7 @@ xps_find_image_brush_source_part(xps_context_t *ctx, char *base_uri, xps_item_t if (p) { *p = 0; - profile_name = p + 1; + *profile_name = p + 1; p = strchr(p + 1, '}'); if (p) *p = 0; @@ -329,33 +424,33 @@ xps_find_image_brush_source_part(xps_context_t *ctx, char *base_uri, xps_item_t else { image_name = image_source_att; - profile_name = NULL; + *profile_name = NULL; } if (!image_name) return gs_throw1(-1, "cannot parse image resource name '%s'", image_source_att); - if (profile_name) - dprintf2("warning: ignoring color profile '%s' associated with image '%s'\n", - profile_name, image_name); - xps_absolute_path(partname, base_uri, image_name, sizeof partname); - part = xps_read_part(ctx, partname); - if (!part) + imagepart = xps_read_part(ctx, partname); + if (!imagepart) return gs_throw1(-1, "cannot find image resource part '%s'", partname); - *partp = part; + *imagepartp = imagepart; + return 0; } int xps_parse_image_brush(xps_context_t *ctx, char *base_uri, xps_resource_t *dict, xps_item_t *root) { - xps_part_t *part; + xps_part_t *imagepart; xps_image_t *image; int code; + char *profilename; + gs_color_space *colorspace; + int profile_comp = 0; - code = xps_find_image_brush_source_part(ctx, base_uri, root, &part); + code = xps_find_image_brush_source_part(ctx, base_uri, root, &imagepart, &profilename); if (code < 0) return gs_rethrow(code, "cannot find image source"); @@ -363,15 +458,43 @@ xps_parse_image_brush(xps_context_t *ctx, char *base_uri, xps_resource_t *dict, if (!image) return gs_throw(-1, "out of memory: image struct"); - code = xps_decode_image(ctx, part, image); + /* If we have an ICC profile, go ahead and set the color space now. + Make sure the profile is valid etc. If we find one in the image + then we will use that if one is not externally defined. If it is + we get back our ICC color space object. However, we also need + to see if the profile count matches the number of channels in the image. + If it does not, then we do not use the profile. Also we may need + to use the embedded profile */ + + image->colorspace = XPS_NOTICC; + if (profilename != NULL) + { + colorspace = NULL; + xps_set_icc(ctx, base_uri, profilename, &colorspace); + if (colorspace != NULL) + { + /* Now, see what the channel count is */ + profile_comp = + gsicc_getsrc_channel_count(colorspace->cmm_icc_profile_data); + image->colorspace = XPS_ICC; + } + } + + code = xps_decode_image(ctx, profilename, profile_comp, imagepart, image); if (code < 0) return gs_rethrow(-1, "cannot decode image resource"); xps_parse_tiling_brush(ctx, base_uri, dict, root, xps_paint_image_brush, image); + /* If we used an embedded profile. then release as these are not cached */ + if (image->embeddedprofile) + { + gsicc_profile_reference(ctx->icc->cmm_icc_profile_data, -1); + } + xps_free_image(ctx, image); - xps_free_part(ctx, part); + xps_free_part(ctx, imagepart); return 0; } @@ -379,25 +502,27 @@ xps_parse_image_brush(xps_context_t *ctx, char *base_uri, xps_resource_t *dict, int xps_image_brush_has_transparency(xps_context_t *ctx, char *base_uri, xps_item_t *root) { - xps_part_t *part; - xps_image_t *image; + xps_part_t *imagepart, *iccpart; int code; int has_alpha; + char *profilename; - code = xps_find_image_brush_source_part(ctx, base_uri, root, &part); + code = xps_find_image_brush_source_part(ctx, base_uri, root, &imagepart, &profilename); if (code < 0) { gs_catch(code, "cannot find image source"); return 0; } - has_alpha = xps_image_has_alpha(ctx, part); + has_alpha = xps_image_has_alpha(ctx, imagepart); if (has_alpha < 0) { gs_catch(-1, "cannot decode image resource"); return 0; } + xps_free_part(ctx, imagepart); + return has_alpha; } diff --git a/xps/xpsjpeg.c b/xps/xpsjpeg.c index e86f037d8..8a59d1e2f 100644 --- a/xps/xpsjpeg.c +++ b/xps/xpsjpeg.c @@ -30,7 +30,8 @@ xps_report_error(stream_state * st, const char *str) } int -xps_decode_jpeg(gs_memory_t *mem, byte *rbuf, int rlen, xps_image_t *image) +xps_decode_jpeg(gs_memory_t *mem, byte *rbuf, int rlen, xps_image_t *image, + unsigned char **profile, int *profile_size) { jpeg_decompress_data jddp; stream_DCT_state state; @@ -39,6 +40,9 @@ xps_decode_jpeg(gs_memory_t *mem, byte *rbuf, int rlen, xps_image_t *image) int code; int wlen; byte *wbuf; + jpeg_saved_marker_ptr curr_marker; + + *profile = NULL; s_init_state((stream_state*)&state, &s_DCTD_template, mem); state.report_error = xps_report_error; @@ -64,10 +68,34 @@ xps_decode_jpeg(gs_memory_t *mem, byte *rbuf, int rlen, xps_image_t *image) wp.ptr = 0; wp.limit = 0; + /* Set up to save the ICC marker APP2. According to the spec + we should be getting APP1 APP2 and APP13. Library gets APP0 and APP14 */ + jpeg_save_markers(&(jddp.dinfo), 0xe2, 0xFFFF); + code = s_DCTD_template.process((stream_state*)&state, &rp, &wp, true); if (code != 1) return gs_throw(-1, "premature EOF or error in jpeg"); + /* Check if we had an ICC profile */ + curr_marker = jddp.dinfo.marker_list; + while (curr_marker != NULL) + { + if (curr_marker->marker == 0xe2) + { + /* Found ICC profile. Create a buffer and copy over now. Strip + JPEG APP2 14 byte header */ + *profile = (unsigned char*) gs_alloc_bytes(mem, curr_marker->data_length - 14, "JPEG ICC Profile"); + if (*profile != NULL) + { + /* If we can't create it, just ignore */ + memcpy(*profile, &(curr_marker->data[14]), (curr_marker->data_length) - 14); + *profile_size = curr_marker->data_length - 14; + } + break; + } + curr_marker = curr_marker->next; + } + image->width = jddp.dinfo.output_width; image->height = jddp.dinfo.output_height; image->comps = jddp.dinfo.output_components; diff --git a/xps/xpspage.c b/xps/xpspage.c index 2fbeec11c..50879c82c 100644 --- a/xps/xpspage.c +++ b/xps/xpspage.c @@ -221,6 +221,14 @@ xps_parse_fixed_page(xps_context_t *ctx, xps_part_t *part) return gs_rethrow(code, "cannot install transparency device"); } + /* Initialize the default profiles in the ctx to what is in the manager */ + ctx->gray->cmm_icc_profile_data = ctx->pgs->icc_manager->default_gray; + ctx->srgb->cmm_icc_profile_data = ctx->pgs->icc_manager->default_rgb; + /* scrgb really needs to be a bit different. Unless we are handling nonlinearity + before conversion from float . ToDo. */ + ctx->scrgb->cmm_icc_profile_data = ctx->pgs->icc_manager->default_rgb; + ctx->cmyk->cmm_icc_profile_data = ctx->pgs->icc_manager->default_cmyk; + /* Draw contents */ for (node = xps_down(root); node; node = xps_next(node)) diff --git a/xps/xpspng.c b/xps/xpspng.c index 1d99eab14..68616f931 100644 --- a/xps/xpspng.c +++ b/xps/xpspng.c @@ -133,7 +133,8 @@ xps_hasalpha_png(gs_memory_t *mem, byte *rbuf, int rlen) } int -xps_decode_png(gs_memory_t *mem, byte *rbuf, int rlen, xps_image_t *image) +xps_decode_png(gs_memory_t *mem, byte *rbuf, int rlen, xps_image_t *image, + unsigned char **profile, int *profile_size) { png_structp png; png_infop info; @@ -149,6 +150,8 @@ xps_decode_png(gs_memory_t *mem, byte *rbuf, int rlen, xps_image_t *image) io.ptr = rbuf; io.lim = rbuf + rlen; + *profile = NULL; + png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, mem, xps_png_malloc, xps_png_free); @@ -205,6 +208,18 @@ xps_decode_png(gs_memory_t *mem, byte *rbuf, int rlen, xps_image_t *image) image->comps = png_get_channels(png, info); image->bits = png_get_bit_depth(png, info); + /* See if we have an icc profile */ + if (info->iccp_profile != NULL) + { + *profile = (unsigned char*) gs_alloc_bytes(mem, info->iccp_proflen, "PNG ICC Profile"); + if (*profile != NULL) + { + /* If we can't create it, just ignore */ + memcpy(*profile, info->iccp_profile, info->iccp_proflen); + *profile_size = info->iccp_proflen; + } + } + switch (png_get_color_type(png, info)) { case PNG_COLOR_TYPE_GRAY: diff --git a/xps/xpstiff.c b/xps/xpstiff.c index 88a794a35..6dcb8d961 100644 --- a/xps/xpstiff.c +++ b/xps/xpstiff.c @@ -76,6 +76,9 @@ struct xps_tiff_s byte *jpegtables; /* point into "file" buffer */ unsigned jpegtableslen; + + byte *iccprofile; + int profile_size; }; enum @@ -115,6 +118,7 @@ enum #define ExtraSamples 338 #define JPEGTables 347 #define YCbCrSubSampling 520 +#define ICCProfile 34675 static const byte bitrev[256] = { @@ -644,6 +648,7 @@ xps_decode_tiff_strips(gs_memory_t *mem, xps_tiff_t *tiff, xps_image_t *image) case 3: image->xres = tiff->xresolution * 2.54 + 0.5; image->yres = tiff->yresolution * 2.54 + 0.5; + break; default: image->xres = 96; @@ -651,6 +656,14 @@ xps_decode_tiff_strips(gs_memory_t *mem, xps_tiff_t *tiff, xps_image_t *image) break; } + /* Note xres and yres could be 0 even if unit was set. If so + default to 96dpi */ + if (image->xres == 0 || image->yres == 0) + { + image->xres = 96; + image->yres = 96; + } + image->samples = gs_alloc_bytes(mem, image->stride * image->height, "samples"); if (!image->samples) return gs_throw(-1, "could not allocate image samples"); @@ -769,6 +782,20 @@ xps_decode_tiff_strips(gs_memory_t *mem, xps_tiff_t *tiff, xps_image_t *image) } static void +xps_read_tiff_bytes(unsigned char *p, xps_tiff_t *tiff, unsigned ofs, unsigned n) +{ + tiff->rp = tiff->bp + ofs; + if (tiff->rp > tiff->ep) + tiff->rp = tiff->bp; + + while (n--) + { + *p++ = readbyte(tiff); + } +} + + +static void xps_read_tiff_tag_value(unsigned *p, xps_tiff_t *tiff, unsigned type, unsigned ofs, unsigned n) { tiff->rp = tiff->bp + ofs; @@ -869,6 +896,15 @@ xps_read_tiff_tag(gs_memory_t *mem, xps_tiff_t *tiff, unsigned offset) case ExtraSamples: xps_read_tiff_tag_value(&tiff->extrasamples, tiff, type, value, 1); break; + case ICCProfile: + tiff->iccprofile = (unsigned char*) gs_alloc_bytes(mem, count , "TIFF ICC Profile"); + if (!tiff->iccprofile) + return gs_throw(-1, "could not allocate embedded icc profile"); + /* ICC profile data type is set to UNDEFINED. TBYTE reading not correct + in xps_read_tiff_tag_value */ + xps_read_tiff_bytes((unsigned*) tiff->iccprofile, tiff, value, count); + tiff->profile_size = count; + break; case JPEGTables: tiff->jpegtables = tiff->bp + value; @@ -925,7 +961,8 @@ xps_swap_byte_order(byte *buf, int n) } int -xps_decode_tiff(gs_memory_t *mem, byte *buf, int len, xps_image_t *image) +xps_decode_tiff(gs_memory_t *mem, byte *buf, int len, xps_image_t *image, + unsigned char **profile, int *profile_size) { int error; xps_tiff_t tiffst; @@ -937,6 +974,7 @@ xps_decode_tiff(gs_memory_t *mem, byte *buf, int len, xps_image_t *image) unsigned i; memset(tiff, 0, sizeof(xps_tiff_t)); + *profile = NULL; tiff->bp = buf; tiff->rp = buf; @@ -1011,6 +1049,9 @@ xps_decode_tiff(gs_memory_t *mem, byte *buf, int len, xps_image_t *image) if (tiff->stripoffsets) gs_free_object(mem, tiff->stripoffsets, "StripOffsets"); if (tiff->stripbytecounts) gs_free_object(mem, tiff->stripbytecounts, "StripByteCounts"); + *profile = tiff->iccprofile; + *profile_size = tiff->profile_size; + /* * Byte swap 16-bit images to big endian if necessary. */ diff --git a/xps/xpstop.c b/xps/xpstop.c index 6a2894223..a213c47c4 100644 --- a/xps/xpstop.c +++ b/xps/xpstop.c @@ -90,6 +90,7 @@ xps_imp_allocate_interp_instance(pl_interp_instance_t **ppinstance, xps_interp_instance_t *instance; xps_context_t *ctx; gs_state *pgs; + int code; instance = (xps_interp_instance_t *) gs_alloc_bytes(pmem, sizeof(xps_interp_instance_t), "xps_imp_allocate_interp_instance"); @@ -122,11 +123,15 @@ xps_imp_allocate_interp_instance(pl_interp_instance_t **ppinstance, ctx->zip_count = 0; ctx->zip_table = NULL; - /* TODO: load some builtin ICC profiles here */ - ctx->gray = gs_cspace_new_DeviceGray(ctx->memory); /* profile for gray images */ - ctx->cmyk = gs_cspace_new_DeviceCMYK(ctx->memory); /* profile for cmyk images */ + /* Gray, RGB and CMYK profiles set when color spaces installed in graphics lib */ + ctx->gray = gs_cspace_new_DeviceGray(ctx->memory); + ctx->cmyk = gs_cspace_new_DeviceCMYK(ctx->memory); ctx->srgb = gs_cspace_new_DeviceRGB(ctx->memory); - ctx->scrgb = gs_cspace_new_DeviceRGB(ctx->memory); + ctx->scrgb = gs_cspace_new_DeviceRGB(ctx->memory); /* This needs a different profile */ + code = gs_cspace_build_ICC(&(ctx->icc), NULL, ctx->memory); /* For profile color spaces */ + if (code < 0) + return gs_error_VMerror; + instance->pre_page_action = 0; instance->pre_page_closure = 0; |