Example #1
0
static int
pdf_patternusesblending(fz_obj *dict)
{
	fz_obj *obj;

	obj = fz_dictgets(dict, "Resources");
	if (fz_isdict(obj) && pdf_resourcesuseblending(obj))
		return 1;

	obj = fz_dictgets(dict, "ExtGState");
	if (fz_isdict(obj) && pdf_extgstateusesblending(obj))
		return 1;

	return 0;
}
static fz_obj *
resolvedest(pdf_xref *xref, fz_obj *dest)
{
	if (fz_isname(dest) || fz_isstring(dest))
	{
		dest = pdf_lookupdest(xref, dest);
		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;
}
Example #3
0
static void
gatherglobalinfo(void)
{
	info = fz_malloc(sizeof (struct info));
	if (!info)
		die(fz_throw("out of memory"));

	info->page = -1;
	info->pageobj = nil;
	info->ref = nil;
	info->u.info.obj = nil;

	info->u.info.obj = fz_dictgets(xref->trailer, "Info");
	if (!fz_isindirect(info->u.info.obj))
		die(fz_throw("not an indirect info object"));

	cryptinfo = fz_malloc(sizeof (struct info));

	cryptinfo->page = -1;
	cryptinfo->pageobj = nil;
	cryptinfo->ref = nil;
	cryptinfo->u.crypt.obj = nil;

	if (xref->crypt)
	{
		cryptinfo->ref = fz_dictgets(xref->trailer, "Encrypt");
		if (!fz_isdict(cryptinfo->ref) && !fz_isindirect(cryptinfo->ref))
			die(fz_throw("not an indirect crypt object"));

		// XXX cryptinfo->u.crypt.obj = xref->crypt->encrypt;
	}
}
Example #4
0
static fz_obj *
resolvedest(pdf_xref *xref, fz_obj *dest)
{
	if (fz_isname(dest) || fz_isstring(dest))
	{
		dest = pdf_lookupdest(xref, dest);
		return resolvedest(xref, dest);
	}

	else if (fz_isarray(dest))
	{
		return dest; /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=275 */
	}

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

	else if (fz_isindirect(dest))
		return dest;

	return nil;
}
Example #5
0
fz_error
pdf_loadpagetree(pdf_xref *xref)
{
	struct info info;
	fz_obj *catalog = fz_dictgets(xref->trailer, "Root");
	fz_obj *pages = fz_dictgets(catalog, "Pages");
	fz_obj *count = fz_dictgets(pages, "Count");

	if (!fz_isdict(pages))
		return fz_throw("missing page tree");
	if (!fz_isint(count))
		return fz_throw("missing page count");

	xref->pagecap = fz_toint(count);
	xref->pagelen = 0;
	xref->pagerefs = fz_malloc(sizeof(fz_obj*) * xref->pagecap);
	xref->pageobjs = fz_malloc(sizeof(fz_obj*) * xref->pagecap);

	info.resources = nil;
	info.mediabox = nil;
	info.cropbox = nil;
	info.rotate = nil;

	pdf_loadpagetreenode(xref, pages, info);

	return fz_okay;
}
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;
}
Example #7
0
static fz_error
gatherpsobjs(int page, fz_obj *pageobj, fz_obj *dict)
{
	int i;

	for (i = 0; i < fz_dictlen(dict); i++)
	{
		fz_obj *ref;
		fz_obj *xobjdict;
		fz_obj *type;
		fz_obj *subtype;
		int k;

		xobjdict = ref = fz_dictgetval(dict, i);
		if (!fz_isdict(xobjdict))
			return fz_throw("not a xobject dict (%d %d R)", fz_tonum(ref), fz_togen(ref));

		type = fz_dictgets(xobjdict, "Subtype");
		if (!fz_isname(type))
			return fz_throw("not a xobject type (%d %d R)", fz_tonum(ref), fz_togen(ref));
		if (strcmp(fz_toname(type), "Form"))
			continue;

		subtype = fz_dictgets(xobjdict, "Subtype2");
		if (subtype && !fz_isname(subtype))
			return fz_throw("not a xobject subtype (%d %d R)", fz_tonum(ref), fz_togen(ref));
		if (strcmp(fz_toname(type), "PS") &&
			(strcmp(fz_toname(type), "Form") || strcmp(fz_toname(subtype), "PS")))
			continue;

		for (k = 0; k < psobjs; k++)
			if (fz_tonum(psobj[k]->ref) == fz_tonum(ref) &&
				fz_togen(psobj[k]->ref) == fz_togen(ref))
				break;

		if (k < psobjs)
			continue;

		psobjs++;

		psobj = fz_realloc(psobj, psobjs * sizeof (struct info *));
		if (!psobj)
			return fz_throw("out of memory");

		psobj[psobjs - 1] = fz_malloc(sizeof (struct info));
		if (!psobj[psobjs - 1])
			return fz_throw("out of memory");

		psobj[psobjs - 1]->page = page;
		psobj[psobjs - 1]->pageobj = pageobj;
		psobj[psobjs - 1]->ref = ref;
	}

	return fz_okay;
}
Example #8
0
static int
pdf_xobjectusesblending(fz_obj *dict)
{
	fz_obj *obj;

	obj = fz_dictgets(dict, "Resources");
	if (fz_isdict(obj) && pdf_resourcesuseblending(obj))
		return 1;

	return 0;
}
Example #9
0
int
epdf_index_item_page_get(const Epdf_Document *doc, const Epdf_Index_Item *item)
{
   fz_obj *dest;
   int p;
   int n;
   int g;

   if (!item || !item->link)
     return -1;

   if (PDF_LGOTO != item->link->kind)
     return -1;

   dest = item->link->dest;
   p = 0;
   if (fz_isint(dest))
     {
        p = fz_toint(dest);
        return p;
     }
   if (fz_isdict(dest))
     {
        /* The destination is linked from a Go-To action's D array */
       fz_obj *D;

       D = fz_dictgets(dest, "D");
       if (D && fz_isarray(D))
         dest = fz_arrayget(D, 0);
     }

   n = fz_tonum(dest);
   g = fz_togen(dest);

   for (p = 1; p <= epdf_document_page_count_get(doc); p++)
     {
        fz_obj *page;
        int np;
        int gp;

        page = pdf_getpageobject(doc->xref, p);
        if (!page)
          continue;

        np = fz_tonum(page);
        gp = fz_togen(page);
        if (n == np && g == gp)
          return p-1;
    }

   return 0;
}
Example #10
0
static fz_error
gathershadings(int page, fz_obj *pageobj, fz_obj *dict)
{
	int i;

	for (i = 0; i < fz_dictlen(dict); i++)
	{
		fz_obj *ref;
		fz_obj *shade;
		fz_obj *type;
		int k;

		shade = ref = fz_dictgetval(dict, i);
		if (!fz_isdict(shade))
			return fz_throw("not a shading dict (%d %d R)", fz_tonum(ref), fz_togen(ref));

		type = fz_dictgets(shade, "ShadingType");
		if (!fz_isint(type) || fz_toint(type) < 1 || fz_toint(type) > 7)
		{
			fz_warn("not a shading type (%d %d R)", fz_tonum(ref), fz_togen(ref));
			type = nil;
		}

		for (k = 0; k < shadings; k++)
			if (fz_tonum(shading[k]->ref) == fz_tonum(ref) &&
				fz_togen(shading[k]->ref) == fz_togen(ref))
				break;

		if (k < shadings)
			continue;

		shadings++;

		shading = fz_realloc(shading, shadings * sizeof (struct info *));
		if (!shading)
			return fz_throw("out of memory");

		shading[shadings - 1] = fz_malloc(sizeof (struct info));
		if (!shading[shadings - 1])
			return fz_throw("out of memory");

		shading[shadings - 1]->page = page;
		shading[shadings - 1]->pageobj = pageobj;
		shading[shadings - 1]->ref = ref;
		shading[shadings - 1]->u.shading.type = type;
	}

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

	if (fz_isindirect(obj))
		sweepref(obj);

	else if (fz_isdict(obj))
		for (i = 0; i < fz_dictlen(obj); i++)
			sweepobj(fz_dictgetval(obj, i));

	else if (fz_isarray(obj))
		for (i = 0; i < fz_arraylen(obj); i++)
			sweepobj(fz_arrayget(obj, i));
}
Example #12
0
static void addhexfilter(fz_obj *dict)
{
	fz_obj *f, *dp, *newf, *newdp;
	fz_obj *ahx, *nullobj;

	ahx = fz_newname("ASCIIHexDecode");
	nullobj = fz_newnull();
	newf = newdp = nil;

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

	if (fz_isname(f))
	{
		newf = fz_newarray(2);
		fz_arraypush(newf, ahx);
		fz_arraypush(newf, f);
		f = newf;
		if (fz_isdict(dp))
		{
			newdp = fz_newarray(2);
			fz_arraypush(newdp, nullobj);
			fz_arraypush(newdp, dp);
			dp = newdp;
		}
	}
	else if (fz_isarray(f))
	{
		fz_arrayinsert(f, ahx);
		if (fz_isarray(dp))
			fz_arrayinsert(dp, nullobj);
	}
	else
		f = ahx;

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

	fz_dropobj(ahx);
	fz_dropobj(nullobj);
	if (newf)
		fz_dropobj(newf);
	if (newdp)
		fz_dropobj(newdp);
}
Example #13
0
static void writeobject(int num, int gen)
{
	fz_error error;
	fz_obj *obj;
	fz_obj *type;

	error = pdf_loadobject(&obj, xref, num, gen);
	if (error)
		die(error);

	/* skip ObjStm and XRef objects */
	if (fz_isdict(obj))
	{
		type = fz_dictgets(obj, "Type");
		if (fz_isname(type) && !strcmp(fz_toname(type), "ObjStm"))
		{
			uselist[num] = 0;
			fz_dropobj(obj);
			return;
		}
		if (fz_isname(type) && !strcmp(fz_toname(type), "XRef"))
		{
			uselist[num] = 0;
			fz_dropobj(obj);
			return;
		}
	}

	if (!pdf_isstream(xref, num, gen))
	{
		fprintf(out, "%d %d obj\n", num, gen);
		fz_fprintobj(out, obj, !doexpand);
		fprintf(out, "endobj\n\n");
	}
	else
	{
		if (doexpand && !pdf_isjpximage(obj))
			expandstream(obj, num, gen);
		else
			copystream(obj, num, gen);
	}

	fz_dropobj(obj);
}
Example #14
0
static void renumberobj(fz_obj *obj)
{
	int i;

	if (fz_isdict(obj))
	{
		for (i = 0; i < fz_dictlen(obj); i++)
		{
			fz_obj *key = fz_dictgetkey(obj, i);
			fz_obj *val = fz_dictgetval(obj, i);
			if (fz_isindirect(val))
			{
				val = fz_newindirect(renumbermap[fz_tonum(val)], 0, xref);
				fz_dictput(obj, key, val);
				fz_dropobj(val);
			}
			else
			{
				renumberobj(val);
			}
		}
	}

	else if (fz_isarray(obj))
	{
		for (i = 0; i < fz_arraylen(obj); i++)
		{
			fz_obj *val = fz_arrayget(obj, i);
			if (fz_isindirect(val))
			{
				val = fz_newindirect(renumbermap[fz_tonum(val)], 0, xref);
				fz_arrayput(obj, i, val);
				fz_dropobj(val);
			}
			else
			{
				renumberobj(val);
			}
		}
	}
}
Example #15
0
static fz_error
gatherimages(int page, fz_obj *pageobj, fz_obj *dict)
{
	int i;

	for (i = 0; i < fz_dictlen(dict); i++)
	{
		fz_obj *ref;
		fz_obj *imagedict;
		fz_obj *type;
		fz_obj *width;
		fz_obj *height;
		fz_obj *bpc = nil;
		fz_obj *filter = nil;
		fz_obj *mask;
		fz_obj *cs = nil;
		fz_obj *altcs;
		int k;

		imagedict = ref = fz_dictgetval(dict, i);
		if (!fz_isdict(imagedict))
			return fz_throw("not an image dict (%d %d R)", fz_tonum(ref), fz_togen(ref));

		type = fz_dictgets(imagedict, "Subtype");
		if (!fz_isname(type))
			return fz_throw("not an image subtype (%d %d R)", fz_tonum(ref), fz_togen(ref));
		if (strcmp(fz_toname(type), "Image"))
			continue;

		filter = fz_dictgets(imagedict, "Filter");
		if (filter && !fz_isname(filter) && !fz_isarray(filter))
			return fz_throw("not an image filter (%d %d R)", fz_tonum(ref), fz_togen(ref));

		mask = fz_dictgets(imagedict, "ImageMask");

		altcs = nil;
		cs = fz_dictgets(imagedict, "ColorSpace");
		if (fz_isarray(cs))
		{
			fz_obj *cses = cs;

			cs = fz_arrayget(cses, 0);
			if (fz_isname(cs) && (!strcmp(fz_toname(cs), "DeviceN") || !strcmp(fz_toname(cs), "Separation")))
			{
				altcs = fz_arrayget(cses, 2);
				if (fz_isarray(altcs))
					altcs = fz_arrayget(altcs, 0);
			}
		}

		if (fz_isbool(mask) && fz_tobool(mask))
		{
			if (cs)
				fz_warn("image mask (%d %d R) may not have colorspace", fz_tonum(ref), fz_togen(ref));
		}
		if (cs && !fz_isname(cs))
			return fz_throw("not an image colorspace (%d %d R)", fz_tonum(ref), fz_togen(ref));
		if (altcs && !fz_isname(altcs))
			return fz_throw("not an image alternate colorspace (%d %d R)", fz_tonum(ref), fz_togen(ref));

		width = fz_dictgets(imagedict, "Width");
		if (!fz_isint(width))
			return fz_throw("not an image width (%d %d R)", fz_tonum(ref), fz_togen(ref));

		height = fz_dictgets(imagedict, "Height");
		if (!fz_isint(height))
			return fz_throw("not an image height (%d %d R)", fz_tonum(ref), fz_togen(ref));

		bpc = fz_dictgets(imagedict, "BitsPerComponent");
		if (!fz_tobool(mask) && !fz_isint(bpc))
			return fz_throw("not an image bits per component (%d %d R)", fz_tonum(ref), fz_togen(ref));
		if (fz_tobool(mask) && fz_isint(bpc) && fz_toint(bpc) != 1)
			return fz_throw("not an image mask bits per component (%d %d R)", fz_tonum(ref), fz_togen(ref));

		for (k = 0; k < images; k++)
			if (fz_tonum(image[k]->ref) == fz_tonum(ref) &&
				fz_togen(image[k]->ref) == fz_togen(ref))
				break;

		if (k < images)
			continue;

		images++;

		image = fz_realloc(image, images * sizeof (struct info *));
		if (!image)
			return fz_throw("out of memory");

		image[images - 1] = fz_malloc(sizeof (struct info));
		if (!image[images - 1])
			return fz_throw("out of memory");

		image[images - 1]->page = page;
		image[images - 1]->pageobj = pageobj;
		image[images - 1]->ref = ref;
		image[images - 1]->u.image.width = width;
		image[images - 1]->u.image.height = height;
		image[images - 1]->u.image.bpc = bpc;
		image[images - 1]->u.image.filter = filter;
		image[images - 1]->u.image.cs = cs;
		image[images - 1]->u.image.altcs = altcs;
	}

	return fz_okay;
}
Example #16
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");
}
Example #17
0
static fz_error
loadsimplefont(pdf_fontdesc **fontdescp, pdf_xref *xref, fz_obj *dict)
{
	fz_error error;
	fz_obj *descriptor;
	fz_obj *encoding;
	fz_obj *widths;
	unsigned short *etable = nil;
	pdf_fontdesc *fontdesc;
	fz_bbox 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;

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

	/* Load font file */

	fontdesc = pdf_newfontdesc();

	pdf_logfont("load simple font (%d %d R) ptr=%p {\n", fz_tonum(dict), fz_togen(dict), fontdesc);
	pdf_logfont("basefont %s -> %s\n", basefont, fontname);

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

	face = fontdesc->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(fontdesc->font, -1000, -1000, 2000, 2000);
	else
		fz_setfontbbox(fontdesc->font, bbox.x0, bbox.y0, bbox.x1, bbox.y1);

	/* Encoding */

	symbolic = fontdesc->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)
			fz_warn("freetype could not set cmap: %s", ft_errorstring(fterr));
	}
	else
		fz_warn("freetype could not find any cmaps");

	etable = fz_malloc(sizeof(unsigned short) * 256);
	for (i = 0; i < 256; i++)
	{
		estrings[i] = nil;
		etable[i] = 0;
	}

	encoding = fz_dictgets(dict, "Encoding");
	if (encoding)
	{
		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));
			else if (!fontdesc->isembedded && !symbolic)
				pdf_loadencoding(estrings, "StandardEncoding");
			/* cf. http://bugs.ghostscript.com/show_bug.cgi?id=690615 and http://code.google.com/p/sumatrapdf/issues/detail?id=687 */
			/* try to extract an encoding from the font or synthesize a likely one */
			/* note: FT_Get_Name_Index fails for symbolic CFF fonts, so let them be encoded by index */
			else if (!fontdesc->encoding && !ftloadt1encoding(face, estrings) && !(symbolic && !strcmp(FT_Get_X11_Font_Format(face), "CFF")))
				pdf_loadencoding(estrings, "StandardEncoding");

			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;
				}
			}
		}
	}

	/* start with the builtin encoding */
	for (i = 0; i < 256; i++)
		etable[i] = ftcharindex(face, i);

	/* encode by glyph name where we can */
	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]);
				if (etable[i] == 0)
				{
					int aglcode = pdf_lookupagl(estrings[i]);
					char **aglnames = pdf_lookupaglnames(aglcode);
					while (*aglnames)
					{
						etable[i] = FT_Get_Name_Index(face, *aglnames);
						if (etable[i])
							break;
						aglnames++;
					}
				}
			}
		}
	}

	/* encode by glyph name where we can */
	if (kind == TRUETYPE)
	{
		/* Unicode cmap */
		if (!symbolic && face->charmap && face->charmap->platform_id == 3)
		{
			pdf_logfont("encode truetype via unicode\n");
			for (i = 0; i < 256; i++)
			{
				if (estrings[i])
				{
					int aglcode = pdf_lookupagl(estrings[i]);
					if (!aglcode)
						etable[i] = FT_Get_Name_Index(face, estrings[i]);
					else
						etable[i] = ftcharindex(face, aglcode);
				}
			}
		}

		/* MacRoman cmap */
		else if (!symbolic && 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);
				}
			}
		}

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

	/* try to reverse the glyph names from the builtin encoding */
	for (i = 0; i < 256; i++)
	{
		if (etable[i] && !estrings[i])
		{
			if (FT_HAS_GLYPH_NAMES(face))
			{
				fterr = FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32);
				if (fterr)
					fz_warn("freetype get glyph name (gid %d): %s", etable[i], ft_errorstring(fterr));
				if (ebuffer[i][0])
					estrings[i] = ebuffer[i];
			}
			else
			{
				estrings[i] = (char*) pdf_winansi[i]; /* discard const */
			}
		}
	}

	/* Prevent encoding Differences from being overwritten by reloading them */
	/* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=115 */
	if (fz_isdict(encoding))
	{
		fz_obj *diff, *item;

		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;
			}
		}
	}

	fontdesc->encoding = pdf_newidentitycmap(0, 1);
	fontdesc->ncidtogid = 256;
	fontdesc->cidtogid = etable;

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

	/* Widths */

	pdf_setdefaulthmtx(fontdesc, fontdesc->missingwidth);

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

		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));
			pdf_addhmtx(fontdesc, i + first, i + first, wid);
		}
	}
	else
	{
		fterr = FT_Set_Char_Size(face, 1000, 1000, 72, 72);
		if (fterr)
			fz_warn("freetype set character size: %s", ft_errorstring(fterr));
		for (i = 0; i < 256; i++)
		{
			pdf_addhmtx(fontdesc, i, i, ftwidth(fontdesc, i));
		}
	}

	pdf_endhmtx(fontdesc);

	pdf_logfont("}\n");

	*fontdescp = fontdesc;
	return fz_okay;

cleanup:
	if (etable != fontdesc->cidtogid)
		fz_free(etable);
	pdf_dropfont(fontdesc);
	return fz_rethrow(error, "cannot load simple font (%d %d R)", fz_tonum(dict), fz_togen(dict));
}
Example #18
0
fz_error
pdf_loadtype3font(pdf_fontdesc **fontdescp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict)
{
	fz_error error;
	char buf[256];
	char *estrings[256];
	pdf_fontdesc *fontdesc;
	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;
	fz_matrix matrix;

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

	fontdesc = pdf_newfontdesc();

	pdf_logfont("load type3 font (%d %d R) ptr=%p {\n", fz_tonum(dict), fz_togen(dict), fontdesc);
	pdf_logfont("name %s\n", buf);

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

	pdf_logfont("matrix [%g %g %g %g %g %g]\n",
		matrix.a, matrix.b,
		matrix.c, matrix.d,
		matrix.e, 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(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);

	fontdesc->font = fz_newtype3font(buf, matrix);

	fz_setfontbbox(fontdesc->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;
	}

	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;
			}
		}
	}

	fontdesc->encoding = pdf_newidentitycmap(0, 1);

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

	/*
	 * Widths
	 */

	pdf_setdefaulthmtx(fontdesc, 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;
	}

	for (i = first; i <= last; i++)
	{
		float w = fz_toreal(fz_arrayget(widths, i - first));
		w = fontdesc->font->t3matrix.a * w * 1000.0;
		fontdesc->font->t3widths[i] = w * 0.001;
		pdf_addhmtx(fontdesc, i, i, w);
	}

	pdf_endhmtx(fontdesc);

	/*
	 * Resources
	 */

	resources = fz_dictgets(dict, "Resources");

	/* Inherit page's resource dict if type3 font does not have one */
	if (!resources && rdb)
		resources = rdb;
	else if (!resources && !rdb)
		fz_warn("no resource dictionary for type 3 font!");

	/*
	 * CharProcs
	 */

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

	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(&fontdesc->font->t3procs[i], xref, resources, obj);
				if (error)
					goto cleanup;

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

	pdf_logfont("}\n");

	*fontdescp = fontdesc;
	return fz_okay;

cleanup:
	fz_dropfont(fontdesc->font);
	fz_free(fontdesc);
	return fz_rethrow(error, "cannot load type3 font");
}
fz_error
pdf_openxrefwithstream(pdf_xref **xrefp, fz_stream *file, char *password)
{
    pdf_xref *xref;
    fz_error error;
    fz_obj *encrypt;
    fz_obj *id;

    xref = fz_malloc(sizeof(pdf_xref));

    memset(xref, 0, sizeof(pdf_xref));

    pdf_logxref("openxref %p\n", xref);

    xref->file = fz_keepstream(file);

    error = pdf_loadxref(xref, xref->scratch, sizeof xref->scratch);
    if (error)
    {
        fz_catch(error, "trying to repair");
        if (xref->table)
        {
            fz_free(xref->table);
            xref->table = NULL;
            xref->len = 0;
            xref->cap = 0;
        }
        error = pdf_repairxref(xref, xref->scratch, sizeof xref->scratch);
        if (error)
        {
            pdf_freexref(xref);
            return fz_rethrow(error, "cannot repair document");
        }
    }

    encrypt = fz_dictgets(xref->trailer, "Encrypt");
    id = fz_dictgets(xref->trailer, "ID");
    if (fz_isdict(encrypt))
    {
        error = pdf_newcrypt(&xref->crypt, encrypt, id);
        if (error)
        {
            pdf_freexref(xref);
            return fz_rethrow(error, "cannot decrypt document");
        }
    }

    if (pdf_needspassword(xref))
    {
        /* Only care if we have a password */
        if (password)
        {
            int okay = pdf_authenticatepassword(xref, password);
            if (!okay)
            {
                pdf_freexref(xref);
                return fz_throw("invalid password");
            }
        }
    }

    *xrefp = xref;
    return fz_okay;
}
static fz_error
loadsimplefont(pdf_fontdesc **fontdescp, pdf_xref *xref, fz_obj *dict)
{
	fz_error error;
	fz_obj *descriptor = nil;
	fz_obj *encoding = nil;
	fz_obj *widths = nil;
	unsigned short *etable = nil;
	pdf_fontdesc *fontdesc;
	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;

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

	/*
	 * Load font file
	 */

	fontdesc = pdf_newfontdesc();
	if (!fontdesc)
		return fz_rethrow(-1, "out of memory");

	pdf_logfont("load simple font (%d %d R) ptr=%p {\n", fz_tonum(dict), fz_togen(dict), fontdesc);
	pdf_logfont("basefont0 %s\n", basefont);
	pdf_logfont("basefont1 %s\n", fontname);

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

	face = fontdesc->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(fontdesc->font, -1000, -1000, 2000, 2000);
	else
		fz_setfontbbox(fontdesc->font, bbox.x0, bbox.y0, bbox.x1, bbox.y1);

	/*
	 * Encoding
	 */

	symbolic = fontdesc->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)
			fz_warn("freetype could not set cmap: %s", ft_errorstring(fterr));
	}
	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))
	{
		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));
			else if (!fontdesc->isembedded)
				pdf_loadencoding(estrings, "StandardEncoding");

			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] = ftcharindex(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);
					fterr = FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32);
					if (fterr)
					{
						error = fz_throw("freetype get glyph name (gid %d): %s", etable[i], ft_errorstring(fterr));
						goto cleanup;
					}
					if (ebuffer[i][0])
						estrings[i] = ebuffer[i];
				}
			}
		}
	}

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

			if (FT_HAS_GLYPH_NAMES(face))
			{
				fterr = FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32);
				if (fterr)
				{
					error = fz_throw("freetype get glyph name (gid %d): %s", etable[i], ft_errorstring(fterr));
					goto cleanup;
				}
				if (ebuffer[i][0])
					estrings[i] = ebuffer[i];
			}
		}
	}

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

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

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

	/*
	 * Widths
	 */

	pdf_setdefaulthmtx(fontdesc, fontdesc->missingwidth);

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

		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 = pdf_addhmtx(fontdesc, i + first, i + first, wid);
			if (error)
				goto cleanup;
		}
	}
	else
	{
		fterr = FT_Set_Char_Size(face, 1000, 1000, 72, 72);
		if (fterr)
			fz_warn("freetype set character size: %s", ft_errorstring(fterr));
		for (i = 0; i < 256; i++)
		{
			error = pdf_addhmtx(fontdesc, i, i, ftwidth(fontdesc, i));
			if (error)
				goto cleanup;
		}
	}

	error = pdf_endhmtx(fontdesc);
	if (error)
		goto cleanup;

	pdf_logfont("}\n");

	*fontdescp = fontdesc;
	return fz_okay;

cleanup:
	fz_free(etable);
	fz_dropfont(fontdesc->font);
	fz_free(fontdesc);
	return fz_rethrow(error, "cannot load simple font");
}
Example #21
0
static fz_error
gatherpatterns(int page, fz_obj *pageobj, fz_obj *dict)
{
	int i;

	for (i = 0; i < fz_dictlen(dict); i++)
	{
		fz_obj *ref;
		fz_obj *patterndict;
		fz_obj *type;
		fz_obj *paint = nil;
		fz_obj *tiling = nil;
		int k;

		patterndict = ref = fz_dictgetval(dict, i);
		if (!fz_isdict(patterndict))
			return fz_throw("not a pattern dict (%d %d R)", fz_tonum(ref), fz_togen(ref));

		type = fz_dictgets(patterndict, "PatternType");
		if (!fz_isint(type) || fz_toint(type) < 1 || fz_toint(type) > 2)
		{
			fz_warn("not a pattern type (%d %d R)", fz_tonum(ref), fz_togen(ref));
			type = nil;
		}

		if (fz_toint(type) == 1)
		{
			paint = fz_dictgets(patterndict, "PaintType");
			if (!fz_isint(paint) || fz_toint(paint) < 1 || fz_toint(paint) > 2)
			{
				fz_warn("not a pattern paint type (%d %d R)", fz_tonum(ref), fz_togen(ref));
				paint = nil;
			}

			tiling = fz_dictgets(patterndict, "TilingType");
			if (!fz_isint(tiling) || fz_toint(tiling) < 1 || fz_toint(tiling) > 3)
			{
				fz_warn("not a pattern tiling type (%d %d R)", fz_tonum(ref), fz_togen(ref));
				tiling = nil;
			}
		}

		for (k = 0; k < patterns; k++)
			if (fz_tonum(pattern[k]->ref) == fz_tonum(ref) &&
				fz_togen(pattern[k]->ref) == fz_togen(ref))
				break;

		if (k < patterns)
			continue;

		patterns++;

		pattern = fz_realloc(pattern, patterns * sizeof (struct info *));
		if (!pattern)
			return fz_throw("out of memory");

		pattern[patterns - 1] = fz_malloc(sizeof (struct info));
		if (!pattern[patterns - 1])
			return fz_throw("out of memory");

		pattern[patterns - 1]->page = page;
		pattern[patterns - 1]->pageobj = pageobj;
		pattern[patterns - 1]->ref = ref;
		pattern[patterns - 1]->u.pattern.pattern = type;
		pattern[patterns - 1]->u.pattern.paint = paint;
		pattern[patterns - 1]->u.pattern.tiling = tiling;
	}

	return fz_okay;
}
Example #22
0
static fz_error
pdf_loadimageimp(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_MAXCOLORS * 2];
	float decode[FZ_MAXCOLORS * 2];

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

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

	w = fz_toint(fz_dictgetsa(dict, "Width", "W"));
	h = fz_toint(fz_dictgetsa(dict, "Height", "H"));
	bpc = fz_toint(fz_dictgetsa(dict, "BitsPerComponent", "BPC"));
	imagemask = fz_tobool(fz_dictgetsa(dict, "ImageMask", "IM"));
	interpolate = fz_tobool(fz_dictgetsa(dict, "Interpolate", "I"));

	indexed = 0;
	usecolorkey = 0;
	colorspace = nil;
	mask = nil;

	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_dictgetsa(dict, "ColorSpace", "CS");
	if (obj && !imagemask && !forcemask)
	{
		/* colorspace resource lookup is only done for inline images */
		if (fz_isname(obj))
		{
			res = fz_dictget(fz_dictgets(rdb, "ColorSpace"), obj);
			if (res)
				obj = res;
		}

		error = pdf_loadcolorspace(&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_dictgetsa(dict, "Decode", "D");
	if (obj)
	{
		for (i = 0; i < n * 2; i++)
			decode[i] = fz_toreal(fz_arrayget(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_dictgetsa(dict, "SMask", "Mask");
	if (fz_isdict(obj))
	{
		/* Not allowed for inline images */
		if (!cstm)
		{
			error = pdf_loadimageimp(&mask, xref, rdb, obj, nil, 1);
			if (error)
			{
				if (colorspace)
					fz_dropcolorspace(colorspace);
				return fz_rethrow(error, "cannot load image mask/softmask");
			}
		}
	}
	else if (fz_isarray(obj))
	{
		usecolorkey = 1;
		for (i = 0; i < n * 2; i++)
			colorkey[i] = fz_toint(fz_arrayget(obj, i));
	}

	stride = (w * n * bpc + 7) / 8;
	samples = fz_calloc(h, stride);

	if (cstm)
	{
		stm = pdf_openinlinestream(cstm, xref, dict, stride * h);
	}
	else
	{
		error = pdf_openstream(&stm, xref, fz_tonum(dict), fz_togen(dict));
		if (error)
		{
			if (colorspace)
				fz_dropcolorspace(colorspace);
			if (mask)
				fz_droppixmap(mask);
			return fz_rethrow(error, "cannot open image data stream (%d 0 R)", fz_tonum(dict));
		}
	}

	len = fz_read(stm, samples, h * stride);
	if (len < 0)
	{
		fz_close(stm);
		if (colorspace)
			fz_dropcolorspace(colorspace);
		if (mask)
			fz_droppixmap(mask);
		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_tonum(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];
	}

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

	/* Unpack samples into pixmap */

	tile = fz_newpixmap(colorspace, 0, 0, w, h);

	scale = 1;
	if (!indexed)
	{
		switch (bpc)
		{
		case 1: scale = 255; break;
		case 2: scale = 85; break;
		case 4: scale = 17; break;
		}
	}

	fz_unpacktile(tile, samples, n, bpc, stride, scale);

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

	if (indexed)
	{
		fz_pixmap *conv;

		fz_decodeindexedtile(tile, decode, (1 << bpc) - 1);

		conv = pdf_expandindexedpixmap(tile);
		fz_droppixmap(tile);
		tile = conv;
	}
	else
	{
		fz_decodetile(tile, decode);
	}

	if (colorspace)
		fz_dropcolorspace(colorspace);

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

	fz_free(samples);

	*imgp = tile;
	return fz_okay;
}
Example #23
0
static fz_error
pdf_loadjpximage(fz_pixmap **imgp, pdf_xref *xref, fz_obj *dict)
{
	fz_error error;
	fz_buffer *buf;
	fz_pixmap *img;
	fz_obj *obj;

	pdf_logimage("jpeg2000\n");

	error = pdf_loadstream(&buf, xref, fz_tonum(dict), fz_togen(dict));
	if (error)
		return fz_rethrow(error, "cannot load jpx image data");

	error = fz_loadjpximage(&img, buf->data, buf->len);
	if (error)
	{
		fz_dropbuffer(buf);
		return fz_rethrow(error, "cannot load jpx image");
	}

	fz_dropbuffer(buf);

	obj = fz_dictgetsa(dict, "SMask", "Mask");
	if (fz_isdict(obj))
	{
		error = pdf_loadimageimp(&img->mask, xref, nil, obj, nil, 1);
		if (error)
		{
			fz_droppixmap(img);
			return fz_rethrow(error, "cannot load image mask/softmask");
		}
	}

	obj = fz_dictgets(dict, "ColorSpace");
	if (obj)
	{
		fz_colorspace *original = img->colorspace;
		img->colorspace = nil;

		error = pdf_loadcolorspace(&img->colorspace, xref, obj);
		if (error)
		{
			fz_dropcolorspace(original);
			return fz_rethrow(error, "cannot load image colorspace");
		}

		if (original->n != img->colorspace->n)
		{
			fz_warn("jpeg-2000 colorspace (%s) does not match promised colorspace (%s)", original->name, img->colorspace->name);
			fz_dropcolorspace(img->colorspace);
			img->colorspace = original;
		}
		else
			fz_dropcolorspace(original);

		if (!strcmp(img->colorspace->name, "Indexed"))
		{
			fz_pixmap *conv;
			conv = pdf_expandindexedpixmap(img);
			fz_droppixmap(img);
			img = conv;
		}
	}

	*imgp = img;
	return fz_okay;
}
Example #24
0
static fz_error
gatherfonts(int page, fz_obj *pageobj, fz_obj *dict)
{
	int i;

	for (i = 0; i < fz_dictlen(dict); i++)
	{
		fz_obj *ref;
		fz_obj *fontdict;
		fz_obj *subtype;
		fz_obj *basefont;
		fz_obj *name;
		int k;

		fontdict = ref = fz_dictgetval(dict, i);
		if (!fz_isdict(fontdict))
		{
			fz_warn("not a font dict (%d %d R)", fz_tonum(ref), fz_togen(ref));
			continue;
		}

		subtype = fz_dictgets(fontdict, "Subtype");
		if (!fz_isname(subtype))
			fz_warn("not a font dict subtype (%d %d R)", fz_tonum(ref), fz_togen(ref));

		basefont = fz_dictgets(fontdict, "BaseFont");
		if (basefont)
		{
			if (!fz_isname(basefont))
				return fz_throw("not a font dict basefont (%d %d R)", fz_tonum(ref), fz_togen(ref));
		}
		else
		{
			name = fz_dictgets(fontdict, "Name");
			if (name && !fz_isname(name))
				return fz_throw("not a font dict name (%d %d R)", fz_tonum(ref), fz_togen(ref));
		}

		for (k = 0; k < fonts; k++)
			if (fz_tonum(font[k]->ref) == fz_tonum(ref) &&
				fz_togen(font[k]->ref) == fz_togen(ref))
				break;

		if (k < fonts)
			continue;

		fonts++;

		font = fz_realloc(font, fonts * sizeof (struct info *));
		if (!font)
			return fz_throw("out of memory");

		font[fonts - 1] = fz_malloc(sizeof (struct info));
		if (!font[fonts - 1])
			return fz_throw("out of memory");

		font[fonts - 1]->page = page;
		font[fonts - 1]->pageobj = pageobj;
		font[fonts - 1]->ref = ref;
		font[fonts - 1]->u.font.subtype = subtype;
		font[fonts - 1]->u.font.name = basefont ? basefont : name;
	}

	return fz_okay;
}
Example #25
0
/*
 * Create a filter given a name and param dictionary.
 */
static fz_error *
buildonefilter(fz_filter **fp, fz_obj *f, fz_obj *p)
{
	fz_filter *decompress;
	fz_filter *predict;
	fz_error *error;
	char *s;

	s = fz_toname(f);

	if (!strcmp(s, "ASCIIHexDecode") || !strcmp(s, "AHx"))
		error = fz_newahxd(fp, p);

	else if (!strcmp(s, "ASCII85Decode") || !strcmp(s, "A85"))
		error = fz_newa85d(fp, p);

	else if (!strcmp(s, "CCITTFaxDecode") || !strcmp(s, "CCF"))
		error = fz_newfaxd(fp, p);

	else if (!strcmp(s, "DCTDecode") || !strcmp(s, "DCT"))
		error = fz_newdctd(fp, p);

	else if (!strcmp(s, "RunLengthDecode") || !strcmp(s, "RL"))
		error = fz_newrld(fp, p);

	else if (!strcmp(s, "FlateDecode") || !strcmp(s, "Fl"))
	{
		if (fz_isdict(p))
		{
			fz_obj *obj = fz_dictgets(p, "Predictor");
			if (obj)
			{
				error = fz_newflated(&decompress, p);
				if (error)
					return fz_rethrow(error, "cannot create deflate filter");

				error = fz_newpredictd(&predict, p);
				if (error)
				{
					fz_dropfilter(decompress);
					return fz_rethrow(error, "cannot create predictor filter");
				}

				error = fz_newpipeline(fp, decompress, predict);
				fz_dropfilter(decompress);
				fz_dropfilter(predict);
				if (error)
					return fz_rethrow(error, "cannot create pipeline filter");
				return fz_okay;
			}
		}
		error = fz_newflated(fp, p);
	}

	else if (!strcmp(s, "LZWDecode") || !strcmp(s, "LZW"))
	{
		if (fz_isdict(p))
		{
			fz_obj *obj = fz_dictgets(p, "Predictor");
			if (obj)
			{
				error = fz_newlzwd(&decompress, p);
				if (error)
					return fz_rethrow(error, "cannot create lzwd filter");

				error = fz_newpredictd(&predict, p);
				if (error)
				{
					fz_dropfilter(decompress);
					return fz_rethrow(error, "cannot create predictor filter");
				}

				error = fz_newpipeline(fp, decompress, predict);
				fz_dropfilter(decompress);
				fz_dropfilter(predict);
				if (error)
					return fz_rethrow(error, "cannot create pipeline filter");
				return fz_okay;
			}
		}
		error = fz_newlzwd(fp, p);
	}

#ifdef HAVE_JBIG2DEC
	else if (!strcmp(s, "JBIG2Decode"))
	{
		/* TODO: extract and feed JBIG2Global */
		error = fz_newjbig2d(fp, p);
	}
#endif

#ifdef HAVE_JASPER
	else if (!strcmp(s, "JPXDecode"))
		error = fz_newjpxd(fp, p);
#endif

	else
	{
		return fz_throw("unknown filter name (%s)", s);
	}

	if (error)
		return fz_rethrow(error, "cannot create filter");
	return fz_okay;
}
Example #26
0
static fz_error
gatherforms(int page, fz_obj *pageobj, fz_obj *dict)
{
	int i;

	for (i = 0; i < fz_dictlen(dict); i++)
	{
		fz_obj *ref;
		fz_obj *xobjdict;
		fz_obj *type;
		fz_obj *subtype;
		fz_obj *group;
		fz_obj *reference;
		int k;

		xobjdict = ref = fz_dictgetval(dict, i);
		if (!fz_isdict(xobjdict))
			return fz_throw("not a xobject dict (%d %d R)", fz_tonum(ref), fz_togen(ref));

		type = fz_dictgets(xobjdict, "Subtype");
		if (!fz_isname(type))
			return fz_throw("not a xobject type (%d %d R)", fz_tonum(ref), fz_togen(ref));
		if (strcmp(fz_toname(type), "Form"))
			continue;

		subtype = fz_dictgets(xobjdict, "Subtype2");
		if (subtype && !fz_isname(subtype))
			return fz_throw("not a xobject subtype (%d %d R)", fz_tonum(ref), fz_togen(ref));
		if (strcmp(fz_toname(subtype), "PS"))
			continue;

		group = fz_dictgets(xobjdict, "Group");
		if (group && !fz_isdict(group))
			return fz_throw("not a form xobject group dict (%d %d R)", fz_tonum(ref), fz_togen(ref));

		reference = fz_dictgets(xobjdict, "Ref");
		if (reference && !fz_isdict(reference))
			return fz_throw("not a form xobject reference dict (%d %d R)", fz_tonum(ref), fz_togen(ref));

		for (k = 0; k < forms; k++)
			if (fz_tonum(form[k]->ref) == fz_tonum(ref) &&
				fz_togen(form[k]->ref) == fz_togen(ref))
				break;

		if (k < forms)
			continue;

		forms++;

		form = fz_realloc(form, forms * sizeof (struct info *));
		if (!form)
			return fz_throw("out of memory");

		form[forms - 1] = fz_malloc(sizeof (struct info));
		if (!form[forms - 1])
			return fz_throw("out of memory");

		form[forms - 1]->page = page;
		form[forms - 1]->pageobj = pageobj;
		form[forms - 1]->ref = ref;
		form[forms - 1]->u.form.group = group;
		form[forms - 1]->u.form.reference = reference;
	}

	return fz_okay;
}