pdf_page *
pdf_load_page(pdf_document *doc, int number)
{
	fz_context *ctx = doc->ctx;
	pdf_page *page;
	pdf_annot *annot;
	pdf_obj *pageobj, *pageref, *obj;
	fz_rect mediabox, cropbox, realbox;
	float userunit;
	fz_matrix mat;

	if (doc->file_reading_linearly)
	{
		pageref = pdf_progressive_advance(doc, number);
		if (pageref == NULL)
			fz_throw(doc->ctx, FZ_ERROR_TRYLATER, "page %d not available yet", number);
	}
	else
		pageref = pdf_lookup_page_obj(doc, number);
	pageobj = pdf_resolve_indirect(pageref);

	page = fz_malloc_struct(ctx, pdf_page);
	page->resources = NULL;
	page->contents = NULL;
	page->transparency = 0;
	page->links = NULL;
	page->annots = NULL;
	page->deleted_annots = NULL;
	page->tmp_annots = NULL;
	page->me = pdf_keep_obj(pageobj);
	page->incomplete = 0;

	obj = pdf_dict_gets(pageobj, "UserUnit");
	if (pdf_is_real(obj))
		userunit = pdf_to_real(obj);
	else
		userunit = 1;

	pdf_to_rect(ctx, pdf_lookup_inherited_page_item(doc, pageobj, "MediaBox"), &mediabox);
	if (fz_is_empty_rect(&mediabox))
	{
		fz_warn(ctx, "cannot find page size for page %d", number + 1);
		mediabox.x0 = 0;
		mediabox.y0 = 0;
		mediabox.x1 = 612;
		mediabox.y1 = 792;
	}

	pdf_to_rect(ctx, pdf_lookup_inherited_page_item(doc, pageobj, "CropBox"), &cropbox);
	if (!fz_is_empty_rect(&cropbox))
		fz_intersect_rect(&mediabox, &cropbox);

	page->mediabox.x0 = fz_min(mediabox.x0, mediabox.x1) * userunit;
	page->mediabox.y0 = fz_min(mediabox.y0, mediabox.y1) * userunit;
	page->mediabox.x1 = fz_max(mediabox.x0, mediabox.x1) * userunit;
	page->mediabox.y1 = fz_max(mediabox.y0, mediabox.y1) * userunit;

	if (page->mediabox.x1 - page->mediabox.x0 < 1 || page->mediabox.y1 - page->mediabox.y0 < 1)
	{
		fz_warn(ctx, "invalid page size in page %d", number + 1);
		page->mediabox = fz_unit_rect;
	}

	page->rotate = pdf_to_int(pdf_lookup_inherited_page_item(doc, pageobj, "Rotate"));
	/* Snap page->rotate to 0, 90, 180 or 270 */
	if (page->rotate < 0)
		page->rotate = 360 - ((-page->rotate) % 360);
	if (page->rotate >= 360)
		page->rotate = page->rotate % 360;
	page->rotate = 90*((page->rotate + 45)/90);
	if (page->rotate > 360)
		page->rotate = 0;

	fz_pre_rotate(fz_scale(&page->ctm, 1, -1), -page->rotate);
	realbox = page->mediabox;
	fz_transform_rect(&realbox, &page->ctm);
	fz_pre_scale(fz_translate(&mat, -realbox.x0, -realbox.y0), userunit, userunit);
	fz_concat(&page->ctm, &page->ctm, &mat);

	fz_try(ctx)
	{
		obj = pdf_dict_gets(pageobj, "Annots");
		if (obj)
		{
			page->links = pdf_load_link_annots(doc, obj, &page->ctm);
			page->annots = pdf_load_annots(doc, obj, page);
		}
	}
	fz_catch(ctx)
	{
		if (fz_caught(ctx) != FZ_ERROR_TRYLATER)
			/* SumatraPDF: ignore annotations in case of unexpected errors */
			fz_warn(ctx, "unexpectedly failed to load page annotations");
		page->incomplete |= PDF_PAGE_INCOMPLETE_ANNOTS;
	}

	page->duration = pdf_to_real(pdf_dict_gets(pageobj, "Dur"));

	obj = pdf_dict_gets(pageobj, "Trans");
	page->transition_present = (obj != NULL);
	if (obj)
	{
		pdf_load_transition(doc, page, obj);
	}

	// TODO: inherit
	page->resources = pdf_lookup_inherited_page_item(doc, pageobj, "Resources");
	if (page->resources)
		pdf_keep_obj(page->resources);

	obj = pdf_dict_gets(pageobj, "Contents");
	fz_try(ctx)
	{
		page->contents = pdf_keep_obj(obj);

		if (pdf_resources_use_blending(doc, page->resources))
			page->transparency = 1;
		/* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=2107 */
		else if (!strcmp(pdf_to_name(pdf_dict_getp(pageobj, "Group/S")), "Transparency"))
			page->transparency = 1;

		for (annot = page->annots; annot && !page->transparency; annot = annot->next)
			if (annot->ap && pdf_resources_use_blending(doc, annot->ap->resources))
				page->transparency = 1;
	}
	fz_catch(ctx)
	{
		if (fz_caught(ctx) != FZ_ERROR_TRYLATER)
		{
			pdf_free_page(doc, page);
			fz_rethrow_message(ctx, "cannot load page %d contents (%d 0 R)", number + 1, pdf_to_num(pageref));
		}
		page->incomplete |= PDF_PAGE_INCOMPLETE_CONTENTS;
	}

	return page;
}
Beispiel #2
0
char *
pdf_parse_link_dest(fz_context *ctx, pdf_document *doc, pdf_obj *dest)
{
	pdf_obj *obj, *pageobj;
	fz_rect mediabox;
	fz_matrix pagectm;
	const char *ld;
	int page, x, y, h;

	dest = resolve_dest(ctx, doc, dest);
	if (dest == NULL)
	{
		fz_warn(ctx, "undefined link destination");
		return NULL;
	}

	if (pdf_is_name(ctx, dest))
	{
		ld = pdf_to_name(ctx, dest);
		return fz_strdup(ctx, ld);
	}
	else if (pdf_is_string(ctx, dest))
	{
		ld = pdf_to_str_buf(ctx, dest);
		return fz_strdup(ctx, ld);
	}

	pageobj = pdf_array_get(ctx, dest, 0);
	if (pdf_is_int(ctx, pageobj))
	{
		page = pdf_to_int(ctx, pageobj);
		pageobj = pdf_lookup_page_obj(ctx, doc, page);
	}
	else
	{
		fz_try(ctx)
			page = pdf_lookup_page_number(ctx, doc, pageobj);
		fz_catch(ctx)
			page = -1;
	}

	if (page < 0)
		return NULL;

	obj = pdf_array_get(ctx, dest, 1);
	if (obj)
	{
		/* Link coords use a coordinate space that does not seem to respect Rotate or UserUnit. */
		/* All we need to do is figure out the page height to flip the coordinate space. */
		pdf_page_obj_transform(ctx, pageobj, &mediabox, &pagectm);
		mediabox = fz_transform_rect(mediabox, pagectm);
		h = mediabox.y1 - mediabox.y0;

		if (pdf_name_eq(ctx, obj, PDF_NAME(XYZ)))
		{
			x = pdf_array_get_int(ctx, dest, 2);
			y = h - pdf_array_get_int(ctx, dest, 3);
		}
		else if (pdf_name_eq(ctx, obj, PDF_NAME(FitR)))
		{
			x = pdf_array_get_int(ctx, dest, 2);
			y = h - pdf_array_get_int(ctx, dest, 5);
		}
		else if (pdf_name_eq(ctx, obj, PDF_NAME(FitH)) || pdf_name_eq(ctx, obj, PDF_NAME(FitBH)))
		{
			x = 0;
			y = h - pdf_array_get_int(ctx, dest, 2);
		}
		else if (pdf_name_eq(ctx, obj, PDF_NAME(FitV)) || pdf_name_eq(ctx, obj, PDF_NAME(FitBV)))
		{
			x = pdf_array_get_int(ctx, dest, 2);
			y = 0;
		}
		else
		{
			x = 0;
			y = 0;
		}
		return fz_asprintf(ctx, "#%d,%d,%d", page + 1, x, y);
	}

	return fz_asprintf(ctx, "#%d", page + 1);
}
Beispiel #3
0
void
xps_parse_tiling_brush(xps_document *doc, const fz_matrix *ctm, const fz_rect *area,
	char *base_uri, xps_resource *dict, fz_xml *root,
	void (*func)(xps_document*, const fz_matrix*, const fz_rect*, char*, xps_resource*, fz_xml*, void*), void *user)
{
	fz_xml *node;
	struct closure c;

	char *opacity_att;
	char *transform_att;
	char *viewbox_att;
	char *viewport_att;
	char *tile_mode_att;

	fz_xml *transform_tag = NULL;

	fz_matrix transform;
	fz_rect viewbox;
	fz_rect viewport;
	float xstep, ystep;
	float xscale, yscale;
	int tile_mode;

	opacity_att = fz_xml_att(root, "Opacity");
	transform_att = fz_xml_att(root, "Transform");
	viewbox_att = fz_xml_att(root, "Viewbox");
	viewport_att = fz_xml_att(root, "Viewport");
	tile_mode_att = fz_xml_att(root, "TileMode");

	c.base_uri = base_uri;
	c.dict = dict;
	c.root = root;
	c.user = user;
	c.func = func;

	for (node = fz_xml_down(root); node; node = fz_xml_next(node))
	{
		if (!strcmp(fz_xml_tag(node), "ImageBrush.Transform"))
			transform_tag = fz_xml_down(node);
		if (!strcmp(fz_xml_tag(node), "VisualBrush.Transform"))
			transform_tag = fz_xml_down(node);
	}

	xps_resolve_resource_reference(doc, dict, &transform_att, &transform_tag, NULL);

	transform = fz_identity;
	if (transform_att)
		xps_parse_render_transform(doc, transform_att, &transform);
	if (transform_tag)
		xps_parse_matrix_transform(doc, transform_tag, &transform);
	fz_concat(&transform, &transform, ctm);

	viewbox = fz_unit_rect;
	if (viewbox_att)
		xps_parse_rectangle(doc, viewbox_att, &viewbox);

	viewport = fz_unit_rect;
	if (viewport_att)
		xps_parse_rectangle(doc, viewport_att, &viewport);

	if (fabsf(viewport.x1 - viewport.x0) < 0.01f || fabsf(viewport.y1 - viewport.y0) < 0.01f)
		fz_warn(doc->ctx, "not drawing tile for viewport size %.4f x %.4f", viewport.x1 - viewport.x0, viewport.y1 - viewport.y0);
	else if (fabsf(viewbox.x1 - viewbox.x0) < 0.01f || fabsf(viewbox.y1 - viewbox.y0) < 0.01f)
		fz_warn(doc->ctx, "not drawing tile for viewbox size %.4f x %.4f", viewbox.x1 - viewbox.x0, viewbox.y1 - viewbox.y0);

	/* some sanity checks on the viewport/viewbox size */
	if (fabsf(viewport.x1 - viewport.x0) < 0.01f) return;
	if (fabsf(viewport.y1 - viewport.y0) < 0.01f) return;
	if (fabsf(viewbox.x1 - viewbox.x0) < 0.01f) return;
	if (fabsf(viewbox.y1 - viewbox.y0) < 0.01f) return;

	xstep = viewbox.x1 - viewbox.x0;
	ystep = viewbox.y1 - viewbox.y0;

	xscale = (viewport.x1 - viewport.x0) / xstep;
	yscale = (viewport.y1 - viewport.y0) / ystep;

	tile_mode = TILE_NONE;
	if (tile_mode_att)
	{
		if (!strcmp(tile_mode_att, "None"))
			tile_mode = TILE_NONE;
		if (!strcmp(tile_mode_att, "Tile"))
			tile_mode = TILE_TILE;
		if (!strcmp(tile_mode_att, "FlipX"))
			tile_mode = TILE_FLIP_X;
		if (!strcmp(tile_mode_att, "FlipY"))
			tile_mode = TILE_FLIP_Y;
		if (!strcmp(tile_mode_att, "FlipXY"))
			tile_mode = TILE_FLIP_X_Y;
	}

	if (tile_mode == TILE_FLIP_X || tile_mode == TILE_FLIP_X_Y)
		xstep *= 2;
	if (tile_mode == TILE_FLIP_Y || tile_mode == TILE_FLIP_X_Y)
		ystep *= 2;

	xps_begin_opacity(doc, &transform, area, base_uri, dict, opacity_att, NULL);

	fz_pre_translate(&transform, viewport.x0, viewport.y0);
	fz_pre_scale(&transform, xscale, yscale);
	fz_pre_translate(&transform, -viewbox.x0, -viewbox.y0);

	if (tile_mode != TILE_NONE)
	{
		int x0, y0, x1, y1;
		fz_matrix invctm;
		fz_rect local_area = *area;
		fz_transform_rect(&local_area, fz_invert_matrix(&invctm, &transform));
		/* SumatraPDF: make sure that the intended area is covered */
		{
			fz_point tl;
			fz_irect bbox;
			fz_rect bigview = viewbox;
			bigview.x1 = bigview.x0 + xstep;
			bigview.y1 = bigview.y0 + ystep;
			fz_irect_from_rect(&bbox, fz_transform_rect(&bigview, &transform));
			tl.x = bbox.x0;
			tl.y = bbox.y0;
			fz_transform_point(&tl, &invctm);
			local_area.x0 -= fz_max(tl.x, 0); local_area.x1 += xstep - fz_max(tl.x, 0);
			local_area.y0 -= fz_max(tl.y, 0); local_area.y1 += ystep - fz_max(tl.y, 0);
		}
		x0 = floorf(local_area.x0 / xstep);
		y0 = floorf(local_area.y0 / ystep);
		x1 = ceilf(local_area.x1 / xstep);
		y1 = ceilf(local_area.y1 / ystep);

#ifdef TILE
		/* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=2248 */
		if ((local_area.x1 - local_area.x0) / xstep > 1 || (local_area.y1 - local_area.y0) / ystep > 1)
#else
		if (0)
#endif
		{
			fz_rect bigview = viewbox;
			bigview.x1 = bigview.x0 + xstep;
			bigview.y1 = bigview.y0 + ystep;
			fz_begin_tile(doc->dev, &local_area, &bigview, xstep, ystep, &transform);
			xps_paint_tiling_brush(doc, &transform, &viewbox, tile_mode, &c);
			fz_end_tile(doc->dev);
		}
		else
		{
			int x, y;
			for (y = y0; y < y1; y++)
			{
				for (x = x0; x < x1; x++)
				{
					fz_matrix ttm = transform;
					fz_pre_translate(&ttm, xstep * x, ystep * y);
					xps_paint_tiling_brush(doc, &ttm, &viewbox, tile_mode, &c);
				}
			}
		}
	}
	else
	{
		xps_paint_tiling_brush(doc, &transform, &viewbox, tile_mode, &c);
	}

	xps_end_opacity(doc, base_uri, dict, opacity_att, NULL);
}
Beispiel #4
0
void
xps_parse_color(xps_document *doc, char *base_uri, char *string,
                fz_colorspace **csp, float *samples)
{
    char *p;
    int i, n;
    char buf[1024];
    char *profile;

    *csp = fz_device_rgb;

    samples[0] = 1;
    samples[1] = 0;
    samples[2] = 0;
    samples[3] = 0;

    if (string[0] == '#')
    {
        if (strlen(string) == 9)
        {
            samples[0] = unhex(string[1]) * 16 + unhex(string[2]);
            samples[1] = unhex(string[3]) * 16 + unhex(string[4]);
            samples[2] = unhex(string[5]) * 16 + unhex(string[6]);
            samples[3] = unhex(string[7]) * 16 + unhex(string[8]);
        }
        else
        {
            samples[0] = 255;
            samples[1] = unhex(string[1]) * 16 + unhex(string[2]);
            samples[2] = unhex(string[3]) * 16 + unhex(string[4]);
            samples[3] = unhex(string[5]) * 16 + unhex(string[6]);
        }

        samples[0] /= 255;
        samples[1] /= 255;
        samples[2] /= 255;
        samples[3] /= 255;
    }

    else if (string[0] == 's' && string[1] == 'c' && string[2] == '#')
    {
        if (count_commas(string) == 2)
            sscanf(string, "sc#%g,%g,%g", samples + 1, samples + 2, samples + 3);
        if (count_commas(string) == 3)
            sscanf(string, "sc#%g,%g,%g,%g", samples, samples + 1, samples + 2, samples + 3);
    }

    else if (strstr(string, "ContextColor ") == string)
    {
        /* Crack the string for profile name and sample values */
        fz_strlcpy(buf, string, sizeof buf);

        profile = strchr(buf, ' ');
        if (!profile)
        {
            fz_warn(doc->ctx, "cannot find icc profile uri in '%s'", string);
            return;
        }

        *profile++ = 0;
        p = strchr(profile, ' ');
        if (!p)
        {
            fz_warn(doc->ctx, "cannot find component values in '%s'", profile);
            return;
        }

        *p++ = 0;
        n = count_commas(p) + 1;
        i = 0;
        while (i < n)
        {
            samples[i++] = fz_atof(p);
            p = strchr(p, ',');
            if (!p)
                break;
            p ++;
            if (*p == ' ')
                p ++;
        }
        while (i < n)
        {
            samples[i++] = 0;
        }

        /* TODO: load ICC profile */
        switch (n)
        {
        case 2:
            *csp = fz_device_gray;
            break;
        case 4:
            *csp = fz_device_rgb;
            break;
        case 5:
            *csp = fz_device_cmyk;
            break;
        default:
            *csp = fz_device_gray;
            break;
        }
    }
}
fz_error
pdf_loadxref(pdf_xref *xref, char *filename)
{
    fz_error error;
    fz_obj *size;
    int i;

    char buf[65536];	/* yeowch! */

    pdf_logxref("loadxref '%s' %p\n", filename, xref);

    error = fz_openrfile(&xref->file, filename);
    if (error)
    {
        return fz_rethrow(error, "cannot open file: '%s'", filename);
    }

    error = loadversion(xref);
    if (error)
    {
        error = fz_rethrow(error, "cannot read version marker");
        goto cleanup;
    }

    error = readstartxref(xref);
    if (error)
    {
        error = fz_rethrow(error, "cannot read startxref");
        goto cleanup;
    }

    error = readtrailer(xref, buf, sizeof buf);
    if (error)
    {
        error = fz_rethrow(error, "cannot read trailer");
        goto cleanup;
    }

    size = fz_dictgets(xref->trailer, "Size");
    if (!size)
    {
        error = fz_throw("trailer missing Size entry");
        goto cleanup;
    }

    pdf_logxref("  size %d at 0x%x\n", fz_toint(size), xref->startxref);

    assert(xref->table == nil);

    xref->len = fz_toint(size);
    xref->cap = xref->len + 1; /* for hack to allow broken pdf generators with off-by-one errors */
    xref->table = fz_malloc(xref->cap * sizeof(pdf_xrefentry));
    if (!xref->table)
    {
        error = fz_rethrow(-1, "out of memory: xref table");
        goto cleanup;
    }

    for (i = 0; i < xref->cap; i++)
    {
        xref->table[i].ofs = 0;
        xref->table[i].gen = 0;
        xref->table[i].stmofs = 0;
        xref->table[i].obj = nil;
        xref->table[i].type = 0;
    }

    error = readxrefsections(xref, xref->startxref, buf, sizeof buf);
    if (error)
    {
        error = fz_rethrow(error, "cannot read xref");
        goto cleanup;
    }

    /* broken pdfs where first object is not free */
    if (xref->table[0].type != 'f')
    {
        fz_warn("first object in xref is not free");
        xref->table[0].type = 'f';
    }

    /* broken pdfs where freed objects have offset and gen set to 0
       but still exits */
    for (i = 0; i < xref->len; i++)
        if (xref->table[i].type == 'n' && xref->table[i].ofs == 0 &&
                xref->table[i].gen == 0 && xref->table[i].obj == nil)
        {
            fz_warn("object (%d %d R) has invalid offset, assumed missing", i, xref->table[i].gen);
            xref->table[i].type = 'f';
        }

    return fz_okay;

cleanup:
    fz_dropstream(xref->file);
    xref->file = nil;
    free(xref->table);
    xref->table = nil;
    return error;
}
Beispiel #6
0
static fz_image *
pdf_load_image_imp(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask)
{
	fz_image *image = NULL;
	pdf_obj *obj, *res;

	int w, h, bpc, n;
	int imagemask;
	int interpolate;
	int indexed;
	fz_image *mask = NULL; /* explicit mask/soft mask image */
	int use_colorkey = 0;
	fz_colorspace *colorspace = NULL;
	float decode[FZ_MAX_COLORS * 2];
	int colorkey[FZ_MAX_COLORS * 2];
	int stride;

	int i;
	fz_compressed_buffer *buffer;

	/* special case for JPEG2000 images */
	if (pdf_is_jpx_image(ctx, dict))
		return pdf_load_jpx_imp(ctx, doc, rdb, dict, cstm, forcemask);

	w = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(Width), PDF_NAME(W)));
	h = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(Height), PDF_NAME(H)));
	bpc = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(BitsPerComponent), PDF_NAME(BPC)));
	if (bpc == 0)
		bpc = 8;
	imagemask = pdf_to_bool(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(ImageMask), PDF_NAME(IM)));
	interpolate = pdf_to_bool(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(Interpolate), PDF_NAME(I)));

	indexed = 0;
	use_colorkey = 0;

	if (imagemask)
		bpc = 1;

	if (w <= 0)
		fz_throw(ctx, FZ_ERROR_GENERIC, "image width is zero (or less)");
	if (h <= 0)
		fz_throw(ctx, FZ_ERROR_GENERIC, "image height is zero (or less)");
	if (bpc <= 0)
		fz_throw(ctx, FZ_ERROR_GENERIC, "image depth is zero (or less)");
	if (bpc > 16)
		fz_throw(ctx, FZ_ERROR_GENERIC, "image depth is too large: %d", bpc);
	if (w > (1 << 16))
		fz_throw(ctx, FZ_ERROR_GENERIC, "image is too wide");
	if (h > (1 << 16))
		fz_throw(ctx, FZ_ERROR_GENERIC, "image is too high");

	fz_var(mask);
	fz_var(image);
	fz_var(colorspace);

	fz_try(ctx)
	{
		obj = pdf_dict_geta(ctx, dict, PDF_NAME(ColorSpace), PDF_NAME(CS));
		if (obj && !imagemask && !forcemask)
		{
			/* colorspace resource lookup is only done for inline images */
			if (pdf_is_name(ctx, obj))
			{
				res = pdf_dict_get(ctx, pdf_dict_get(ctx, rdb, PDF_NAME(ColorSpace)), obj);
				if (res)
					obj = res;
			}

			colorspace = pdf_load_colorspace(ctx, obj);
			indexed = fz_colorspace_is_indexed(ctx, colorspace);

			n = fz_colorspace_n(ctx, colorspace);
		}
		else
		{
			n = 1;
		}

		obj = pdf_dict_geta(ctx, dict, PDF_NAME(Decode), PDF_NAME(D));
		if (obj)
		{
			for (i = 0; i < n * 2; i++)
				decode[i] = pdf_array_get_real(ctx, obj, i);
		}
		else if (fz_colorspace_is_lab(ctx, colorspace) || fz_colorspace_is_lab_icc(ctx, colorspace))
		{
			decode[0] = 0;
			decode[1] = 100;
			decode[2] = -128;
			decode[3] = 127;
			decode[4] = -128;
			decode[5] = 127;
		}
		else
		{
			float maxval = indexed ? (1 << bpc) - 1 : 1;
			for (i = 0; i < n * 2; i++)
				decode[i] = i & 1 ? maxval : 0;
		}

		obj = pdf_dict_geta(ctx, dict, PDF_NAME(SMask), PDF_NAME(Mask));
		if (pdf_is_dict(ctx, obj))
		{
			/* Not allowed for inline images or soft masks */
			if (cstm)
				fz_warn(ctx, "Ignoring invalid inline image soft mask");
			else if (forcemask)
				fz_warn(ctx, "Ignoring recursive image soft mask");
			else
			{
				mask = pdf_load_image_imp(ctx, doc, rdb, obj, NULL, 1);
				obj = pdf_dict_get(ctx, obj, PDF_NAME(Matte));
				if (pdf_is_array(ctx, obj))
				{
					use_colorkey = 1;
					for (i = 0; i < n; i++)
						colorkey[i] = pdf_array_get_real(ctx, obj, i) * 255;
				}
			}
		}
		else if (pdf_is_array(ctx, obj))
		{
			use_colorkey = 1;
			for (i = 0; i < n * 2; i++)
			{
				if (!pdf_is_int(ctx, pdf_array_get(ctx, obj, i)))
				{
					fz_warn(ctx, "invalid value in color key mask");
					use_colorkey = 0;
				}
				colorkey[i] = pdf_array_get_int(ctx, obj, i);
			}
		}

		/* Do we load from a ref, or do we load an inline stream? */
		if (cstm == NULL)
		{
			/* Just load the compressed image data now and we can decode it on demand. */
			buffer = pdf_load_compressed_stream(ctx, doc, pdf_to_num(ctx, dict));
			image = fz_new_image_from_compressed_buffer(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, use_colorkey ? colorkey : NULL, buffer, mask);
			image->invert_cmyk_jpeg = 0;
		}
		else
		{
			/* Inline stream */
			stride = (w * n * bpc + 7) / 8;
			image = fz_new_image_from_compressed_buffer(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, use_colorkey ? colorkey : NULL, NULL, mask);
			image->invert_cmyk_jpeg = 0;
			pdf_load_compressed_inline_image(ctx, doc, dict, stride * h, cstm, indexed, (fz_compressed_image *)image);
		}
	}
	fz_always(ctx)
	{
		fz_drop_colorspace(ctx, colorspace);
		fz_drop_image(ctx, mask);
	}
	fz_catch(ctx)
	{
		fz_drop_image(ctx, image);
		fz_rethrow(ctx);
	}
	return image;
}
Beispiel #7
0
fz_pixmap *
fz_load_jpx(fz_context *ctx, unsigned char *data, int size, fz_colorspace *defcs, int indexed)
{
	fz_pixmap *img;
	fz_colorspace *origcs;
	opj_dparameters_t params;
	opj_codec_t *codec;
	opj_image_t *jpx;
	opj_stream_t *stream;
	fz_colorspace *colorspace;
	unsigned char *p;
	OPJ_CODEC_FORMAT format;
	int a, n, w, h, depth, sgnd;
	int x, y, k, v;
	stream_block sb;

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

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

	opj_set_default_decoder_parameters(&params);
	if (indexed)
		params.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG;

	codec = opj_create_decompress(format);
	opj_set_info_handler(codec, fz_opj_info_callback, ctx);
	opj_set_warning_handler(codec, fz_opj_warning_callback, ctx);
	opj_set_error_handler(codec, fz_opj_error_callback, ctx);
	if (!opj_setup_decoder(codec, &params))
	{
		fz_throw(ctx, FZ_ERROR_GENERIC, "j2k decode failed");
	}

	stream = opj_stream_default_create(OPJ_TRUE);
	sb.data = data;
	sb.pos = 0;
	sb.size = size;

	opj_stream_set_read_function(stream, fz_opj_stream_read);
	opj_stream_set_skip_function(stream, fz_opj_stream_skip);
	opj_stream_set_seek_function(stream, fz_opj_stream_seek);
	opj_stream_set_user_data(stream, &sb);
	/* Set the length to avoid an assert */
	opj_stream_set_user_data_length(stream, size);

	if (!opj_read_header(stream, codec, &jpx))
	{
		opj_stream_destroy(stream);
		opj_destroy_codec(codec);
		fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to read JPX header");
	}

	if (!opj_decode(codec, stream, jpx))
	{
		opj_stream_destroy(stream);
		opj_destroy_codec(codec);
		opj_image_destroy(jpx);
		fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to decode JPX image");
	}

	opj_stream_destroy(stream);
	opj_destroy_codec(codec);

	/* jpx should never be NULL here, but check anyway */
	if (!jpx)
		fz_throw(ctx, FZ_ERROR_GENERIC, "opj_decode failed");

	for (k = 1; k < (int)jpx->numcomps; k++)
	{
		if (!jpx->comps[k].data)
		{
			opj_image_destroy(jpx);
			fz_throw(ctx, FZ_ERROR_GENERIC, "image components are missing data");
		}
		if (jpx->comps[k].w != jpx->comps[0].w)
		{
			opj_image_destroy(jpx);
			fz_throw(ctx, FZ_ERROR_GENERIC, "image components have different width");
		}
		if (jpx->comps[k].h != jpx->comps[0].h)
		{
			opj_image_destroy(jpx);
			fz_throw(ctx, FZ_ERROR_GENERIC, "image components have different height");
		}
		if (jpx->comps[k].prec != jpx->comps[0].prec)
		{
			opj_image_destroy(jpx);
			fz_throw(ctx, FZ_ERROR_GENERIC, "image components have different precision");
		}
	}

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

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

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

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

	fz_try(ctx)
	{
		img = fz_new_pixmap(ctx, colorspace, w, h);
	}
	fz_catch(ctx)
	{
		opj_image_destroy(jpx);
		fz_rethrow_message(ctx, "out of memory loading jpx");
	}

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

	opj_image_destroy(jpx);

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

	if (origcs != defcs)
	{
		fz_pixmap *tmp = fz_new_pixmap(ctx, origcs, w, h);
		fz_convert_pixmap(ctx, tmp, img);
		fz_drop_pixmap(ctx, img);
		img = tmp;
	}

	return img;
}
static fz_error
readoldxref(fz_obj **trailerp, pdf_xref *xref, char *buf, int cap)
{
    fz_error error;
    int ofs, len;
    char *s;
    int n;
    pdf_token_e tok;
    int i;
    int c;

    pdf_logxref("load old xref format\n");

    error = fz_readline(xref->file, buf, cap);
    if (error)
        return fz_rethrow(error, "cannot read xref marker");
    if (strncmp(buf, "xref", 4) != 0)
        return fz_throw("cannot find xref marker");

    while (1)
    {
        c = fz_peekbyte(xref->file);
        if (!(c >= '0' && c <= '9'))
            break;

        error = fz_readline(xref->file, buf, cap);
        if (error)
            return fz_rethrow(error, "cannot read xref count");

        s = buf;
        ofs = atoi(strsep(&s, " "));
        len = atoi(strsep(&s, " "));

        /* broken pdfs where the section is not on a separate line */
        if (s && *s != '\0')
        {
            fz_warn("broken xref section. proceeding anyway.");
            error = fz_seek(xref->file, -(2 + strlen(s)), 1);
            if (error)
                return fz_rethrow(error, "cannot seek to xref");
        }

        /* broken pdfs where size in trailer undershoots
           entries in xref sections */
        if ((ofs + len) > xref->cap)
        {
            fz_warn("broken xref section, proceeding anyway.");
            xref->cap = ofs + len;
            xref->table = fz_realloc(xref->table, xref->cap * sizeof(pdf_xrefentry));
            if (!xref->table)
                return fz_rethrow(-1, "out of memory: xref table");
        }

        if ((ofs + len) > xref->len)
        {
            for (i = xref->len; i < (ofs + len); i++)
            {
                xref->table[i].ofs = 0;
                xref->table[i].gen = 0;
                xref->table[i].stmofs = 0;
                xref->table[i].obj = nil;
                xref->table[i].type = 0;
            }
            xref->len = ofs + len;
        }

        for (i = 0; i < len; i++)
        {
            error = fz_read(&n, xref->file, (unsigned char *) buf, 20);
            if (error)
                return fz_rethrow(error, "cannot read xref table");
            if (!xref->table[ofs + i].type)
            {
                s = buf;

                /* broken pdfs where line start with white space */
                while (*s != '\0' && iswhite(*s))
                    s++;

                xref->table[ofs + i].ofs = atoi(s);
                xref->table[ofs + i].gen = atoi(s + 11);
                xref->table[ofs + i].type = s[17];
            }
        }
    }

    error = pdf_lex(&tok, xref->file, buf, cap, &n);
    if (error)
        return fz_rethrow(error, "cannot parse trailer");
    if (tok != PDF_TTRAILER)
        return fz_throw("expected trailer marker");

    error = pdf_lex(&tok, xref->file, buf, cap, &n);
    if (error)
        return fz_rethrow(error, "cannot parse trailer");
    if (tok != PDF_TODICT)
        return fz_throw("expected trailer dictionary");

    error = pdf_parsedict(trailerp, xref, xref->file, buf, cap);
    if (error)
        return fz_rethrow(error, "cannot parse trailer");
    return fz_okay;
}
Beispiel #9
0
static int
readlzwd(fz_stream *stm, unsigned char *buf, int len)
{
	fz_lzwd *lzw = stm->state;
	unsigned char *p = buf;
	unsigned char *ep = buf + len;
	unsigned char *s;
	int codelen;

	while (lzw->rp < lzw->wp && p < ep)
		*p++ = *lzw->rp++;

	while (p < ep)
	{
		if (lzw->eod)
			return 0;

		if (fillbits(lzw))
		{
			if (lzw->bidx > 32 - lzw->codebits)
			{
				lzw->eod = 1;
				return p - buf;
			}
		}

		lzw->code = lzw->word >> (32 - lzw->codebits);
		lzw->code &= (1 << lzw->codebits) - 1;
		eatbits(lzw, lzw->codebits);

		if (lzw->code == LZW_EOD)
		{
			lzw->eod = 1;
			return p - buf;
		}

		if (lzw->code == LZW_CLEAR)
		{
			lzw->codebits = MINBITS;
			lzw->nextcode = LZW_FIRST;
			lzw->oldcode = -1;
			continue;
		}

		/* if stream starts without a clear code, oldcode is undefined... */
		if (lzw->oldcode == -1)
		{
			lzw->oldcode = lzw->code;
			goto output;
		}

		/* add new entry to the code table */
		lzw->table[lzw->nextcode].prev = lzw->oldcode;
		lzw->table[lzw->nextcode].firstchar = lzw->table[lzw->oldcode].firstchar;
		lzw->table[lzw->nextcode].length = lzw->table[lzw->oldcode].length + 1;
		if (lzw->code < lzw->nextcode)
			lzw->table[lzw->nextcode].value = lzw->table[lzw->code].firstchar;
		else if (lzw->code == lzw->nextcode)
			lzw->table[lzw->nextcode].value = lzw->table[lzw->nextcode].firstchar;
		else
			fz_warn("out of range code encountered in lzw decode");

		lzw->nextcode ++;

		if (lzw->nextcode > (1 << lzw->codebits) - lzw->earlychange - 1)
		{
			lzw->codebits ++;
			if (lzw->codebits > MAXBITS)
				lzw->codebits = MAXBITS;	/* FIXME */
		}

		lzw->oldcode = lzw->code;

output:

		/* code maps to a string, copy to output (in reverse...) */
		if (lzw->code > 255)
		{
			codelen = lzw->table[lzw->code].length;
			lzw->rp = lzw->bp;
			lzw->wp = lzw->bp + codelen;

			assert(codelen < MAXLENGTH);

			s = lzw->wp;
			do {
				*(--s) = lzw->table[lzw->code].value;
				lzw->code = lzw->table[lzw->code].prev;
			} while (lzw->code >= 0 && s > lzw->bp);
		}

		/* ... or just a single character */
		else
		{
			lzw->bp[0] = lzw->code;
			lzw->rp = lzw->bp;
			lzw->wp = lzw->bp + 1;
		}

		/* copy to output */
		while (lzw->rp < lzw->wp && p < ep)
			*p++ = *lzw->rp++;
	}

	return p - buf;
}
Beispiel #10
0
static void fz_opj_warning_callback(const char *msg, void *client_data)
{
	fz_context *ctx = (fz_context *)client_data;
	fz_warn(ctx, "openjpeg warning: %s", msg);
}
Beispiel #11
0
void
pdf_sort_cmap(fz_context *ctx, pdf_cmap *cmap)
{
	pdf_range *a;			/* last written range on output */
	pdf_range *b;			/* current range examined on input */

	if (cmap->rlen == 0)
		return;

	qsort(cmap->ranges, cmap->rlen, sizeof(pdf_range), cmprange);

	if (cmap->tlen == USHRT_MAX)
	{
		fz_warn(ctx, "cmap table is full; will not combine ranges");
		return;
	}

	a = cmap->ranges;
	b = cmap->ranges + 1;

	while (b < cmap->ranges + cmap->rlen)
	{
		/* ignore one-to-many mappings */
		if (pdf_range_flags(b) == PDF_CMAP_MULTI)
		{
			*(++a) = *b;
		}

		/* input contiguous */
		else if (pdf_range_high(a) + 1 == b->low)
		{
			/* output contiguous */
			if (pdf_range_high(a) - a->low + a->offset + 1 == b->offset)
			{
				/* SR -> R and SS -> R and RR -> R and RS -> R */
				if ((pdf_range_flags(a) == PDF_CMAP_SINGLE || pdf_range_flags(a) == PDF_CMAP_RANGE) && (pdf_range_high(b) - a->low <= 0x3fff))
				{
					pdf_range_set_flags(a, PDF_CMAP_RANGE);
					pdf_range_set_high(a, pdf_range_high(b));
				}

				/* LS -> L */
				else if (pdf_range_flags(a) == PDF_CMAP_TABLE && pdf_range_flags(b) == PDF_CMAP_SINGLE && (pdf_range_high(b) - a->low <= 0x3fff))
				{
					pdf_range_set_high(a, pdf_range_high(b));
					add_table(ctx, cmap, b->offset);
				}

				/* LR -> LR */
				else if (pdf_range_flags(a) == PDF_CMAP_TABLE && pdf_range_flags(b) == PDF_CMAP_RANGE)
				{
					*(++a) = *b;
				}

				/* XX -> XX */
				else
				{
					*(++a) = *b;
				}
			}

			/* output separated */
			else
			{
				/* SS -> L */
				if (pdf_range_flags(a) == PDF_CMAP_SINGLE && pdf_range_flags(b) == PDF_CMAP_SINGLE)
				{
					pdf_range_set_flags(a, PDF_CMAP_TABLE);
					pdf_range_set_high(a, pdf_range_high(b));
					add_table(ctx, cmap, a->offset);
					add_table(ctx, cmap, b->offset);
					a->offset = cmap->tlen - 2;
				}

				/* LS -> L */
				else if (pdf_range_flags(a) == PDF_CMAP_TABLE && pdf_range_flags(b) == PDF_CMAP_SINGLE && (pdf_range_high(b) - a->low <= 0x3fff))
				{
					pdf_range_set_high(a, pdf_range_high(b));
					add_table(ctx, cmap, b->offset);
				}

				/* XX -> XX */
				else
				{
					*(++a) = *b;
				}
			}
		}

		/* input separated: XX -> XX */
		else
		{
			*(++a) = *b;
		}

		b ++;
	}

	cmap->rlen = a - cmap->ranges + 1;

	fz_flush_warnings(ctx);
}
Beispiel #12
0
static void
pdf_load_mesh_params(fz_context *ctx, pdf_document *doc, fz_shade *shade, pdf_obj *dict)
{
	pdf_obj *obj;
	int i, n;

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

	shade->u.m.vprow = pdf_dict_get_int(ctx, dict, PDF_NAME(VerticesPerRow));
	shade->u.m.bpflag = pdf_dict_get_int(ctx, dict, PDF_NAME(BitsPerFlag));
	shade->u.m.bpcoord = pdf_dict_get_int(ctx, dict, PDF_NAME(BitsPerCoordinate));
	shade->u.m.bpcomp = pdf_dict_get_int(ctx, dict, PDF_NAME(BitsPerComponent));

	obj = pdf_dict_get(ctx, dict, PDF_NAME(Decode));
	if (pdf_array_len(ctx, obj) >= 6)
	{
		n = fz_mini(FZ_MAX_COLORS, (pdf_array_len(ctx, obj) - 4) / 2);
		shade->u.m.x0 = pdf_array_get_real(ctx, obj, 0);
		shade->u.m.x1 = pdf_array_get_real(ctx, obj, 1);
		shade->u.m.y0 = pdf_array_get_real(ctx, obj, 2);
		shade->u.m.y1 = pdf_array_get_real(ctx, obj, 3);
		for (i = 0; i < n; i++)
		{
			shade->u.m.c0[i] = pdf_array_get_real(ctx, obj, 4 + i * 2);
			shade->u.m.c1[i] = pdf_array_get_real(ctx, obj, 5 + i * 2);
		}
	}

	if (shade->u.m.vprow < 2 && shade->type == 5)
	{
		fz_warn(ctx, "Too few vertices per row (%d)", shade->u.m.vprow);
		shade->u.m.vprow = 2;
	}

	if (shade->u.m.bpflag != 2 && shade->u.m.bpflag != 4 && shade->u.m.bpflag != 8 &&
		shade->type != 5)
	{
		fz_warn(ctx, "Invalid number of bits per flag (%d)", shade->u.m.bpflag);
		shade->u.m.bpflag = 8;
	}

	if (shade->u.m.bpcoord != 1 && shade->u.m.bpcoord != 2 && shade->u.m.bpcoord != 4 &&
		shade->u.m.bpcoord != 8 && shade->u.m.bpcoord != 12 && shade->u.m.bpcoord != 16 &&
		shade->u.m.bpcoord != 24 && shade->u.m.bpcoord != 32)
	{
		fz_warn(ctx, "Invalid number of bits per coordinate (%d)", shade->u.m.bpcoord);
		shade->u.m.bpcoord = 8;
	}

	if (shade->u.m.bpcomp != 1 && shade->u.m.bpcomp != 2 && shade->u.m.bpcomp != 4 &&
		shade->u.m.bpcomp != 8 && shade->u.m.bpcomp != 12 && shade->u.m.bpcomp != 16)
	{
		fz_warn(ctx, "Invalid number of bits per component (%d)", shade->u.m.bpcomp);
		shade->u.m.bpcomp = 8;
	}
}
Beispiel #13
0
fz_error
pdf_parse_ind_obj(fz_obj **op, pdf_xref *xref,
	fz_stream *file, char *buf, int cap,
	int *onum, int *ogen, int *ostmofs)
{
	fz_error error = fz_okay;
	fz_obj *obj = NULL;
	int num = 0, gen = 0, stm_ofs;
	int tok;
	int len;
	int a, b;

	error = pdf_lex(&tok, file, buf, cap, &len);
	if (error)
		return fz_rethrow(error, "cannot parse indirect object (%d %d R)", num, gen);
	if (tok != PDF_TOK_INT)
		return fz_throw("expected object number (%d %d R)", num, gen);
	num = atoi(buf);

	error = pdf_lex(&tok, file, buf, cap, &len);
	if (error)
		return fz_rethrow(error, "cannot parse indirect object (%d %d R)", num, gen);
	if (tok != PDF_TOK_INT)
		return fz_throw("expected generation number (%d %d R)", num, gen);
	gen = atoi(buf);

	error = pdf_lex(&tok, file, buf, cap, &len);
	if (error)
		return fz_rethrow(error, "cannot parse indirect object (%d %d R)", num, gen);
	if (tok != PDF_TOK_OBJ)
		return fz_throw("expected 'obj' keyword (%d %d R)", num, gen);

	error = pdf_lex(&tok, file, buf, cap, &len);
	if (error)
		return fz_rethrow(error, "cannot parse indirect object (%d %d R)", num, gen);

	switch (tok)
	{
	case PDF_TOK_OPEN_ARRAY:
		error = pdf_parse_array(&obj, xref, file, buf, cap);
		if (error)
			return fz_rethrow(error, "cannot parse indirect object (%d %d R)", num, gen);
		break;

	case PDF_TOK_OPEN_DICT:
		error = pdf_parse_dict(&obj, xref, file, buf, cap);
		if (error)
			return fz_rethrow(error, "cannot parse indirect object (%d %d R)", num, gen);
		break;

	case PDF_TOK_NAME: obj = fz_new_name(buf); break;
	case PDF_TOK_REAL: obj = fz_new_real(fz_atof(buf)); break;
	case PDF_TOK_STRING: obj = fz_new_string(buf, len); break;
	case PDF_TOK_TRUE: obj = fz_new_bool(1); break;
	case PDF_TOK_FALSE: obj = fz_new_bool(0); break;
	case PDF_TOK_NULL: obj = fz_new_null(); break;

	case PDF_TOK_INT:
		a = atoi(buf);
		error = pdf_lex(&tok, file, buf, cap, &len);
		if (error)
			return fz_rethrow(error, "cannot parse indirect object (%d %d R)", num, gen);
		if (tok == PDF_TOK_STREAM || tok == PDF_TOK_ENDOBJ)
		{
			obj = fz_new_int(a);
			goto skip;
		}
		if (tok == PDF_TOK_INT)
		{
			b = atoi(buf);
			error = pdf_lex(&tok, file, buf, cap, &len);
			if (error)
				return fz_rethrow(error, "cannot parse indirect object (%d %d R)", num, gen);
			if (tok == PDF_TOK_R)
			{
				obj = fz_new_indirect(a, b, xref);
				break;
			}
		}
		return fz_throw("expected 'R' keyword (%d %d R)", num, gen);

	case PDF_TOK_ENDOBJ:
		obj = fz_new_null();
		goto skip;

	default:
		return fz_throw("syntax error in object (%d %d R)", num, gen);
	}

	error = pdf_lex(&tok, file, buf, cap, &len);
	if (error)
	{
		fz_drop_obj(obj);
		return fz_rethrow(error, "cannot parse indirect object (%d %d R)", num, gen);
	}

skip:
	if (tok == PDF_TOK_STREAM)
	{
		int c = fz_read_byte(file);
		while (c == ' ')
			c = fz_read_byte(file);
		if (c == '\r')
		{
			c = fz_peek_byte(file);
			if (c != '\n')
				fz_warn("line feed missing after stream begin marker (%d %d R)", num, gen);
			else
				fz_read_byte(file);
		}
		stm_ofs = fz_tell(file);
	}
	else if (tok == PDF_TOK_ENDOBJ)
	{
		stm_ofs = 0;
	}
	else
	{
		fz_warn("expected 'endobj' or 'stream' keyword (%d %d R)", num, gen);
		stm_ofs = 0;
	}

	if (onum) *onum = num;
	if (ogen) *ogen = gen;
	if (ostmofs) *ostmofs = stm_ofs;
	*op = obj;
	return fz_okay;
}
Beispiel #14
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_calloc(256, sizeof(unsigned short));
	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");

			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 */
			}
		}
	}

	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)
		fz_catch(error, "cannot load tounicode");

	/* 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));
}
Beispiel #15
0
/*
 * Create a filter given a name and param dictionary.
 */
static fz_stream *
build_filter(fz_stream *chain, pdf_document * xref, pdf_obj * f, pdf_obj * p, int num, int gen, pdf_image_params *params)
{
	fz_context *ctx = chain->ctx;
	char *s = pdf_to_name(f);

	int predictor = pdf_to_int(pdf_dict_gets(p, "Predictor"));
	int columns = pdf_to_int(pdf_dict_gets(p, "Columns"));
	int colors = pdf_to_int(pdf_dict_gets(p, "Colors"));
	int bpc = pdf_to_int(pdf_dict_gets(p, "BitsPerComponent"));

	if (predictor == 0) predictor = 1;
	if (columns == 0) columns = 1;
	if (colors == 0) colors = 1;
	if (bpc == 0) bpc = 8;

	if (!strcmp(s, "ASCIIHexDecode") || !strcmp(s, "AHx"))
		return fz_open_ahxd(chain);

	else if (!strcmp(s, "ASCII85Decode") || !strcmp(s, "A85"))
		return fz_open_a85d(chain);

	else if (!strcmp(s, "CCITTFaxDecode") || !strcmp(s, "CCF"))
	{
		pdf_obj *k = pdf_dict_gets(p, "K");
		pdf_obj *eol = pdf_dict_gets(p, "EndOfLine");
		pdf_obj *eba = pdf_dict_gets(p, "EncodedByteAlign");
		pdf_obj *columns = pdf_dict_gets(p, "Columns");
		pdf_obj *rows = pdf_dict_gets(p, "Rows");
		pdf_obj *eob = pdf_dict_gets(p, "EndOfBlock");
		pdf_obj *bi1 = pdf_dict_gets(p, "BlackIs1");
		if (params)
		{
			/* We will shortstop here */
			params->type = PDF_IMAGE_FAX;
			params->u.fax.k = (k ? pdf_to_int(k) : 0);
			params->u.fax.eol = (eol ? pdf_to_bool(eol) : 0);
			params->u.fax.eba = (eba ? pdf_to_bool(eba) : 0);
			params->u.fax.columns = (columns ? pdf_to_int(columns) : 1728);
			params->u.fax.rows = (rows ? pdf_to_int(rows) : 0);
			params->u.fax.eob = (eob ? pdf_to_bool(eob) : 1);
			params->u.fax.bi1 = (bi1 ? pdf_to_bool(bi1) : 0);
			return chain;
		}
		return fz_open_faxd(chain,
				k ? pdf_to_int(k) : 0,
				eol ? pdf_to_bool(eol) : 0,
				eba ? pdf_to_bool(eba) : 0,
				columns ? pdf_to_int(columns) : 1728,
				rows ? pdf_to_int(rows) : 0,
				eob ? pdf_to_bool(eob) : 1,
				bi1 ? pdf_to_bool(bi1) : 0);
	}

	else if (!strcmp(s, "DCTDecode") || !strcmp(s, "DCT"))
	{
		pdf_obj *ct = pdf_dict_gets(p, "ColorTransform");
		if (params)
		{
			/* We will shortstop here */
			params->type = PDF_IMAGE_JPEG;
			params->u.jpeg.ct = (ct ? pdf_to_int(ct) : -1);
			return chain;
		}
		return fz_open_dctd(chain, ct ? pdf_to_int(ct) : -1);
	}

	else if (!strcmp(s, "RunLengthDecode") || !strcmp(s, "RL"))
	{
		if (params)
		{
			/* We will shortstop here */
			params->type = PDF_IMAGE_RLD;
			return chain;
		}
		return fz_open_rld(chain);
	}
	else if (!strcmp(s, "FlateDecode") || !strcmp(s, "Fl"))
	{
		if (params)
		{
			/* We will shortstop here */
			params->type = PDF_IMAGE_FLATE;
			params->u.flate.predictor = predictor;
			params->u.flate.columns = columns;
			params->u.flate.colors = colors;
			params->u.flate.bpc = bpc;
			return chain;
		}
		chain = fz_open_flated(chain);
		if (predictor > 1)
			chain = fz_open_predict(chain, predictor, columns, colors, bpc);
		return chain;
	}

	else if (!strcmp(s, "LZWDecode") || !strcmp(s, "LZW"))
	{
		pdf_obj *ec = pdf_dict_gets(p, "EarlyChange");
		if (params)
		{
			/* We will shortstop here */
			params->type = PDF_IMAGE_LZW;
			params->u.lzw.predictor = predictor;
			params->u.lzw.columns = columns;
			params->u.lzw.colors = colors;
			params->u.lzw.bpc = bpc;
			params->u.lzw.ec = (ec ? pdf_to_int(ec) : 1);
			return chain;
		}
		chain = fz_open_lzwd(chain, ec ? pdf_to_int(ec) : 1);
		if (predictor > 1)
			chain = fz_open_predict(chain, predictor, columns, colors, bpc);
		return chain;
	}

	else if (!strcmp(s, "JBIG2Decode"))
	{
		fz_buffer *globals = NULL;
		pdf_obj *obj = pdf_dict_gets(p, "JBIG2Globals");
		if (obj)
			globals = pdf_load_stream(xref, pdf_to_num(obj), pdf_to_gen(obj));
		/* fz_open_jbig2d takes possession of globals */
		return fz_open_jbig2d(chain, globals);
	}

	else if (!strcmp(s, "JPXDecode"))
		return chain; /* JPX decoding is special cased in the image loading code */

	else if (!strcmp(s, "Crypt"))
	{
		pdf_obj *name;

		if (!xref->crypt)
		{
			fz_warn(ctx, "crypt filter in unencrypted document");
			return chain;
		}

		name = pdf_dict_gets(p, "Name");
		if (pdf_is_name(name))
			return pdf_open_crypt_with_filter(chain, xref->crypt, pdf_to_name(name), num, gen);

		return chain;
	}

	fz_warn(ctx, "unknown filter name (%s)", s);
	return chain;
}
static void savefont(fz_obj *dict, int num, int gen)
{
	fz_error error;
	char name[1024];
	char *subtype;
	fz_buffer *buf;
	fz_obj *stream = nil;
	fz_obj *obj;
	char *ext = "";
	FILE *f;
	unsigned char *p;
	char *fontname = "font";

	obj = fz_dictgets(dict, "FontName");
	if (obj)
		fontname = fz_toname(obj);

	obj = fz_dictgets(dict, "FontFile");
	if (obj)
	{
		stream = obj;
		ext = "pfa";
	}

	obj = fz_dictgets(dict, "FontFile2");
	if (obj)
	{
		stream = obj;
		ext = "ttf";
	}

	obj = fz_dictgets(dict, "FontFile3");
	if (obj)
	{
		stream = obj;

		obj = fz_dictgets(obj, "Subtype");
		if (obj && !fz_isname(obj))
			die(fz_throw("Invalid font descriptor subtype"));

		subtype = fz_toname(obj);
		if (!strcmp(subtype, "Type1C"))
			ext = "cff";
		else if (!strcmp(subtype, "CIDFontType0C"))
			ext = "cid";
		else
			die(fz_throw("Unhandled font type '%s'", subtype));
	}

	if (!stream)
	{
		fz_warn("Unhandled font type");
		return;
	}

	buf = fz_newbuffer(0);

	error = pdf_loadstream(&buf, xref, fz_tonum(stream), fz_togen(stream));
	if (error)
		die(error);

	sprintf(name, "%s-%04d.%s", fontname, num, ext);

	f = fopen(name, "wb");
	if (f == NULL)
		die(fz_throw("Error creating image file"));

	for (p = buf->rp; p < buf->wp; p ++)
		fprintf(f, "%c", *p);

	if (fclose(f) < 0)
		die(fz_throw("Error closing image file"));

	fz_dropbuffer(buf);
}
Beispiel #17
0
static void savefont(fz_obj *dict, int num)
{
	fz_error error;
	char name[1024];
	char *subtype;
	fz_buffer *buf;
	fz_obj *stream = NULL;
	fz_obj *obj;
	char *ext = "";
	FILE *f;
	char *fontname = "font";
	int n;

	obj = fz_dict_gets(ctx, dict, "FontName");
	if (obj)
		fontname = fz_to_name(ctx, obj);

	obj = fz_dict_gets(ctx, dict, "FontFile");
	if (obj)
	{
		stream = obj;
		ext = "pfa";
	}

	obj = fz_dict_gets(ctx, dict, "FontFile2");
	if (obj)
	{
		stream = obj;
		ext = "ttf";
	}

	obj = fz_dict_gets(ctx, dict, "FontFile3");
	if (obj)
	{
		stream = obj;

		obj = fz_dict_gets(ctx, obj, "Subtype");
		if (obj && !fz_is_name(ctx, obj))
			die(fz_error_make(ctx, "Invalid font descriptor subtype"));

		subtype = fz_to_name(ctx, obj);
		if (!strcmp(subtype, "Type1C"))
			ext = "cff";
		else if (!strcmp(subtype, "CIDFontType0C"))
			ext = "cid";
		else
			die(fz_error_make(ctx, "Unhandled font type '%s'", subtype));
	}

	if (!stream)
	{
		fz_warn(ctx, "Unhandled font type");
		return;
	}

	buf = fz_new_buffer(ctx, 0);

	error = pdf_load_stream(&buf, xref, fz_to_num(stream), fz_to_gen(stream));
	if (error)
		die(error);

	sprintf(name, "%s-%04d.%s", fontname, num, ext);
	printf("extracting font %s\n", name);

	f = fopen(name, "wb");
	if (f == NULL)
		die(fz_error_make(ctx, "Error creating font file"));

	n = fwrite(buf->data, 1, buf->len, f);
	if (n < buf->len)
		die(fz_error_make(ctx, "Error writing font file"));

	if (fclose(f) < 0)
		die(fz_error_make(ctx, "Error closing font file"));

	fz_drop_buffer(ctx, buf);
}
static fz_error
readnewxref(fz_obj **trailerp, pdf_xref *xref, char *buf, int cap)
{
    fz_error error;
    fz_stream *stm;
    fz_obj *trailer;
    fz_obj *index;
    fz_obj *obj;
    int oid, gen, stmofs;
    int size, w0, w1, w2;
    int t;

    pdf_logxref("load new xref format\n");

    error = pdf_parseindobj(&trailer, xref, xref->file, buf, cap, &oid, &gen, &stmofs);
    if (error)
        return fz_rethrow(error, "cannot parse compressed xref stream object");

    if (oid < 0 || oid >= xref->len)
    {
        if (oid == xref->len && oid < xref->cap)
        {
            /* allow broken pdf files that have off-by-one errors in the xref */
            fz_warn("object id (%d %d R) out of range (0..%d)", oid, gen, xref->len - 1);
            xref->len ++;
        }
        else
        {
            fz_dropobj(trailer);
            return fz_throw("object id (%d %d R) out of range (0..%d)", oid, gen, xref->len - 1);
        }
    }

    xref->table[oid].type = 'n';
    xref->table[oid].gen = gen;
    xref->table[oid].obj = fz_keepobj(trailer);
    xref->table[oid].stmofs = stmofs;
    xref->table[oid].ofs = 0;

    obj = fz_dictgets(trailer, "Size");
    if (!obj)
    {
        fz_dropobj(trailer);
        return fz_throw("xref stream missing Size entry");
    }
    size = fz_toint(obj);

    obj = fz_dictgets(trailer, "W");
    if (!obj) {
        fz_dropobj(trailer);
        return fz_throw("xref stream missing W entry");
    }
    w0 = fz_toint(fz_arrayget(obj, 0));
    w1 = fz_toint(fz_arrayget(obj, 1));
    w2 = fz_toint(fz_arrayget(obj, 2));

    index = fz_dictgets(trailer, "Index");

    error = pdf_openstream(&stm, xref, oid, gen);
    if (error)
    {
        fz_dropobj(trailer);
        return fz_rethrow(error, "cannot open compressed xref stream");
    }

    if (!index)
    {
        error = readnewxrefsection(xref, stm, 0, size, w0, w1, w2);
        if (error)
        {
            fz_dropstream(stm);
            fz_dropobj(trailer);
            return fz_rethrow(error, "cannot read xref stream");
        }
    }
    else
    {
        for (t = 0; t < fz_arraylen(index); t += 2)
        {
            int i0 = fz_toint(fz_arrayget(index, t + 0));
            int i1 = fz_toint(fz_arrayget(index, t + 1));
            error = readnewxrefsection(xref, stm, i0, i1, w0, w1, w2);
            if (error)
            {
                fz_dropstream(stm);
                fz_dropobj(trailer);
                return fz_rethrow(error, "cannot read xref stream section");
            }
        }
    }

    fz_dropstream(stm);

    *trailerp = trailer;

    return fz_okay;
}
/*
 * Create a filter given a name and param dictionary.
 */
static fz_stream *
build_filter(fz_stream *chain, pdf_xref * xref, fz_obj * f, fz_obj * p, int num, int gen)
{
	fz_error error;
	char *s;

	s = fz_to_name(f);

	if (!strcmp(s, "ASCIIHexDecode") || !strcmp(s, "AHx"))
		return fz_open_ahxd(chain);

	else if (!strcmp(s, "ASCII85Decode") || !strcmp(s, "A85"))
		return fz_open_a85d(chain);

	else if (!strcmp(s, "CCITTFaxDecode") || !strcmp(s, "CCF"))
		return fz_open_faxd(chain, p);

	else if (!strcmp(s, "DCTDecode") || !strcmp(s, "DCT"))
		return fz_open_dctd(chain, p);

	else if (!strcmp(s, "RunLengthDecode") || !strcmp(s, "RL"))
		return fz_open_rld(chain);

	else if (!strcmp(s, "FlateDecode") || !strcmp(s, "Fl"))
	{
		fz_obj *obj = fz_dict_gets(p, "Predictor");
		if (fz_to_int(obj) > 1)
			return fz_open_predict(fz_open_flated(chain), p);
		return fz_open_flated(chain);
	}

	else if (!strcmp(s, "LZWDecode") || !strcmp(s, "LZW"))
	{
		fz_obj *obj = fz_dict_gets(p, "Predictor");
		if (fz_to_int(obj) > 1)
			return fz_open_predict(fz_open_lzwd(chain, p), p);
		return fz_open_lzwd(chain, p);
	}

	else if (!strcmp(s, "JBIG2Decode"))
	{
		fz_obj *obj = fz_dict_gets(p, "JBIG2Globals");
		if (obj)
		{
			fz_buffer *globals;
			error = pdf_load_stream(&globals, xref, fz_to_num(obj), fz_to_gen(obj));
			if (error)
				fz_catch(error, "cannot load jbig2 global segments");
			chain = fz_open_jbig2d(chain, globals);
			fz_drop_buffer(globals);
			return chain;
		}
		return fz_open_jbig2d(chain, NULL);
	}

	else if (!strcmp(s, "JPXDecode"))
		return chain; /* JPX decoding is special cased in the image loading code */

	else if (!strcmp(s, "Crypt"))
	{
		fz_obj *name;

		if (!xref->crypt)
		{
			fz_warn("crypt filter in unencrypted document");
			return chain;
		}

		name = fz_dict_gets(p, "Name");
		if (fz_is_name(name))
			return pdf_open_crypt_with_filter(chain, xref->crypt, fz_to_name(name), num, gen);

		return chain;
	}

	fz_warn("unknown filter name (%s)", s);
	return chain;
}
Beispiel #20
0
static fz_image *
pdf_load_jpx(fz_context *ctx, pdf_document *doc, pdf_obj *dict, int forcemask)
{
	fz_buffer *buf = NULL;
	fz_colorspace *colorspace = NULL;
	fz_pixmap *pix = NULL;
	pdf_obj *obj;
	fz_image *mask = NULL;
	fz_image *img = NULL;

	fz_var(pix);
	fz_var(buf);
	fz_var(colorspace);
	fz_var(mask);

	buf = pdf_load_stream(ctx, dict);

	/* FIXME: We can't handle decode arrays for indexed images currently */
	fz_try(ctx)
	{
		unsigned char *data;
		size_t len;

		obj = pdf_dict_get(ctx, dict, PDF_NAME(ColorSpace));
		if (obj)
			colorspace = pdf_load_colorspace(ctx, obj);

		len = fz_buffer_storage(ctx, buf, &data);
		pix = fz_load_jpx(ctx, data, len, colorspace);

		obj = pdf_dict_geta(ctx, dict, PDF_NAME(SMask), PDF_NAME(Mask));
		if (pdf_is_dict(ctx, obj))
		{
			if (forcemask)
				fz_warn(ctx, "Ignoring recursive JPX soft mask");
			else
				mask = pdf_load_image_imp(ctx, doc, NULL, obj, NULL, 1);
		}

		obj = pdf_dict_geta(ctx, dict, PDF_NAME(Decode), PDF_NAME(D));
		if (obj && !fz_colorspace_is_indexed(ctx, colorspace))
		{
			float decode[FZ_MAX_COLORS * 2];
			int i;

			for (i = 0; i < pix->n * 2; i++)
				decode[i] = pdf_array_get_real(ctx, obj, i);

			fz_decode_tile(ctx, pix, decode);
		}

		img = fz_new_image_from_pixmap(ctx, pix, mask);
	}
	fz_always(ctx)
	{
		fz_drop_image(ctx, mask);
		fz_drop_pixmap(ctx, pix);
		fz_drop_colorspace(ctx, colorspace);
		fz_drop_buffer(ctx, buf);
	}
	fz_catch(ctx)
	{
		fz_rethrow(ctx);
	}

	return img;
}
Beispiel #21
0
pdf_xobject *
pdf_load_xobject(pdf_document *doc, pdf_obj *dict)
{
	pdf_xobject *form;
	pdf_obj *obj;
	fz_context *ctx = doc->ctx;

	if ((form = pdf_find_item(ctx, pdf_free_xobject_imp, dict)))
	{
		return form;
	}

	form = fz_malloc_struct(ctx, pdf_xobject);
	FZ_INIT_STORABLE(form, 1, pdf_free_xobject_imp);
	form->resources = NULL;
	form->contents = NULL;
	form->colorspace = NULL;
	form->me = NULL;
	form->iteration = 0;

	/* Store item immediately, to avoid possible recursion if objects refer back to this one */
	pdf_store_item(ctx, dict, form, pdf_xobject_size(form));

	fz_try(ctx)
	{
		obj = pdf_dict_gets(dict, "BBox");
		pdf_to_rect(ctx, obj, &form->bbox);

		obj = pdf_dict_gets(dict, "Matrix");
		if (obj)
			pdf_to_matrix(ctx, obj, &form->matrix);
		else
			form->matrix = fz_identity;

		form->isolated = 0;
		form->knockout = 0;
		form->transparency = 0;

		obj = pdf_dict_gets(dict, "Group");
		if (obj)
		{
			pdf_obj *attrs = obj;

			form->isolated = pdf_to_bool(pdf_dict_gets(attrs, "I"));
			form->knockout = pdf_to_bool(pdf_dict_gets(attrs, "K"));

			obj = pdf_dict_gets(attrs, "S");
			if (pdf_is_name(obj) && !strcmp(pdf_to_name(obj), "Transparency"))
				form->transparency = 1;

			obj = pdf_dict_gets(attrs, "CS");
			if (obj)
			{
				fz_try(ctx)
				{
					form->colorspace = pdf_load_colorspace(doc, obj);
				}
				fz_catch(ctx)
				{
					fz_warn(ctx, "cannot load xobject colorspace");
				}
			}
		}

		form->resources = pdf_dict_gets(dict, "Resources");
		if (form->resources)
			pdf_keep_obj(form->resources);

		form->contents = pdf_keep_obj(dict);
	}
	fz_catch(ctx)
	{
		pdf_remove_item(ctx, pdf_free_xobject_imp, dict);
		pdf_drop_xobject(ctx, form);
		fz_rethrow_message(ctx, "cannot load xobject content stream (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict));
	}
	form->me = pdf_keep_obj(dict);

	return form;
}
Beispiel #22
0
void
xps_parse_canvas(xps_document *doc, const fz_matrix *ctm, const fz_rect *area, char *base_uri, xps_resource *dict, fz_xml *root)
{
	xps_resource *new_dict = NULL;
	fz_xml *node;
	char *opacity_mask_uri;

	char *transform_att;
	char *clip_att;
	char *opacity_att;
	char *opacity_mask_att;
	char *navigate_uri_att;

	fz_xml *transform_tag = NULL;
	fz_xml *clip_tag = NULL;
	fz_xml *opacity_mask_tag = NULL;

	fz_matrix transform;

	transform_att = fz_xml_att(root, "RenderTransform");
	clip_att = fz_xml_att(root, "Clip");
	opacity_att = fz_xml_att(root, "Opacity");
	opacity_mask_att = fz_xml_att(root, "OpacityMask");
	navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri");

	for (node = fz_xml_down(root); node; node = fz_xml_next(node))
	{
		if (!strcmp(fz_xml_tag(node), "Canvas.Resources") && fz_xml_down(node))
		{
			if (new_dict)
			{
				fz_warn(doc->ctx, "ignoring follow-up resource dictionaries");
			}
			else
			{
				new_dict = xps_parse_resource_dictionary(doc, base_uri, fz_xml_down(node));
				if (new_dict)
				{
					new_dict->parent = dict;
					dict = new_dict;
				}
			}
		}

		if (!strcmp(fz_xml_tag(node), "Canvas.RenderTransform"))
			transform_tag = fz_xml_down(node);
		if (!strcmp(fz_xml_tag(node), "Canvas.Clip"))
			clip_tag = fz_xml_down(node);
		if (!strcmp(fz_xml_tag(node), "Canvas.OpacityMask"))
			opacity_mask_tag = fz_xml_down(node);
	}

	opacity_mask_uri = base_uri;
	xps_resolve_resource_reference(doc, dict, &transform_att, &transform_tag, NULL);
	xps_resolve_resource_reference(doc, dict, &clip_att, &clip_tag, NULL);
	xps_resolve_resource_reference(doc, dict, &opacity_mask_att, &opacity_mask_tag, &opacity_mask_uri);

	transform = fz_identity;
	if (transform_att)
		xps_parse_render_transform(doc, transform_att, &transform);
	if (transform_tag)
		xps_parse_matrix_transform(doc, transform_tag, &transform);
	fz_concat(&transform, &transform, ctm);

	/* SumatraPDF: extended link support */
	xps_extract_anchor_info(doc, &fz_empty_rect, navigate_uri_att, NULL, 1);
	navigate_uri_att = NULL;

	if (navigate_uri_att)
		xps_add_link(doc, area, base_uri, navigate_uri_att);

	if (clip_att || clip_tag)
		xps_clip(doc, &transform, dict, clip_att, clip_tag);

	xps_begin_opacity(doc, &transform, area, opacity_mask_uri, dict, opacity_att, opacity_mask_tag);

	for (node = fz_xml_down(root); node; node = fz_xml_next(node))
	{
		xps_parse_element(doc, &transform, area, base_uri, dict, node);
	}

	xps_end_opacity(doc, opacity_mask_uri, dict, opacity_att, opacity_mask_tag);

	/* SumatraPDF: extended link support */
	xps_extract_anchor_info(doc, area, NULL, fz_xml_att(root, "Name"), 2);

	if (clip_att || clip_tag)
		fz_pop_clip(doc->dev);

	if (new_dict)
		xps_free_resource_dictionary(doc, new_dict);
}
Beispiel #23
0
int main(int argc, char **argv)
#endif
{
	const GLFWvidmode *video_mode;
	int c;

	while ((c = fz_getopt(argc, argv, "p:r:W:H:S:U:")) != -1)
	{
		switch (c)
		{
		default: usage(argv[0]); break;
		case 'p': password = fz_optarg; break;
		case 'r': currentzoom = fz_atof(fz_optarg); break;
		case 'W': layout_w = fz_atof(fz_optarg); break;
		case 'H': layout_h = fz_atof(fz_optarg); break;
		case 'S': layout_em = fz_atof(fz_optarg); break;
		case 'U': layout_css = fz_optarg; break;
		}
	}

	if (fz_optind < argc)
	{
		fz_strlcpy(filename, argv[fz_optind], sizeof filename);
	}
	else
	{
#ifdef _WIN32
		win_install();
		if (!win_open_file(filename, sizeof filename))
			exit(0);
#else
		usage(argv[0]);
#endif
	}

	title = strrchr(filename, '/');
	if (!title)
		title = strrchr(filename, '\\');
	if (title)
		++title;
	else
		title = filename;

	memset(&ui, 0, sizeof ui);

	search_input.p = search_input.text;
	search_input.q = search_input.p;
	search_input.end = search_input.p;

	glfwSetErrorCallback(on_error);

	if (!glfwInit()) {
		fprintf(stderr, "cannot initialize glfw\n");
		exit(1);
	}

	video_mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
	screen_w = video_mode->width;
	screen_h = video_mode->height;

	window = glfwCreateWindow(DEFAULT_WINDOW_W, DEFAULT_WINDOW_H, filename, NULL, NULL);
	if (!window) {
		fprintf(stderr, "cannot create glfw window\n");
		exit(1);
	}

	glfwMakeContextCurrent(window);

	ctx = fz_new_context(NULL, NULL, 0);
	fz_register_document_handlers(ctx);

	if (layout_css)
	{
		fz_buffer *buf = fz_read_file(ctx, layout_css);
		fz_set_user_css(ctx, fz_string_from_buffer(ctx, buf));
		fz_drop_buffer(ctx, buf);
	}

	has_ARB_texture_non_power_of_two = glfwExtensionSupported("GL_ARB_texture_non_power_of_two");
	if (!has_ARB_texture_non_power_of_two)
		fz_warn(ctx, "OpenGL implementation does not support non-power of two texture sizes");

	glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);

	ui.fontsize = DEFAULT_UI_FONTSIZE;
	ui.baseline = DEFAULT_UI_BASELINE;
	ui.lineheight = DEFAULT_UI_LINEHEIGHT;

	ui_init_fonts(ctx, ui.fontsize);

	reload();

	shrinkwrap();

	glfwSetFramebufferSizeCallback(window, on_reshape);
	glfwSetCursorPosCallback(window, on_mouse_motion);
	glfwSetMouseButtonCallback(window, on_mouse_button);
	glfwSetScrollCallback(window, on_scroll);
	glfwSetCharModsCallback(window, on_char);
	glfwSetKeyCallback(window, on_key);
	glfwSetWindowRefreshCallback(window, on_display);

	glfwGetFramebufferSize(window, &window_w, &window_h);

	ui_needs_update = 1;

	while (!glfwWindowShouldClose(window))
	{
		glfwWaitEvents();
		if (ui_needs_update)
			run_main_loop();
	}

	ui_finish_fonts(ctx);

	fz_drop_link(ctx, links);
	fz_drop_page(ctx, page);
	fz_drop_outline(ctx, outline);
	fz_drop_document(ctx, doc);
	fz_drop_context(ctx);

	glfwTerminate();

	return 0;
}
fz_error
pdf_loadsystemfont(pdf_fontdesc *font, char *fontname, char *collection)
{
	fz_error error;
	char *name;

	int isbold = 0;
	int isitalic = 0;
	int isserif = 0;
	int isscript = 0;
	int isfixed = 0;

	if (strstr(fontname, "Bold"))
		isbold = 1;
	if (strstr(fontname, "Italic"))
		isitalic = 1;
	if (strstr(fontname, "Oblique"))
		isitalic = 1;

	if (font->flags & FD_FIXED)
		isfixed = 1;
	if (font->flags & FD_SERIF)
		isserif = 1;
	if (font->flags & FD_ITALIC)
		isitalic = 1;
	if (font->flags & FD_SCRIPT)
		isscript = 1;
	if (font->flags & FD_FORCEBOLD)
		isbold = 1;

	pdf_logfont("fixed-%d serif-%d italic-%d script-%d bold-%d\n",
			isfixed, isserif, isitalic, isscript, isbold);

	if (collection)
	{
		int kind;

		if (isserif)
			kind = MINCHO;
		else
			kind = GOTHIC;

		if (!strcmp(collection, "Adobe-CNS1"))
			return loadsystemcidfont(font, CNS, kind);
		else if (!strcmp(collection, "Adobe-GB1"))
			return loadsystemcidfont(font, GB, kind);
		else if (!strcmp(collection, "Adobe-Japan1"))
			return loadsystemcidfont(font, Japan, kind);
		else if (!strcmp(collection, "Adobe-Japan2"))
			return loadsystemcidfont(font, Japan, kind);
		else if (!strcmp(collection, "Adobe-Korea1"))
			return loadsystemcidfont(font, Korea, kind);

		fz_warn("unknown cid collection: %s", collection);
	}

	if (isscript)
		name = "Chancery";

	else if (isfixed)
	{
		if (isitalic) {
			if (isbold) name = "Courier-BoldOblique";
			else name = "Courier-Oblique";
		}
		else {
			if (isbold) name = "Courier-Bold";
			else name = "Courier";
		}
	}

	else if (isserif)
	{
		if (isitalic) {
			if (isbold) name = "Times-BoldItalic";
			else name = "Times-Italic";
		}
		else {
			if (isbold) name = "Times-Bold";
			else name = "Times-Roman";
		}
	}

	else
	{
		if (isitalic) {
			if (isbold) name = "Helvetica-BoldOblique";
			else name = "Helvetica-Oblique";
		}
		else {
			if (isbold) name = "Helvetica-Bold";
			else name = "Helvetica";
		}
	}

	error = pdf_loadbuiltinfont(font, name);
	if (error)
		return fz_throw("cannot load builtin substitute font: %s", name);

	/* it's a substitute font: override the metrics */
	font->font->ftsubstitute = 1;

	return fz_okay;
}
Beispiel #25
0
static void
fz_stext_extract(fz_context *ctx, fz_stext_device *dev, fz_text_span *span, const fz_matrix *ctm, fz_stext_style *style)
{
	fz_font *font = span->font;
	FT_Face face = font->ft_face;
	fz_matrix tm = span->trm;
	fz_matrix trm;
	float adv;
	float ascender = 1;
	float descender = 0;
	int multi;
	int i, j, err;

	if (span->len == 0)
		return;

	if (dev->spans == NULL)
		dev->spans = new_span_soup(ctx);

	if (style->wmode == 0)
	{
		if (font->ft_face)
		{
			fz_lock(ctx, FZ_LOCK_FREETYPE);
			err = FT_Set_Char_Size(font->ft_face, 64, 64, 72, 72);
			if (err)
				fz_warn(ctx, "freetype set character size: %s", ft_error_string(err));
			ascender = (float)face->ascender / face->units_per_EM;
			descender = (float)face->descender / face->units_per_EM;
			fz_unlock(ctx, FZ_LOCK_FREETYPE);
		}
		else if (font->t3procs && !fz_is_empty_rect(&font->bbox))
		{
			ascender = font->bbox.y1;
			descender = font->bbox.y0;
		}
	}
	else
	{
		ascender = font->bbox.x1;
		descender = font->bbox.x0;
	}
	style->ascender = ascender;
	style->descender = descender;

	tm.e = 0;
	tm.f = 0;
	fz_concat(&trm, &tm, ctm);

	for (i = 0; i < span->len; i++)
	{
		/* Calculate new pen location and delta */
		tm.e = span->items[i].x;
		tm.f = span->items[i].y;
		fz_concat(&trm, &tm, ctm);

		/* Calculate bounding box and new pen position based on font metrics */
		adv = fz_advance_glyph(ctx, font, span->items[i].gid);

		/* Check for one glyph to many char mapping */
		for (j = i + 1; j < span->len; j++)
			if (span->items[j].gid >= 0)
				break;
		multi = j - i;

		if (multi == 1)
		{
			fz_add_stext_char(ctx, dev, style, span->items[i].ucs, &trm, adv, span->wmode);
		}
		else
		{
			for (j = 0; j < multi; j++)
			{
				fz_add_stext_char(ctx, dev, style, span->items[i + j].ucs, &trm, adv/multi, span->wmode);
			}
			i += j - 1;
		}

		dev->lastchar = span->items[i].ucs;
	}
}
Beispiel #26
0
static void savefont(pdf_obj *dict, int num)
{
    char namebuf[1024];
    fz_buffer *buf;
    pdf_obj *stream = NULL;
    pdf_obj *obj;
    char *ext = "";
    FILE *f;
    char *fontname = "font";
    int n, len;
    unsigned char *data;

    obj = pdf_dict_get(ctx, dict, PDF_NAME_FontName);
    if (obj)
        fontname = pdf_to_name(ctx, obj);

    obj = pdf_dict_get(ctx, dict, PDF_NAME_FontFile);
    if (obj)
    {
        stream = obj;
        ext = "pfa";
    }

    obj = pdf_dict_get(ctx, dict, PDF_NAME_FontFile2);
    if (obj)
    {
        stream = obj;
        ext = "ttf";
    }

    obj = pdf_dict_get(ctx, dict, PDF_NAME_FontFile3);
    if (obj)
    {
        stream = obj;

        obj = pdf_dict_get(ctx, obj, PDF_NAME_Subtype);
        if (obj && !pdf_is_name(ctx, obj))
            fz_throw(ctx, FZ_ERROR_GENERIC, "invalid font descriptor subtype");

        if (pdf_name_eq(ctx, obj, PDF_NAME_Type1C))
            ext = "cff";
        else if (pdf_name_eq(ctx, obj, PDF_NAME_CIDFontType0C))
            ext = "cid";
        else if (pdf_name_eq(ctx, obj, PDF_NAME_OpenType))
            ext = "otf";
        else
            fz_throw(ctx, FZ_ERROR_GENERIC, "unhandled font type '%s'", pdf_to_name(ctx, obj));
    }

    if (!stream)
    {
        fz_warn(ctx, "unhandled font type");
        return;
    }

    buf = pdf_load_stream(ctx, doc, pdf_to_num(ctx, stream), pdf_to_gen(ctx, stream));

    snprintf(namebuf, sizeof(namebuf), "%s-%04d.%s", fontname, num, ext);
    printf("extracting font %s\n", namebuf);

    f = fz_fopen(namebuf, "wb");
    if (!f)
        fz_throw(ctx, FZ_ERROR_GENERIC, "cannot create font file");

    len = fz_buffer_storage(ctx, buf, &data);
    n = fwrite(data, 1, len, f);
    if (n < len)
        fz_throw(ctx, FZ_ERROR_GENERIC, "cannot write font file");

    if (fclose(f) < 0)
        fz_throw(ctx, FZ_ERROR_GENERIC, "cannot close font file");

    fz_drop_buffer(ctx, buf);
}
void
fz_run_display_list(fz_display_list *list, fz_device *dev, fz_matrix top_ctm, fz_bbox scissor, fz_cookie *cookie)
{
	fz_display_node *node;
	fz_matrix ctm;
	fz_rect rect;
	fz_bbox bbox;
	int clipped = 0;
	int tiled = 0;
	int empty;
	int progress = 0;
	fz_context *ctx = dev->ctx;

	if (cookie)
	{
		cookie->progress_max = list->len;
		cookie->progress = 0;
	}

	for (node = list->first; node; node = node->next)
	{
		/* Check the cookie for aborting */
		if (cookie)
		{
			if (cookie->abort)
				break;
			cookie->progress = progress++;
		}

		/* cull objects to draw using a quick visibility test */

		if (tiled || node->cmd == FZ_CMD_BEGIN_TILE || node->cmd == FZ_CMD_END_TILE)
		{
			empty = 0;
		}
		else
		{
			bbox = fz_bbox_covering_rect(fz_transform_rect(top_ctm, node->rect));
			bbox = fz_intersect_bbox(bbox, scissor);
			empty = fz_is_empty_bbox(bbox);
		}

		if (clipped || empty)
		{
			switch (node->cmd)
			{
			case FZ_CMD_CLIP_PATH:
			case FZ_CMD_CLIP_STROKE_PATH:
			case FZ_CMD_CLIP_STROKE_TEXT:
			case FZ_CMD_CLIP_IMAGE_MASK:
			case FZ_CMD_BEGIN_MASK:
			case FZ_CMD_BEGIN_GROUP:
				clipped++;
				continue;
			case FZ_CMD_CLIP_TEXT:
				/* Accumulated text has no extra pops */
				if (node->flag != 2)
					clipped++;
				continue;
			case FZ_CMD_POP_CLIP:
			case FZ_CMD_END_GROUP:
				if (!clipped)
					goto visible;
				clipped--;
				continue;
			case FZ_CMD_END_MASK:
				if (!clipped)
					goto visible;
				continue;
			default:
				continue;
			}
		}

visible:
		ctm = fz_concat(node->ctm, top_ctm);

		fz_try(ctx)
		{
			switch (node->cmd)
			{
			case FZ_CMD_FILL_PATH:
				fz_fill_path(dev, node->item.path, node->flag, ctm,
					node->colorspace, node->color, node->alpha);
				break;
			case FZ_CMD_STROKE_PATH:
				fz_stroke_path(dev, node->item.path, node->stroke, ctm,
					node->colorspace, node->color, node->alpha);
				break;
			case FZ_CMD_CLIP_PATH:
			{
				fz_rect trect = fz_transform_rect(top_ctm, node->rect);
				fz_clip_path(dev, node->item.path, &trect, node->flag, ctm);
				break;
			}
			case FZ_CMD_CLIP_STROKE_PATH:
			{
				fz_rect trect = fz_transform_rect(top_ctm, node->rect);
				fz_clip_stroke_path(dev, node->item.path, &trect, node->stroke, ctm);
				break;
			}
			case FZ_CMD_FILL_TEXT:
				fz_fill_text(dev, node->item.text, ctm,
					node->colorspace, node->color, node->alpha);
				break;
			case FZ_CMD_STROKE_TEXT:
				fz_stroke_text(dev, node->item.text, node->stroke, ctm,
					node->colorspace, node->color, node->alpha);
				break;
			case FZ_CMD_CLIP_TEXT:
				fz_clip_text(dev, node->item.text, ctm, node->flag);
				break;
			case FZ_CMD_CLIP_STROKE_TEXT:
				fz_clip_stroke_text(dev, node->item.text, node->stroke, ctm);
				break;
			case FZ_CMD_IGNORE_TEXT:
				fz_ignore_text(dev, node->item.text, ctm);
				break;
			case FZ_CMD_FILL_SHADE:
				fz_fill_shade(dev, node->item.shade, ctm, node->alpha);
				break;
			case FZ_CMD_FILL_IMAGE:
				fz_fill_image(dev, node->item.image, ctm, node->alpha);
				break;
			case FZ_CMD_FILL_IMAGE_MASK:
				fz_fill_image_mask(dev, node->item.image, ctm,
					node->colorspace, node->color, node->alpha);
				break;
			case FZ_CMD_CLIP_IMAGE_MASK:
			{
				fz_rect trect = fz_transform_rect(top_ctm, node->rect);
				fz_clip_image_mask(dev, node->item.image, &trect, ctm);
				break;
			}
			case FZ_CMD_POP_CLIP:
				fz_pop_clip(dev);
				break;
			case FZ_CMD_BEGIN_MASK:
				rect = fz_transform_rect(top_ctm, node->rect);
				fz_begin_mask(dev, rect, node->flag, node->colorspace, node->color);
				break;
			case FZ_CMD_END_MASK:
				fz_end_mask(dev);
				break;
			case FZ_CMD_BEGIN_GROUP:
				rect = fz_transform_rect(top_ctm, node->rect);
				fz_begin_group(dev, rect,
					(node->flag & ISOLATED) != 0, (node->flag & KNOCKOUT) != 0,
					node->item.blendmode, node->alpha);
				break;
			case FZ_CMD_END_GROUP:
				fz_end_group(dev);
				break;
			case FZ_CMD_BEGIN_TILE:
				tiled++;
				rect.x0 = node->color[2];
				rect.y0 = node->color[3];
				rect.x1 = node->color[4];
				rect.y1 = node->color[5];
				fz_begin_tile(dev, node->rect, rect,
					node->color[0], node->color[1], ctm);
				break;
			case FZ_CMD_END_TILE:
				tiled--;
				fz_end_tile(dev);
				break;
			/* SumatraPDF: support transfer functions */
			case FZ_CMD_APPLY_TRANSFER_FUNCTION:
				fz_apply_transfer_function(dev, node->item.tr, node->flag);
				break;
			}
		}
		fz_catch(ctx)
		{
			/* Swallow the error */
			if (cookie)
				cookie->errors++;
			fz_warn(ctx, "Ignoring error during interpretation");
		}
	}
}
pdf_font_desc *
pdf_load_type3_font(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict)
{
	char buf[256];
	char *estrings[256];
	pdf_font_desc *fontdesc = NULL;
	pdf_obj *encoding;
	pdf_obj *widths;
	pdf_obj *charprocs;
	pdf_obj *obj;
	int first, last;
	int i, k, n;
	fz_rect bbox;
	fz_matrix matrix;
	fz_context *ctx = xref->ctx;

	fz_var(fontdesc);

	fz_try(ctx)
	{
		obj = pdf_dict_gets(dict, "Name");
		if (pdf_is_name(obj))
			fz_strlcpy(buf, pdf_to_name(obj), sizeof buf);
		else
			sprintf(buf, "Unnamed-T3");

		fontdesc = pdf_new_font_desc(ctx);

		obj = pdf_dict_gets(dict, "FontMatrix");
		matrix = pdf_to_matrix(ctx, obj);

		obj = pdf_dict_gets(dict, "FontBBox");
		bbox = pdf_to_rect(ctx, obj);
		bbox = fz_transform_rect(matrix, bbox);

		fontdesc->font = fz_new_type3_font(ctx, buf, matrix);
		fontdesc->size += sizeof(fz_font) + 256 * (sizeof(fz_buffer*) + sizeof(float));

		fz_set_font_bbox(ctx, fontdesc->font, bbox.x0, bbox.y0, bbox.x1, bbox.y1);

		/* SumatraPDF: expose Type3 FontDescriptor flags */
		fontdesc->flags = pdf_to_int(pdf_dict_gets(pdf_dict_gets(dict, "FontDescriptor"), "Flags"));

		/* Encoding */

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

		encoding = pdf_dict_gets(dict, "Encoding");
		if (!encoding)
		{
			fz_throw(ctx, "syntaxerror: Type3 font missing Encoding");
		}

		if (pdf_is_name(encoding))
			pdf_load_encoding(estrings, pdf_to_name(encoding));

		if (pdf_is_dict(encoding))
		{
			pdf_obj *base, *diff, *item;

			base = pdf_dict_gets(encoding, "BaseEncoding");
			if (pdf_is_name(base))
				pdf_load_encoding(estrings, pdf_to_name(base));

			diff = pdf_dict_gets(encoding, "Differences");
			if (pdf_is_array(diff))
			{
				n = pdf_array_len(diff);
				k = 0;
				for (i = 0; i < n; i++)
				{
					item = pdf_array_get(diff, i);
					if (pdf_is_int(item))
						k = pdf_to_int(item);
					if (pdf_is_name(item) && k >= 0 && k < nelem(estrings))
						estrings[k++] = pdf_to_name(item);
				}
			}
		}

		fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1);
		fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding);

		pdf_load_to_unicode(xref, fontdesc, estrings, NULL, pdf_dict_gets(dict, "ToUnicode"));

		/* SumatraPDF: trying to match Adobe Reader's behavior */
		if (!(fontdesc->flags & PDF_FD_SYMBOLIC) && fontdesc->cid_to_ucs_len >= 128)
			for (i = 32; i < 128; i++)
				if (fontdesc->cid_to_ucs[i] == '?' || fontdesc->cid_to_ucs[i] == '\0')
					fontdesc->cid_to_ucs[i] = i;

		/* Widths */

		pdf_set_default_hmtx(ctx, fontdesc, 0);

		first = pdf_to_int(pdf_dict_gets(dict, "FirstChar"));
		last = pdf_to_int(pdf_dict_gets(dict, "LastChar"));

		/* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1966 */
		if (first >= 256 && last - first < 256)
		{
			fz_warn(ctx, "ignoring out-of-bound values for FirstChar/LastChar: %d/%d", first, last);
			last -= first;
			first = 0;
		}

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

		widths = pdf_dict_gets(dict, "Widths");
		if (!widths)
		{
			fz_throw(ctx, "syntaxerror: Type3 font missing Widths");
		}

		for (i = first; i <= last; i++)
		{
			float w = pdf_to_real(pdf_array_get(widths, i - first));
			w = fontdesc->font->t3matrix.a * w * 1000;
			fontdesc->font->t3widths[i] = w * 0.001f;
			pdf_add_hmtx(ctx, fontdesc, i, i, w);
		}

		pdf_end_hmtx(ctx, fontdesc);

		/* Resources -- inherit page resources if the font doesn't have its own */

		fontdesc->font->t3freeres = pdf_t3_free_resources;
		fontdesc->font->t3resources = pdf_dict_gets(dict, "Resources");
		if (!fontdesc->font->t3resources)
			fontdesc->font->t3resources = rdb;
		if (fontdesc->font->t3resources)
			pdf_keep_obj(fontdesc->font->t3resources);
		if (!fontdesc->font->t3resources)
			fz_warn(ctx, "no resource dictionary for type 3 font!");

		fontdesc->font->t3doc = xref;
		fontdesc->font->t3run = pdf_run_glyph_func;

		/* CharProcs */

		charprocs = pdf_dict_gets(dict, "CharProcs");
		if (!charprocs)
		{
			fz_throw(ctx, "syntaxerror: Type3 font missing CharProcs");
		}

		for (i = 0; i < 256; i++)
		{
			if (estrings[i])
			{
				obj = pdf_dict_gets(charprocs, estrings[i]);
				if (pdf_is_stream(xref, pdf_to_num(obj), pdf_to_gen(obj)))
				{
					fontdesc->font->t3procs[i] = pdf_load_stream(xref, pdf_to_num(obj), pdf_to_gen(obj));
					fontdesc->size += fontdesc->font->t3procs[i]->cap;
					fontdesc->size += 0; // TODO: display list size calculation
				}
			}
		}
	}
	fz_catch(ctx)
	{
		if (fontdesc)
			pdf_drop_font(ctx, fontdesc);
		fz_throw(ctx, "cannot load type3 font (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict));
	}
	return fontdesc;
}
Beispiel #29
0
static void
epub_parse_header(fz_context *ctx, epub_document *doc)
{
	fz_archive *zip = doc->zip;
	fz_buffer *buf;
	fz_xml *container_xml, *content_opf;
	fz_xml *container, *rootfiles, *rootfile;
	fz_xml *package, *manifest, *spine, *itemref;
	char base_uri[2048];
	const char *full_path;
	const char *version;
	char ncx[2048], s[2048];
	epub_chapter *head, *tail;

	if (fz_has_archive_entry(ctx, zip, "META-INF/rights.xml"))
		fz_throw(ctx, FZ_ERROR_GENERIC, "EPUB is locked by DRM");
	if (fz_has_archive_entry(ctx, zip, "META-INF/encryption.xml"))
		fz_throw(ctx, FZ_ERROR_GENERIC, "EPUB is locked by DRM");

	/* parse META-INF/container.xml to find OPF */

	buf = fz_read_archive_entry(ctx, zip, "META-INF/container.xml");
	fz_write_buffer_byte(ctx, buf, 0);
	container_xml = fz_parse_xml(ctx, buf->data, buf->len, 0);
	fz_drop_buffer(ctx, buf);

	container = fz_xml_find(container_xml, "container");
	rootfiles = fz_xml_find_down(container, "rootfiles");
	rootfile = fz_xml_find_down(rootfiles, "rootfile");
	full_path = fz_xml_att(rootfile, "full-path");
	if (!full_path)
		fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find root file in EPUB");

	printf("epub: found root: %s\n", full_path);

	fz_dirname(base_uri, full_path, sizeof base_uri);

	/* parse OPF to find NCX and spine */

	buf = fz_read_archive_entry(ctx, zip, full_path);
	fz_write_buffer_byte(ctx, buf, 0);
	content_opf = fz_parse_xml(ctx, buf->data, buf->len, 0);
	fz_drop_buffer(ctx, buf);

	package = fz_xml_find(content_opf, "package");
	version = fz_xml_att(package, "version");
	if (!version || strcmp(version, "2.0"))
		fz_warn(ctx, "unknown epub version: %s", version ? version : "<none>");

	manifest = fz_xml_find_down(package, "manifest");
	spine = fz_xml_find_down(package, "spine");

	if (path_from_idref(ncx, manifest, base_uri, fz_xml_att(spine, "toc"), sizeof ncx))
	{
		/* TODO: parse NCX to create fz_outline */
		printf("epub: found outline: %s\n", ncx);
	}

	head = tail = NULL;
	itemref = fz_xml_find_down(spine, "itemref");
	while (itemref)
	{
		if (path_from_idref(s, manifest, base_uri, fz_xml_att(itemref, "idref"), sizeof s))
		{
			printf("epub: found spine %s\n", s);
			if (!head)
				head = tail = epub_parse_chapter(ctx, doc, s);
			else
				tail = tail->next = epub_parse_chapter(ctx, doc, s);
		}
		itemref = fz_xml_find_next(itemref, "itemref");
	}

	doc->spine = head;

	printf("epub: done.\n");

	fz_drop_xml(ctx, container_xml);
	fz_drop_xml(ctx, content_opf);
}