Exemple #1
0
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);
}
Exemple #2
0
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);
}
Exemple #3
0
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);
}
Exemple #4
0
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);
}
Exemple #5
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;
}
Exemple #8
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;
}
/*
	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;
}