Exemple #1
0
static pdf_annot *
pdf_create_highlight_annot(pdf_xref *xref, fz_obj *obj)
{
	fz_context *ctx = xref->ctx;
	fz_buffer *content = fz_new_buffer(ctx, 512);
	fz_rect rect = pdf_to_rect(ctx, fz_dict_gets(ctx, obj, "Rect"));
	fz_obj *quad_points = fz_dict_gets(ctx, obj, "QuadPoints");
	fz_obj *resources = pdf_dict_from_string(xref, ANNOT_HIGHLIGHT_AP_RESOURCES);
	fz_rect a, b;
	float rgb[3];
	float skew;
	int i;

	for (i = 0; i < fz_array_len(ctx, quad_points) / 8; i++)
	{
		pdf_get_quadrilaterals(ctx, quad_points, i, &a, &b);
		skew = 0.15 * fabs(a.y0 - b.y0);
		b.x0 -= skew; b.x1 += skew;
		rect = fz_union_rect(rect, fz_union_rect(a, b));
	}
	pdf_get_annot_color(ctx, obj, rgb);

	fz_buffer_printf(ctx, content, "q /GS gs %.4f %.4f %.4f rg 1 0 0 1 -%.4f -%.4f cm ",
		rgb[0], rgb[1], rgb[2], rect.x0, rect.y0);
	for (i = 0; i < fz_array_len(ctx, quad_points) / 8; i++)
	{
		pdf_get_quadrilaterals(ctx, quad_points, i, &a, &b);
		skew = 0.15 * fabs(a.y0 - b.y0);
		fz_buffer_printf(ctx, content, "%.4f %.4f m %.4f %.4f l %.4f %.4f l %.4f %.4f l h ",
			a.x0, a.y0, b.x1 + skew, b.y1, a.x1, a.y1, b.x0 - skew, b.y0);
	}
	fz_buffer_printf(ctx, content, "f Q");

	return pdf_create_annot(ctx, rect, fz_keep_obj(obj), content, resources, 1);
}
Exemple #2
0
static pdf_annot *
pdf_create_freetext_annot(pdf_xref *xref, fz_obj *obj)
{
	fz_context *ctx = xref->ctx;
	fz_buffer *content = fz_new_buffer(ctx, 256);
	fz_buffer *base_ap = fz_new_buffer(ctx, 256);
	fz_obj *ap = fz_dict_gets(ctx, obj, "DA");
	fz_obj *value = fz_dict_gets(ctx, obj, "Contents");
	fz_rect rect = pdf_to_rect(ctx, fz_dict_gets(ctx, obj, "Rect"));
	int align = fz_to_int(ctx, fz_dict_gets(ctx, obj, "Q"));
	fz_obj *res = pdf_dict_from_string(xref, ANNOT_FREETEXT_AP_RESOURCES);
	unsigned short *ucs2, *rest;
	float x;

	char *font_name = NULL;
	float font_size = pdf_extract_font_size(xref, fz_to_str_buf(ctx, ap), &font_name);
	if (!font_size)
		font_size = 10;
	/* TODO: what resource dictionary does this font name refer to? */
	if (font_name)
	{
		fz_obj *font = fz_dict_gets(ctx, res, "Font");
		fz_dict_puts(ctx, font, font_name, fz_dict_gets(ctx, font, "Default"));
		fz_free(ctx, font_name);
	}

	fz_buffer_printf(ctx, content, "q 1 1 %.4f %.4f re W n BT %s ",
		rect.x1 - rect.x0 - 2.0f, rect.y1 - rect.y0 - 2.0f, fz_to_str_buf(ctx, ap));
	fz_buffer_printf(ctx, base_ap, "q BT %s ", fz_to_str_buf(ctx, ap));
	fz_buffer_printf(ctx, content, "/Default %.4f Tf ", font_size);
	fz_buffer_printf(ctx, base_ap, "/Default %.4f Tf ", font_size);
	fz_buffer_printf(ctx, content, "1 0 0 1 2 %.4f Tm ", rect.y1 - rect.y0 - 2);

	/* Adobe Reader seems to consider "[1 0 0] r" and "1 0 0 rg" to mean the same(?) */
	if (strchr(base_ap->data, '['))
	{
		float r, g, b;
		if (sscanf(strchr(base_ap->data, '['), "[%f %f %f] r", &r, &g, &b) == 3)
			fz_buffer_printf(ctx, content, "%.4f %.4f %.4f rg ", r, g, b);
	}

	ucs2 = pdf_to_ucs2(ctx, value);
	for (rest = ucs2; *rest; rest++)
		if (*rest > 0xFF)
			*rest = '?';

	x = 0;
	rest = ucs2;
	while (*rest)
		rest = pdf_append_line(xref, res, content, base_ap, rest, font_size, align, rect.x1 - rect.x0 - 4.0f, 1, &x);

	fz_free(ctx, ucs2);
	fz_buffer_printf(ctx, content, "ET Q");
	fz_drop_buffer(ctx, base_ap);

	return pdf_create_annot(ctx, rect, fz_keep_obj(obj), content, res, 0);
}
fz_error
pdf_load_pattern(pdf_pattern **patp, pdf_xref *xref, fz_obj *dict)
{
	fz_error error;
	pdf_pattern *pat;
	fz_obj *obj;

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

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

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

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

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

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

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

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

	*patp = pat;
	return fz_okay;
}
Exemple #4
0
fz_error
pdf_load_object(fz_obj **objp, pdf_xref *xref, int num, int gen)
{
	fz_error error;

	error = pdf_cache_object(xref, num, gen);
	if (error)
		return fz_rethrow(error, "cannot load object (%d %d R) into cache", num, gen);

	assert(xref->table[num].obj);

	*objp = fz_keep_obj(xref->table[num].obj);

	return fz_okay;
}
Exemple #5
0
void
fz_array_push(fz_obj *obj, fz_obj *item)
{
	RESOLVE(obj);

	if (!obj)
		return; /* Can't warn :( */
	if (obj->kind != FZ_ARRAY)
		fz_warn(obj->ctx, "assert: not an array (%s)", fz_objkindstr(obj));
	else
	{
		if (obj->u.a.len + 1 > obj->u.a.cap)
			fz_array_grow(obj);
		obj->u.a.items[obj->u.a.len] = fz_keep_obj(item);
		obj->u.a.len++;
	}
}
Exemple #6
0
void
fz_array_insert(fz_obj *obj, fz_obj *item)
{
	RESOLVE(obj);

	if (!obj)
		return; /* Can't warn :( */
	if (obj->kind != FZ_ARRAY)
		fz_warn(obj->ctx, "assert: not an array (%s)", fz_objkindstr(obj));
	else
	{
		if (obj->u.a.len + 1 > obj->u.a.cap)
			fz_array_grow(obj);
		memmove(obj->u.a.items + 1, obj->u.a.items, obj->u.a.len * sizeof(fz_obj*));
		obj->u.a.items[0] = fz_keep_obj(item);
		obj->u.a.len++;
	}
}
Exemple #7
0
void
fz_array_put(fz_obj *obj, int i, fz_obj *item)
{
	RESOLVE(obj);

	if (!obj)
		return; /* Can't warn :( */
	if (obj->kind != FZ_ARRAY)
		fz_warn(obj->ctx, "assert: not an array (%s)", fz_objkindstr(obj));
	else if (i < 0)
		fz_warn(obj->ctx, "assert: index %d < 0", i);
	else if (i >= obj->u.a.len)
		fz_warn(obj->ctx, "assert: index %d > length %d", i, obj->u.a.len);
	else
	{
		if (obj->u.a.items[i])
			fz_drop_obj(obj->u.a.items[i]);
		obj->u.a.items[i] = fz_keep_obj(item);
	}
}
Exemple #8
0
/* Replace numbered object -- for use by pdfclean and similar tools */
void
pdf_update_object(pdf_xref *xref, int num, int gen, fz_obj *newobj)
{
	pdf_xref_entry *x;

	if (num < 0 || num >= xref->len)
	{
		fz_warn("object out of range (%d %d R); xref size %d", num, gen, xref->len);
		return;
	}

	x = &xref->table[num];

	if (x->obj)
		fz_drop_obj(x->obj);

	x->obj = fz_keep_obj(newobj);
	x->type = 'n';
	x->ofs = 0;
}
Exemple #9
0
static pdf_annot *
pdf_create_markup_annot(pdf_xref *xref, fz_obj *obj, char *type)
{
	fz_context *ctx = xref->ctx;
	fz_buffer *content = fz_new_buffer(ctx, 512);
	fz_rect rect = pdf_to_rect(ctx, fz_dict_gets(ctx, obj, "Rect"));
	fz_obj *quad_points = fz_dict_gets(ctx, obj, "QuadPoints");
	fz_rect a, b;
	float rgb[3];
	int i;

	for (i = 0; i < fz_array_len(ctx, quad_points) / 8; i++)
	{
		pdf_get_quadrilaterals(ctx, quad_points, i, &a, &b);
		b.y0 -= 0.25; a.y1 += 0.25;
		rect = fz_union_rect(rect, fz_union_rect(a, b));
	}
	pdf_get_annot_color(ctx, obj, rgb);

	fz_buffer_printf(ctx, content, "q %.4f %.4f %.4f RG 1 0 0 1 -%.4f -%.4f cm 0.5 w ",
		rgb[0], rgb[1], rgb[2], rect.x0, rect.y0);
	if (!strcmp(type, "Squiggly"))
		fz_buffer_printf(ctx, content, "[1 1] d ");
	for (i = 0; i < fz_array_len(ctx, quad_points) / 8; i++)
	{
		pdf_get_quadrilaterals(ctx, quad_points, i, &a, &b);
		if (!strcmp(type, "StrikeOut"))
			fz_buffer_printf(ctx, content, "%.4f %.4f m %.4f %.4f l ",
				(a.x0 + b.x0) / 2, (a.y0 + b.y0) / 2, (a.x1 + b.x1) / 2, (a.y1 + b.y1) / 2);
		else
			fz_buffer_printf(ctx, content, "%.4f %.4f m %.4f %.4f l ", b.x0, b.y0, a.x1, a.y1);
	}
	fz_buffer_printf(ctx, content, "S Q");

	return pdf_create_annot(ctx, rect, fz_keep_obj(obj), content, NULL, 0);
}
Exemple #10
0
fz_error
pdf_ocg_set_config(pdf_xref *xref, int config)
{
	int i, j, len, len2;
	pdf_ocg_descriptor *desc = xref->ocg;
	fz_obj *obj, *cobj;
	char *name;

	obj = fz_dict_gets(fz_dict_gets(xref->trailer, "Root"), "OCProperties");
	if (obj == NULL)
	{
		if (config == 0)
			return fz_okay;
		else
			return fz_throw("Unknown OCG config (None known!)");
	}
	if (config == 0)
	{
		cobj = fz_dict_gets(obj, "D");
		if (cobj == NULL)
			return fz_throw("No default OCG config");
	}
	else
	{
		cobj = fz_array_get(fz_dict_gets(obj, "Configs"), config);
		if (cobj == NULL)
			return fz_throw("Illegal OCG config");
	}

	if (desc->intent != NULL)
		fz_drop_obj(desc->intent);
	desc->intent = fz_dict_gets(cobj, "Intent");
	if (desc->intent != NULL)
		fz_keep_obj(desc->intent);

	len = desc->len;
	name = fz_to_name(fz_dict_gets(cobj, "BaseState"));
	if (strcmp(name, "Unchanged") == 0)
	{
		/* Do nothing */
	}
	else if (strcmp(name, "OFF") == 0)
	{
		for (i = 0; i < len; i++)
		{
			desc->ocgs[i].state = 0;
		}
	}
	else /* Default to ON */
	{
		for (i = 0; i < len; i++)
		{
			desc->ocgs[i].state = 1;
		}
	}

	obj = fz_dict_gets(cobj, "ON");
	len2 = fz_array_len(obj);
	for (i = 0; i < len2; i++)
	{
		fz_obj *o = fz_array_get(obj, i);
		int n = fz_to_num(o);
		int g = fz_to_gen(o);
		for (j=0; j < len; j++)
		{
			if (desc->ocgs[j].num == n && desc->ocgs[j].gen == g)
			{
				desc->ocgs[j].state = 1;
				break;
			}
		}
	}

	obj = fz_dict_gets(cobj, "OFF");
	len2 = fz_array_len(obj);
	for (i = 0; i < len2; i++)
	{
		fz_obj *o = fz_array_get(obj, i);
		int n = fz_to_num(o);
		int g = fz_to_gen(o);
		for (j=0; j < len; j++)
		{
			if (desc->ocgs[j].num == n && desc->ocgs[j].gen == g)
			{
				desc->ocgs[j].state = 0;
				break;
			}
		}
	}

	/* FIXME: Should make 'num configs' available in the descriptor. */
	/* FIXME: Should copy out 'Intent' here into the descriptor, and remove
	 * csi->intent in favour of that. */
	/* FIXME: Should copy 'AS' into the descriptor, and visibility
	 * decisions should respect it. */
	/* FIXME: Make 'Order' available via the descriptor (when we have an
	 * app that needs it) */
	/* FIXME: Make 'ListMode' available via the descriptor (when we have
	 * an app that needs it) */
	/* FIXME: Make 'RBGroups' available via the descriptor (when we have
	 * an app that needs it) */
	/* FIXME: Make 'Locked' available via the descriptor (when we have
	 * an app that needs it) */
	return fz_okay;
}
Exemple #11
0
void
pdf_load_annots(pdf_annot **annotp, pdf_xref *xref, fz_obj *annots)
{
	pdf_annot *annot, *head, *tail;
	fz_obj *obj, *ap, *as, *n, *rect;
	pdf_xobject *form;
	fz_error error;
	int i;
	fz_context *ctx = xref->ctx;

	head = tail = NULL;
	annot = NULL;

	for (i = 0; i < fz_array_len(ctx, annots); i++)
	{
		obj = fz_array_get(ctx, annots, i);

		/* cf. http://bugs.ghostscript.com/show_bug.cgi?id=692078 */
		if ((annot = pdf_update_tx_widget_annot(xref, obj)))
		{
			if (!head)
				head = tail = annot;
			else
			{
				tail->next = annot;
				tail = annot;
			}
			continue;
		}

		rect = fz_dict_gets(ctx, obj, "Rect");
		ap = fz_dict_gets(ctx, obj, "AP");
		as = fz_dict_gets(ctx, obj, "AS");
		if (fz_is_dict(ctx, ap))
		{
			n = fz_dict_gets(ctx, ap, "N"); /* normal state */

			/* lookup current state in sub-dictionary */
			if (!pdf_is_stream(xref, fz_to_num(n), fz_to_gen(n)))
				n = fz_dict_get(ctx, n, as);

			if (pdf_is_stream(xref, fz_to_num(n), fz_to_gen(n)))
			{
				error = pdf_load_xobject(&form, xref, n);
				if (error)
				{
					fz_error_handle(ctx, error, "ignoring broken annotation");
					continue;
				}

				annot = fz_malloc(ctx, sizeof(pdf_annot));
				annot->obj = fz_keep_obj(obj);
				annot->rect = pdf_to_rect(ctx, rect);
				annot->ap = form;
				annot->next = NULL;

				pdf_transform_annot(annot);

				if (annot)
				{
					if (!head)
						head = tail = annot;
					else
					{
						tail->next = annot;
						tail = annot;
					}
				}
			}
		}
		/* SumatraPDF: synthesize appearance streams for a few more annotations */
		else if ((annot = pdf_create_annot_with_appearance(xref, obj)))
		{
			if (!head)
				head = tail = annot;
			else
			{
				tail->next = annot;
				tail = annot;
			}
		}
	}

	*annotp = head;
}
Exemple #12
0
static pdf_annot *
pdf_update_tx_widget_annot(pdf_xref *xref, fz_obj *obj)
{
	fz_obj *ap, *res, *value;
	fz_rect rect;
	fz_buffer *content, *base_ap;
	int flags, align, rotate, is_multiline;
	float font_size, x, y;
	char *font_name;
	unsigned short *ucs2, *rest;

	fz_context *ctx = xref->ctx;

	if (strcmp(fz_to_name(ctx, fz_dict_gets(ctx, obj, "Subtype")), "Widget") != 0)
		return NULL;
	if (!fz_to_bool(ctx, pdf_dict_get_inheritable(xref, NULL, "NeedAppearances")) && pdf_get_ap_stream(xref, obj))
		return NULL;
	value = pdf_dict_get_inheritable(xref, obj, "FT");
	if (strcmp(fz_to_name(ctx, value), "Tx") != 0)
		return NULL;

	ap = pdf_dict_get_inheritable(xref, obj, "DA");
	value = pdf_dict_get_inheritable(xref, obj, "V");
	if (!ap || !value)
		return NULL;

	res = pdf_dict_get_inheritable(xref, obj, "DR");
	rect = pdf_to_rect(ctx, fz_dict_gets(ctx, obj, "Rect"));
	rotate = fz_to_int(ctx, fz_dict_gets(ctx, fz_dict_gets(ctx, obj, "MK"), "R"));
	rect = fz_transform_rect(fz_rotate(rotate), rect);

	flags = fz_to_int(ctx, fz_dict_gets(ctx, obj, "Ff"));
	is_multiline = (flags & (1 << 12)) != 0;
	if ((flags & (1 << 25) /* richtext */))
		fz_warn(ctx, "missing support for richtext fields");
	align = fz_to_int(ctx, fz_dict_gets(ctx, obj, "Q"));

	font_size = pdf_extract_font_size(xref, fz_to_str_buf(ctx, ap), &font_name);
	if (!font_size || !font_name)
		font_size = is_multiline ? 10 /* FIXME */ : floor(rect.y1 - rect.y0 - 2);

	content = fz_new_buffer(ctx, 256);
	base_ap = fz_new_buffer(ctx, 256);
	pdf_prepend_ap_background(content, xref, obj);
	fz_buffer_printf(ctx, content, "/Tx BMC q 1 1 %.4f %.4f re W n BT %s ",
		rect.x1 - rect.x0 - 2.0f, rect.y1 - rect.y0 - 2.0f, fz_to_str_buf(ctx, ap));
	fz_buffer_printf(ctx, base_ap, "/Tx BMC q BT %s ", fz_to_str_buf(ctx, ap));
	if (font_name)
	{
		fz_buffer_printf(ctx, content, "/%s %.4f Tf ", font_name, font_size);
		fz_buffer_printf(ctx, base_ap, "/%s %.4f Tf ", font_name, font_size);
		fz_free(ctx, font_name);
	}
	y = 0.5f * (rect.y1 - rect.y0) + 0.6f * font_size;
	if (is_multiline)
		y = rect.y1 - rect.y0 - 2;
	fz_buffer_printf(ctx, content, "1 0 0 1 2 %.4f Tm ", y);

	ucs2 = pdf_to_ucs2(ctx, value);
	for (rest = ucs2; *rest; rest++)
		if (*rest > 0xFF)
			*rest = '?';
	if ((flags & (1 << 13) /* password */))
		for (rest = ucs2; *rest; rest++)
			*rest = '*';

	x = 0;
	rest = ucs2;
	if ((flags & (1 << 24) /* comb */))
	{
		pdf_append_combed_line(xref, res, content, base_ap, ucs2, font_size, rect.x1 - rect.x0, fz_to_int(ctx, pdf_dict_get_inheritable(xref, obj, "MaxLen")));
		rest = L"";
	}
	while (*rest)
		rest = pdf_append_line(xref, res, content, base_ap, rest, font_size, align, rect.x1 - rect.x0 - 4.0f, is_multiline, &x);

	fz_free(ctx, ucs2);
	fz_buffer_printf(ctx, content, "ET Q EMC");
	fz_drop_buffer(ctx, base_ap);

	rect = fz_transform_rect(fz_rotate(-rotate), rect);
	return pdf_create_annot(ctx, rect, fz_keep_obj(obj), content, res ? fz_keep_obj(res) : NULL, 0);
}
Exemple #13
0
pdf_link *
pdf_load_link(pdf_xref *xref, fz_obj *dict)
{
	fz_obj *dest;
	fz_obj *action;
	fz_obj *obj;
	fz_rect bbox;
	pdf_link_kind kind;
	fz_context *ctx = xref->ctx;

	dest = NULL;

	obj = fz_dict_gets(ctx, dict, "Rect");
	if (obj)
		bbox = pdf_to_rect(ctx, obj);
	else
		bbox = fz_empty_rect;

	obj = fz_dict_gets(ctx, dict, "Dest");
	if (obj)
	{
		kind = PDF_LINK_GOTO;
		dest = resolve_dest(xref, obj);
	}

	action = fz_dict_gets(ctx, dict, "A");

	/* fall back to additional action button's down/up action */
	if (!action)
		action = fz_dict_getsa(ctx, fz_dict_gets(ctx, dict, "AA"), "U", "D");

	if (action)
	{
		obj = fz_dict_gets(ctx, action, "S");
		if (fz_is_name(ctx, obj) && !strcmp(fz_to_name(ctx, obj), "GoTo"))
		{
			kind = PDF_LINK_GOTO;
			dest = resolve_dest(xref, fz_dict_gets(ctx, action, "D"));
		}
		else if (fz_is_name(ctx, obj) && !strcmp(fz_to_name(ctx, obj), "URI"))
		{
			kind = PDF_LINK_URI;
			dest = fz_dict_gets(ctx, action, "URI");
		}
		else if (fz_is_name(ctx, obj) && !strcmp(fz_to_name(ctx, obj), "Launch"))
		{
			kind = PDF_LINK_LAUNCH;
			dest = fz_dict_gets(ctx, action, "F");
		}
		else if (fz_is_name(ctx, obj) && !strcmp(fz_to_name(ctx, obj), "Named"))
		{
			kind = PDF_LINK_NAMED;
			dest = fz_dict_gets(ctx, action, "N");
		}
		else if (fz_is_name(ctx, obj) && (!strcmp(fz_to_name(ctx, obj), "GoToR")))
		{
			kind = PDF_LINK_ACTION;
			dest = action;
		}
		else
		{
			dest = NULL;
		}
	}

	if (dest)
	{
		pdf_link *link = fz_malloc(ctx, sizeof(pdf_link));
		link->kind = kind;
		link->rect = bbox;
		link->dest = fz_keep_obj(dest);
		link->next = NULL;
		return link;
	}

	return NULL;
}