summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2011-03-31 03:18:51 +0200
committerTor Andersson <tor.andersson@artifex.com>2011-03-31 03:18:51 +0200
commitb3f90095897b64f854efc4b2f37df428a71fd508 (patch)
tree27ad639a052b967e1fdc03f7d58ff63b5b0a8f46
parent4f484b32f3cf8682180ccb9e36f929edff175498 (diff)
downloadmupdf-b3f90095897b64f854efc4b2f37df428a71fd508.tar.xz
xps: Clean up image loading code, and handle images with alpha.
-rw-r--r--draw/imageunpack.c10
-rw-r--r--fitz/fitz.h1
-rw-r--r--fitz/res_pixmap.c18
-rw-r--r--xps/muxps.h28
-rw-r--r--xps/xpsimage.c76
-rw-r--r--xps/xpsjpeg.c59
-rw-r--r--xps/xpsjxr.c257
-rw-r--r--xps/xpspng.c178
-rw-r--r--xps/xpstiff.c207
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;
}