예제 #1
0
static void
fz_draw_begin_tile(fz_context *ctx, void *user, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm)
{
	fz_draw_device *dev = user;
	fz_colorspace *model = dev->dest->colorspace;
	fz_pixmap *dest;
	fz_bbox bbox;

	/* area, view, xstep, ystep are in pattern space */
	/* ctm maps from pattern space to device space */

	if (dev->top == dev->stack_max)
		fz_grow_stack(dev);

	if (dev->blendmode & FZ_BLEND_KNOCKOUT)
		fz_knockout_begin(ctx, dev);

	bbox = fz_round_rect(fz_transform_rect(ctm, view));
	/* We should never have a bbox that entirely covers our destination.
	 * If we do, then the check for only 1 tile being visible above has
	 * failed. */
	/* SumatraPDF: assertion intentionally disabled
	assert(bbox.x0 > dev->dest->x || bbox.x1 < dev->dest->x + dev->dest->w ||
		bbox.y0 > dev->dest->y || bbox.y1 < dev->dest->y + dev->dest->h);
	/* cf. http://bugs.ghostscript.com/show_bug.cgi?id=692418 */
	dest = fz_new_pixmap_with_limit(ctx, model, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0);
	if (dest)
	{
		dest->x = bbox.x0;
		dest->y = bbox.y0;
	}
	else
	{
		bbox.x1 = bbox.x0;
		bbox.y1 = bbox.y0;
		dest = fz_new_pixmap_with_rect(ctx, model, bbox);
	}
	/* FIXME: See note #1 */
	fz_clear_pixmap(dest);

	dev->stack[dev->top].scissor = dev->scissor;
	dev->stack[dev->top].dest = dev->dest;
	dev->stack[dev->top].shape = dev->shape;
	/* FIXME: See note #1 */
	dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED;
	dev->stack[dev->top].xstep = xstep;
	dev->stack[dev->top].ystep = ystep;
	dev->stack[dev->top].area = area;
	dev->stack[dev->top].ctm = ctm;
#ifdef DUMP_GROUP_BLENDS
	dump_spaces(dev->top, "Tile begin\n");
#endif
	dev->top++;

	dev->scissor = bbox;
	dev->dest = dest;
}
예제 #2
0
static fz_error
pdf_load_image_imp(fz_pixmap **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cstm, int forcemask)
{
	fz_stream *stm;
	fz_pixmap *tile;
	fz_obj *obj, *res;
	fz_error error;

	int w, h, bpc, n;
	int imagemask;
	int interpolate;
	int indexed;
	fz_colorspace *colorspace;
	fz_pixmap *mask; /* explicit mask/softmask image */
	int usecolorkey;
	int colorkey[FZ_MAX_COLORS * 2];
	float decode[FZ_MAX_COLORS * 2];

	int stride;
	unsigned char *samples;
	int i, len;

	/* special case for JPEG2000 images */
	if (pdf_is_jpx_image(dict))
	{
		tile = NULL;
		error = pdf_load_jpx_image(&tile, xref, dict);
		if (error)
			return fz_rethrow(error, "cannot load jpx image");
		if (forcemask)
		{
			if (tile->n != 2)
			{
				fz_drop_pixmap(tile);
				return fz_throw("softmask must be grayscale");
			}
			mask = fz_alpha_from_gray(tile, 1);
			fz_drop_pixmap(tile);
			*imgp = mask;
			return fz_okay;
		}
		*imgp = tile;
		return fz_okay;
	}

	w = fz_to_int(fz_dict_getsa(dict, "Width", "W"));
	h = fz_to_int(fz_dict_getsa(dict, "Height", "H"));
	bpc = fz_to_int(fz_dict_getsa(dict, "BitsPerComponent", "BPC"));
	imagemask = fz_to_bool(fz_dict_getsa(dict, "ImageMask", "IM"));
	interpolate = fz_to_bool(fz_dict_getsa(dict, "Interpolate", "I"));

	indexed = 0;
	usecolorkey = 0;
	colorspace = NULL;
	mask = NULL;

	if (imagemask)
		bpc = 1;

	if (w == 0)
		return fz_throw("image width is zero");
	if (h == 0)
		return fz_throw("image height is zero");
	if (bpc == 0)
		return fz_throw("image depth is zero");
	if (w > (1 << 16))
		return fz_throw("image is too wide");
	if (h > (1 << 16))
		return fz_throw("image is too high");

	obj = fz_dict_getsa(dict, "ColorSpace", "CS");
	if (obj && !imagemask && !forcemask)
	{
		/* colorspace resource lookup is only done for inline images */
		if (fz_is_name(obj))
		{
			res = fz_dict_get(fz_dict_gets(rdb, "ColorSpace"), obj);
			if (res)
				obj = res;
		}

		error = pdf_load_colorspace(&colorspace, xref, obj);
		if (error)
			return fz_rethrow(error, "cannot load image colorspace");

		if (!strcmp(colorspace->name, "Indexed"))
			indexed = 1;

		n = colorspace->n;
	}
	else
	{
		n = 1;
	}

	obj = fz_dict_getsa(dict, "Decode", "D");
	if (obj)
	{
		for (i = 0; i < n * 2; i++)
			decode[i] = fz_to_real(fz_array_get(obj, i));
	}
	else
	{
		float maxval = indexed ? (1 << bpc) - 1 : 1;
		for (i = 0; i < n * 2; i++)
			decode[i] = i & 1 ? maxval : 0;
	}

	obj = fz_dict_getsa(dict, "SMask", "Mask");
	if (fz_is_dict(obj))
	{
		/* Not allowed for inline images */
		if (!cstm)
		{
			error = pdf_load_image_imp(&mask, xref, rdb, obj, NULL, 1);
			if (error)
			{
				if (colorspace)
					fz_drop_colorspace(colorspace);
				return fz_rethrow(error, "cannot load image mask/softmask");
			}
		}
	}
	else if (fz_is_array(obj))
	{
		usecolorkey = 1;
		for (i = 0; i < n * 2; i++)
			colorkey[i] = fz_to_int(fz_array_get(obj, i));
	}

	/* Allocate now, to fail early if we run out of memory */
	tile = fz_new_pixmap_with_limit(colorspace, w, h);
	if (!tile)
	{
		if (colorspace)
			fz_drop_colorspace(colorspace);
		if (mask)
			fz_drop_pixmap(mask);
		return fz_throw("out of memory");
	}

	if (colorspace)
		fz_drop_colorspace(colorspace);

	tile->mask = mask;
	tile->interpolate = interpolate;

	stride = (w * n * bpc + 7) / 8;

	if (cstm)
	{
		stm = pdf_open_inline_stream(cstm, xref, dict, stride * h);
	}
	else
	{
		error = pdf_open_stream(&stm, xref, fz_to_num(dict), fz_to_gen(dict));
		if (error)
		{
			fz_drop_pixmap(tile);
			return fz_rethrow(error, "cannot open image data stream (%d 0 R)", fz_to_num(dict));
		}
	}

	samples = fz_calloc(h, stride);

	len = fz_read(stm, samples, h * stride);
	if (len < 0)
	{
		fz_close(stm);
		fz_free(samples);
		fz_drop_pixmap(tile);
		return fz_rethrow(len, "cannot read image data");
	}

	/* Make sure we read the EOF marker (for inline images only) */
	if (cstm)
	{
		unsigned char tbuf[512];
		int tlen = fz_read(stm, tbuf, sizeof tbuf);
		if (tlen < 0)
			fz_catch(tlen, "ignoring error at end of image");
		if (tlen > 0)
			fz_warn("ignoring garbage at end of image");
	}

	fz_close(stm);

	/* Pad truncated images */
	if (len < stride * h)
	{
		fz_warn("padding truncated image (%d 0 R)", fz_to_num(dict));
		memset(samples + len, 0, stride * h - len);
	}

	/* Invert 1-bit image masks */
	if (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, n, bpc, stride, indexed);

	fz_free(samples);

	if (usecolorkey)
		pdf_mask_color_key(tile, n, colorkey);

	if (indexed)
	{
		fz_pixmap *conv;
		fz_decode_indexed_tile(tile, decode, (1 << bpc) - 1);
		conv = pdf_expand_indexed_pixmap(tile);
		fz_drop_pixmap(tile);
		tile = conv;
	}
	else
	{
		fz_decode_tile(tile, decode);
	}

	*imgp = tile;
	return fz_okay;
}
예제 #3
0
fz_error
fz_load_jpx_image(fz_pixmap **imgp, unsigned char *data, int size, fz_colorspace *defcs)
{
	fz_pixmap *img;
	opj_event_mgr_t evtmgr;
	opj_dparameters_t params;
	opj_dinfo_t *info;
	opj_cio_t *cio;
	opj_image_t *jpx;
	fz_colorspace *colorspace;
	unsigned char *p;
	int format;
	int a, n, w, h, depth, sgnd;
	int x, y, k, v;

	if (size < 2)
		return fz_throw("not enough data to determine image format");

	/* Check for SOC marker -- if found we have a bare J2K stream */
	if (data[0] == 0xFF && data[1] == 0x4F)
		format = CODEC_J2K;
	else
		format = CODEC_JP2;

	memset(&evtmgr, 0, sizeof(evtmgr));
	evtmgr.error_handler = fz_opj_error_callback;
	evtmgr.warning_handler = fz_opj_warning_callback;
	evtmgr.info_handler = fz_opj_info_callback;

	opj_set_default_decoder_parameters(&params);

	info = opj_create_decompress(format);
	opj_set_event_mgr((opj_common_ptr)info, &evtmgr, stderr);
	opj_setup_decoder(info, &params);

	cio = opj_cio_open((opj_common_ptr)info, data, size);

	jpx = opj_decode(info, cio);

	opj_cio_close(cio);
	opj_destroy_decompress(info);

	if (!jpx)
		return fz_throw("opj_decode failed");

	for (k = 1; k < jpx->numcomps; k++)
	{
		if (jpx->comps[k].w != jpx->comps[0].w)
			return fz_throw("image components have different width");
		if (jpx->comps[k].h != jpx->comps[0].h)
			return fz_throw("image components have different height");
		if (jpx->comps[k].prec != jpx->comps[0].prec)
			return fz_throw("image components have different precision");
	}

	n = jpx->numcomps;
	w = jpx->comps[0].w;
	h = jpx->comps[0].h;
	depth = jpx->comps[0].prec;
	sgnd = jpx->comps[0].sgnd;

	if (jpx->color_space == CLRSPC_SRGB && n == 4) { n = 3; a = 1; }
	else if (jpx->color_space == CLRSPC_SYCC && n == 4) { n = 3; a = 1; }
	else if (n == 2) { n = 1; a = 1; }
	else if (n > 4) { n = 4; a = 1; }
	else { a = 0; }

	if (defcs)
	{
		if (defcs->n == n)
		{
			colorspace = defcs;
		}
		else
		{
			fz_warn("jpx file and dict colorspaces do not match");
			defcs = NULL;
		}
	}

	if (!defcs)
	{
		switch (n)
		{
		case 1: colorspace = fz_device_gray; break;
		case 3: colorspace = fz_device_rgb; break;
		case 4: colorspace = fz_device_cmyk; break;
		}
	}

	img = fz_new_pixmap_with_limit(colorspace, w, h);
	if (!img)
	{
		opj_image_destroy(jpx);
		return fz_throw("out of memory");
	}

	p = img->samples;
	for (y = 0; y < h; y++)
	{
		for (x = 0; x < w; x++)
		{
			for (k = 0; k < n + a; k++)
			{
				v = jpx->comps[k].data[y * w + x];
				if (sgnd)
					v = v + (1 << (depth - 1));
				if (depth > 8)
					v = v >> (depth - 8);
				*p++ = v;
			}
			if (!a)
				*p++ = 255;
		}
	}

	if (a)
	{
		if (n == 4)
		{
			fz_pixmap *tmp = fz_new_pixmap(fz_device_rgb, w, h);
			fz_convert_pixmap(img, tmp);
			fz_drop_pixmap(img);
			img = tmp;
		}
		fz_premultiply_pixmap(img);
	}

	opj_image_destroy(jpx);

	*imgp = img;
	return fz_okay;
}