Ejemplo n.º 1
0
static fz_obj *
resolvedest(pdf_xref *xref, fz_obj *dest)
{
	if (fz_isname(dest))
	{
		dest = fz_dictget(xref->dests, dest);
		if (dest)
			pdf_resolve(&dest, xref); /* XXX */
		return resolvedest(xref, dest);
	}

	else if (fz_isstring(dest))
	{
		dest = fz_dictget(xref->dests, dest);
		if (dest)
			pdf_resolve(&dest, xref); /* XXX */
		return resolvedest(xref, dest);
	}

	else if (fz_isarray(dest))
	{
		return fz_arrayget(dest, 0);
	}

	else if (fz_isdict(dest))
	{
		dest = fz_dictgets(dest, "D");
		return resolvedest(xref, dest);
	}

	else if (fz_isindirect(dest))
		return dest;

	return nil;
}
Ejemplo n.º 2
0
static fz_error *
loadoutline(pdf_outline **nodep, pdf_xref *xref, fz_obj *dict)
{
	fz_error *error;
	pdf_outline *node;
	fz_obj *obj;

	node = fz_malloc(sizeof(pdf_outline));
	node->title = "<unknown>";
	node->link = nil;
	node->child = nil;
	node->next = nil;

	pdf_logpage("load outline {\n");

	obj = fz_dictgets(dict, "Title");
	if (obj)
	{
		error = pdf_toutf8(&node->title, obj);
		if (error)
			return error;
		pdf_logpage("title %s\n", node->title);
	}

	if (fz_dictgets(dict, "Dest") || fz_dictgets(dict, "A"))
	{
		error = pdf_loadlink(&node->link, xref, dict);
		if (error)
			return error;
	}

	obj = fz_dictgets(dict, "First");
	if (obj)
	{
		error = pdf_resolve(&obj, xref);
		if (error)
			return error;
		error = loadoutline(&node->child, xref, obj);
		fz_dropobj(obj);
		if (error)
			return error;
	}

	pdf_logpage("}\n");

	obj = fz_dictgets(dict, "Next");
	if (obj)
	{
		error = pdf_resolve(&obj, xref);
		if (error)
			return error;
		error = loadoutline(&node->next, xref, obj);
		fz_dropobj(obj);
		if (error)
			return error;
	}

	*nodep = node;
	return nil;
}
Ejemplo n.º 3
0
fz_error*
setPageMediaBox(
    pdf_xref*   pdfXRef,
    fz_obj*     pageObj,
    fz_rect     mediaBox
    )
{
    fz_error    *error;
    fz_obj      *objMedia;
    fz_irect    mRect;
    fz_obj      *objInt;

    // Delete the CropBox. This is done because we are reducing
    // the size of the media box and CropBox is of no use to us
    fz_dictdels(pageObj, "CropBox");
    //objMedia = fz_dictgets(pageObj, "CropBox");
    //if (objMedia == NULL) return fz_throw("no CropBox entry");
    //error = pdf_resolve(&objMedia, pdfXRef);
    //if (error) return fz_rethrow(error, "cannot resolve page bounds");
    //if (! fz_isarray(objMedia)) return fz_throw("cannot find page bounds");
    //fz_rect cRect = pdf_torect(objMedia);

    // Get the media box
    objMedia = fz_dictgets(pageObj, "MediaBox");
    if (objMedia == NULL) return fz_throw("no MediaBox entry");

    error = pdf_resolve(&objMedia, pdfXRef);
    if (error) return fz_rethrow(error, "cannot resolve page bounds");

    if (! fz_isarray(objMedia)) return fz_throw("cannot find page bounds");


    // We have the MediaBox array here
    mRect = fz_roundrect(mediaBox);

    error = fz_newint(&objInt, mRect.x0);
    if (error) return fz_rethrow(error, "cannot allocate int"); 
    fz_arrayput(objMedia, 0, objInt);
    fz_dropobj(objInt);

    error = fz_newint(&objInt, mRect.y0);
    if (error) return fz_rethrow(error, "cannot allocate int"); 
    fz_arrayput(objMedia, 1, objInt);
    fz_dropobj(objInt);

    error = fz_newint(&objInt, mRect.x1);
    if (error) return fz_rethrow(error, "cannot allocate int"); 
    fz_arrayput(objMedia, 2, objInt);
    fz_dropobj(objInt);

    error = fz_newint(&objInt, mRect.y1);
    if (error) return fz_rethrow(error, "cannot allocate int"); 
    fz_arrayput(objMedia, 3, objInt);
    fz_dropobj(objInt);

    return NULL;
}
Ejemplo n.º 4
0
fz_error *
pdf_loadannots(pdf_comment **cp, pdf_link **lp, pdf_xref *xref, fz_obj *annots)
{
	fz_error *error;
	pdf_comment *comment;
	pdf_link *link;
	fz_obj *subtype;
	fz_obj *obj;
	int i;

	comment = nil;
	link = nil;

	pdf_logpage("load annotations {\n");

	for (i = 0; i < fz_arraylen(annots); i++)
	{
		obj = fz_arrayget(annots, i);
		error = pdf_resolve(&obj, xref);
		if (error)
			goto cleanup;

		subtype = fz_dictgets(obj, "Subtype");
		if (!strcmp(fz_toname(subtype), "Link"))
		{
			pdf_link *temp = nil;

			error = pdf_loadlink(&temp, xref, obj);
			fz_dropobj(obj);
			if (error)
				goto cleanup;

			if (temp)
			{
				temp->next = link;
				link = temp;
			}
		}
		else
		{
			error = loadcomment(&comment, xref, obj);
			fz_dropobj(obj);
			if (error)
				goto cleanup;
		}
	}

	pdf_logpage("}\n");

	*cp = comment;
	*lp = link;
	return nil;

cleanup:
	pdf_droplink(link);
	return error;
}
Ejemplo n.º 5
0
static fz_error *
loadseparation(fz_colorspace **csp, pdf_xref *xref, fz_obj *array)
{
	fz_error *error;
	struct separation *cs;
	fz_obj *nameobj = fz_arrayget(array, 1);
	fz_obj *baseobj = fz_arrayget(array, 2);
	fz_obj *tintobj = fz_arrayget(array, 3);
	fz_colorspace *base;
	pdf_function *tint;
	int n;

	pdf_logrsrc("load Separation {\n");

	if (fz_isarray(nameobj))
		n = fz_arraylen(nameobj);
	else
		n = 1;

	pdf_logrsrc("n = %d\n", n);

	error = pdf_resolve(&baseobj, xref);
	if (error)
		return error;
	error = pdf_loadcolorspace(&base, xref, baseobj);
	fz_dropobj(baseobj);
	if (error)
		return error;

	error = pdf_loadfunction(&tint, xref, tintobj);
	if (error)
	{
		fz_dropcolorspace(base);
		return error;
	}

	cs = fz_malloc(sizeof(struct separation));
	if (!cs)
	{
		pdf_dropfunction(tint);
		fz_dropcolorspace(base);
		return fz_outofmem;
	}

	initcs((fz_colorspace*)cs,
		n == 1 ? "Separation" : "DeviceN", n,
		separationtoxyz, nil, dropseparation);

	cs->base = base;
	cs->tint = tint;

	pdf_logrsrc("}\n");

	*csp = (fz_colorspace*)cs;
	return nil;
}
Ejemplo n.º 6
0
static fz_error *
loadtype0(pdf_font **fontp, pdf_xref *xref, fz_obj *dict, fz_obj *ref)
{
	fz_error *error;
	fz_obj *dfonts;
	fz_obj *dfont;
	fz_obj *subtype;
	fz_obj *encoding;
	fz_obj *tounicode;

	dfonts = fz_dictgets(dict, "DescendantFonts");
	error = pdf_resolve(&dfonts, xref);
	if (error)
		return fz_rethrow(error, "cannot find DescendantFonts");

	dfont = fz_arrayget(dfonts, 0);
	error = pdf_resolve(&dfont, xref);
	if (error)
	{
		fz_dropobj(dfonts);
		return fz_rethrow(error, "cannot find descendant font");
	}

	subtype = fz_dictgets(dfont, "Subtype");
	encoding = fz_dictgets(dict, "Encoding");
	tounicode = fz_dictgets(dict, "ToUnicode");

	if (!strcmp(fz_toname(subtype), "CIDFontType0"))
		error = loadcidfont(fontp, xref, dfont, ref, encoding, tounicode);
	else if (!strcmp(fz_toname(subtype), "CIDFontType2"))
		error = loadcidfont(fontp, xref, dfont, ref, encoding, tounicode);
	else
		error = fz_throw("syntaxerror: unknown cid font type");

	fz_dropobj(dfont);
	fz_dropobj(dfonts);

	if (error)
		return fz_rethrow(error, "cannot load descendant font");

	return fz_okay;
}
Ejemplo n.º 7
0
static fz_error *
loadcalgray(fz_colorspace **csp, pdf_xref *xref, fz_obj *dict)
{
	fz_error *error;
	struct calgray *cs;
	fz_obj *tmp;

	error = pdf_resolve(&dict, xref);
	if (error)
		return error;

	cs = fz_malloc(sizeof(struct calgray));
	if (!cs)
		return fz_outofmem;

	pdf_logrsrc("load CalGray\n");

	initcs((fz_colorspace*)cs, "CalGray", 1, graytoxyz, xyztogray, nil);

	cs->white[0] = 1.0;
	cs->white[1] = 1.0;
	cs->white[2] = 1.0;

	cs->black[0] = 0.0;
	cs->black[1] = 0.0;
	cs->black[2] = 0.0;

	cs->gamma = 1.0;

	tmp = fz_dictgets(dict, "WhitePoint");
	if (fz_isarray(tmp))
	{
		cs->white[0] = fz_toreal(fz_arrayget(tmp, 0));
		cs->white[1] = fz_toreal(fz_arrayget(tmp, 1));
		cs->white[2] = fz_toreal(fz_arrayget(tmp, 2));
	}

	tmp = fz_dictgets(dict, "BlackPoint");
	if (fz_isarray(tmp))
	{
		cs->black[0] = fz_toreal(fz_arrayget(tmp, 0));
		cs->black[1] = fz_toreal(fz_arrayget(tmp, 1));
		cs->black[2] = fz_toreal(fz_arrayget(tmp, 2));
	}

	tmp = fz_dictgets(dict, "Gamma");
	if (fz_isreal(tmp))
		cs->gamma = fz_toreal(tmp);

	fz_dropobj(dict);

	*csp = (fz_colorspace*) cs;
	return nil;
}
Ejemplo n.º 8
0
fz_error *
pdf_loadoutline(pdf_outline **nodep, pdf_xref *xref)
{
	fz_error *error;
	pdf_outline *node;
	fz_obj *obj;
	fz_obj *first;

	pdf_logpage("load outlines {\n");

	node = nil;

	obj = fz_dictgets(xref->root, "Outlines");
	if (obj)
	{
		error = pdf_resolve(&obj, xref);
		if (error)
			return error;

		first = fz_dictgets(obj, "First");
		if (first)
		{
			error = pdf_resolve(&first, xref);
			fz_dropobj(obj);
			if (error)
				return error;
			error = loadoutline(&node, xref, first);
			fz_dropobj(first);
			if (error)
				return error;
		}
		else
			fz_dropobj(obj);
	}

	pdf_logpage("}\n");

	*nodep = node;
	return nil;
}
Ejemplo n.º 9
0
fz_error *
pdf_loadnametrees(pdf_xref *xref)
{
	fz_error *error;
	fz_obj *names;
	fz_obj *dests;

	/* PDF 1.1 */
	dests = fz_dictgets(xref->root, "Dests");
	if (dests)
	{
		error = pdf_resolve(&dests, xref);
		if (error)
			return error;
		xref->dests = dests;
		return nil;
	}

	/* PDF 1.2 */
	names = fz_dictgets(xref->root, "Names");
	if (names)
	{
		error = pdf_resolve(&names, xref);
		if (error)
			return error;
		dests = fz_dictgets(names, "Dests");
		if (dests)
		{
			error = pdf_loadnametree(&xref->dests, xref, dests);
			if (error)
			{
				fz_dropobj(names);
				return error;
			}
		}
		fz_dropobj(names);
	}

	return nil;
}
Ejemplo n.º 10
0
/*
 * Build a filter for reading raw stream data.
 * This is a null filter to constrain reading to the
 * stream length, followed by a decryption filter.
 */
static fz_error *
buildrawfilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj, int oid, int gen)
{
	fz_error *error;
	fz_filter *base;
	fz_obj *stmlen;
	int len;

	stmlen = fz_dictgets(stmobj, "Length");
	error = pdf_resolve(&stmlen, xref);
	if (error)
		return fz_rethrow(error, "cannot resolve stream /Length");
	len = fz_toint(stmlen);
	fz_dropobj(stmlen);

	error = fz_newnullfilter(&base, len);
	if (error)
		return fz_rethrow(error, "cannot create null filter");

	if (xref->crypt)
	{
		fz_filter *crypt;
		fz_filter *pipe;

		error = pdf_cryptstream(&crypt, xref->crypt, oid, gen);
		if (error)
		{
			fz_dropfilter(base);
			return fz_rethrow(error, "cannot create decryption filter");
		}

		error = fz_newpipeline(&pipe, base, crypt);
		fz_dropfilter(base);
		fz_dropfilter(crypt);
		if (error)
			return fz_rethrow(error, "cannot create pipeline filter");

		*filterp = pipe;
	}
	else
	{
		*filterp = base;
	}

	return fz_okay;
}
Ejemplo n.º 11
0
fz_error *
pdf_loadcolorspace(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj)
{
	if (fz_isname(obj))
	{
		if (!strcmp(fz_toname(obj), "DeviceGray"))
			*csp = pdf_devicegray;
		else if (!strcmp(fz_toname(obj), "DeviceRGB"))
			*csp = pdf_devicergb;
		else if (!strcmp(fz_toname(obj), "DeviceCMYK"))
			*csp = pdf_devicecmyk;
		else if (!strcmp(fz_toname(obj), "G"))
			*csp = pdf_devicegray;
		else if (!strcmp(fz_toname(obj), "RGB"))
			*csp = pdf_devicergb;
		else if (!strcmp(fz_toname(obj), "CMYK"))
			*csp = pdf_devicecmyk;
		else if (!strcmp(fz_toname(obj), "Pattern"))
			*csp = pdf_devicepattern;
		else
			return fz_throw("unknown colorspace: %s", fz_toname(obj));
		return nil;
	}

	else if (fz_isarray(obj))
	{
		fz_obj *name = fz_arrayget(obj, 0);

		if (fz_isname(name))
		{
			if (!strcmp(fz_toname(name), "CalCMYK"))
				*csp = pdf_devicecmyk;

#ifdef USECAL
			else if (!strcmp(fz_toname(name), "CalGray"))
				return loadcalgray(csp, xref, fz_arrayget(obj, 1));
			else if (!strcmp(fz_toname(name), "CalRGB"))
				return loadcalrgb(csp, xref, fz_arrayget(obj, 1));
			else if (!strcmp(fz_toname(name), "Lab"))
				return loadlab(csp, xref, fz_arrayget(obj, 1));
#else
			else if (!strcmp(fz_toname(name), "CalGray"))
				*csp = pdf_devicegray;
			else if (!strcmp(fz_toname(name), "CalRGB"))
				*csp = pdf_devicergb;
			else if (!strcmp(fz_toname(name), "Lab"))
				*csp = pdf_devicelab;
#endif

			else if (!strcmp(fz_toname(name), "ICCBased"))
				return loadiccbased(csp, xref, fz_arrayget(obj, 1));

			else if (!strcmp(fz_toname(name), "Indexed"))
				return loadindexed(csp, xref, obj);

			else if (!strcmp(fz_toname(name), "I"))
				return loadindexed(csp, xref, obj);

			else if (!strcmp(fz_toname(name), "Separation"))
				return loadseparation(csp, xref, obj);

			else if (!strcmp(fz_toname(name), "DeviceN"))
				return loadseparation(csp, xref, obj);

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

				obj = fz_arrayget(obj, 1);
				if (!obj)
				{
					*csp = pdf_devicepattern;
					return nil;
				}

				error = pdf_resolve(&obj, xref);
				if (error)
					return error;
				error = pdf_loadcolorspace(csp, xref, obj);
				fz_dropobj(obj);
				return error;
			}

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

			return nil;
		}
	}

	return fz_throw("syntaxerror: could not parse color space");
}
Ejemplo n.º 12
0
static fz_error *
loadindexed(fz_colorspace **csp, pdf_xref *xref, fz_obj *array)
{
	fz_error *error;
	pdf_indexed *cs;
	fz_obj *baseobj = fz_arrayget(array, 1);
	fz_obj *highobj = fz_arrayget(array, 2);
	fz_obj *lookup = fz_arrayget(array, 3);
	fz_colorspace *base;
	int n;

	pdf_logrsrc("load Indexed {\n");

	error = pdf_resolve(&baseobj, xref);
	if (error)
		return error;
	error = pdf_loadcolorspace(&base, xref, baseobj);
	fz_dropobj(baseobj);
	if (error)
		return error;

	pdf_logrsrc("base %s\n", base->name);

	cs = fz_malloc(sizeof(pdf_indexed));
	if (!cs)
	{
		fz_dropcolorspace(base);
		return fz_outofmem;
	}

	initcs((fz_colorspace*)cs, "Indexed", 1, nil, nil, dropindexed);

	cs->base = base;
	cs->high = fz_toint(highobj);

	n = base->n * (cs->high + 1);

	cs->lookup = fz_malloc(n);
	if (!cs->lookup)
	{
		fz_dropcolorspace((fz_colorspace*)cs);
		return fz_outofmem;
	}

	if (fz_isstring(lookup) && fz_tostrlen(lookup) == n)
	{
		unsigned char *buf;
		int i;

		pdf_logrsrc("string lookup\n");

		buf = fz_tostrbuf(lookup);
		for (i = 0; i < n; i++)
			cs->lookup[i] = buf[i];
	}

	if (fz_isindirect(lookup))
	{
		fz_buffer *buf;
		int i;

		pdf_logrsrc("stream lookup\n");

		error = pdf_loadstream(&buf, xref, fz_tonum(lookup), fz_togen(lookup));
		if (error)
		{
			fz_dropcolorspace((fz_colorspace*)cs);
			return error;
		}

		for (i = 0; i < n && i < (buf->wp - buf->rp); i++)
			cs->lookup[i] = buf->rp[i];

		fz_dropbuffer(buf);
	}

	pdf_logrsrc("}\n");

	*csp = (fz_colorspace*)cs;
	return nil;
}
Ejemplo n.º 13
0
/* TODO error cleanup */
fz_error *
pdf_loadimage(pdf_image **imgp, pdf_xref *xref, fz_obj *dict, fz_obj *ref)
{
	fz_error *error;
	pdf_image *img;
	pdf_image *mask;
	int ismask;
	fz_obj *obj;
	fz_obj *sub;
	int i;

	int w, h, bpc;
	int n = 0;
	int a = 0;
	int usecolorkey = 0;
	fz_colorspace *cs = nil;
	pdf_indexed *indexed = nil;
	int stride;
#ifndef PSP
	printf("LI\n");
#endif
	if ((*imgp = pdf_finditem(xref->store, PDF_KIMAGE, ref)))
	{
		fz_keepimage((fz_image*)*imgp);
		return nil;
	}

	img = fz_malloc(sizeof(pdf_image));
	if (!img)
		return fz_outofmem;

	img->super.refs = 0;

	pdf_logimage("load image %d %d (%p) {\n", fz_tonum(ref), fz_togen(ref), img);

	/*
	 * Dimensions, BPC and ColorSpace
	 */

	w = fz_toint(fz_dictgets(dict, "Width"));
	h = fz_toint(fz_dictgets(dict, "Height"));
	bpc = fz_toint(fz_dictgets(dict, "BitsPerComponent"));

	pdf_logimage("size %dx%d %d\n", w, h, bpc);

	cs = nil;
	obj = fz_dictgets(dict, "ColorSpace");
	if (obj)
	{
		cs = pdf_finditem(xref->store, PDF_KCOLORSPACE, obj);
		if (cs)
			fz_keepcolorspace(cs);
		else
		{
			error = pdf_resolve(&obj, xref);
			if (error)
				return error;

			error = pdf_loadcolorspace(&cs, xref, obj);
			if (error)
				return error;

			fz_dropobj(obj);
		}

		if (!strcmp(cs->name, "Indexed"))
		{
			pdf_logimage("indexed\n");
			indexed = (pdf_indexed*)cs;
			cs = indexed->base;
		}
		n = cs->n;
		a = 0;

		pdf_logimage("colorspace %s\n", cs->name);
	}

	/*
	 * ImageMask, Mask and SoftMask
	 */

	mask = nil;

	ismask = fz_tobool(fz_dictgets(dict, "ImageMask"));
	if (ismask)
	{
		pdf_logimage("is mask\n");
		bpc = 1;
		n = 0;
		a = 1;
	}

	obj = fz_dictgets(dict, "SMask");
	if (fz_isindirect(obj))
	{
		pdf_logimage("has soft mask\n");

		error = pdf_loadindirect(&sub, xref, obj);
		if (error)
			return error;

		error = pdf_loadimage(&mask, xref, sub, obj);
		if (error)
			return error;

		if (mask->super.cs != pdf_devicegray)
			return fz_throw("syntaxerror: SMask must be DeviceGray");

		mask->super.cs = 0;
		mask->super.n = 0;
		mask->super.a = 1;

		fz_dropobj(sub);
	}

	obj = fz_dictgets(dict, "Mask");
	if (fz_isindirect(obj))
	{
		error = pdf_loadindirect(&sub, xref, obj);
		if (error)
			return error;
		if (fz_isarray(sub))
		{
			usecolorkey = 1;
			loadcolorkey(img->colorkey, bpc, indexed != nil, sub);
		}
		else
		{
			pdf_logimage("has mask\n");
			error = pdf_loadimage(&mask, xref, sub, obj);
			if (error)
				return error;
		}
		fz_dropobj(sub);
	}
	else if (fz_isarray(obj))
	{
		usecolorkey = 1;
		loadcolorkey(img->colorkey, bpc, indexed != nil, obj);
	}

	/*
	 * Decode
	 */

	obj = fz_dictgets(dict, "Decode");
	if (fz_isarray(obj))
	{
		pdf_logimage("decode array\n");
		if (indexed)
			for (i = 0; i < 2; i++)
				img->decode[i] = fz_toreal(fz_arrayget(obj, i));
		else
			for (i = 0; i < (n + a) * 2; i++)
				img->decode[i] = fz_toreal(fz_arrayget(obj, i));
	}
	else
	{
		if (indexed)
			for (i = 0; i < 2; i++)
				img->decode[i] = i & 1 ? (1 << bpc) - 1 : 0;
		else
			for (i = 0; i < (n + a) * 2; i++)
				img->decode[i] = i & 1;
	}

	/*
	 * Load samples
	 */

	if (indexed)
		stride = (w * bpc + 7) / 8;
	else
		stride = (w * (n + a) * bpc + 7) / 8;

	// ccm
	// do not load images larger than 2MB uncompressed
	int early_reject = 0;
	if (h * stride <= 2*1024*1024) {
		error = pdf_loadstream(&img->samples, xref, fz_tonum(ref), fz_togen(ref));
		if (error)
		{
			/* TODO: colorspace? */
			fz_free(img);
			return error;
		}
	
		if (img->samples->wp - img->samples->bp < stride * h)
		{
			/* TODO: colorspace? */
			fz_dropbuffer(img->samples);
			fz_free(img);
			return fz_throw("syntaxerror: truncated image data");
		}
	
		/* 0 means opaque and 1 means transparent, so we invert to get alpha */
		if (ismask)
		{
			unsigned char *p;
			for (p = img->samples->bp; p < img->samples->ep; p++)
				*p = ~*p;
		}
	} else {
#ifndef PSP
		printf("LI - %p - early reject\n", img);
#endif
		img->samples = nil;
		early_reject = 1;
	}

	/*
	 * Create image object
	 */

	img->super.loadtile = pdf_loadtile;
	img->super.drop = pdf_dropimage;
	img->super.cs = cs;
	img->super.w = w;
	img->super.h = h;
	img->super.n = n;
	img->super.a = a;
	img->indexed = indexed;
	img->stride = stride;
	img->bpc = bpc;
	img->mask = (fz_image*)mask;
	img->usecolorkey = usecolorkey;
	if (img->mask)
		fz_keepimage(img->mask);

	// ccm
	#if 1
	int bs = 0;
	if (img->samples)
		bs = (int)(img->samples->wp) - (int)(img->samples->rp);
	if (early_reject || (image_buffers_size + bs >= image_buffers_size_max)) {
#ifndef PSP
		printf("LI - %p - optimized out\n", img);
#endif
		if (img->samples)
			fz_dropbuffer(img->samples);
		if (img->mask)
			fz_dropimage(img->mask);
		fz_newbuffer(&img->samples, 8);
		img->super.w = 1;
		img->super.h = 1;
		img->super.n = 3;
		img->super.a = 0;
		img->super.refs = 0;
		unsigned char *p;
		for (p = img->samples->bp; p < img->samples->ep; p++)
			*p = 0x7f;
		img->indexed = 0;
		img->stride = (1 * (3 + 0) * 8 + 7) / 8; //(w * (n + a) * bpc + 7) / 8;
		img->super.cs = cs;
		img->super.loadtile = fakeImageTile;
		img->bpc = 8;
		img->mask = NULL;
		img->usecolorkey = 0;
	} else {
		image_buffers_size += bs;
	}
	#endif

	pdf_logimage("}\n");

	error = pdf_storeitem(xref->store, PDF_KIMAGE, ref, img);
	if (error)
	{
		fz_dropimage((fz_image*)img);
		return error;
	}

	*imgp = img;
	return nil;
}
Ejemplo n.º 14
0
static fz_error *
loadlab(fz_colorspace **csp, pdf_xref *xref, fz_obj *dict)
{
	fz_error *error;
	struct cielab *cs;
	fz_obj *tmp;

	error = pdf_resolve(&dict, xref);
	if (error)
		return error;

	cs = fz_malloc(sizeof(struct cielab));
	if (!cs)
		return fz_outofmem;

	pdf_logrsrc("load Lab\n");

	initcs((fz_colorspace*)cs, "Lab", 3, labtoxyz, xyztolab, nil);

	cs->white[0] = 1.0;
	cs->white[1] = 1.0;
	cs->white[2] = 1.0;

	cs->black[0] = 0.0;
	cs->black[1] = 0.0;
	cs->black[2] = 0.0;

	cs->range[0] = -100;
	cs->range[1] = 100;
	cs->range[2] = -100;
	cs->range[3] = 100;

	tmp = fz_dictgets(dict, "WhitePoint");
	if (fz_isarray(tmp))
	{
		cs->white[0] = fz_toreal(fz_arrayget(tmp, 0));
		cs->white[1] = fz_toreal(fz_arrayget(tmp, 1));
		cs->white[2] = fz_toreal(fz_arrayget(tmp, 2));
	}

	tmp = fz_dictgets(dict, "BlackPoint");
	if (fz_isarray(tmp))
	{
		cs->black[0] = fz_toreal(fz_arrayget(tmp, 0));
		cs->black[1] = fz_toreal(fz_arrayget(tmp, 1));
		cs->black[2] = fz_toreal(fz_arrayget(tmp, 2));
	}

	tmp = fz_dictgets(dict, "Range");
	if (fz_isarray(tmp))
	{
		cs->range[0] = fz_toreal(fz_arrayget(tmp, 0));
		cs->range[1] = fz_toreal(fz_arrayget(tmp, 1));
		cs->range[2] = fz_toreal(fz_arrayget(tmp, 2));
		cs->range[3] = fz_toreal(fz_arrayget(tmp, 3));
	}

	fz_dropobj(dict);

	*csp = (fz_colorspace*) cs;
	return nil;
}
Ejemplo n.º 15
0
fz_error *
pdf_loadxobject(pdf_xobject **formp, pdf_xref *xref, fz_obj *dict, fz_obj *ref)
{
	fz_error *error;
	pdf_xobject *form;
	fz_obj *obj;

	if ((*formp = pdf_finditem(xref->store, PDF_KXOBJECT, ref)))
	{
		pdf_keepxobject(*formp);
		return fz_okay;
	}

	form = fz_malloc(sizeof(pdf_xobject));
	if (!form)
		return fz_throw("outofmem: xobject struct");

	form->refs = 1;
	form->resources = nil;
	form->contents = nil;

	/* Store item immediately, to avoid infinite recursion if contained
	   objects refer again to this xobject */
	error = pdf_storeitem(xref->store, PDF_KXOBJECT, ref, form);
	if (error)
	{
		pdf_dropxobject(form);
		return fz_rethrow(error, "cannot store xobject resource");
	}

	pdf_logrsrc("load xobject %d %d (%p) {\n", fz_tonum(ref), fz_togen(ref), form);

	obj = fz_dictgets(dict, "BBox");
	form->bbox = pdf_torect(obj);

	pdf_logrsrc("bbox [%g %g %g %g]\n",
			form->bbox.x0, form->bbox.y0,
			form->bbox.x1, form->bbox.y1);

	obj = fz_dictgets(dict, "Matrix");
	if (obj)
		form->matrix = pdf_tomatrix(obj);
	else
		form->matrix = fz_identity();

	pdf_logrsrc("matrix [%g %g %g %g %g %g]\n",
			form->matrix.a, form->matrix.b,
			form->matrix.c, form->matrix.d,
			form->matrix.e, form->matrix.f);

	obj = fz_dictgets(dict, "I");
	form->isolated = fz_tobool(obj);
	obj = fz_dictgets(dict, "K");
	form->knockout = fz_tobool(obj);

	pdf_logrsrc("isolated %d\n", form->isolated);
	pdf_logrsrc("knockout %d\n", form->knockout);

	obj = fz_dictgets(dict, "Resources");
	if (obj)
	{
		error = pdf_resolve(&obj, xref);
		if (error)
		{
			fz_dropobj(obj);
			error = fz_rethrow(error, "cannot resolve xobject resources");
			goto cleanup;
		}
		error = pdf_loadresources(&form->resources, xref, obj);
		fz_dropobj(obj);
		if (error)
		{
			error = fz_rethrow(error, "cannot load xobject resources");
			goto cleanup;
		}
	}

	error = pdf_loadstream(&form->contents, xref, fz_tonum(ref), fz_togen(ref));
	if (error)
	{
		error = fz_rethrow(error, "cannot load xobject content stream");
		goto cleanup;
	}

	pdf_logrsrc("stream %d bytes\n", form->contents->wp - form->contents->rp);

	pdf_logrsrc("}\n");

	*formp = form;
	return fz_okay;
cleanup:
	pdf_removeitem(xref->store, PDF_KXOBJECT, ref);
	pdf_dropxobject(form);
	return error;
}
Ejemplo n.º 16
0
fz_error *
pdf_loadshade(fz_shade **shadep, pdf_xref *xref, fz_obj *dict, fz_obj *ref)
{
	fz_error *error;
	fz_matrix mat;
	fz_obj *obj;
	fz_obj *shd;

	if ((*shadep = pdf_finditem(xref->store, PDF_KSHADE, ref)))
		return nil;

	/*
	 * Type 2 pattern dictionary
	 */
	if (fz_dictgets(dict, "PatternType"))
	{
		pdf_logshade("load shade pattern %d %d {\n", fz_tonum(ref), fz_togen(ref));

		obj = fz_dictgets(dict, "Matrix");
		if (obj)
		{
			mat = pdf_tomatrix(obj);
			pdf_logshade("matrix [%g %g %g %g %g %g]\n",
				mat.a, mat.b, mat.c, mat.d, mat.e, mat.f);
		}
		else
		{
			mat = fz_identity();
		}

		obj = fz_dictgets(dict, "ExtGState");
		if (obj)
		{
			pdf_logshade("extgstate ...\n");
		}

		obj = fz_dictgets(dict, "Shading");
		if (!obj)
			return fz_throw("syntaxerror: missing shading dictionary");

		shd = obj;
		error = pdf_resolve(&shd, xref);
		if (error)
			return error;
		error = loadshadedict(shadep, xref, shd, obj, mat);
		fz_dropobj(shd);
		if (error)
			return error;

		pdf_logshade("}\n");
	}

	/*
	 * Naked shading dictionary
	 */
	else
	{
		error = loadshadedict(shadep, xref, dict, ref, fz_identity());
		if (error)
			return error;
	}

	error = pdf_storeitem(xref->store, PDF_KSHADE, ref, *shadep);
	if (error)
	{
		fz_dropshade(*shadep);
		return error;
	}

	return nil;
}
Ejemplo n.º 17
0
static fz_error *
loadcidfont(pdf_font **fontp, pdf_xref *xref, fz_obj *dict, fz_obj *ref, fz_obj *encoding, fz_obj *tounicode)
{
	fz_error *error;
	fz_obj *widths = nil;
	fz_obj *descriptor;
	pdf_font *font;
	FT_Face face;
	fz_irect bbox;
	int kind;
	char collection[256];
	char *basefont;
	int i, k;

	/*
	 * Get font name and CID collection
	 */

	basefont = fz_toname(fz_dictgets(dict, "BaseFont"));

	{
		fz_obj *cidinfo;
		fz_obj *obj;
		char tmpstr[64];
		int tmplen;

		cidinfo = fz_dictgets(dict, "CIDSystemInfo");

		error = pdf_resolve(&cidinfo, xref);
		if (error)
			return fz_rethrow(error, "cannot find CIDSystemInfo");

		obj = fz_dictgets(cidinfo, "Registry");
		tmplen = MIN(sizeof tmpstr - 1, fz_tostrlen(obj));
		memcpy(tmpstr, fz_tostrbuf(obj), tmplen);
		tmpstr[tmplen] = '\0';
		strlcpy(collection, tmpstr, sizeof collection);

		strlcat(collection, "-", sizeof collection);

		obj = fz_dictgets(cidinfo, "Ordering");
		tmplen = MIN(sizeof tmpstr - 1, fz_tostrlen(obj));
		memcpy(tmpstr, fz_tostrbuf(obj), tmplen);
		tmpstr[tmplen] = '\0';
		strlcat(collection, tmpstr, sizeof collection);

		fz_dropobj(cidinfo);
	}

	/*
	 * Load font file
	 */

	font = pdf_newfont(basefont);
	if (!font)
		return fz_outofmem;

	pdf_logfont("load cid font %d %d (%p) {\n", fz_tonum(ref), fz_togen(ref), font);
	pdf_logfont("basefont %s\n", basefont);
	pdf_logfont("collection %s\n", collection);

	descriptor = fz_dictgets(dict, "FontDescriptor");
	if (descriptor)
		error = pdf_loadfontdescriptor(font, xref, descriptor, collection);
	else
		error = fz_throw("syntaxerror: missing font descriptor");
	if (error)
		goto cleanup;

	face = font->ftface;
	kind = ftkind(face);

	bbox.x0 = (face->bbox.xMin * 1000) / face->units_per_EM;
	bbox.y0 = (face->bbox.yMin * 1000) / face->units_per_EM;
	bbox.x1 = (face->bbox.xMax * 1000) / face->units_per_EM;
	bbox.y1 = (face->bbox.yMax * 1000) / face->units_per_EM;

	pdf_logfont("ft bbox [%d %d %d %d]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1);

	if (bbox.x0 == bbox.x1)
		fz_setfontbbox((fz_font*)font, -1000, -1000, 2000, 2000);
	else
		fz_setfontbbox((fz_font*)font, bbox.x0, bbox.y0, bbox.x1, bbox.y1);

	/*
	 * Encoding
	 */

	if (fz_isname(encoding))
	{
		pdf_logfont("encoding /%s\n", fz_toname(encoding));
		if (!strcmp(fz_toname(encoding), "Identity-H"))
			error = pdf_newidentitycmap(&font->encoding, 0, 2);
		else if (!strcmp(fz_toname(encoding), "Identity-V"))
			error = pdf_newidentitycmap(&font->encoding, 1, 2);
		else
			error = pdf_loadsystemcmap(&font->encoding, fz_toname(encoding));
	}
	else if (fz_isindirect(encoding))
	{
		pdf_logfont("encoding %d %d R\n", fz_tonum(encoding), fz_togen(encoding));
		error = pdf_loadembeddedcmap(&font->encoding, xref, encoding);
	}
	else
	{
		error = fz_throw("syntaxerror: font missing encoding");
	}
	if (error)
		goto cleanup;

	fz_setfontwmode((fz_font*)font, pdf_getwmode(font->encoding));
	pdf_logfont("wmode %d\n", pdf_getwmode(font->encoding));

	if (kind == TRUETYPE)
	{
		fz_obj *cidtogidmap;

		cidtogidmap = fz_dictgets(dict, "CIDToGIDMap");
		if (fz_isindirect(cidtogidmap))
		{
			unsigned short *map;
			fz_buffer *buf;
			int len;

			pdf_logfont("cidtogidmap stream\n");

			error = pdf_loadstream(&buf, xref, fz_tonum(cidtogidmap), fz_togen(cidtogidmap));
			if (error)
				goto cleanup;

			len = (buf->wp - buf->rp) / 2;

			map = fz_malloc(len * sizeof(unsigned short));
			if (!map) {
				fz_dropbuffer(buf);
				error = fz_outofmem;
				goto cleanup;
			}

			for (i = 0; i < len; i++)
				map[i] = (buf->rp[i * 2] << 8) + buf->rp[i * 2 + 1];

			font->ncidtogid = len;
			font->cidtogid = map;

			fz_dropbuffer(buf);
		}

		/* if truetype font is external, cidtogidmap should not be identity */
		/* so we map from cid to unicode and then map that through the (3 1) */
		/* unicode cmap to get a glyph id */
		else if (font->substitute)
		{
			int e;

			pdf_logfont("emulate ttf cidfont\n");

			e = FT_Select_Charmap(face, ft_encoding_unicode);
			if (e)
				return fz_throw("fonterror: no unicode cmap when emulating CID font");

			if (!strcmp(collection, "Adobe-CNS1"))
				error = pdf_loadsystemcmap(&font->tottfcmap, "Adobe-CNS1-UCS2");
			else if (!strcmp(collection, "Adobe-GB1"))
				error = pdf_loadsystemcmap(&font->tottfcmap, "Adobe-GB1-UCS2");
			else if (!strcmp(collection, "Adobe-Japan1"))
				error = pdf_loadsystemcmap(&font->tottfcmap, "Adobe-Japan1-UCS2");
			else if (!strcmp(collection, "Adobe-Japan2"))
				error = pdf_loadsystemcmap(&font->tottfcmap, "Adobe-Japan2-UCS2");
			else if (!strcmp(collection, "Adobe-Korea1"))
				error = pdf_loadsystemcmap(&font->tottfcmap, "Adobe-Korea1-UCS2");
			else
				error = fz_okay;

			if (error)
				return fz_rethrow(error, "cannot load system cmap %s", collection);
		}
	}

	error = pdf_loadtounicode(font, xref, nil, collection, tounicode);
	if (error)
		goto cleanup;

	/*
	 * Horizontal
	 */

	fz_setdefaulthmtx((fz_font*)font, fz_toint(fz_dictgets(dict, "DW")));

	widths = fz_dictgets(dict, "W");
	if (widths)
	{
		int c0, c1, w;
		fz_obj *obj;

		error = pdf_resolve(&widths, xref);
		if (error)
			goto cleanup;

		for (i = 0; i < fz_arraylen(widths); )
		{
			c0 = fz_toint(fz_arrayget(widths, i));
			obj = fz_arrayget(widths, i + 1);
			if (fz_isarray(obj))
			{
				for (k = 0; k < fz_arraylen(obj); k++)
				{
					w = fz_toint(fz_arrayget(obj, k));
					error = fz_addhmtx((fz_font*)font, c0 + k, c0 + k, w);
					if (error)
						goto cleanup;
				}
				i += 2;
			}
			else
			{
				c1 = fz_toint(obj);
				w = fz_toint(fz_arrayget(widths, i + 2));
				error = fz_addhmtx((fz_font*)font, c0, c1, w);
				if (error)
					goto cleanup;
				i += 3;
			}
		}

		fz_dropobj(widths);
	}

	error = fz_endhmtx((fz_font*)font);
	if (error)
		goto cleanup;

	/*
	 * Vertical
	 */

	if (pdf_getwmode(font->encoding) == 1)
	{
		fz_obj *obj;
		int dw2y = 880;
		int dw2w = -1000;

		obj = fz_dictgets(dict, "DW2");
		if (obj)
		{
			dw2y = fz_toint(fz_arrayget(obj, 0));
			dw2w = fz_toint(fz_arrayget(obj, 1));
		}

		fz_setdefaultvmtx((fz_font*)font, dw2y, dw2w);

		widths = fz_dictgets(dict, "W2");
		if (widths)
		{
			int c0, c1, w, x, y, k;

			error = pdf_resolve(&widths, xref);
			if (error)
				goto cleanup;

			for (i = 0; i < fz_arraylen(widths); )
			{
				c0 = fz_toint(fz_arrayget(widths, i));
				obj = fz_arrayget(widths, i + 1);
				if (fz_isarray(obj))
				{
					for (k = 0; k < fz_arraylen(obj); k += 3)
					{
						w = fz_toint(fz_arrayget(obj, k + 0));
						x = fz_toint(fz_arrayget(obj, k + 1));
						y = fz_toint(fz_arrayget(obj, k + 2));
						error = fz_addvmtx((fz_font*)font, c0 + k, c0 + k, x, y, w);
						if (error)
							goto cleanup;
					}
					i += 2;
				}
				else
				{
					c1 = fz_toint(obj);
					w = fz_toint(fz_arrayget(widths, i + 2));
					x = fz_toint(fz_arrayget(widths, i + 3));
					y = fz_toint(fz_arrayget(widths, i + 4));
					error = fz_addvmtx((fz_font*)font, c0, c1, x, y, w);
					if (error)
						goto cleanup;
					i += 5;
				}
			}

			fz_dropobj(widths);
		}

		error = fz_endvmtx((fz_font*)font);
		if (error)
			goto cleanup;
	}

	pdf_logfont("}\n");

	*fontp = font;
	return fz_okay;

cleanup:
	if (widths)
		fz_dropobj(widths);
	fz_dropfont((fz_font*)font);
	return fz_rethrow(error, "cannot load cid font");
}
Ejemplo n.º 18
0
static fz_error *
loadsimplefont(pdf_font **fontp, pdf_xref *xref, fz_obj *dict, fz_obj *ref)
{
	fz_error *error;
	fz_obj *descriptor = nil;
	fz_obj *encoding = nil;
	fz_obj *widths = nil;
	fz_obj *basefontobj = nil;
	unsigned short *etable = nil;
	pdf_font *font;
	fz_irect bbox;
	FT_Face face;
	FT_CharMap cmap;
	int kind;
	int symbolic;

	char *basefont;
	char *fontname;
	char *estrings[256];
	char ebuffer[256][32];
	int i, k, n;
	int fterr;

	basefontobj = fz_dictgets(dict, "BaseFont");
	error = pdf_resolve(&basefontobj, xref);
	if (error)
		return fz_rethrow(error, "cannot load simple font");
	basefont = fz_toname(basefontobj);
	fontname = cleanfontname(basefont);

	/*
	 * Load font file
	 */

	font = pdf_newfont(fontname);
	if (!font)
		return fz_outofmem;

	pdf_logfont("load simple font %d %d (%p) {\n", fz_tonum(ref), fz_togen(ref), font);
	pdf_logfont("basefont0 %s\n", basefont);
	pdf_logfont("basefont1 %s\n", fontname);

	descriptor = fz_dictgets(dict, "FontDescriptor");
	if (descriptor && basefont == fontname)
		error = pdf_loadfontdescriptor(font, xref, descriptor, nil);
	else
		error = pdf_loadbuiltinfont(font, fontname);
	if (error)
		goto cleanup;

	face = font->ftface;
	kind = ftkind(face);

	pdf_logfont("ft name '%s' '%s'\n", face->family_name, face->style_name);

	bbox.x0 = (face->bbox.xMin * 1000) / face->units_per_EM;
	bbox.y0 = (face->bbox.yMin * 1000) / face->units_per_EM;
	bbox.x1 = (face->bbox.xMax * 1000) / face->units_per_EM;
	bbox.y1 = (face->bbox.yMax * 1000) / face->units_per_EM;

	pdf_logfont("ft bbox [%d %d %d %d]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1);

	if (bbox.x0 == bbox.x1)
		fz_setfontbbox((fz_font*)font, -1000, -1000, 2000, 2000);
	else
		fz_setfontbbox((fz_font*)font, bbox.x0, bbox.y0, bbox.x1, bbox.y1);

	/*
	 * Encoding
	 */

	symbolic = font->flags & 4;

	if (face->num_charmaps > 0)
		cmap = face->charmaps[0];
	else
		cmap = nil;

	for (i = 0; i < face->num_charmaps; i++)
	{
		FT_CharMap test = face->charmaps[i];

		if (kind == TYPE1)
		{
			if (test->platform_id == 7)
				cmap = test;
		}

		if (kind == TRUETYPE)
		{
			if (test->platform_id == 1 && test->encoding_id == 0)
				cmap = test;
			if (test->platform_id == 3 && test->encoding_id == 1)
				cmap = test;
		}
	}

	if (cmap)
	{
		fterr = FT_Set_Charmap(face, cmap);
		if (fterr)
		{
			error = fz_throw("freetype could not set cmap: %s", ft_errstr(fterr));
			goto cleanup;
		}
	}
	else
		fz_warn("freetype could not find any cmaps");

	etable = fz_malloc(sizeof(unsigned short) * 256);
	if (!etable)
		goto cleanup;

	for (i = 0; i < 256; i++)
	{
		estrings[i] = nil;
		etable[i] = 0;
	}

	encoding = fz_dictgets(dict, "Encoding");
	if (encoding && !(kind == TRUETYPE && symbolic))
	{
		error = pdf_resolve(&encoding, xref);
		if (error)
			goto cleanup;

		if (fz_isname(encoding))
			pdf_loadencoding(estrings, fz_toname(encoding));

		if (fz_isdict(encoding))
		{
			fz_obj *base, *diff, *item;

			base = fz_dictgets(encoding, "BaseEncoding");
			if (fz_isname(base))
				pdf_loadencoding(estrings, fz_toname(base));

			diff = fz_dictgets(encoding, "Differences");
			if (fz_isarray(diff))
			{
				n = fz_arraylen(diff);
				k = 0;
				for (i = 0; i < n; i++)
				{
					item = fz_arrayget(diff, i);
					if (fz_isint(item))
						k = fz_toint(item);
					if (fz_isname(item))
						estrings[k++] = fz_toname(item);
					if (k < 0) k = 0;
					if (k > 255) k = 255;
				}
			}
		}

		if (kind == TYPE1)
		{
			pdf_logfont("encode type1/cff by strings\n");
			for (i = 0; i < 256; i++)
				if (estrings[i])
					etable[i] = FT_Get_Name_Index(face, estrings[i]);
				else
					etable[i] = FT_Get_Char_Index(face, i);
		}

		if (kind == TRUETYPE)
		{
			/* Unicode cmap */
			if (face->charmap && face->charmap->platform_id == 3)
			{
				pdf_logfont("encode truetype via unicode\n");
				for (i = 0; i < 256; i++)
					if (estrings[i])
					{
						int aglbuf[256];
						int aglnum;
						aglnum = pdf_lookupagl(estrings[i], aglbuf, nelem(aglbuf));
						if (aglnum != 1)
							etable[i] = FT_Get_Name_Index(face, estrings[i]);
						else
							etable[i] = ftcharindex(face, aglbuf[0]);
					}
					else
						etable[i] = ftcharindex(face, i);
			}

			/* MacRoman cmap */
			else if (face->charmap && face->charmap->platform_id == 1)
			{
				pdf_logfont("encode truetype via macroman\n");
				for (i = 0; i < 256; i++)
					if (estrings[i])
					{
						k = mrecode(estrings[i]);
						if (k <= 0)
							etable[i] = FT_Get_Name_Index(face, estrings[i]);
						else
							etable[i] = ftcharindex(face, k);
					}
					else
						etable[i] = ftcharindex(face, i);
			}

			/* Symbolic cmap */
			else
			{
				pdf_logfont("encode truetype symbolic\n");
				for (i = 0; i < 256; i++)
				{
					etable[i] = ftcharindex(face, i);
					if (etable[i])
						FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32);
					else
						FT_Get_Glyph_Name(face, i, ebuffer[i], 32);
				}

				/* map encoding to gid via glyph names */
				for (i = 0; i < 256; i++)
				{
					char *s = estrings[i];
					if (!etable[i] && s)
					{
						int j;
						/* TODO: this is horribly slow */
						for (j = 0; j < 256; j++)
						{
							if (ebuffer[j][0] && !strcmp(s, ebuffer[j]))
							{
								etable[i] = j;
								break;
							}
						}
					}
					/* TODO: should this really be here? */
					if (ebuffer[i][0])
						estrings[i] = ebuffer[i];
				}
			}
		}

		fz_dropobj(encoding);
	}

	else
	{
		pdf_logfont("encode builtin\n");
		for (i = 0; i < 256; i++)
		{
			etable[i] = ftcharindex(face, i);
			FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32);
			if (ebuffer[i][0])
				estrings[i] = ebuffer[i];
		}
	}

	error = pdf_newidentitycmap(&font->encoding, 0, 1);
	if (error)
		goto cleanup;

	font->ncidtogid = 256;
	font->cidtogid = etable;

	error = pdf_loadtounicode(font, xref,
			estrings, nil, fz_dictgets(dict, "ToUnicode"));
	if (error)
		goto cleanup;

	/*
	 * Widths
	 */

	fz_setdefaulthmtx((fz_font*)font, font->missingwidth);

	widths = fz_dictgets(dict, "Widths");
	if (widths)
	{
		int first, last;

		error = pdf_resolve(&widths, xref);
		if (error)
			goto cleanup;

		first = fz_toint(fz_dictgets(dict, "FirstChar"));
		last = fz_toint(fz_dictgets(dict, "LastChar"));

		if (first < 0 || last > 255 || first > last)
			first = last = 0;

		for (i = 0; i < last - first + 1; i++)
		{
			int wid = fz_toint(fz_arrayget(widths, i));
			error = fz_addhmtx((fz_font*)font, i + first, i + first, wid);
			if (error)
				goto cleanup;
		}

		fz_dropobj(widths);
	}
	else
	{
		FT_Set_Char_Size(face, 1000, 1000, 72, 72);
		for (i = 0; i < 256; i++)
		{
			error = fz_addhmtx((fz_font*)font, i, i, ftwidth(font, i));
			if (error)
				goto cleanup;
		}
	}

	error = fz_endhmtx((fz_font*)font);
	if (error)
		goto cleanup;

	pdf_logfont("}\n");

	*fontp = font;
	return fz_okay;

cleanup:
	fz_free(etable);
	if (widths)
		fz_dropobj(widths);
	fz_dropfont((fz_font*)font);
	return fz_rethrow(error, "cannot load simple font");
}
Ejemplo n.º 19
0
fz_error *
pdf_loadfontdescriptor(pdf_font *font, pdf_xref *xref, fz_obj *desc, char *collection)
{
	fz_error *error;
	fz_obj *obj1, *obj2, *obj3, *obj;
	fz_rect bbox;
	char *fontname;

	error = pdf_resolve(&desc, xref);
	if (error)
		return fz_rethrow(error, "cannot find font descriptor");

	pdf_logfont("load fontdescriptor {\n");

	obj = fz_dictgets(desc, "FontName");
	if (error)
		return fz_rethrow(error, "cannot resolve FontName");
	fontname = fz_toname(obj);

	pdf_logfont("fontname %s\n", fontname);

	font->flags = fz_toint(fz_dictgets(desc, "Flags"));
	font->italicangle = fz_toreal(fz_dictgets(desc, "ItalicAngle"));
	font->ascent = fz_toreal(fz_dictgets(desc, "Ascent"));
	font->descent = fz_toreal(fz_dictgets(desc, "Descent"));
	font->capheight = fz_toreal(fz_dictgets(desc, "CapHeight"));
	font->xheight = fz_toreal(fz_dictgets(desc, "XHeight"));
	font->missingwidth = fz_toreal(fz_dictgets(desc, "MissingWidth"));

	bbox = pdf_torect(fz_dictgets(desc, "FontBBox"));
	pdf_logfont("bbox [%g %g %g %g]\n",
			bbox.x0, bbox.y0,
			bbox.x1, bbox.y1);

	pdf_logfont("flags %d\n", font->flags);

	obj1 = fz_dictgets(desc, "FontFile");
	obj2 = fz_dictgets(desc, "FontFile2");
	obj3 = fz_dictgets(desc, "FontFile3");
	obj = obj1 ? obj1 : obj2 ? obj2 : obj3;

	if (getenv("NOFONT"))
		obj = nil;

	if (fz_isindirect(obj))
	{
		error = pdf_loadembeddedfont(font, xref, obj);
		if (error)
			goto cleanup;
	}
	else
	{
		error = pdf_loadsystemfont(font, fontname, collection);
		if (error)
			goto cleanup;
	}

	fz_dropobj(desc);

	pdf_logfont("}\n");

	return fz_okay;

cleanup:
	fz_dropobj(desc);
	return fz_rethrow(error, "cannot load font descriptor");
}
Ejemplo n.º 20
0
static fz_error *
loadnametreenode(fz_obj *tree, pdf_xref *xref, fz_obj *node)
{
	fz_error *error;
	fz_obj *names;
	fz_obj *kids;
	fz_obj *key;
	fz_obj *val;
	int i, len;

	error = pdf_resolve(&node, xref);
	if (error)
		return error;

	names = fz_dictgets(node, "Names");
	if (names)
	{
		error = pdf_resolve(&names, xref);
		if (error)
			goto cleanup;

		len = fz_arraylen(names) / 2;

		for (i = 0; i < len; ++i)
		{
			key = fz_arrayget(names, i * 2 + 0);
			val = fz_arrayget(names, i * 2 + 1);
			error = fz_dictput(tree, key, val);
			if (error)
			{
				fz_dropobj(names);
				goto cleanup;
			}
		}

		fz_dropobj(names);
	}

	kids = fz_dictgets(node, "Kids");
	if (kids)
	{
		error = pdf_resolve(&kids, xref);
		if (error)
			goto cleanup;

		len = fz_arraylen(kids);
		for (i = 0; i < len; ++i)
		{
			error = loadnametreenode(tree, xref, fz_arrayget(kids, i));
			if (error)
			{
				fz_dropobj(kids);
				goto cleanup;
			}
		}

		fz_dropobj(kids);
	}

	fz_dropobj(node);
	return nil;

cleanup:
	fz_dropobj(node);
	return error;
}
Ejemplo n.º 21
0
fz_error *
pdf_loadlink(pdf_link **linkp, pdf_xref *xref, fz_obj *dict)
{
	fz_error *error;
	pdf_link *link;
	fz_obj *dest;
	fz_obj *action;
	fz_obj *obj;
	fz_rect bbox;
	pdf_linkkind kind;

	pdf_logpage("load link {\n");

	link = nil;
	dest = nil;

	obj = fz_dictgets(dict, "Rect");
	if (obj)
	{
		bbox = pdf_torect(obj);
		pdf_logpage("rect [%g %g %g %g]\n",
			bbox.x0, bbox.y0,
			bbox.x1, bbox.y1);
	}
	else
		bbox = fz_emptyrect;

	obj = fz_dictgets(dict, "Dest");
	if (obj)
	{
		error = pdf_resolve(&obj, xref);
		if (error)
			return error;
		dest = resolvedest(xref, obj);
		pdf_logpage("dest %d %d R\n", fz_tonum(dest), fz_togen(dest));
		fz_dropobj(obj);
	}

	kind = PDF_LUNKNOWN;
	action = fz_dictgets(dict, "A");
	if (action)
	{
		error = pdf_resolve(&action, xref);
		if (error)
			return error;

		obj = fz_dictgets(action, "S");
		if (!strcmp(fz_toname(obj), "GoTo"))
		{
			kind = PDF_LGOTO;
			dest = resolvedest(xref, fz_dictgets(action, "D"));
			pdf_logpage("action goto %d %d R\n", fz_tonum(dest), fz_togen(dest));
		}
		else if (!strcmp(fz_toname(obj), "URI"))
		{
			kind = PDF_LURI;
			dest = fz_dictgets(action, "URI");
			pdf_logpage("action uri %s\n", fz_tostrbuf(dest));
		}
		else
			pdf_logpage("action ... ?\n");

		fz_dropobj(action);
	}

	pdf_logpage("}\n");

	if (dest)
	{
		error = pdf_newlink(&link, bbox, dest, kind);
		if (error)
			return error;
		*linkp = link;
	}

	return nil;
}
Ejemplo n.º 22
0
fz_error*
processErrorPage(
    soPdfFile* inFile,
    fz_obj *pageObj,
    int pageNo,
    fz_rect *bbRect,
    fz_error *error
    )
{
    // Wrap the error
    error = fz_rethrow(error, "Cannot process page %d", pageNo + 1);

    // If we are not supposed to proceed with error then it ends
    if (p_proceedWithErrors == false)
            return error;

    // Save the error in the list
    if (g_errorCount >= MAX_ERRORS_BEFORE_STOP)
        return soPdfErrorList(error);
                
    g_errorList[g_errorCount++] = error;


    // Get the box for the page
    fz_obj *obj = fz_dictgets(pageObj, "CropBox");
    if (!obj)
        obj = fz_dictgets(pageObj, "MediaBox");

    error = pdf_resolve(&obj, inFile->xref);
    if (error)
        return fz_rethrow(error, "Cannot proceed with error %d", pageNo + 1);

    if (!fz_isarray(obj))
        return fz_throw("Cannot find page bounds : %d", pageNo + 1);

    fz_rect bbox = pdf_torect(obj);
    fz_rect mediaBox;

	mediaBox.x0 = MIN(bbox.x0, bbox.x1);
	mediaBox.y0 = MIN(bbox.y0, bbox.y1);
	mediaBox.x1 = MAX(bbox.x0, bbox.x1);
	mediaBox.y1 = MAX(bbox.y0, bbox.y1);
    float mbHeight = mediaBox.y1 - mediaBox.y0;


    switch(p_mode)
    {
    case FitHeight:
    case FitWidth:
        bbRect[0] = mediaBox;
        break;

    case Fit2xHeight:
    case Fit2xWidth:
        {
            float overlap = (mbHeight * (float)(p_overlap / 100)) / 2;
            bbRect[0] = mediaBox;
            bbRect[0].y0 = bbRect[0].y0 + (float)(0.5 * mbHeight) - overlap;
            bbRect[1] = mediaBox;
            bbRect[1].y1 = bbRect[1].y1 - (float)(0.5 * mbHeight) + overlap;
        }
        break;

    case SmartFitHeight:
    case SmartFitWidth:
    default:
        return fz_throw("Mode(%d) not yet implemented.", p_mode);
        break;
    }

    return NULL;
}
Ejemplo n.º 23
0
static fz_error *
loadpagetree(pdf_xref *xref, pdf_pagetree *pages,
		struct stuff inherit, fz_obj *obj, fz_obj *ref, int *pagenum)
{
	fz_error *error;
	fz_obj *type;
	fz_obj *kids;
	fz_obj *kref, *kobj;
	fz_obj *inh;
	int i;

	type = fz_dictgets(obj, "Type");

	if (strcmp(fz_toname(type), "Page") == 0)
	{
		pdf_logpage("page %d, %d %d\n", *pagenum, ref->u.r.oid, ref->u.r.gid);
		(*pagenum)++;

		if (inherit.resources && !fz_dictgets(obj, "Resources"))
		{
			pdf_logpage("inherit resources (%d)\n", pages->cursor);
			error = fz_dictputs(obj, "Resources", inherit.resources);
			if (error) return fz_rethrow(error, "cannot inherit page tree resources");
		}

		if (inherit.mediabox && !fz_dictgets(obj, "MediaBox"))
		{
			pdf_logpage("inherit mediabox (%d)\n", pages->cursor);
			error = fz_dictputs(obj, "MediaBox", inherit.mediabox);
			if (error) return fz_rethrow(error, "cannot inherit page tree mediabox");
		}

		if (inherit.cropbox && !fz_dictgets(obj, "CropBox"))
		{
			pdf_logpage("inherit cropbox (%d)\n", pages->cursor);
			error = fz_dictputs(obj, "CropBox", inherit.cropbox);
			if (error) return fz_rethrow(error, "cannot inherit page tree cropbox");
		}

		if (inherit.rotate && !fz_dictgets(obj, "Rotate"))
		{
			pdf_logpage("inherit rotate (%d)\n", pages->cursor);
			error = fz_dictputs(obj, "Rotate", inherit.rotate);
			if (error) return fz_rethrow(error, "cannot inherit page tree rotate");
		}

		pages->pref[pages->cursor] = fz_keepobj(ref);
		pages->pobj[pages->cursor] = fz_keepobj(obj);
		pages->cursor ++;
	}

	else if (strcmp(fz_toname(type), "Pages") == 0)
	{
		inh = fz_dictgets(obj, "Resources");
		if (inh) inherit.resources = inh;

		inh = fz_dictgets(obj, "MediaBox");
		if (inh) inherit.mediabox = inh;

		inh = fz_dictgets(obj, "CropBox");
		if (inh) inherit.cropbox = inh;

		inh = fz_dictgets(obj, "Rotate");
		if (inh) inherit.rotate = inh;

		kids = fz_dictgets(obj, "Kids");
		error = pdf_resolve(&kids, xref);
		if (error)
			return fz_rethrow(error, "cannot resolve /Kids");

		pdf_logpage("subtree %d pages, %d %d {\n",
				fz_arraylen(kids), ref->u.r.oid, ref->u.r.gid);

		for (i = 0; i < fz_arraylen(kids); i++)
		{
			kref = fz_arrayget(kids, i);

			error = pdf_loadindirect(&kobj, xref, kref);
			if (error) { fz_dropobj(kids); return fz_rethrow(error, "cannot load kid"); }

			if (kobj == obj)
			{
				/* prevent infinite recursion possible in maliciously crafted PDFs */
				fz_dropobj(kids);
				return fz_throw("corrupted pdf file");
			}

			error = loadpagetree(xref, pages, inherit, kobj, kref, pagenum);
			fz_dropobj(kobj);
			if (error) { fz_dropobj(kids); return fz_rethrow(error, "cannot load subtree"); }
		}

		fz_dropobj(kids);

		pdf_logpage("}\n");
	}

	else
		return fz_throw("pagetree node has unexpected type %s", fz_toname(type));

	return fz_okay;
}
Ejemplo n.º 24
0
static fz_error *
loadshadedict(fz_shade **shadep, pdf_xref *xref, fz_obj *dict, fz_obj *ref, fz_matrix matrix)
{
	fz_error *error;
	fz_shade *shade;
	fz_obj *obj;
	int type;
	int i;

	pdf_logshade("load shade dict %d %d {\n", fz_tonum(ref), fz_togen(ref));

	shade = fz_malloc(sizeof(fz_shade));
	if (!shade)
		return fz_outofmem;

	shade->refs = 1;
	shade->usebackground = 0;
	shade->usefunction = 0;
	shade->matrix = matrix;
	shade->bbox = fz_infiniterect;

	shade->meshlen = 0;
	shade->meshcap = 0;
	shade->mesh = nil;

	obj = fz_dictgets(dict, "ShadingType");
	type = fz_toint(obj);
	pdf_logshade("type %d\n", type);

	/* TODO: flatten indexed... */
	obj = fz_dictgets(dict, "ColorSpace");
	if (obj)
	{
		shade->cs = pdf_finditem(xref->store, PDF_KCOLORSPACE, obj);
		if (shade->cs)
			fz_keepcolorspace(shade->cs);
		else
		{
			error = pdf_resolve(&obj, xref);
			if (error)
				return error;
			error = pdf_loadcolorspace(&shade->cs, xref, obj);
			if (error)
				return error;
			fz_dropobj(obj);
		}
	}
	pdf_logshade("colorspace %s\n", shade->cs->name);

	obj = fz_dictgets(dict, "Background");
	if (obj)
	{
		pdf_logshade("background\n");
		shade->usebackground = 1;
		for (i = 0; i < shade->cs->n; i++)
			shade->background[i] = fz_toreal(fz_arrayget(obj, i));
	}

	obj = fz_dictgets(dict, "BBox");
	if (fz_isarray(obj))
	{
		shade->bbox = pdf_torect(obj);
		pdf_logshade("bbox [%g %g %g %g]\n",
			shade->bbox.x0, shade->bbox.y0,
			shade->bbox.x1, shade->bbox.y1);
	}

	switch(type)
	{
	case 1:
		error = pdf_loadtype1shade(shade, xref, dict, ref);
		if (error) goto cleanup;
		break;
	case 2:
		error = pdf_loadtype2shade(shade, xref, dict, ref);
		if (error) goto cleanup;
		break;
	case 3:
		error = pdf_loadtype3shade(shade, xref, dict, ref);
		if (error) goto cleanup;
		break;
	case 4:
		error = pdf_loadtype4shade(shade, xref, dict, ref);
		if (error) goto cleanup;
		break;
	case 5:
		error = pdf_loadtype5shade(shade, xref, dict, ref);
		if (error) goto cleanup;
		break;
	case 6:
		error = pdf_loadtype6shade(shade, xref, dict, ref);
		if (error) goto cleanup;
		break;
	case 7:
		error = pdf_loadtype7shade(shade, xref, dict, ref);
		if (error) goto cleanup;
		break;
	default:
		fz_warn("syntaxerror: unknown shading type: %d", type);
		break;
	};

	pdf_logshade("}\n");

	*shadep = shade;
	return nil;

cleanup:
	fz_dropshade(shade);
	return error;
}
Ejemplo n.º 25
0
static fz_error *
loadcalrgb(fz_colorspace **csp, pdf_xref *xref, fz_obj *dict)
{
	fz_error *error;
	struct calrgb *cs;
	fz_obj *tmp;
	int i;

	error = pdf_resolve(&dict, xref);
	if (error)
		return error;

	cs = fz_malloc(sizeof(struct calrgb));
	if (!cs)
		return fz_outofmem;

	pdf_logrsrc("load CalRGB\n");

	initcs((fz_colorspace*)cs, "CalRGB", 3, rgbtoxyz, xyztorgb, nil);

	cs->white[0] = 1.0;
	cs->white[1] = 1.0;
	cs->white[2] = 1.0;

	cs->black[0] = 0.0;
	cs->black[1] = 0.0;
	cs->black[2] = 0.0;

	cs->gamma[0] = 1.0;
	cs->gamma[1] = 1.0;
	cs->gamma[2] = 1.0;

	cs->matrix[0] = 1.0; cs->matrix[1] = 0.0; cs->matrix[2] = 0.0;
	cs->matrix[3] = 0.0; cs->matrix[4] = 1.0; cs->matrix[5] = 0.0;
	cs->matrix[6] = 0.0; cs->matrix[7] = 0.0; cs->matrix[8] = 1.0;

	tmp = fz_dictgets(dict, "WhitePoint");
	if (fz_isarray(tmp))
	{
		cs->white[0] = fz_toreal(fz_arrayget(tmp, 0));
		cs->white[1] = fz_toreal(fz_arrayget(tmp, 1));
		cs->white[2] = fz_toreal(fz_arrayget(tmp, 2));
	}

	tmp = fz_dictgets(dict, "BlackPoint");
	if (fz_isarray(tmp))
	{
		cs->black[0] = fz_toreal(fz_arrayget(tmp, 0));
		cs->black[1] = fz_toreal(fz_arrayget(tmp, 1));
		cs->black[2] = fz_toreal(fz_arrayget(tmp, 2));
	}

	tmp = fz_dictgets(dict, "Gamma");
	if (fz_isarray(tmp))
	{
		cs->gamma[0] = fz_toreal(fz_arrayget(tmp, 0));
		cs->gamma[1] = fz_toreal(fz_arrayget(tmp, 1));
		cs->gamma[2] = fz_toreal(fz_arrayget(tmp, 2));
	}

	tmp = fz_dictgets(dict, "Matrix");
	if (fz_isarray(tmp))
	{
		for (i = 0; i < 9; i++)
			cs->matrix[i] = fz_toreal(fz_arrayget(tmp, i));
	}

	fz_invert3x3(cs->invmat, cs->matrix);

	fz_dropobj(dict);

	*csp = (fz_colorspace*) cs;
	return nil;
}
Ejemplo n.º 26
0
/*
 * Construct a filter to decode a stream, constraining
 * to stream length and decrypting.
 */
static fz_error *
pdf_buildfilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj, int oid, int gen)
{
	fz_error *error;
	fz_filter *base, *pipe, *tmp;
	fz_obj *filters;
	fz_obj *params;

	error = buildrawfilter(&base, xref, stmobj, oid, gen);
	if (error)
		return fz_rethrow(error, "cannot create raw filter chain");

	filters = fz_dictgetsa(stmobj, "Filter", "F");
	params = fz_dictgetsa(stmobj, "DecodeParms", "DP");

	if (filters)
	{
		error = pdf_resolve(&filters, xref);
		if (error)
		{
			error = fz_rethrow(error, "cannot resolve stream /Filter");
			goto cleanup0;
		}

		if (params)
		{
			error = pdf_resolve(&params, xref);
			if (error)
			{
				error = fz_rethrow(error, "cannot resolve stream /DecodeParms");
				goto cleanup1;
			}
		}

		if (fz_isname(filters))
		{
			error = buildonefilter(&tmp, filters, params);
			if (error)
			{
				error = fz_rethrow(error, "cannot create filter");
				goto cleanup2;
			}

			error = fz_newpipeline(&pipe, base, tmp);
			fz_dropfilter(base);
			fz_dropfilter(tmp);
			if (error)
			{
				error = fz_rethrow(error, "cannot create filter pipeline");
				goto cleanup2;
			}
		}
		else
		{
			error = buildfilterchain(&pipe, base, filters, params);
			if (error)
			{
				error = fz_rethrow(error, "cannot create filter chain");
				goto cleanup2;
			}
		}

		if (params)
			fz_dropobj(params);

		fz_dropobj(filters);

		*filterp = pipe;
	}
	else
	{
		*filterp = base;
	}

	return fz_okay;

cleanup2:
	if (params)
		fz_dropobj(params);
cleanup1:
	fz_dropobj(filters);
cleanup0:
	fz_dropfilter(base);
	return error; /* already rethrown */
}
Ejemplo n.º 27
0
fz_error *
pdf_loadtype3font(pdf_font **fontp, pdf_xref *xref, fz_obj *dict, fz_obj *ref)
{
    fz_error *error;
    char buf[256];
    char *estrings[256];
    pdf_font *font;
    fz_obj *encoding;
    fz_obj *widths;
    fz_obj *resources;
    fz_obj *charprocs;
    fz_obj *obj;
    int first, last;
    int i, k, n;
    fz_rect bbox;

    obj = fz_dictgets(dict, "Name");
    if (obj)
        strlcpy(buf, fz_toname(obj), sizeof buf);
    else
        sprintf(buf, "Unnamed-T3");

    font = pdf_newfont(buf);
    if (!font)
        return fz_throw("outofmem: font struct");

    pdf_logfont("load type3 font %d %d (%p) {\n", fz_tonum(ref), fz_togen(ref), font);
    pdf_logfont("name %s\n", buf);

    font->super.render = t3render;
    font->super.drop = (void(*)(fz_font*)) t3dropfont;

    obj = fz_dictgets(dict, "FontMatrix");
    font->matrix = pdf_tomatrix(obj);

    pdf_logfont("matrix [%g %g %g %g %g %g]\n",
                font->matrix.a, font->matrix.b,
                font->matrix.c, font->matrix.d,
                font->matrix.e, font->matrix.f);

    obj = fz_dictgets(dict, "FontBBox");
    bbox = pdf_torect(obj);

    pdf_logfont("bbox [%g %g %g %g]\n",
                bbox.x0, bbox.y0,
                bbox.x1, bbox.y1);

    bbox = fz_transformaabb(font->matrix, bbox);
    bbox.x0 = fz_floor(bbox.x0 * 1000);
    bbox.y0 = fz_floor(bbox.y0 * 1000);
    bbox.x1 = fz_ceil(bbox.x1 * 1000);
    bbox.y1 = fz_ceil(bbox.y1 * 1000);
    fz_setfontbbox((fz_font*)font, bbox.x0, bbox.y0, bbox.x1, bbox.y1);

    /*
     * Encoding
     */

    for (i = 0; i < 256; i++)
        estrings[i] = nil;

    encoding = fz_dictgets(dict, "Encoding");
    if (!encoding) {
        error = fz_throw("syntaxerror: Type3 font missing Encoding");
        goto cleanup;
    }

    error = pdf_resolve(&encoding, xref);
    if (error)
        goto cleanup;

    if (fz_isname(obj))
        pdf_loadencoding(estrings, fz_toname(encoding));

    if (fz_isdict(encoding))
    {
        fz_obj *base, *diff, *item;

        base = fz_dictgets(encoding, "BaseEncoding");
        if (fz_isname(base))
            pdf_loadencoding(estrings, fz_toname(base));

        diff = fz_dictgets(encoding, "Differences");
        if (fz_isarray(diff))
        {
            n = fz_arraylen(diff);
            k = 0;
            for (i = 0; i < n; i++)
            {
                item = fz_arrayget(diff, i);
                if (fz_isint(item))
                    k = fz_toint(item);
                if (fz_isname(item))
                    estrings[k++] = fz_toname(item);
                if (k < 0) k = 0;
                if (k > 255) k = 255;
            }
        }
    }

    fz_dropobj(encoding);

    error = pdf_newidentitycmap(&font->encoding, 0, 1);
    if (error)
        goto cleanup;

    error = pdf_loadtounicode(font, xref,
                              estrings, nil, fz_dictgets(dict, "ToUnicode"));
    if (error)
        goto cleanup;

    /*
     * Widths
     */

    fz_setdefaulthmtx((fz_font*)font, 0);

    first = fz_toint(fz_dictgets(dict, "FirstChar"));
    last = fz_toint(fz_dictgets(dict, "LastChar"));

    widths = fz_dictgets(dict, "Widths");
    if (!widths) {
        error = fz_throw("syntaxerror: Type3 font missing Widths");
        goto cleanup;
    }

    error = pdf_resolve(&widths, xref);
    if (error)
        goto cleanup;

    for (i = first; i <= last; i++)
    {
        float w = fz_toreal(fz_arrayget(widths, i - first));
        w = font->matrix.a * w * 1000.0;
        error = fz_addhmtx((fz_font*)font, i, i, w);
        if (error) {
            fz_dropobj(widths);
            goto cleanup;
        }
    }

    fz_dropobj(widths);

    error = fz_endhmtx((fz_font*)font);
    if (error)
        goto cleanup;

    /*
     * Resources
     */

    resources = nil;

    obj = fz_dictgets(dict, "Resources");
    if (obj)
    {
        error = pdf_resolve(&obj, xref);
        if (error)
            goto cleanup;

        error = pdf_loadresources(&resources, xref, obj);

        fz_dropobj(obj);

        if (error)
            goto cleanup;
    }
    else
        pdf_logfont("no resource dict!\n");

    /*
     * CharProcs
     */

    charprocs = fz_dictgets(dict, "CharProcs");
    if (!charprocs)
    {
        error = fz_throw("syntaxerror: Type3 font missing CharProcs");
        goto cleanup2;
    }

    error = pdf_resolve(&charprocs, xref);
    if (error)
        goto cleanup2;

    for (i = 0; i < 256; i++)
    {
        if (estrings[i])
        {
            obj = fz_dictgets(charprocs, estrings[i]);
            if (obj)
            {
                pdf_logfont("load charproc %s {\n", estrings[i]);
                error = loadcharproc(&font->charprocs[i], xref, resources, obj);
                if (error)
                    goto cleanup2;

                error = fz_optimizetree(font->charprocs[i]);
                if (error)
                    goto cleanup2;

                pdf_logfont("}\n");
            }
        }
    }

    fz_dropobj(charprocs);
    if (resources)
        fz_dropobj(resources);

    pdf_logfont("}\n");

    *fontp = font;
    return fz_okay;

cleanup2:
    if (resources)
        fz_dropobj(resources);
cleanup:
    fz_dropfont((fz_font*)font);
    return fz_rethrow(error, "cannot load type3 font");
}