Example #1
0
static fz_error
pdf_read_ocg(pdf_xref *xref)
{
	fz_obj *obj, *ocg;
	int len, i;
	pdf_ocg_descriptor *desc;

	obj = fz_dict_gets(fz_dict_gets(xref->trailer, "Root"), "OCProperties");
	if (obj == NULL)
		return fz_okay;
	ocg = fz_dict_gets(obj, "OCGs");
	if (ocg == NULL || !fz_is_array(ocg))
		/* Not ever supposed to happen, but live with it. */
		return fz_okay;
	len = fz_array_len(ocg);
	desc = fz_malloc(sizeof(*desc));
	desc->len = len;
	desc->ocgs = fz_calloc(len, sizeof(*desc->ocgs));
	desc->intent = NULL;

	for (i=0; i < len; i++)
	{
		fz_obj *o = fz_array_get(ocg, i);
		desc->ocgs[i].num = fz_to_num(o);
		desc->ocgs[i].gen = fz_to_gen(o);
		desc->ocgs[i].state = 0;
	}
	xref->ocg = desc;

	return pdf_ocg_set_config(xref, 0);
}
Example #2
0
static fz_obj *
resolve_dest(pdf_xref *xref, fz_obj *dest)
{
	if (fz_is_name(xref->ctx, dest) || fz_is_string(xref->ctx, dest))
	{
		dest = pdf_lookup_dest(xref, dest);
		return resolve_dest(xref, dest);
	}

	else if (fz_is_array(xref->ctx, dest))
	{
		return dest;
	}

	else if (fz_is_dict(xref->ctx, dest))
	{
		dest = fz_dict_gets(xref->ctx, dest, "D");
		return resolve_dest(xref, dest);
	}

	else if (fz_is_indirect(dest))
		return dest;

	return NULL;
}
Example #3
0
static void addhexfilter(fz_obj *dict)
{
	fz_obj *f, *dp, *newf, *newdp;
	fz_obj *ahx, *nullobj;

	ahx = fz_new_name(ctx, "ASCIIHexDecode");
	nullobj = fz_new_null(ctx);
	newf = newdp = NULL;

	f = fz_dict_gets(dict, "Filter");
	dp = fz_dict_gets(dict, "DecodeParms");

	if (fz_is_name(f))
	{
		newf = fz_new_array(ctx, 2);
		fz_array_push(newf, ahx);
		fz_array_push(newf, f);
		f = newf;
		if (fz_is_dict(dp))
		{
			newdp = fz_new_array(ctx, 2);
			fz_array_push(newdp, nullobj);
			fz_array_push(newdp, dp);
			dp = newdp;
		}
	}
	else if (fz_is_array(f))
	{
		fz_array_insert(f, ahx);
		if (fz_is_array(dp))
			fz_array_insert(dp, nullobj);
	}
	else
		f = ahx;

	fz_dict_puts(dict, "Filter", f);
	if (dp)
		fz_dict_puts(dict, "DecodeParms", dp);

	fz_drop_obj(ahx);
	fz_drop_obj(nullobj);
	if (newf)
		fz_drop_obj(newf);
	if (newdp)
		fz_drop_obj(newdp);
}
Example #4
0
static int _pdf_doc_find_page_no(
    struct _pdf_doc *self, fz_obj *dest)
{
    if (fz_is_dict(dest)) {
        /* The destination is linked from a Go-To action's D array. */
        fz_obj * D = fz_dict_gets(dest, "D");
        if (D && fz_is_array(D))
            dest = D;
    }

    if (fz_is_array(dest))
        dest = fz_array_get(dest, 0);

    if (fz_is_int(dest))
        return fz_to_int(dest);

    return pdf_find_page_number(self->xref, dest);
}
Example #5
0
static fz_colorspace *
load_separation(pdf_document *xref, fz_obj *array)
{
	fz_colorspace *cs;
	struct separation *sep = NULL;
	fz_context *ctx = xref->ctx;
	fz_obj *nameobj = fz_array_get(array, 1);
	fz_obj *baseobj = fz_array_get(array, 2);
	fz_obj *tintobj = fz_array_get(array, 3);
	fz_colorspace *base;
	pdf_function *tint = NULL;
	int n;

	fz_var(tint);
	fz_var(sep);

	if (fz_is_array(nameobj))
		n = fz_array_len(nameobj);
	else
		n = 1;

	if (n > FZ_MAX_COLORS)
		fz_throw(ctx, "too many components in colorspace");

	base = pdf_load_colorspace(xref, baseobj);
	/* RJW: "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj) */

	fz_try(ctx)
	{
		tint = pdf_load_function(xref, tintobj);
		/* RJW: fz_drop_colorspace(ctx, base);
		 * "cannot load tint function (%d %d R)", fz_to_num(tintobj), fz_to_gen(tintobj) */

		sep = fz_malloc_struct(ctx, struct separation);
		sep->base = base;
		sep->tint = tint;

		cs = fz_new_colorspace(ctx, n == 1 ? "Separation" : "DeviceN", n);
		cs->to_rgb = separation_to_rgb;
		cs->free_data = free_separation;
		cs->data = sep;
		cs->size += sizeof(struct separation) + (base ? base->size : 0) + pdf_function_size(tint);
	}
	fz_catch(ctx)
	{
		fz_drop_colorspace(ctx, base);
		pdf_drop_function(ctx, tint);
		fz_free(ctx, sep);
		fz_rethrow(ctx);
	}

	return cs;
}
Example #6
0
static void sweepobj(fz_obj *obj)
{
	int i;

	if (fz_is_indirect(obj))
		sweepref(obj);

	else if (fz_is_dict(ctx, obj))
		for (i = 0; i < fz_dict_len(ctx, obj); i++)
			sweepobj(fz_dict_get_val(ctx, obj, i));

	else if (fz_is_array(ctx, obj))
		for (i = 0; i < fz_array_len(ctx, obj); i++)
			sweepobj(fz_array_get(ctx, obj, i));
}
static fz_error
load_separation(fz_colorspace **csp, pdf_xref *xref, fz_obj *array)
{
	fz_error error;
	fz_colorspace *cs;
	struct separation *sep;
	fz_obj *nameobj = fz_array_get(array, 1);
	fz_obj *baseobj = fz_array_get(array, 2);
	fz_obj *tintobj = fz_array_get(array, 3);
	fz_colorspace *base;
	pdf_function *tint;
	int n;

	if (fz_is_array(nameobj))
		n = fz_array_len(nameobj);
	else
		n = 1;

	if (n > FZ_MAX_COLORS)
		return fz_throw("too many components in colorspace");

	error = pdf_load_colorspace(&base, xref, baseobj);
	if (error)
		return fz_rethrow(error, "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj));

	error = pdf_load_function(&tint, xref, tintobj);
	if (error)
	{
		fz_drop_colorspace(base);
		return fz_rethrow(error, "cannot load tint function (%d %d R)", fz_to_num(tintobj), fz_to_gen(tintobj));
	}

	sep = fz_malloc(sizeof(struct separation));
	sep->base = base;
	sep->tint = tint;

	cs = fz_new_colorspace(n == 1 ? "Separation" : "DeviceN", n);
	cs->to_rgb = separation_to_rgb;
	cs->free_data = free_separation;
	cs->data = sep;

	*csp = cs;
	return fz_okay;
}
Example #8
0
static void renumberobj(fz_obj *obj)
{
	int i;
	fz_context *ctx = xref->ctx;

	if (fz_is_dict(obj))
	{
		int n = fz_dict_len(obj);
		for (i = 0; i < n; i++)
		{
			fz_obj *key = fz_dict_get_key(obj, i);
			fz_obj *val = fz_dict_get_val(obj, i);
			if (fz_is_indirect(val))
			{
				val = fz_new_indirect(ctx, renumbermap[fz_to_num(val)], 0, xref);
				fz_dict_put(obj, key, val);
				fz_drop_obj(val);
			}
			else
			{
				renumberobj(val);
			}
		}
	}

	else if (fz_is_array(obj))
	{
		int n = fz_array_len(obj);
		for (i = 0; i < n; i++)
		{
			fz_obj *val = fz_array_get(obj, i);
			if (fz_is_indirect(val))
			{
				val = fz_new_indirect(ctx, renumbermap[fz_to_num(val)], 0, xref);
				fz_array_put(obj, i, val);
				fz_drop_obj(val);
			}
			else
			{
				renumberobj(val);
			}
		}
	}
}
Example #9
0
static void sweepobj(fz_obj *obj)
{
	int i;

	if (fz_is_indirect(obj))
		sweepref(obj);

	else if (fz_is_dict(obj))
	{
		int n = fz_dict_len(obj);
		for (i = 0; i < n; i++)
			sweepobj(fz_dict_get_val(obj, i));
	}

	else if (fz_is_array(obj))
	{
		int n = fz_array_len(obj);
		for (i = 0; i < n; i++)
			sweepobj(fz_array_get(obj, i));
	}
}
/*
 * Scan stream dictionary for an explicit /Crypt filter
 */
static int
pdf_stream_has_crypt(fz_obj *stm)
{
	fz_obj *filters;
	fz_obj *obj;
	int i;

	filters = fz_dict_getsa(stm, "Filter", "F");
	if (filters)
	{
		if (!strcmp(fz_to_name(filters), "Crypt"))
			return 1;
		if (fz_is_array(filters))
		{
			for (i = 0; i < fz_array_len(filters); i++)
			{
				obj = fz_array_get(filters, i);
				if (!strcmp(fz_to_name(obj), "Crypt"))
					return 1;
			}
		}
	}
	return 0;
}
Example #11
0
static int _pdf_doc_load(struct _pdf_doc *self, mume_stream_t *stm)
{
    fz_error error;
    fz_stream *fzstm;
    fz_rect *mbox;
    fz_obj *page_obj, *box_obj;
    int i, c;

    _pdf_doc_clear(self);

    fzstm = fz_new_stream(stm, _pdf_stream_read, _pdf_stream_close);
    mume_stream_reference(stm);
    fzstm->seek = _pdf_stream_seek;
    error = pdf_open_xref_with_stream(&self->xref, fzstm, NULL);
    fz_close(fzstm);
    if (error) {
        mume_error(("Read xref failed\n", error));
        return 0;
    }

    assert(!pdf_needs_password(self->xref));

    /* Load meta information. */
    error = pdf_load_page_tree(self->xref);
    if (error) {
        mume_error(("Cannot load page tree\n"));
        return 0;
    }

    c = pdf_count_pages(self->xref);
    self->glyph_cache = fz_new_glyph_cache();
    self->pages = calloc_abort(c, sizeof(pdf_page*));
    self->disps = calloc_abort(c, sizeof(fz_display_list*));
    self->media_boxes = malloc_abort(c * sizeof(fz_rect));
    self->page_rotates = malloc_abort(c * sizeof(int));

    /* Extract each pages' media box and rotation. */
    for (i = 0; i < c; ++i) {
        mbox = self->media_boxes + i;
        page_obj = self->xref->page_objs[i];
        if (!page_obj) {
            *mbox = fz_empty_rect;
            continue;
        }

        box_obj = fz_dict_gets(page_obj, "MediaBox");
        *mbox = pdf_to_rect(box_obj);
        if (fz_is_empty_rect(*mbox)) {
            fz_warn("Cannot find page bounds, guessing page bounds.");
            mbox->x1 = 612;
            mbox->y1 = 792;
        }

        box_obj = fz_dict_gets(page_obj, "CropBox");
        if (fz_is_array(box_obj))
            *mbox = fz_intersect_rect(*mbox, pdf_to_rect(box_obj));

        self->page_rotates[i] = fz_to_int(
            fz_dict_gets(page_obj, "Rotate"));

        if (self->page_rotates[i] % 90)
            self->page_rotates[i] = 0;
    }

    return 1;
}
static fz_error
pdf_load_colorspace_imp(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj)
{
	if (fz_is_name(obj))
	{
		if (!strcmp(fz_to_name(obj), "Pattern"))
			*csp = fz_device_gray;
		else if (!strcmp(fz_to_name(obj), "G"))
			*csp = fz_device_gray;
		else if (!strcmp(fz_to_name(obj), "RGB"))
			*csp = fz_device_rgb;
		else if (!strcmp(fz_to_name(obj), "CMYK"))
			*csp = fz_device_cmyk;
		else if (!strcmp(fz_to_name(obj), "DeviceGray"))
			*csp = fz_device_gray;
		else if (!strcmp(fz_to_name(obj), "DeviceRGB"))
			*csp = fz_device_rgb;
		else if (!strcmp(fz_to_name(obj), "DeviceCMYK"))
			*csp = fz_device_cmyk;
		else
			return fz_throw("unknown colorspace: %s", fz_to_name(obj));
		return fz_okay;
	}

	else if (fz_is_array(obj))
	{
		fz_obj *name = fz_array_get(obj, 0);

		if (fz_is_name(name))
		{
			/* load base colorspace instead */
			if (!strcmp(fz_to_name(name), "Pattern"))
			{
				fz_error error;

				obj = fz_array_get(obj, 1);
				if (!obj)
				{
					*csp = fz_device_gray;
					return fz_okay;
				}

				error = pdf_load_colorspace(csp, xref, obj);
				if (error)
					return fz_rethrow(error, "cannot load pattern (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
			}

			else if (!strcmp(fz_to_name(name), "G"))
				*csp = fz_device_gray;
			else if (!strcmp(fz_to_name(name), "RGB"))
				*csp = fz_device_rgb;
			else if (!strcmp(fz_to_name(name), "CMYK"))
				*csp = fz_device_cmyk;
			else if (!strcmp(fz_to_name(name), "DeviceGray"))
				*csp = fz_device_gray;
			else if (!strcmp(fz_to_name(name), "DeviceRGB"))
				*csp = fz_device_rgb;
			else if (!strcmp(fz_to_name(name), "DeviceCMYK"))
				*csp = fz_device_cmyk;
			else if (!strcmp(fz_to_name(name), "CalGray"))
				*csp = fz_device_gray;
			else if (!strcmp(fz_to_name(name), "CalRGB"))
				*csp = fz_device_rgb;
			else if (!strcmp(fz_to_name(name), "CalCMYK"))
				*csp = fz_device_cmyk;
			else if (!strcmp(fz_to_name(name), "Lab"))
				*csp = fz_device_lab;

			else if (!strcmp(fz_to_name(name), "ICCBased"))
				return load_icc_based(csp, xref, fz_array_get(obj, 1));

			else if (!strcmp(fz_to_name(name), "Indexed"))
				return load_indexed(csp, xref, obj);
			else if (!strcmp(fz_to_name(name), "I"))
				return load_indexed(csp, xref, obj);

			else if (!strcmp(fz_to_name(name), "Separation"))
				return load_separation(csp, xref, obj);

			else if (!strcmp(fz_to_name(name), "DeviceN"))
				return load_separation(csp, xref, obj);

			else
				return fz_throw("syntaxerror: unknown colorspace %s", fz_to_name(name));

			return fz_okay;
		}
	}

	return fz_throw("syntaxerror: could not parse color space (%d %d R)", fz_to_num(obj), fz_to_gen(obj));
}
Example #13
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;
}
Example #14
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));
}