static void fz_list_fill_image(void *user, fz_pixmap *image, fz_matrix ctm, float alpha) { fz_display_node *node; node = fz_new_display_node(FZ_CMD_FILL_IMAGE, ctm, NULL, NULL, alpha); node->rect = fz_transform_rect(ctm, fz_unit_rect); node->item.image = fz_keep_pixmap(image); fz_append_display_node(user, node); }
static void fz_list_clip_image_mask(void *user, fz_pixmap *image, fz_rect *rect, fz_matrix ctm) { fz_display_node *node; node = fz_new_display_node(FZ_CMD_CLIP_IMAGE_MASK, ctm, NULL, NULL, 0); node->rect = fz_transform_rect(ctm, fz_unit_rect); if (rect != NULL) node->rect = fz_intersect_rect(node->rect, *rect); node->item.image = fz_keep_pixmap(image); fz_append_display_node(user, node); }
static fz_pixmap * pdf_image_get_pixmap(fz_context *ctx, fz_image *image_, int w, int h) { pdf_image *image = (pdf_image *)image_; fz_pixmap *tile; fz_stream *stm; int l2factor; pdf_image_key key; int native_l2factor; int indexed; /* 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->base.w) w = image->base.w; if (h > image->base.h) h = image->base.h; /* What is our ideal factor? */ if (w == 0 || h == 0) l2factor = 0; else for (l2factor=0; image->base.w>>(l2factor+1) >= w && image->base.h>>(l2factor+1) >= h && l2factor < 8; l2factor++); /* Can we find any suitable tiles in the cache? */ key.refs = 1; key.image = &image->base; key.l2factor = l2factor; do { tile = fz_find_item(ctx, fz_free_pixmap_imp, &key, &pdf_image_store_type); if (tile) return tile; key.l2factor--; } while (key.l2factor >= 0); /* We need to make a new one. */ native_l2factor = l2factor; stm = fz_open_image_decomp_stream(ctx, image->buffer, &native_l2factor); indexed = fz_colorspace_is_indexed(image->base.colorspace); return decomp_image_from_stream(ctx, stm, image, 0, indexed, l2factor, native_l2factor, 1); }
static fz_pixmap * pdf_image_get_pixmap(fz_context *ctx, fz_image *image_, int w, int h) { pdf_image *image = (pdf_image *)image_; fz_pixmap *tile; fz_stream *stm; int factor; pdf_image_key key; /* Check for 'simple' images which are just pixmaps */ /* SumatraPDF: don't produce additional tiles for preloaded images */ if (image->tile || !image->buffer) { 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->base.w) w = image->base.w; if (h > image->base.h) h = image->base.h; /* What is our ideal factor? */ if (w == 0 || h == 0) factor = 1; else for (factor=1; image->base.w/(2*factor) >= w && image->base.h/(2*factor) >= h && factor < 8; factor *= 2); /* Can we find any suitable tiles in the cache? */ key.refs = 1; key.image = &image->base; key.factor = factor; do { tile = fz_find_item(ctx, fz_free_pixmap_imp, &key, &pdf_image_store_type); if (tile) return tile; key.factor >>= 1; } while (key.factor > 0); /* We need to make a new one. */ stm = pdf_open_image_decomp_stream(ctx, image->buffer, &image->params, &factor); return decomp_image_from_stream(ctx, stm, image, 0, 0, factor, 0); }
void fz_convert_pixmap(fz_context *ctx, fz_pixmap *sp, fz_pixmap *dp) { fz_colorspace *ss = sp->colorspace; fz_colorspace *ds = dp->colorspace; assert(ss && ds); if (sp->mask) dp->mask = fz_keep_pixmap(ctx, sp->mask); dp->interpolate = sp->interpolate; if (ss == fz_device_gray) { if (ds == fz_device_rgb) fast_gray_to_rgb(sp, dp); else if (ds == fz_device_bgr) fast_gray_to_rgb(sp, dp); /* bgr == rgb here */ else if (ds == fz_device_cmyk) fast_gray_to_cmyk(sp, dp); else fz_std_conv_pixmap(ctx, sp, dp); } else if (ss == fz_device_rgb) { if (ds == fz_device_gray) fast_rgb_to_gray(sp, dp); else if (ds == fz_device_bgr) fast_rgb_to_bgr(sp, dp); else if (ds == fz_device_cmyk) fast_rgb_to_cmyk(sp, dp); else fz_std_conv_pixmap(ctx, sp, dp); } else if (ss == fz_device_bgr) { if (ds == fz_device_gray) fast_bgr_to_gray(sp, dp); else if (ds == fz_device_rgb) fast_rgb_to_bgr(sp, dp); /* bgr = rgb here */ else if (ds == fz_device_cmyk) fast_bgr_to_cmyk(sp, dp); else fz_std_conv_pixmap(ctx, sp, dp); } else if (ss == fz_device_cmyk) { if (ds == fz_device_gray) fast_cmyk_to_gray(sp, dp); else if (ds == fz_device_bgr) fast_cmyk_to_bgr(ctx, sp, dp); else if (ds == fz_device_rgb) fast_cmyk_to_rgb(ctx, sp, dp); else fz_std_conv_pixmap(ctx, sp, dp); } else fz_std_conv_pixmap(ctx, sp, dp); }
fz_error pdf_load_image(fz_pixmap **pixp, pdf_xref *xref, fz_obj *dict) { fz_error error; if ((*pixp = pdf_find_item(xref->store, fz_drop_pixmap, dict))) { fz_keep_pixmap(*pixp); return fz_okay; } error = pdf_load_image_imp(pixp, xref, NULL, dict, NULL, 0); if (error) return fz_rethrow(error, "cannot load image (%d 0 R)", fz_to_num(dict)); // EBookDroid: Commented out for saving A LOTS of memory. Caching is not needed for embedded solutions // pdf_store_item(xref->store, fz_keep_pixmap, fz_drop_pixmap, dict, *pixp); return fz_okay; }
fz_pixmap * pdf_expand_indexed_pixmap(fz_pixmap *src) { struct indexed *idx; fz_pixmap *dst; unsigned char *s, *d; int y, x, k, n, high; unsigned char *lookup; assert(src->colorspace->to_rgb == indexed_to_rgb); assert(src->n == 2); idx = src->colorspace->data; high = idx->high; lookup = idx->lookup; n = idx->base->n; dst = fz_new_pixmap_with_rect(idx->base, fz_bound_pixmap(src)); s = src->samples; d = dst->samples; for (y = 0; y < src->h; y++) { for (x = 0; x < src->w; x++) { int v = *s++; int a = *s++; v = MIN(v, high); for (k = 0; k < n; k++) *d++ = fz_mul255(lookup[v * n + k], a); *d++ = a; } } if (src->mask) dst->mask = fz_keep_pixmap(src->mask); dst->interpolate = src->interpolate; return dst; }
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; }
/* Render a glyph and return a bitmap. If the glyph is too large to fit the cache we have two choices: 1) Return NULL so the caller can draw the glyph using an outline. Only supported for freetype fonts. 2) Render a clipped glyph by using the scissor rectangle. Only supported for type 3 fonts. This must not be inserted into the cache. */ fz_pixmap * fz_render_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *ctm, fz_colorspace *model, fz_irect scissor) { fz_glyph_cache *cache; fz_glyph_key key; fz_pixmap *val; float size = fz_matrix_expansion(ctm); int do_cache, locked, caching; fz_matrix local_ctm = *ctm; fz_glyph_cache_entry *entry; unsigned hash; fz_var(locked); fz_var(caching); if (size <= MAX_GLYPH_SIZE) { scissor = fz_infinite_irect; do_cache = 1; } else { /* SumatraPDF: don't break clipping by larger glyphs */ if (font->ft_face && size > 3000) return NULL; do_cache = 0; } cache = ctx->glyph_cache; memset(&key, 0, sizeof key); key.font = font; key.gid = gid; key.a = local_ctm.a * 65536; key.b = local_ctm.b * 65536; key.c = local_ctm.c * 65536; key.d = local_ctm.d * 65536; key.e = (local_ctm.e - floorf(local_ctm.e)) * 256; key.f = (local_ctm.f - floorf(local_ctm.f)) * 256; key.aa = fz_aa_level(ctx); local_ctm.e = floorf(local_ctm.e) + key.e / 256.0f; local_ctm.f = floorf(local_ctm.f) + key.f / 256.0f; fz_lock(ctx, FZ_LOCK_GLYPHCACHE); hash = do_hash((unsigned char *)&key, sizeof(key)) % GLYPH_HASH_LEN; entry = cache->entry[hash]; while (entry) { if (memcmp(&entry->key, &key, sizeof(key)) == 0) { move_to_front(cache, entry); val = fz_keep_pixmap(ctx, entry->val); fz_unlock(ctx, FZ_LOCK_GLYPHCACHE); return val; } entry = entry->bucket_next; } locked = 1; caching = 0; fz_try(ctx) { if (font->ft_face) { val = fz_render_ft_glyph(ctx, font, gid, &local_ctm, key.aa); } else if (font->t3procs) { /* We drop the glyphcache here, and execute the t3 * glyph code. The danger here is that some other * thread will come along, and want the same glyph * too. If it does, we may both end up rendering * pixmaps. We cope with this later on, by ensuring * that only one gets inserted into the cache. If * we insert ours to find one already there, we * abandon ours, and use the one there already. */ fz_unlock(ctx, FZ_LOCK_GLYPHCACHE); locked = 0; val = fz_render_t3_glyph(ctx, font, gid, &local_ctm, model, scissor); fz_lock(ctx, FZ_LOCK_GLYPHCACHE); locked = 1; } else { fz_warn(ctx, "assert: uninitialized font structure"); val = NULL; } if (val && do_cache) { if (val->w < MAX_GLYPH_SIZE && val->h < MAX_GLYPH_SIZE) { /* If we throw an exception whilst caching, * just ignore the exception and carry on. */ caching = 1; if (!font->ft_face) { /* We had to unlock. Someone else might * have rendered in the meantime */ entry = cache->entry[hash]; while (entry) { if (memcmp(&entry->key, &key, sizeof(key)) == 0) { fz_drop_pixmap(ctx, val); move_to_front(cache, entry); val = fz_keep_pixmap(ctx, entry->val); fz_unlock(ctx, FZ_LOCK_GLYPHCACHE); return val; } entry = entry->bucket_next; } } entry = fz_malloc_struct(ctx, fz_glyph_cache_entry); entry->key = key; entry->hash = hash; entry->bucket_next = cache->entry[hash]; if (entry->bucket_next) entry->bucket_next->bucket_prev = entry; cache->entry[hash] = entry; entry->val = fz_keep_pixmap(ctx, val); fz_keep_font(ctx, key.font); entry->lru_next = cache->lru_head; if (entry->lru_next) entry->lru_next->lru_prev = entry; else cache->lru_tail = entry; cache->lru_head = entry; cache->total += val->w * val->h; while (cache->total > MAX_CACHE_SIZE) { drop_glyph_cache_entry(ctx, cache->lru_tail); } } } } fz_always(ctx) { if (locked) fz_unlock(ctx, FZ_LOCK_GLYPHCACHE); } fz_catch(ctx) { if (caching) fz_warn(ctx, "cannot encache glyph; continuing"); else fz_rethrow(ctx); } return val; }