diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2011-03-31 03:18:51 +0200 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2011-03-31 03:18:51 +0200 |
commit | b3f90095897b64f854efc4b2f37df428a71fd508 (patch) | |
tree | 27ad639a052b967e1fdc03f7d58ff63b5b0a8f46 | |
parent | 4f484b32f3cf8682180ccb9e36f929edff175498 (diff) | |
download | mupdf-b3f90095897b64f854efc4b2f37df428a71fd508.tar.xz |
xps: Clean up image loading code, and handle images with alpha.
-rw-r--r-- | draw/imageunpack.c | 10 | ||||
-rw-r--r-- | fitz/fitz.h | 1 | ||||
-rw-r--r-- | fitz/res_pixmap.c | 18 | ||||
-rw-r--r-- | xps/muxps.h | 28 | ||||
-rw-r--r-- | xps/xpsimage.c | 76 | ||||
-rw-r--r-- | xps/xpsjpeg.c | 59 | ||||
-rw-r--r-- | xps/xpsjxr.c | 257 | ||||
-rw-r--r-- | xps/xpspng.c | 178 | ||||
-rw-r--r-- | xps/xpstiff.c | 207 |
9 files changed, 221 insertions, 613 deletions
diff --git a/draw/imageunpack.c b/draw/imageunpack.c index bbc22c70..2c7cb452 100644 --- a/draw/imageunpack.c +++ b/draw/imageunpack.c @@ -58,6 +58,16 @@ fz_unpacktile(fz_pixmap *dst, unsigned char * restrict src, int n, int depth, in if (depth == 1) initget1tables(); + if (scale == 0) + { + switch (depth) + { + case 1: scale = 255; break; + case 2: scale = 85; break; + case 4: scale = 17; break; + } + } + for (y = 0; y < dst->h; y++) { unsigned char *sp = src + y * stride; diff --git a/fitz/fitz.h b/fitz/fitz.h index 72af4532..5d3ba1c1 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -685,6 +685,7 @@ fz_pixmap *fz_keeppixmap(fz_pixmap *pix); void fz_droppixmap(fz_pixmap *pix); void fz_clearpixmap(fz_pixmap *pix); void fz_clearpixmapwithcolor(fz_pixmap *pix, int value); +void fz_premultiplypixmap(fz_pixmap *pix); fz_pixmap *fz_alphafromgray(fz_pixmap *gray, int luminosity); fz_bbox fz_boundpixmap(fz_pixmap *pix); diff --git a/fitz/res_pixmap.c b/fitz/res_pixmap.c index e70d084d..b37b7a3e 100644 --- a/fitz/res_pixmap.c +++ b/fitz/res_pixmap.c @@ -97,6 +97,24 @@ fz_clearpixmapwithcolor(fz_pixmap *pix, int value) } } +void +fz_premultiplypixmap(fz_pixmap *pix) +{ + unsigned char *s = pix->samples; + unsigned char a; + int k, x, y; + for (y = 0; y < pix->h; y++) + { + for (x = 0; x < pix->w; x++) + { + a = s[pix->n - 1]; + for (k = 0; k < pix->n - 1; k++) + s[k] = fz_mul255(s[k], a); + s += pix->n; + } + } +} + fz_bbox fz_boundpixmap(fz_pixmap *pix) { diff --git a/xps/muxps.h b/xps/muxps.h index ba826b10..1b137a59 100644 --- a/xps/muxps.h +++ b/xps/muxps.h @@ -97,35 +97,21 @@ void xps_debug_fixdocseq(xps_context *ctx); * Images. */ -typedef struct xps_image_s xps_image; +typedef struct xps_image xps_image; /* type for the information derived directly from the raster file format */ -struct xps_image_s +struct xps_image { - int width; - int height; - int stride; - fz_colorspace *colorspace; - int comps; - int hasalpha; /* chunky alpha */ - int bits; + fz_pixmap *pixmap; int xres; int yres; - byte *samples; - byte *profile; - int profilesize; - fz_pixmap *pixmap; }; -int xps_decode_jpeg(xps_context *ctx, byte *rbuf, int rlen, xps_image *image); -int xps_decode_png(xps_context *ctx, byte *rbuf, int rlen, xps_image *image); -int xps_decode_tiff(xps_context *ctx, byte *rbuf, int rlen, xps_image *image); -int xps_decode_jpegxr(xps_context *ctx, byte *buf, int len, xps_image *image); - -int xps_png_has_alpha(xps_context *ctx, byte *rbuf, int rlen); -int xps_tiff_has_alpha(xps_context *ctx, byte *rbuf, int rlen); -int xps_jpegxr_has_alpha(xps_context *ctx, byte *buf, int len); +int xps_decode_jpeg(xps_image **imagep, xps_context *ctx, byte *rbuf, int rlen); +int xps_decode_png(xps_image **imagep, xps_context *ctx, byte *rbuf, int rlen); +int xps_decode_tiff(xps_image **imagep, xps_context *ctx, byte *rbuf, int rlen); +int xps_decode_jpegxr(xps_image **imagep, xps_context *ctx, byte *rbuf, int rlen); void xps_free_image(xps_context *ctx, xps_image *image); diff --git a/xps/xpsimage.c b/xps/xpsimage.c index 7dcb54aa..8fc2f7a1 100644 --- a/xps/xpsimage.c +++ b/xps/xpsimage.c @@ -2,7 +2,7 @@ #include "muxps.h" static int -xps_decode_image(xps_context *ctx, xps_part *part, xps_image *image) +xps_decode_image(xps_image **imagep, xps_context *ctx, xps_part *part) { byte *buf = part->data; int len = part->size; @@ -11,40 +11,33 @@ xps_decode_image(xps_context *ctx, xps_part *part, xps_image *image) if (len < 8) return fz_throw("unknown image file format"); - memset(image, 0, sizeof(xps_image)); - if (buf[0] == 0xff && buf[1] == 0xd8) { - error = xps_decode_jpeg(ctx, buf, len, image); + error = xps_decode_jpeg(imagep, ctx, buf, len); if (error) return fz_rethrow(error, "cannot decode jpeg image"); } else if (memcmp(buf, "\211PNG\r\n\032\n", 8) == 0) { - error = xps_decode_png(ctx, buf, len, image); + error = xps_decode_png(imagep, ctx, buf, len); if (error) return fz_rethrow(error, "cannot decode png image"); } else if (memcmp(buf, "II", 2) == 0 && buf[2] == 0xBC) { - error = xps_decode_jpegxr(ctx, buf, len, image); + error = xps_decode_jpegxr(imagep, ctx, buf, len); if (error) return fz_rethrow(error, "cannot decode JPEG-XR image"); } else if (memcmp(buf, "MM", 2) == 0 || memcmp(buf, "II", 2) == 0) { - error = xps_decode_tiff(ctx, buf, len, image); + error = xps_decode_tiff(imagep, ctx, buf, len); if (error) return fz_rethrow(error, "cannot decode TIFF image"); } else return fz_throw("unknown image file format"); - image->pixmap = fz_newpixmap(image->colorspace, 0, 0, image->width, image->height); - fz_unpacktile(image->pixmap, image->samples, image->comps, image->bits, image->stride, 1); - fz_free(image->samples); - image->samples = NULL; - return fz_okay; } @@ -52,19 +45,18 @@ static void xps_paint_image_brush(xps_context *ctx, fz_matrix ctm, char *base_uri, xps_resource *dict, xps_item *root, void *vimage) { xps_image *image = vimage; - float xs = image->width * 96.0 / image->xres; - float ys = image->height * 96.0 / image->yres; + fz_pixmap *pixmap = image->pixmap; + float xs = pixmap->w * 96.0 / image->xres; + float ys = pixmap->h * 96.0 / image->yres; fz_matrix im = fz_scale(xs, -ys); im.f = ys; ctm = fz_concat(im, ctm); - ctx->dev->fillimage(ctx->dev->user, image->pixmap, ctm, 1.0); + ctx->dev->fillimage(ctx->dev->user, pixmap, ctm, 1.0); } -static int -xps_find_image_brush_source_part(xps_context *ctx, char *base_uri, xps_item *root, - xps_part **partp, char **profilep) +static xps_part * +xps_find_image_brush_source_part(xps_context *ctx, char *base_uri, xps_item *root) { - xps_part *part; char *image_source_att; char buf[1024]; char partname[1024]; @@ -74,7 +66,7 @@ xps_find_image_brush_source_part(xps_context *ctx, char *base_uri, xps_item *roo image_source_att = xps_att(root, "ImageSource"); if (!image_source_att) - return fz_throw("missing ImageSource attribute"); + return NULL; /* "{ColorConvertedBitmap /Resources/Image.tiff /Resources/Profile.icc}" */ if (strstr(image_source_att, "{ColorConvertedBitmap") == image_source_att) @@ -105,18 +97,11 @@ xps_find_image_brush_source_part(xps_context *ctx, char *base_uri, xps_item *roo } if (!image_name) - return fz_throw("cannot parse image resource name '%s'", image_source_att); + return NULL; xps_absolute_path(partname, base_uri, image_name, sizeof partname); - part = xps_read_part(ctx, partname); - if (!part) - return fz_throw("cannot find image resource part '%s'", partname); - *partp = part; - if (profile_name) - *profilep = fz_strdup(profile_name); - - return 0; + return xps_read_part(ctx, partname); } void @@ -124,42 +109,22 @@ xps_parse_image_brush(xps_context *ctx, fz_matrix ctm, char *base_uri, xps_resou { xps_part *part; xps_image *image; - fz_colorspace *colorspace; - char *profilename; int code; - profilename = NULL; - - code = xps_find_image_brush_source_part(ctx, base_uri, root, &part, &profilename); - if (code < 0) { - fz_catch(code, "cannot find image source"); + part = xps_find_image_brush_source_part(ctx, base_uri, root); + if (!part) { + fz_warn("cannot find image source"); return; } - image = fz_malloc(sizeof(xps_image)); - - code = xps_decode_image(ctx, part, image); + code = xps_decode_image(&image, ctx, part); if (code < 0) { - fz_free(image); fz_catch(-1, "cannot decode image resource"); return; } - /* Override any embedded colorspace profiles if the external one matches. */ - if (profilename) - { - colorspace = xps_read_icc_colorspace(ctx, base_uri, profilename); - if (colorspace && colorspace->n == image->colorspace->n) - { - // TODO: refcount image->colorspace - image->colorspace = colorspace; - } - } - xps_parse_tiling_brush(ctx, ctm, base_uri, dict, root, xps_paint_image_brush, image); - if (profilename) - fz_free(profilename); xps_free_image(ctx, image); xps_free_part(ctx, part); } @@ -167,12 +132,7 @@ xps_parse_image_brush(xps_context *ctx, fz_matrix ctm, char *base_uri, xps_resou void xps_free_image(xps_context *ctx, xps_image *image) { - // TODO: refcount image->colorspace if (image->pixmap) fz_droppixmap(image->pixmap); - if (image->samples) - fz_free(image->samples); - if (image->profile) - fz_free(image->profile); fz_free(image); } diff --git a/xps/xpsjpeg.c b/xps/xpsjpeg.c index 41534eeb..4dc2a7e4 100644 --- a/xps/xpsjpeg.c +++ b/xps/xpsjpeg.c @@ -48,18 +48,21 @@ static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) } int -xps_decode_jpeg(xps_context *ctx, byte *rbuf, int rlen, xps_image *image) +xps_decode_jpeg(xps_image **imagep, xps_context *ctx, byte *rbuf, int rlen) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr_jmp err; struct jpeg_source_mgr src; - unsigned char *buffer[1]; + unsigned char *row[1], *sp, *dp; + fz_colorspace *colorspace; + int x, k; + + xps_image *image = NULL; if (setjmp(err.env)) { - if (image->samples) - fz_free(image->samples); - image->samples = NULL; + if (image) + xps_free_image(ctx, image); return fz_throw("jpeg error: %s", err.msg); } @@ -81,19 +84,19 @@ xps_decode_jpeg(xps_context *ctx, byte *rbuf, int rlen, xps_image *image) jpeg_start_decompress(&cinfo); - image->width = cinfo.output_width; - image->height = cinfo.output_height; - image->comps = cinfo.output_components; - image->stride = cinfo.output_width * cinfo.output_components; - image->bits = 8; - image->samples = fz_calloc(image->height, image->stride); + if (cinfo.output_components == 1) + colorspace = fz_devicegray; + else if (cinfo.output_components == 3) + colorspace = fz_devicergb; + else if (cinfo.output_components == 4) + colorspace = fz_devicecmyk; + else + return fz_throw("bad number of components in jpeg: %d", cinfo.output_components); - if (image->comps == 1) - image->colorspace = fz_devicegray; - if (image->comps == 3) - image->colorspace = fz_devicergb; - if (image->comps == 4) - image->colorspace = fz_devicecmyk; + image = fz_malloc(sizeof(xps_image)); + image->pixmap = fz_newpixmap(colorspace, 0, 0, cinfo.output_width, cinfo.output_height); + image->xres = 96; + image->yres = 96; if (cinfo.density_unit == 1) { @@ -105,23 +108,27 @@ xps_decode_jpeg(xps_context *ctx, byte *rbuf, int rlen, xps_image *image) image->xres = cinfo.X_density * 2.54; image->yres = cinfo.Y_density * 2.54; } - else - { - image->xres = 96; - image->yres = 96; - } - memset(image->samples, 127, image->stride * image->height); + fz_clearpixmap(image->pixmap); - buffer[0] = image->samples; + row[0] = fz_malloc(cinfo.output_components * cinfo.output_width); + dp = image->pixmap->samples; while (cinfo.output_scanline < cinfo.output_height) { - jpeg_read_scanlines(&cinfo, buffer, 1); - buffer[0] += image->comps * image->width; + jpeg_read_scanlines(&cinfo, row, 1); + sp = row[0]; + for (x = 0; x < cinfo.output_width; x++) + { + for (k = 0; k < cinfo.output_components; k++) + *dp++ = *sp++; + *dp++ = 255; + } } + fz_free(row[0]); jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); + *imagep = image; return fz_okay; } diff --git a/xps/xpsjxr.c b/xps/xpsjxr.c index bbe5f66e..9499bdec 100644 --- a/xps/xpsjxr.c +++ b/xps/xpsjxr.c @@ -3,263 +3,8 @@ #include "fitz.h" #include "muxps.h" -#ifdef HAVE_JPEGXR - -#ifdef _MSC_VER -#undef _MSC_VER -#endif - -#include "jpegxr.h" - -struct state { xps_context *ctx; xps_image *output; }; - -static const char * -jxr_error_string(int code) -{ - switch (code) - { - case JXR_EC_OK: return "No error"; - default: - case JXR_EC_ERROR: return "Unspecified error"; - case JXR_EC_BADMAGIC: return "Stream lacks proper magic number"; - case JXR_EC_FEATURE_NOT_IMPLEMENTED: return "Feature not implemented"; - case JXR_EC_IO: return "Error reading/writing data"; - case JXR_EC_BADFORMAT: return "Bad file format"; - } -} - -#define CLAMP(v, mn, mx) (v < mn ? mn : v > mx ? mx : v) - -static inline int -scale_bits(int depth, int value) -{ - union { int iv; float fv; } bd32f; - - switch (depth) - { - case JXR_BD1WHITE1: - return value * 255; - case JXR_BD1BLACK1: - return value ? 0 : 255; - case JXR_BD8: - return value; - case JXR_BD16: - return value >> 8; - case JXR_BD16S: /* -4 .. 4 ; 8192 = 1.0 */ - value = value >> 5; - return CLAMP(value, 0, 255); - case JXR_BD32S: /* -128 .. 128 ; 16777216 = 1.0 */ - value = value >> 16; - return CLAMP(value, 0, 255); - case JXR_BD32F: - bd32f.iv = value; - value = bd32f.fv * 255; - return CLAMP(value, 0, 255); -#if 0 - case JXR_BDRESERVED: return value; - case JXR_BD16F: return value; - case JXR_BD5: return value; - case JXR_BD10: return value; - case JXR_BD565: return value; -#endif - } - return value; -} - -static void -xps_decode_jpegxr_block(jxr_image image, int mx, int my, int *data) -{ - struct state *state = jxr_get_user_data(image); - xps_context *ctx = state->ctx; - xps_image *output = state->output; - int depth; - unsigned char *p; - int x, y, k; - - if (!output->samples) - { - output->width = jxr_get_IMAGE_WIDTH(image); - output->height = jxr_get_IMAGE_HEIGHT(image); - output->comps = jxr_get_IMAGE_CHANNELS(image); - output->hasalpha = jxr_get_ALPHACHANNEL_FLAG(image); - output->bits = 8; - output->stride = output->width * output->comps; - output->samples = fz_malloc(output->stride * output->height); - - switch (output->comps) - { - default: - case 1: output->colorspace = ctx->gray; break; - case 3: output->colorspace = ctx->srgb; break; - case 4: output->colorspace = ctx->cmyk; break; - } - } - - depth = jxr_get_OUTPUT_BITDEPTH(image); - - my = my * 16; - mx = mx * 16; - - for (y = 0; y < 16; y++) - { - if (my + y >= output->height) - return; - p = output->samples + (my + y) * output->stride + mx * output->comps; - for (x = 0; x < 16; x++) - { - if (mx + x >= output->width) - data += output->comps; - else - for (k = 0; k < output->comps; k++) - *p++ = scale_bits(depth, *data++); - } - } -} - -static void -xps_decode_jpegxr_alpha_block(jxr_image image, int mx, int my, int *data) -{ - struct state *state = jxr_get_user_data(image); - xps_context *ctx = state->ctx; - xps_image *output = state->output; - int depth; - unsigned char *p; - int x, y, k; - - if (!output->alpha) - { - output->alpha = fz_malloc(output->width * output->height); - } - - depth = jxr_get_OUTPUT_BITDEPTH(image); - - my = my * 16; - mx = mx * 16; - - for (y = 0; y < 16; y++) - { - if (my + y >= output->height) - return; - p = output->alpha + (my + y) * output->width + mx; - for (x = 0; x < 16; x++) - { - if (mx + x >= output->width) - data ++; - else - *p++ = scale_bits(depth, *data++); - } - } -} - int -xps_decode_jpegxr(xps_context *ctx, byte *buf, int len, xps_image *output) -{ - FILE *file; - char name[gp_file_name_sizeof]; - struct state state; - jxr_container container; - jxr_image image; - int offset, alpha_offset; - int rc; - - memset(output, 0, sizeof(*output)); - - file = gp_open_scratch_file(ctx->memory, "jpegxr-scratch-", name, "wb+"); - if (!file) - return gs_throw(gs_error_invalidfileaccess, "cannot open scratch file"); - rc = fwrite(buf, 1, len, file); - if (rc != len) - return gs_throw(gs_error_invalidfileaccess, "cannot write to scratch file"); - fseek(file, 0, SEEK_SET); - - container = jxr_create_container(); - rc = jxr_read_image_container(container, file); - if (rc < 0) - return gs_throw1(-1, "jxr_read_image_container: %s", jxr_error_string(rc)); - - offset = jxrc_image_offset(container, 0); - alpha_offset = jxrc_alpha_offset(container, 0); - - output->xres = jxrc_width_resolution(container, 0); - output->yres = jxrc_height_resolution(container, 0); - - image = jxr_create_input(); - jxr_set_PROFILE_IDC(image, 111); - jxr_set_LEVEL_IDC(image, 255); - jxr_set_pixel_format(image, jxrc_image_pixelformat(container, 0)); - jxr_set_container_parameters(image, - jxrc_image_pixelformat(container, 0), - jxrc_image_width(container, 0), - jxrc_image_height(container, 0), - jxrc_alpha_offset(container, 0), - jxrc_image_band_presence(container, 0), - jxrc_alpha_band_presence(container, 0), 0); - - jxr_set_block_output(image, xps_decode_jpegxr_block); - state.ctx = ctx; - state.output = output; - jxr_set_user_data(image, &state); - - fseek(file, offset, SEEK_SET); - rc = jxr_read_image_bitstream(image, file); - if (rc < 0) - return gs_throw1(-1, "jxr_read_image_bitstream: %s", jxr_error_string(rc)); - - jxr_destroy(image); - - if (alpha_offset > 0) - { - image = jxr_create_input(); - jxr_set_PROFILE_IDC(image, 111); - jxr_set_LEVEL_IDC(image, 255); - jxr_set_pixel_format(image, jxrc_image_pixelformat(container, 0)); - jxr_set_container_parameters(image, - jxrc_image_pixelformat(container, 0), - jxrc_image_width(container, 0), - jxrc_image_height(container, 0), - jxrc_alpha_offset(container, 0), - jxrc_image_band_presence(container, 0), - jxrc_alpha_band_presence(container, 0), 0); - - jxr_set_block_output(image, xps_decode_jpegxr_alpha_block); - state.ctx = ctx; - state.output = output; - jxr_set_user_data(image, &state); - - fseek(file, alpha_offset, SEEK_SET); - rc = jxr_read_image_bitstream(image, file); - if (rc < 0) - return gs_throw1(-1, "jxr_read_image_bitstream: %s", jxr_error_string(rc)); - - jxr_destroy(image); - } - - jxr_destroy_container(container); - - fclose(file); - unlink(name); - - return fz_okay; -} - -int -xps_jpegxr_has_alpha(xps_context *ctx, byte *buf, int len) -{ - return 1; -} - -#else - -int -xps_decode_jpegxr(xps_context *ctx, byte *buf, int len, xps_image *image) +xps_decode_jpegxr(xps_image **imagep, xps_context *ctx, byte *rbuf, int rlen) { return fz_throw("JPEG-XR codec is not available"); } - -int -xps_jpegxr_has_alpha(xps_context *ctx, byte *buf, int len) -{ - return 0; -} - -#endif diff --git a/xps/xpspng.c b/xps/xpspng.c index 641101fe..6af62e63 100644 --- a/xps/xpspng.c +++ b/xps/xpspng.c @@ -3,10 +3,6 @@ #include <png.h> -/* - * PNG using libpng directly (no gs wrappers) - */ - struct xps_png_io_s { byte *ptr; @@ -35,94 +31,20 @@ xps_png_free(png_structp png, png_voidp ptr) fz_free(ptr); } -/* This only determines if we have an alpha value */ -int -xps_png_has_alpha(xps_context *ctx, byte *rbuf, int rlen) -{ - png_structp png; - png_infop info; - struct xps_png_io_s io; - int has_alpha; - - /* - * Set up PNG structs and input source - */ - - io.ptr = rbuf; - io.lim = rbuf + rlen; - - png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, - NULL, NULL, NULL, - ctx, xps_png_malloc, xps_png_free); - if (!png) { - fz_warn("png_create_read_struct"); - return 0; - } - - info = png_create_info_struct(png); - if (!info) { - fz_warn("png_create_info_struct"); - return 0; - } - - png_set_read_fn(png, &io, xps_png_read); - png_set_crc_action(png, PNG_CRC_WARN_USE, PNG_CRC_WARN_USE); - - /* - * Jump to here on errors. - */ - - if (setjmp(png_jmpbuf(png))) - { - png_destroy_read_struct(&png, &info, NULL); - fz_warn("png reading failed"); - return 0; - } - - /* - * Read PNG header - */ - - png_read_info(png, info); - - switch (png_get_color_type(png, info)) - { - case PNG_COLOR_TYPE_PALETTE: - case PNG_COLOR_TYPE_GRAY: - case PNG_COLOR_TYPE_RGB: - has_alpha = 0; - break; - - case PNG_COLOR_TYPE_GRAY_ALPHA: - case PNG_COLOR_TYPE_RGB_ALPHA: - has_alpha = 1; - break; - - default: - fz_warn("cannot handle this png color type"); - has_alpha = 0; - break; - } - - /* - * Clean up memory. - */ - - png_destroy_read_struct(&png, &info, NULL); - - return has_alpha; -} - int -xps_decode_png(xps_context *ctx, byte *rbuf, int rlen, xps_image *image) +xps_decode_png(xps_image **imagep, xps_context *ctx, byte *rbuf, int rlen) { png_structp png; png_infop info; struct xps_png_io_s io; + int width, height, stride, premul; int npasses; int pass; int y; + fz_pixmap *pixmap = NULL; + xps_image *image = NULL; + /* * Set up PNG structs and input source */ @@ -149,8 +71,12 @@ xps_decode_png(xps_context *ctx, byte *rbuf, int rlen, xps_image *image) if (setjmp(png_jmpbuf(png))) { + if (pixmap) + fz_droppixmap(pixmap); + if (image) + fz_free(image); png_destroy_read_struct(&png, &info, NULL); - return fz_throw("png reading failed"); + return fz_throw("cannot read png image"); } /* @@ -160,77 +86,49 @@ xps_decode_png(xps_context *ctx, byte *rbuf, int rlen, xps_image *image) png_read_info(png, info); if (png_get_interlace_type(png, info) == PNG_INTERLACE_ADAM7) - { npasses = png_set_interlace_handling(png); - } else - { npasses = 1; - } - if (png_get_color_type(png, info) == PNG_COLOR_TYPE_PALETTE) - { - png_set_palette_to_rgb(png); - } + png_set_expand(png); + png_set_packing(png); + png_set_strip_16(png); - if (png_get_valid(png, info, PNG_INFO_tRNS)) - { - /* this will also expand the depth to 8-bits */ - png_set_tRNS_to_alpha(png); - } + premul = 0; + if (png_get_color_type(png, info) == PNG_COLOR_TYPE_GRAY) + png_set_add_alpha(png, 0xff, PNG_FILLER_AFTER); + else if (png_get_color_type(png, info) == PNG_COLOR_TYPE_RGB) + png_set_add_alpha(png, 0xff, PNG_FILLER_AFTER); + else + premul = 1; png_read_update_info(png, info); - image->width = png_get_image_width(png, info); - image->height = png_get_image_height(png, info); - 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) - { - image->profilesize = info->iccp_proflen; - image->profile = fz_malloc(info->iccp_proflen); - if (image->profile) - { - /* If we can't create it, just ignore */ - memcpy(image->profile, info->iccp_profile, info->iccp_proflen); - } - } + width = png_get_image_width(png, info); + height = png_get_image_height(png, info); + stride = png_get_rowbytes(png, info); switch (png_get_color_type(png, info)) { - case PNG_COLOR_TYPE_GRAY: - image->colorspace = fz_devicegray; - image->hasalpha = 0; - break; - - case PNG_COLOR_TYPE_RGB: - image->colorspace = fz_devicergb; - image->hasalpha = 0; - break; - case PNG_COLOR_TYPE_GRAY_ALPHA: - image->colorspace = fz_devicegray; - image->hasalpha = 1; + pixmap = fz_newpixmap(fz_devicegray, 0, 0, width, height); break; - case PNG_COLOR_TYPE_RGB_ALPHA: - image->colorspace = fz_devicergb; - image->hasalpha = 1; + pixmap = fz_newpixmap(fz_devicergb, 0, 0, width, height); break; - default: return fz_throw("cannot handle this png color type"); } + image = fz_malloc(sizeof(xps_image)); + image->pixmap = pixmap; + image->xres = 96; + image->yres = 96; + /* * Extract DPI, default to 96 dpi */ - image->xres = 96; - image->yres = 96; - if (info->valid & PNG_INFO_pHYs) { png_uint_32 xres, yres; @@ -247,17 +145,12 @@ xps_decode_png(xps_context *ctx, byte *rbuf, int rlen, xps_image *image) * Read rows, filling transformed output into image buffer. */ - image->stride = (image->width * image->comps * image->bits + 7) / 8; - - image->samples = fz_calloc(image->height, image->stride); - for (pass = 0; pass < npasses; pass++) - { - for (y = 0; y < image->height; y++) - { - png_read_row(png, image->samples + (y * image->stride), NULL); - } - } + for (y = 0; y < height; y++) + png_read_row(png, pixmap->samples + (y * stride), NULL); + + if (premul) + fz_premultiplypixmap(pixmap); /* * Clean up memory. @@ -265,5 +158,6 @@ xps_decode_png(xps_context *ctx, byte *rbuf, int rlen, xps_image *image) png_destroy_read_struct(&png, &info, NULL); + *imagep = image; return fz_okay; } diff --git a/xps/xpstiff.c b/xps/xpstiff.c index 30150a93..4c9494f2 100644 --- a/xps/xpstiff.c +++ b/xps/xpstiff.c @@ -10,9 +10,9 @@ * TODO: RGBPal images */ -typedef struct xps_tiff_s xps_tiff; +typedef struct xps_tiff xps_tiff; -struct xps_tiff_s +struct xps_tiff { /* "file" */ byte *bp, *rp, *ep; @@ -53,6 +53,11 @@ struct xps_tiff_s byte *profile; int profilesize; + + /* decoded data */ + fz_colorspace *colorspace; + byte *samples; + int stride; }; enum @@ -134,6 +139,7 @@ static int xps_decode_tiff_uncompressed(xps_context *ctx, xps_tiff *tiff, fz_stream *stm, byte *wp, int wlen) { int n = fz_read(stm, wp, wlen); + fz_close(stm); if (n < 0) return fz_rethrow(n, "cannot read uncompressed strip"); return fz_okay; @@ -297,9 +303,9 @@ xps_invert_tiff(byte *line, int width, int comps, int bits, int alpha) } static int -xps_expand_colormap(xps_context *ctx, xps_tiff *tiff, xps_image *image) +xps_expand_tiff_colormap(xps_context *ctx, xps_tiff *tiff) { - int maxval = 1 << image->bits; + int maxval = 1 << tiff->bitspersample; byte *samples; byte *src, *dst; int stride; @@ -309,37 +315,37 @@ xps_expand_colormap(xps_context *ctx, xps_tiff *tiff, xps_image *image) /* colormap values are 0..65535, bits is 4 or 8 */ /* image can be with or without extrasamples: comps is 1 or 2 */ - if (image->comps != 1 && image->comps != 2) + if (tiff->samplesperpixel != 1 && tiff->samplesperpixel != 2) return fz_throw("invalid number of samples for RGBPal"); - if (image->bits != 4 && image->bits != 8) + if (tiff->bitspersample != 4 && tiff->bitspersample != 8) return fz_throw("invalid number of bits for RGBPal"); - stride = image->width * (image->comps + 2); + stride = tiff->imagewidth * (tiff->samplesperpixel + 2); - samples = fz_malloc(stride * image->height); + samples = fz_malloc(stride * tiff->imagelength); if (!samples) return fz_throw("out of memory: samples"); - for (y = 0; y < image->height; y++) + for (y = 0; y < tiff->imagelength; y++) { - src = image->samples + (image->stride * y); + src = tiff->samples + (tiff->stride * y); dst = samples + (stride * y); - for (x = 0; x < image->width; x++) + for (x = 0; x < tiff->imagewidth; x++) { if (tiff->extrasamples) { - int c = getcomp(src, x * 2, image->bits); - int a = getcomp(src, x * 2 + 1, image->bits); + int c = getcomp(src, x * 2, tiff->bitspersample); + int a = getcomp(src, x * 2 + 1, tiff->bitspersample); *dst++ = tiff->colormap[c + 0] >> 8; *dst++ = tiff->colormap[c + maxval] >> 8; *dst++ = tiff->colormap[c + maxval * 2] >> 8; - *dst++ = a << (8 - image->bits); + *dst++ = a << (8 - tiff->bitspersample); } else { - int c = getcomp(src, x, image->bits); + int c = getcomp(src, x, tiff->bitspersample); *dst++ = tiff->colormap[c + 0] >> 8; *dst++ = tiff->colormap[c + maxval] >> 8; *dst++ = tiff->colormap[c + maxval * 2] >> 8; @@ -347,15 +353,15 @@ xps_expand_colormap(xps_context *ctx, xps_tiff *tiff, xps_image *image) } } - image->bits = 8; - image->stride = stride; - image->samples = samples; + tiff->bitspersample = 8; + tiff->stride = stride; + tiff->samples = samples; return fz_okay; } static int -xps_decode_tiff_strips(xps_context *ctx, xps_tiff *tiff, xps_image *image) +xps_decode_tiff_strips(xps_context *ctx, xps_tiff *tiff) { fz_buffer buf; fz_stream *stm; @@ -381,32 +387,28 @@ xps_decode_tiff_strips(xps_context *ctx, xps_tiff *tiff, xps_image *image) if (tiff->planar != 1) return fz_throw("image data is not in chunky format"); - image->width = tiff->imagewidth; - image->height = tiff->imagelength; - image->comps = tiff->samplesperpixel; - image->bits = tiff->bitspersample; - image->stride = (image->width * image->comps * image->bits + 7) / 8; + tiff->stride = (tiff->imagewidth * tiff->samplesperpixel * tiff->bitspersample + 7) / 8; switch (tiff->photometric) { case 0: /* WhiteIsZero -- inverted */ - image->colorspace = fz_devicegray; + tiff->colorspace = fz_devicegray; break; case 1: /* BlackIsZero */ - image->colorspace = fz_devicegray; + tiff->colorspace = fz_devicegray; break; case 2: /* RGB */ - image->colorspace = fz_devicergb; + tiff->colorspace = fz_devicergb; break; case 3: /* RGBPal */ - image->colorspace = fz_devicergb; + tiff->colorspace = fz_devicergb; break; case 5: /* CMYK */ - image->colorspace = fz_devicecmyk; + tiff->colorspace = fz_devicecmyk; break; case 6: /* YCbCr */ /* it's probably a jpeg ... we let jpeg convert to rgb */ - image->colorspace = fz_devicergb; + tiff->colorspace = fz_devicergb; break; default: return fz_throw("unknown photometric: %d", tiff->photometric); @@ -415,43 +417,39 @@ xps_decode_tiff_strips(xps_context *ctx, xps_tiff *tiff, xps_image *image) switch (tiff->resolutionunit) { case 2: - image->xres = tiff->xresolution; - image->yres = tiff->yresolution; + /* no unit conversion needed */ break; case 3: - image->xres = tiff->xresolution * 2.54 + 0.5; - image->yres = tiff->yresolution * 2.54 + 0.5; - + tiff->xresolution *= 2.54; + tiff->yresolution *= 2.54; break; default: - image->xres = 96; - image->yres = 96; + tiff->xresolution = 96; + tiff->yresolution = 96; 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) + /* Note xres and yres could be 0 even if unit was set. If so default to 96dpi. */ + if (tiff->xresolution == 0 || tiff->yresolution == 0) { - image->xres = 96; - image->yres = 96; + tiff->xresolution = 96; + tiff->yresolution = 96; } - image->samples = fz_malloc(image->stride * image->height); - - memset(image->samples, 0x55, image->stride * image->height); - - wp = image->samples; + tiff->samples = fz_calloc(tiff->imagelength, tiff->stride); + memset(tiff->samples, 0x55, tiff->imagelength * tiff->stride); + wp = tiff->samples; strip = 0; for (row = 0; row < tiff->imagelength; row += tiff->rowsperstrip) { unsigned offset = tiff->stripoffsets[strip]; unsigned rlen = tiff->stripbytecounts[strip]; - unsigned wlen = image->stride * tiff->rowsperstrip; + unsigned wlen = tiff->stride * tiff->rowsperstrip; byte *rp = tiff->bp + offset; - if (wp + wlen > image->samples + image->stride * image->height) - wlen = image->samples + image->stride * image->height - wp; + if (wp + wlen > tiff->samples + tiff->stride * tiff->imagelength) + wlen = tiff->samples + tiff->stride * tiff->imagelength - wp; if (rp + rlen > tiff->ep) return fz_throw("strip extends beyond the end of the file"); @@ -462,11 +460,12 @@ xps_decode_tiff_strips(xps_context *ctx, xps_tiff *tiff, xps_image *image) rp[i] = bitrev[rp[i]]; /* create a fz_buffer on the stack */ - buf.refs = 1; + buf.refs = 2; buf.data = rp; buf.len = rlen; buf.cap = rlen; + /* the strip decoders will close this */ stm = fz_openbuffer(&buf); switch (tiff->compression) @@ -502,8 +501,6 @@ xps_decode_tiff_strips(xps_context *ctx, xps_tiff *tiff, xps_image *image) error = fz_throw("unknown TIFF compression: %d", tiff->compression); } - fz_close(stm); - if (error) return fz_rethrow(error, "cannot decode strip %d", row / tiff->rowsperstrip); @@ -512,25 +509,25 @@ xps_decode_tiff_strips(xps_context *ctx, xps_tiff *tiff, xps_image *image) for (i = 0; i < rlen; i++) rp[i] = bitrev[rp[i]]; - wp += image->stride * tiff->rowsperstrip; + wp += tiff->stride * tiff->rowsperstrip; strip ++; } /* Predictor (only for LZW and Flate) */ if ((tiff->compression == 5 || tiff->compression == 8) && tiff->predictor == 2) { - byte *p = image->samples; - for (i = 0; i < image->height; i++) + byte *p = tiff->samples; + for (i = 0; i < tiff->imagelength; i++) { - xps_unpredict_tiff(p, image->width, tiff->samplesperpixel, image->bits); - p += image->stride; + xps_unpredict_tiff(p, tiff->imagewidth, tiff->samplesperpixel, tiff->bitspersample); + p += tiff->stride; } } /* RGBPal */ if (tiff->photometric == 3 && tiff->colormap) { - error = xps_expand_colormap(ctx, tiff, image); + error = xps_expand_tiff_colormap(ctx, tiff); if (error) return fz_rethrow(error, "cannot expand colormap"); } @@ -538,26 +535,14 @@ xps_decode_tiff_strips(xps_context *ctx, xps_tiff *tiff, xps_image *image) /* WhiteIsZero .. invert */ if (tiff->photometric == 0) { - byte *p = image->samples; - for (i = 0; i < image->height; i++) + byte *p = tiff->samples; + for (i = 0; i < tiff->imagelength; i++) { - xps_invert_tiff(p, image->width, image->comps, image->bits, tiff->extrasamples); - p += image->stride; + xps_invert_tiff(p, tiff->imagewidth, tiff->samplesperpixel, tiff->bitspersample, tiff->extrasamples); + p += tiff->stride; } } - /* Premultiplied transparency */ - if (tiff->extrasamples == 1) - { - image->hasalpha = 1; - } - - /* Non-pre-multiplied transparency */ - if (tiff->extrasamples == 2) - { - image->hasalpha = 1; - } - return fz_okay; } @@ -594,6 +579,7 @@ xps_read_tiff_bytes(unsigned char *p, xps_tiff *tiff, unsigned ofs, unsigned n) tiff->rp = tiff->bp + ofs; if (tiff->rp > tiff->ep) tiff->rp = tiff->bp; + while (n--) *p++ = readbyte(tiff); } @@ -699,6 +685,7 @@ xps_read_tiff_tag(xps_context *ctx, xps_tiff *tiff, unsigned offset) case ExtraSamples: xps_read_tiff_tag_value(&tiff->extrasamples, tiff, type, value, 1); break; + case ICCProfile: tiff->profile = fz_malloc(count); /* ICC profile data type is set to UNDEFINED. @@ -714,23 +701,17 @@ xps_read_tiff_tag(xps_context *ctx, xps_tiff *tiff, unsigned offset) break; case StripOffsets: - tiff->stripoffsets = (unsigned*) fz_malloc(count * sizeof(unsigned)); - if (!tiff->stripoffsets) - return fz_throw("cannot allocate strip offsets"); + tiff->stripoffsets = fz_calloc(count, sizeof(unsigned)); xps_read_tiff_tag_value(tiff->stripoffsets, tiff, type, value, count); break; case StripByteCounts: - tiff->stripbytecounts = (unsigned*) fz_malloc(count * sizeof(unsigned)); - if (!tiff->stripbytecounts) - return fz_throw("cannot allocate strip byte counts"); + tiff->stripbytecounts = fz_calloc(count, sizeof(unsigned)); xps_read_tiff_tag_value(tiff->stripbytecounts, tiff, type, value, count); break; case ColorMap: - tiff->colormap = (unsigned*) fz_malloc(count * sizeof(unsigned)); - if (!tiff->colormap) - return fz_throw("cannot allocate color map"); + tiff->colormap = fz_calloc(count, sizeof(unsigned)); xps_read_tiff_tag_value(tiff->colormap, tiff, type, value, count); break; @@ -827,49 +808,55 @@ xps_decode_tiff_header(xps_context *ctx, xps_tiff *tiff, byte *buf, int len) } int -xps_decode_tiff(xps_context *ctx, byte *buf, int len, xps_image *image) +xps_decode_tiff(xps_image **imagep, xps_context *ctx, byte *buf, int len) { int error; - xps_tiff tiffst; - xps_tiff *tiff = &tiffst; + fz_pixmap *pixmap; + xps_image *image; + xps_tiff tiff; - error = xps_decode_tiff_header(ctx, tiff, buf, len); + error = xps_decode_tiff_header(ctx, &tiff, buf, len); if (error) return fz_rethrow(error, "cannot decode tiff header"); - /* - * Decode the image strips - */ + /* Decode the image strips */ - if (tiff->rowsperstrip > tiff->imagelength) - tiff->rowsperstrip = tiff->imagelength; + if (tiff.rowsperstrip > tiff.imagelength) + tiff.rowsperstrip = tiff.imagelength; - error = xps_decode_tiff_strips(ctx, tiff, image); + error = xps_decode_tiff_strips(ctx, &tiff); if (error) return fz_rethrow(error, "cannot decode image data"); - /* - * Byte swap 16-bit images to big endian if necessary. - */ - if (image->bits == 16) + /* Byte swap 16-bit images to big endian if necessary */ + if (tiff.bitspersample == 16) { - if (tiff->order == TII) - xps_swap_byte_order(image->samples, image->width * image->height * image->comps); + if (tiff.order == TII) + xps_swap_byte_order(tiff.samples, tiff.imagewidth * tiff.imagelength * tiff.samplesperpixel); } - /* - * Save ICC profile data - */ - image->profile = tiff->profile; - image->profilesize = tiff->profilesize; + /* Expand into fz_pixmap struct */ - /* - * Clean up scratch memory - */ + pixmap = fz_newpixmap(tiff.colorspace, 0, 0, tiff.imagewidth, tiff.imagelength); + + fz_unpacktile(pixmap, tiff.samples, tiff.samplesperpixel, tiff.bitspersample, tiff.stride, 0); + + /* Non-pre-multiplied transparency */ + if (tiff.extrasamples == 2) + fz_premultiplypixmap(pixmap); + + image = fz_malloc(sizeof(xps_image)); + image->pixmap = pixmap; + image->xres = tiff.xresolution; + image->yres = tiff.yresolution; + + /* Clean up scratch memory */ - if (tiff->colormap) fz_free(tiff->colormap); - if (tiff->stripoffsets) fz_free(tiff->stripoffsets); - if (tiff->stripbytecounts) fz_free(tiff->stripbytecounts); + if (tiff.colormap) fz_free(tiff.colormap); + if (tiff.stripoffsets) fz_free(tiff.stripoffsets); + if (tiff.stripbytecounts) fz_free(tiff.stripbytecounts); + if (tiff.samples) fz_free(tiff.samples); + *imagep = image; return fz_okay; } |