コード例 #1
0
ファイル: pdf_annot.c プロジェクト: DeepGopani/mupdf
/* SumatraPDF: partial support for link borders */
static pdf_annot *
pdf_create_link_annot(pdf_xref *xref, fz_obj *obj)
{
	fz_obj *border, *dashes;
	fz_buffer *content;
	fz_rect rect;
	float rgb[3];
	int i;

	border = fz_dict_gets(xref->ctx, obj, "Border");
	if (fz_to_real(xref->ctx, fz_array_get(xref->ctx, border, 2)) <= 0)
		return NULL;

	pdf_get_annot_color(xref->ctx, obj, rgb);
	dashes = fz_array_get(xref->ctx, border, 3);
	rect = pdf_to_rect(xref->ctx, fz_dict_gets(xref->ctx, obj, "Rect"));

	obj = pdf_clone_for_view_only(xref, obj);

	// TODO: draw rounded rectangles if the first two /Border values are non-zero
	content = fz_new_buffer(xref->ctx, 128);
	fz_buffer_printf(xref->ctx, content, "q %.4f w [", fz_to_real(xref->ctx, fz_array_get(xref->ctx, border, 2)));
	for (i = 0; i < fz_array_len(xref->ctx, dashes); i++)
		fz_buffer_printf(xref->ctx, content, "%.4f ", fz_to_real(xref->ctx, fz_array_get(xref->ctx, dashes, i)));
	fz_buffer_printf(xref->ctx, content, "] 0 d %.4f %.4f %.4f RG 0 0 %.4f %.4f re S Q",
		rgb[0], rgb[1], rgb[2], rect.x1 - rect.x0, rect.y1 - rect.y0);

	return pdf_create_annot(xref->ctx, rect, obj, content, NULL, 0);
}
コード例 #2
0
fz_rect
pdf_to_rect(fz_obj *array)
{
	fz_rect r;
	float a = fz_to_real(fz_array_get(array, 0));
	float b = fz_to_real(fz_array_get(array, 1));
	float c = fz_to_real(fz_array_get(array, 2));
	float d = fz_to_real(fz_array_get(array, 3));
	r.x0 = MIN(a, c);
	r.y0 = MIN(b, d);
	r.x1 = MAX(a, c);
	r.y1 = MAX(b, d);
	return r;
}
コード例 #3
0
fz_error
pdf_load_pattern(pdf_pattern **patp, pdf_xref *xref, fz_obj *dict)
{
	fz_error error;
	pdf_pattern *pat;
	fz_obj *obj;

	if ((*patp = pdf_find_item(xref->store, pdf_drop_pattern, dict)))
	{
		pdf_keep_pattern(*patp);
		return fz_okay;
	}

	pat = fz_malloc(sizeof(pdf_pattern));
	pat->refs = 1;
	pat->resources = NULL;
	pat->contents = NULL;

	/* Store pattern now, to avoid possible recursion if objects refer back to this one */
	pdf_store_item(xref->store, pdf_keep_pattern, pdf_drop_pattern, dict, pat);

	pat->ismask = fz_to_int(fz_dict_gets(dict, "PaintType")) == 2;
	pat->xstep = fz_to_real(fz_dict_gets(dict, "XStep"));
	pat->ystep = fz_to_real(fz_dict_gets(dict, "YStep"));

	obj = fz_dict_gets(dict, "BBox");
	pat->bbox = pdf_to_rect(obj);

	obj = fz_dict_gets(dict, "Matrix");
	if (obj)
		pat->matrix = pdf_to_matrix(obj);
	else
		pat->matrix = fz_identity;

	pat->resources = fz_dict_gets(dict, "Resources");
	if (pat->resources)
		fz_keep_obj(pat->resources);

	error = pdf_load_stream(&pat->contents, xref, fz_to_num(dict), fz_to_gen(dict));
	if (error)
	{
		pdf_remove_item(xref->store, pdf_drop_pattern, dict);
		pdf_drop_pattern(pat);
		return fz_rethrow(error, "cannot load pattern stream (%d %d R)", fz_to_num(dict), fz_to_gen(dict));
	}

	*patp = pat;
	return fz_okay;
}
コード例 #4
0
ファイル: pdf_annot.c プロジェクト: DeepGopani/mupdf
static void
pdf_get_annot_color(fz_context *ctx, fz_obj *obj, float rgb[3])
{
	int k;
	obj = fz_dict_gets(ctx, obj, "C");
	for (k = 0; k < 3; k++)
		rgb[k] = fz_to_real(ctx, fz_array_get(ctx, obj, k));
}
コード例 #5
0
ファイル: pdf_annot.c プロジェクト: DeepGopani/mupdf
/* a: top/left to bottom/right; b: bottom/left to top/right */
static void
pdf_get_quadrilaterals(fz_context *ctx, fz_obj *quad_points, int i, fz_rect *a, fz_rect *b)
{
	a->x0 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 0));
	a->y0 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 1));
	b->x1 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 2));
	b->y1 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 3));
	b->x0 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 4));
	b->y0 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 5));
	a->x1 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 6));
	a->y1 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 7));
}
コード例 #6
0
ファイル: pdf_shade.c プロジェクト: DeepGopani/mupdf
static void
pdf_load_radial_shading(fz_shade *shade, pdf_xref *xref, fz_obj *dict, int funcs, pdf_function **func)
{
	fz_obj *obj;
	float d0, d1;
	int e0, e1;
	float x0, y0, r0, x1, y1, r1;
	struct vertex p1, p2;
	fz_context *ctx = xref->ctx;

	obj = fz_dict_gets(ctx, dict, "Coords");
	x0 = fz_to_real(ctx, fz_array_get(ctx, obj, 0));
	y0 = fz_to_real(ctx, fz_array_get(ctx, obj, 1));
	r0 = fz_to_real(ctx, fz_array_get(ctx, obj, 2));
	x1 = fz_to_real(ctx, fz_array_get(ctx, obj, 3));
	y1 = fz_to_real(ctx, fz_array_get(ctx, obj, 4));
	r1 = fz_to_real(ctx, fz_array_get(ctx, obj, 5));

	d0 = 0;
	d1 = 1;
	obj = fz_dict_gets(ctx, dict, "Domain");
	if (fz_array_len(ctx, obj) == 2)
	{
		d0 = fz_to_real(ctx, fz_array_get(ctx, obj, 0));
		d1 = fz_to_real(ctx, fz_array_get(ctx, obj, 1));
	}

	e0 = e1 = 0;
	obj = fz_dict_gets(ctx, dict, "Extend");
	if (fz_array_len(ctx, obj) == 2)
	{
		e0 = fz_to_bool(ctx, fz_array_get(ctx, obj, 0));
		e1 = fz_to_bool(ctx, fz_array_get(ctx, obj, 1));
	}

	pdf_sample_shade_function(ctx, shade, funcs, func, d0, d1);

	shade->type = FZ_RADIAL;

	shade->extend[0] = e0;
	shade->extend[1] = e1;

	p1.x = x0;
	p1.y = y0;
	p1.c[0] = r0;
	pdf_add_vertex(ctx, shade, &p1);

	p2.x = x1;
	p2.y = y1;
	p2.c[0] = r1;
	pdf_add_vertex(ctx, shade, &p2);
}
コード例 #7
0
fz_matrix
pdf_to_matrix(fz_obj *array)
{
	fz_matrix m;
	m.a = fz_to_real(fz_array_get(array, 0));
	m.b = fz_to_real(fz_array_get(array, 1));
	m.c = fz_to_real(fz_array_get(array, 2));
	m.d = fz_to_real(fz_array_get(array, 3));
	m.e = fz_to_real(fz_array_get(array, 4));
	m.f = fz_to_real(fz_array_get(array, 5));
	return m;
}
コード例 #8
0
ファイル: pdf_shade.c プロジェクト: DeepGopani/mupdf
static void
pdf_load_mesh_params(pdf_xref *xref, fz_obj *dict, struct mesh_params *p)
{
	fz_obj *obj;
	int i, n;
	fz_context *ctx = xref->ctx;

	p->x0 = p->y0 = 0;
	p->x1 = p->y1 = 1;
	for (i = 0; i < FZ_MAX_COLORS; i++)
	{
		p->c0[i] = 0;
		p->c1[i] = 1;
	}

	p->vprow = fz_to_int(ctx, fz_dict_gets(ctx, dict, "VerticesPerRow"));
	p->bpflag = fz_to_int(ctx, fz_dict_gets(ctx, dict, "BitsPerFlag"));
	p->bpcoord = fz_to_int(ctx, fz_dict_gets(ctx, dict, "BitsPerCoordinate"));
	p->bpcomp = fz_to_int(ctx, fz_dict_gets(ctx, dict, "BitsPerComponent"));

	obj = fz_dict_gets(ctx, dict, "Decode");
	if (fz_array_len(ctx, obj) >= 6)
	{
		n = (fz_array_len(ctx, obj) - 4) / 2;
		p->x0 = fz_to_real(ctx, fz_array_get(ctx, obj, 0));
		p->x1 = fz_to_real(ctx, fz_array_get(ctx, obj, 1));
		p->y0 = fz_to_real(ctx, fz_array_get(ctx, obj, 2));
		p->y1 = fz_to_real(ctx, fz_array_get(ctx, obj, 3));

		for (i = 0; i < n; i++)
		{
			p->c0[i] = fz_to_real(ctx, fz_array_get(ctx, obj, 4 + i * 2));
			p->c1[i] = fz_to_real(ctx, fz_array_get(ctx, obj, 5 + i * 2));
		}
	}

	if (p->vprow < 2)
		p->vprow = 2;

	if (p->bpflag != 2 && p->bpflag != 4 && p->bpflag != 8)
		p->bpflag = 8;

	if (p->bpcoord != 1 && p->bpcoord != 2 && p->bpcoord != 4 &&
		p->bpcoord != 8 && p->bpcoord != 12 && p->bpcoord != 16 &&
		p->bpcoord != 24 && p->bpcoord != 32)
		p->bpcoord = 8;

	if (p->bpcomp != 1 && p->bpcomp != 2 && p->bpcomp != 4 &&
		p->bpcomp != 8 && p->bpcomp != 12 && p->bpcomp != 16)
		p->bpcomp = 8;
}
コード例 #9
0
static void
pdf_load_axial_shading(fz_shade *shade, pdf_xref *xref, fz_obj *dict, int funcs, pdf_function **func)
{
	fz_obj *obj;
	float d0, d1;
	int e0, e1;
	float x0, y0, x1, y1;
	struct vertex p1, p2;

	obj = fz_dict_gets(dict, "Coords");
	x0 = fz_to_real(fz_array_get(obj, 0));
	y0 = fz_to_real(fz_array_get(obj, 1));
	x1 = fz_to_real(fz_array_get(obj, 2));
	y1 = fz_to_real(fz_array_get(obj, 3));

	d0 = 0;
	d1 = 1;
	obj = fz_dict_gets(dict, "Domain");
	if (fz_array_len(obj) == 2)
	{
		d0 = fz_to_real(fz_array_get(obj, 0));
		d1 = fz_to_real(fz_array_get(obj, 1));
	}

	e0 = e1 = 0;
	obj = fz_dict_gets(dict, "Extend");
	if (fz_array_len(obj) == 2)
	{
		e0 = fz_to_bool(fz_array_get(obj, 0));
		e1 = fz_to_bool(fz_array_get(obj, 1));
	}

	pdf_sample_shade_function(shade, funcs, func, d0, d1);

	shade->type = FZ_LINEAR;

	shade->extend[0] = e0;
	shade->extend[1] = e1;

	p1.x = x0;
	p1.y = y0;
	p1.c[0] = 0;
	pdf_add_vertex(shade, &p1);

	p2.x = x1;
	p2.y = y1;
	p2.c[0] = 0;
	pdf_add_vertex(shade, &p2);
}
コード例 #10
0
ファイル: mume-pdf-doc.c プロジェクト: tomnotcat/mume
static mume_rect_t _pdf_doc_get_link_dest_rect(
    struct _pdf_doc *self, pdf_link *link)
{
    mume_rect_t rect = mume_rect_empty;
    fz_obj *dest = link->dest;
    fz_obj *obj = fz_array_get(dest, 1);
    const char *type = fz_to_name(obj);

    if (strcmp(type, "XYZ") == 0) {
        /* NULL values for the coordinates mean: keep the
         * current position. */
        if (!fz_is_null(fz_array_get(dest, 2)))
            rect.x = round(fz_to_real(fz_array_get(dest, 2)));

        if (!fz_is_null(fz_array_get(dest, 3)))
            rect.y = round(fz_to_real(fz_array_get(dest, 3)));
    }
    else if (strcmp(type, "FitR") == 0) {
        double x0, y0, x1, y1;

        x0 = fz_to_real(fz_array_get(dest, 2));
        y0 = fz_to_real(fz_array_get(dest, 5));
        x1 = fz_to_real(fz_array_get(dest, 4));
        y1 = fz_to_real(fz_array_get(dest, 3));

        rect.x = round(x0);
        rect.y = round(y0);
        rect.width = round(x1 - x0);
        rect.height = round(y1 - y0);
    }
    else if (strcmp(type, "FitH") == 0 || strcmp(type, "FitBH") == 0) {
        rect.y = round(fz_to_real(fz_array_get(dest, 2)));
    }

    return rect;
}
コード例 #11
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;
}
コード例 #12
0
static fz_error
pdf_load_shading_dict(fz_shade **shadep, pdf_xref *xref, fz_obj *dict, fz_matrix transform)
{
	fz_error error;
	fz_shade *shade;
	pdf_function *func[FZ_MAX_COLORS] = { NULL };
	fz_stream *stream = NULL;
	fz_obj *obj;
	int funcs;
	int type;
	int i;

	shade = fz_malloc(sizeof(fz_shade));
	shade->refs = 1;
	shade->type = FZ_MESH;
	shade->use_background = 0;
	shade->use_function = 0;
	shade->matrix = transform;
	shade->bbox = fz_infinite_rect;
	shade->extend[0] = 0;
	shade->extend[1] = 0;

	shade->mesh_len = 0;
	shade->mesh_cap = 0;
	shade->mesh = NULL;

	shade->colorspace = NULL;

	funcs = 0;

	obj = fz_dict_gets(dict, "ShadingType");
	type = fz_to_int(obj);

	obj = fz_dict_gets(dict, "ColorSpace");
	if (!obj)
	{
		fz_drop_shade(shade);
		return fz_throw("shading colorspace is missing");
	}
	error = pdf_load_colorspace(&shade->colorspace, xref, obj);
	if (error)
	{
		fz_drop_shade(shade);
		return fz_rethrow(error, "cannot load colorspace (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
	}

	obj = fz_dict_gets(dict, "Background");
	if (obj)
	{
		shade->use_background = 1;
		for (i = 0; i < shade->colorspace->n; i++)
			shade->background[i] = fz_to_real(fz_array_get(obj, i));
	}

	obj = fz_dict_gets(dict, "BBox");
	if (fz_is_array(obj))
	{
		shade->bbox = pdf_to_rect(obj);
	}

	obj = fz_dict_gets(dict, "Function");
	if (fz_is_dict(obj))
	{
		funcs = 1;

		error = pdf_load_function(&func[0], xref, obj);
		if (error)
		{
			error = fz_rethrow(error, "cannot load shading function (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
			goto cleanup;
		}
	}
	else if (fz_is_array(obj))
	{
		funcs = fz_array_len(obj);
		if (funcs != 1 && funcs != shade->colorspace->n)
		{
			error = fz_throw("incorrect number of shading functions");
			goto cleanup;
		}

		for (i = 0; i < funcs; i++)
		{
			error = pdf_load_function(&func[i], xref, fz_array_get(obj, i));
			if (error)
			{
				error = fz_rethrow(error, "cannot load shading function (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
				goto cleanup;
			}
		}
	}

	if (type >= 4 && type <= 7)
	{
		error = pdf_open_stream(&stream, xref, fz_to_num(dict), fz_to_gen(dict));
		if (error)
		{
			error = fz_rethrow(error, "cannot open shading stream (%d %d R)", fz_to_num(dict), fz_to_gen(dict));
			goto cleanup;
		}
	}

	switch (type)
	{
	case 1: pdf_load_function_based_shading(shade, xref, dict, func[0]); break;
	case 2: pdf_load_axial_shading(shade, xref, dict, funcs, func); break;
	case 3: pdf_load_radial_shading(shade, xref, dict, funcs, func); break;
	case 4: pdf_load_type4_shade(shade, xref, dict, funcs, func, stream); break;
	case 5: pdf_load_type5_shade(shade, xref, dict, funcs, func, stream); break;
	case 6: pdf_load_type6_shade(shade, xref, dict, funcs, func, stream); break;
	case 7: pdf_load_type7_shade(shade, xref, dict, funcs, func, stream); break;
	default:
		error = fz_throw("unknown shading type: %d", type);
		goto cleanup;
	}

	if (stream)
		fz_close(stream);
	for (i = 0; i < funcs; i++)
		if (func[i])
			pdf_drop_function(func[i]);

	*shadep = shade;
	return fz_okay;

cleanup:
	if (stream)
		fz_close(stream);
	for (i = 0; i < funcs; i++)
		if (func[i])
			pdf_drop_function(func[i]);
	fz_drop_shade(shade);

	return fz_rethrow(error, "cannot load shading type %d (%d %d R)", type, fz_to_num(dict), fz_to_gen(dict));
}
コード例 #13
0
static void
pdf_load_function_based_shading(fz_shade *shade, pdf_xref *xref, fz_obj *dict, pdf_function *func)
{
	fz_obj *obj;
	float x0, y0, x1, y1;
	fz_matrix matrix;
	struct vertex v[4];
	int xx, yy;
	float x, y;
	float xn, yn;
	int i;

	x0 = y0 = 0;
	x1 = y1 = 1;
	obj = fz_dict_gets(dict, "Domain");
	if (fz_array_len(obj) == 4)
	{
		x0 = fz_to_real(fz_array_get(obj, 0));
		x1 = fz_to_real(fz_array_get(obj, 1));
		y0 = fz_to_real(fz_array_get(obj, 2));
		y1 = fz_to_real(fz_array_get(obj, 3));
	}

	matrix = fz_identity;
	obj = fz_dict_gets(dict, "Matrix");
	if (fz_array_len(obj) == 6)
		matrix = pdf_to_matrix(obj);

	for (yy = 0; yy < FUNSEGS; yy++)
	{
		y = y0 + (y1 - y0) * yy / FUNSEGS;
		yn = y0 + (y1 - y0) * (yy + 1) / FUNSEGS;

		for (xx = 0; xx < FUNSEGS; xx++)
		{
			x = x0 + (x1 - x0) * xx / FUNSEGS;
			xn = x0 + (x1 - x0) * (xx + 1) / FUNSEGS;

			v[0].x = x; v[0].y = y;
			v[1].x = xn; v[1].y = y;
			v[2].x = xn; v[2].y = yn;
			v[3].x = x; v[3].y = yn;

			for (i = 0; i < 4; i++)
			{
				fz_point pt;
				float fv[2];

				fv[0] = v[i].x;
				fv[1] = v[i].y;
				pdf_eval_function(func, fv, 2, v[i].c, shade->colorspace->n);

				pt.x = v[i].x;
				pt.y = v[i].y;
				pt = fz_transform_point(matrix, pt);
				v[i].x = pt.x;
				v[i].y = pt.y;
			}

			pdf_add_quad(shade, &v[0], &v[1], &v[2], &v[3]);
		}
	}
}