static void fz_text_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *img, const fz_matrix *ctm, fz_colorspace *cspace, float *color, float alpha) { fz_text_device *tdev = (fz_text_device*)dev; fz_text_page *page = tdev->page; fz_image_block *block; /* If the alpha is less than 50% then it's probably a watermark or * effect or something. Skip it */ if (alpha < 0.5) return; /* New block */ if (page->len == page->cap) { int newcap = (page->cap ? page->cap*2 : 4); page->blocks = fz_resize_array(ctx, page->blocks, newcap, sizeof(*page->blocks)); page->cap = newcap; } block = fz_malloc_struct(ctx, fz_image_block); page->blocks[page->len].type = FZ_PAGE_BLOCK_IMAGE; page->blocks[page->len].u.image = block; block->image = fz_keep_image(ctx, img); block->cspace = fz_keep_colorspace(ctx, cspace); if (cspace) memcpy(block->colors, color, sizeof(block->colors[0])*cspace->n); block->mat = *ctm; block->bbox.x0 = 0; block->bbox.y0 = 0; block->bbox.x1 = 1; block->bbox.y1 = 1; fz_transform_rect(&block->bbox, ctm); page->len++; }
static void add_flow_image(fz_context *ctx, fz_pool *pool, fz_html *top, fz_css_style *style, fz_image *img) { fz_html_flow *flow; add_flow_glue(ctx, pool, top, style, "", 0); flow = add_flow(ctx, pool, top, style, FLOW_IMAGE); flow->content.image = fz_keep_image(ctx, img); add_flow_glue(ctx, pool, top, style, "", 0); }
static void fz_list_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha) { fz_display_node *node; node = fz_new_display_node(dev->ctx, FZ_CMD_FILL_IMAGE, ctm, NULL, NULL, alpha); node->rect = fz_transform_rect(ctm, fz_unit_rect); node->item.image = fz_keep_image(dev->ctx, image); fz_append_display_node(dev->user, node); }
static void fz_list_fill_image_mask(fz_device *dev, fz_image *image, const fz_matrix *ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_display_node *node; node = fz_new_display_node(dev->ctx, FZ_CMD_FILL_IMAGE_MASK, ctm, colorspace, color, alpha); node->rect = fz_unit_rect; fz_transform_rect(&node->rect, ctm); node->item.image = fz_keep_image(dev->ctx, image); fz_append_display_node(dev->user, node); }
static void fz_list_clip_image_mask(fz_device *dev, fz_image *image, fz_rect *rect, fz_matrix ctm) { fz_display_node *node; node = fz_new_display_node(dev->ctx, FZ_CMD_CLIP_IMAGE_MASK, ctm, NULL, NULL, 0); node->rect = fz_transform_rect(ctm, fz_unit_rect); if (rect) node->rect = fz_intersect_rect(node->rect, *rect); node->item.image = fz_keep_image(dev->ctx, image); fz_append_display_node(dev->user, node); }
static img_document * img_new_document(fz_context *ctx, fz_image *image) { img_document *doc = fz_new_document(ctx, sizeof *doc); doc->super.close = (fz_document_close_fn *)img_close_document; doc->super.count_pages = (fz_document_count_pages_fn *)img_count_pages; doc->super.load_page = (fz_document_load_page_fn *)img_load_page; doc->super.lookup_metadata = (fz_document_lookup_metadata_fn *)img_lookup_metadata; doc->image = fz_keep_image(ctx, image); return doc; }
static img_page * img_load_page(fz_context *ctx, img_document *doc, int number) { img_page *page; if (number != 0) return NULL; page = fz_new_page(ctx, sizeof *page); page->super.bound_page = (fz_page_bound_page_fn *)img_bound_page; page->super.run_page_contents = (fz_page_run_page_contents_fn *)img_run_page; page->super.drop_page_imp = (fz_page_drop_page_imp_fn *)img_drop_page_imp; page->image = fz_keep_image(ctx, doc->image); return page; }
static tiff_page * tiff_load_page(fz_context *ctx, tiff_document *doc, int number) { fz_pixmap *pixmap = NULL; fz_image *image = NULL; tiff_page *page = NULL; if (number < 0 || number >= doc->page_count) return NULL; fz_var(pixmap); fz_var(image); fz_var(page); fz_try(ctx) { size_t len; unsigned char *data; len = fz_buffer_storage(ctx, doc->buffer, &data); pixmap = fz_load_tiff_subimage(ctx, data, len, number); image = fz_new_image_from_pixmap(ctx, pixmap, NULL); page = fz_new_page(ctx, sizeof *page); page->super.bound_page = (fz_page_bound_page_fn *)tiff_bound_page; page->super.run_page_contents = (fz_page_run_page_contents_fn *)tiff_run_page; page->super.drop_page = (fz_page_drop_page_fn *)tiff_drop_page; page->image = fz_keep_image(ctx, image); } fz_always(ctx) { fz_drop_image(ctx, image); fz_drop_pixmap(ctx, pixmap); } fz_catch(ctx) { fz_free(ctx, page); fz_rethrow(ctx); } return page; }
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 void add_flow_image(fz_context *ctx, fz_html *top, fz_css_style *style, fz_image *img) { fz_html_flow *flow = add_flow(ctx, top, style, FLOW_IMAGE); flow->image = fz_keep_image(ctx, img); }
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_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; }