static int pdf_image_size(fz_context *ctx, pdf_image *im) { if (im == NULL) return 0; return sizeof(*im) + fz_pixmap_size(ctx, im->tile) + (im->buffer && im->buffer->buffer ? im->buffer->buffer->cap : 0); }
fz_pixmap * fz_image_get_pixmap(fz_context *ctx, fz_image *image, int w, int h) { fz_pixmap *tile; fz_stream *stm; int l2factor; fz_image_key key; int native_l2factor; int indexed; fz_image_key *keyp; /* Check for 'simple' images which are just pixmaps */ if (image->buffer == NULL) { tile = image->tile; if (!tile) return NULL; return fz_keep_pixmap(ctx, tile); /* That's all we can give you! */ } /* Ensure our expectations for tile size are reasonable */ if (w > image->w) w = image->w; if (h > image->h) h = image->h; /* What is our ideal factor? */ if (w == 0 || h == 0) l2factor = 0; else for (l2factor=0; image->w>>(l2factor+1) >= w && image->h>>(l2factor+1) >= h && l2factor < 8; l2factor++); /* Can we find any suitable tiles in the cache? */ key.refs = 1; key.image = image; key.l2factor = l2factor; do { tile = fz_find_item(ctx, fz_free_pixmap_imp, &key, &fz_image_store_type); if (tile) return tile; key.l2factor--; } while (key.l2factor >= 0); /* We need to make a new one. */ /* First check for ones that we can't decode using streams */ switch (image->buffer->params.type) { case FZ_IMAGE_PNG: tile = fz_load_png(ctx, image->buffer->buffer->data, image->buffer->buffer->len); break; case FZ_IMAGE_TIFF: tile = fz_load_tiff(ctx, image->buffer->buffer->data, image->buffer->buffer->len); break; default: native_l2factor = l2factor; stm = fz_open_image_decomp_stream(ctx, image->buffer, &native_l2factor); indexed = fz_colorspace_is_indexed(image->colorspace); tile = fz_decomp_image_from_stream(ctx, stm, image, 0, indexed, l2factor, native_l2factor); break; } /* Now we try to cache the pixmap. Any failure here will just result * in us not caching. */ fz_var(keyp); fz_try(ctx) { fz_pixmap *existing_tile; keyp = fz_malloc_struct(ctx, fz_image_key); keyp->refs = 1; keyp->image = fz_keep_image(ctx, image); keyp->l2factor = l2factor; existing_tile = fz_store_item(ctx, keyp, tile, fz_pixmap_size(ctx, tile), &fz_image_store_type); if (existing_tile) { /* We already have a tile. This must have been produced by a * racing thread. We'll throw away ours and use that one. */ fz_drop_pixmap(ctx, tile); tile = existing_tile; } } fz_always(ctx) { fz_drop_image_key(ctx, keyp); } fz_catch(ctx) { /* Do nothing */ } return tile; }
static fz_pixmap * decomp_image_from_stream(fz_context *ctx, fz_stream *stm, pdf_image *image, int in_line, int indexed, int l2factor, int native_l2factor, int cache) { fz_pixmap *tile = NULL; fz_pixmap *existing_tile; int stride, len, i; unsigned char *samples = NULL; int f = 1<<native_l2factor; int w = (image->base.w + f-1) >> native_l2factor; int h = (image->base.h + f-1) >> native_l2factor; pdf_image_key *key = NULL; fz_var(tile); fz_var(samples); fz_var(key); fz_try(ctx) { tile = fz_new_pixmap(ctx, image->base.colorspace, w, h); tile->interpolate = image->interpolate; stride = (w * image->n * image->base.bpc + 7) / 8; samples = fz_malloc_array(ctx, h, stride); len = fz_read(stm, samples, h * stride); if (len < 0) { fz_throw(ctx, "cannot read image data"); } /* Make sure we read the EOF marker (for inline images only) */ if (in_line) { unsigned char tbuf[512]; fz_try(ctx) { int tlen = fz_read(stm, tbuf, sizeof tbuf); if (tlen > 0) fz_warn(ctx, "ignoring garbage at end of image"); } fz_catch(ctx) { fz_warn(ctx, "ignoring error at end of image"); } } /* Pad truncated images */ if (len < stride * h) { fz_warn(ctx, "padding truncated image"); memset(samples + len, 0, stride * h - len); } /* Invert 1-bit image masks */ if (image->imagemask) { /* 0=opaque and 1=transparent so we need to invert */ unsigned char *p = samples; len = h * stride; for (i = 0; i < len; i++) p[i] = ~p[i]; } fz_unpack_tile(tile, samples, image->n, image->base.bpc, stride, indexed); fz_free(ctx, samples); samples = NULL; if (image->usecolorkey) pdf_mask_color_key(tile, image->n, image->colorkey); if (indexed) { fz_pixmap *conv; fz_decode_indexed_tile(tile, image->decode, (1 << image->base.bpc) - 1); conv = pdf_expand_indexed_pixmap(ctx, tile); fz_drop_pixmap(ctx, tile); tile = conv; } else { fz_decode_tile(tile, image->decode); } } fz_always(ctx) { fz_close(stm); } fz_catch(ctx) { if (tile) fz_drop_pixmap(ctx, tile); fz_free(ctx, samples); fz_rethrow(ctx); } /* Now apply any extra subsampling required */ if (l2factor - native_l2factor > 0) { if (l2factor - native_l2factor > 8) l2factor = native_l2factor + 8; fz_subsample_pixmap(ctx, tile, l2factor - native_l2factor); } if (!cache) return tile; /* Now we try to cache the pixmap. Any failure here will just result * in us not caching. */ fz_try(ctx) { key = fz_malloc_struct(ctx, pdf_image_key); key->refs = 1; key->image = fz_keep_image(ctx, &image->base); key->l2factor = l2factor; existing_tile = fz_store_item(ctx, key, tile, fz_pixmap_size(ctx, tile), &pdf_image_store_type); if (existing_tile) { /* We already have a tile. This must have been produced by a * racing thread. We'll throw away ours and use that one. */ fz_drop_pixmap(ctx, tile); tile = existing_tile; } } fz_always(ctx) { pdf_drop_image_key(ctx, key); } fz_catch(ctx) { /* Do nothing */ } return tile; }
static fz_pixmap * decomp_image_banded(fz_context *ctx, fz_stream *stm, pdf_image *image, int indexed, int l2factor, int native_l2factor, int cache) { fz_pixmap *tile = NULL, *part = NULL; int w = (image->base.w + (1 << l2factor) - 1) >> l2factor; int h = (image->base.h + (1 << l2factor) - 1) >> l2factor; int part_h, orig_h = image->base.h; int band = 1 << fz_maxi(8, l2factor); fz_var(tile); fz_var(part); fz_try(ctx) { tile = fz_new_pixmap(ctx, image->base.colorspace, w, h); tile->interpolate = image->interpolate; tile->has_alpha = 0; /* SumatraPDF: allow optimizing non-alpha pixmaps */ /* decompress the image in bands of 256 lines */ for (part_h = h; part_h > 0; part_h -= band >> l2factor) { image->base.h = part_h > band >> l2factor ? band : (orig_h - 1) % band + 1; part = decomp_image_from_stream(ctx, fz_keep_stream(stm), image, -1, indexed, l2factor, native_l2factor, 0); memcpy(tile->samples + (h - part_h) * tile->w * tile->n, part->samples, part->h * part->w * part->n); tile->has_alpha |= part->has_alpha; /* SumatraPDF: allow optimizing non-alpha pixmaps */ fz_drop_pixmap(ctx, part); part = NULL; } /* cf. http://bugs.ghostscript.com/show_bug.cgi?id=693517 */ if (image->usecolorkey && image->base.mask) pdf_unblend_masked_tile(ctx, tile, image); } fz_always(ctx) { image->base.h = orig_h; fz_close(stm); } fz_catch(ctx) { fz_drop_pixmap(ctx, part); fz_drop_pixmap(ctx, tile); fz_rethrow(ctx); } if (cache) { pdf_image_key *key = NULL; fz_var(key); fz_try(ctx) { key = fz_malloc_struct(ctx, pdf_image_key); key->refs = 1; key->image = fz_keep_image(ctx, &image->base); key->l2factor = l2factor; fz_store_item(ctx, key, tile, fz_pixmap_size(ctx, tile), &pdf_image_store_type); } fz_always(ctx) { pdf_drop_image_key(ctx, key); } fz_catch(ctx) { } } return tile; }