summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gardiner <paulg.artifex@glidos.net>2013-01-30 16:49:43 +0000
committerRobin Watts <robin.watts@artifex.com>2013-01-31 11:17:32 +0000
commitaeed1e16e440cefbf5137eef7f4af608b0c70569 (patch)
tree40a55a1bff17a6ef632eaab053437f40123d1f4e
parent0203bd8921ffa9569273a077c1cb8bb92a35e520 (diff)
downloadmupdf-aeed1e16e440cefbf5137eef7f4af608b0c70569.tar.xz
Add support for annotation creation
-rw-r--r--fitz/doc_interactive.c10
-rw-r--r--fitz/fitz-internal.h18
-rw-r--r--fitz/fitz.h1
-rw-r--r--pdf/mupdf-internal.h5
-rw-r--r--pdf/mupdf.h1
-rw-r--r--pdf/pdf_annot.c129
-rw-r--r--pdf/pdf_form.c2
-rw-r--r--pdf/pdf_object.c19
-rw-r--r--pdf/pdf_page.c2
9 files changed, 181 insertions, 6 deletions
diff --git a/fitz/doc_interactive.c b/fitz/doc_interactive.c
index f2fb059d..ea08577d 100644
--- a/fitz/doc_interactive.c
+++ b/fitz/doc_interactive.c
@@ -81,6 +81,16 @@ void fz_choice_widget_set_value(fz_interactive *idoc, fz_widget *tw, int n, char
pdf_choice_widget_set_value((pdf_document *)idoc, tw, n, opts);
}
+fz_annot *fz_create_annot(fz_interactive *idoc, fz_page *page, fz_annot_type type)
+{
+ return (fz_annot *)pdf_create_annot((pdf_document *)idoc, (pdf_page *)page, type);
+}
+
+void fz_set_annot_appearance(fz_interactive *idoc, fz_annot *annot, fz_display_list *disp_list)
+{
+ pdf_set_annot_appearance((pdf_document *)idoc, (pdf_annot *)annot, disp_list);
+}
+
void fz_set_doc_event_callback(fz_interactive *idoc, fz_doc_event_cb *event_cb, void *data)
{
pdf_set_doc_event_callback((pdf_document *)idoc, event_cb, data);
diff --git a/fitz/fitz-internal.h b/fitz/fitz-internal.h
index 13fd94de..4839af7d 100644
--- a/fitz/fitz-internal.h
+++ b/fitz/fitz-internal.h
@@ -1194,6 +1194,24 @@ fz_pixmap *fz_render_stroked_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz
void fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gid, fz_matrix trm, void *gstate, int nestedDepth);
void fz_prepare_t3_glyph(fz_context *ctx, fz_font *font, int gid, int nestedDepth);
+typedef enum
+{
+ FZ_ANNOT_STRIKEOUT
+} fz_annot_type;
+
+/*
+ fz_create_annot: create a new annotation of the specified type on the
+ specified page. The returned pdf_annot structure is owned by the page
+ and does not need to be freed.
+*/
+fz_annot *fz_create_annot(fz_interactive *idoc, fz_page *page, fz_annot_type type);
+
+/*
+ fz_set_annot_appearance: update the appearance of an annotation based
+ on a display list.
+*/
+void fz_set_annot_appearance(fz_interactive *idoc, fz_annot *annot, fz_display_list *disp_list);
+
/*
* Text buffer.
*
diff --git a/fitz/fitz.h b/fitz/fitz.h
index 8f39d3f4..43634dd9 100644
--- a/fitz/fitz.h
+++ b/fitz/fitz.h
@@ -2511,6 +2511,7 @@ fz_transition *fz_page_presentation(fz_document *doc, fz_page *page, float *dura
/* Types of widget */
enum
{
+ FZ_WIDGET_TYPE_NOT_WIDGET = -1,
FZ_WIDGET_TYPE_PUSHBUTTON,
FZ_WIDGET_TYPE_CHECKBOX,
FZ_WIDGET_TYPE_RADIOBUTTON,
diff --git a/pdf/mupdf-internal.h b/pdf/mupdf-internal.h
index 4f2524ad..6ac228ef 100644
--- a/pdf/mupdf-internal.h
+++ b/pdf/mupdf-internal.h
@@ -494,6 +494,7 @@ float pdf_text_stride(fz_context *ctx, pdf_font_desc *fontdesc, float fontsize,
struct pdf_annot_s
{
+ pdf_page *page;
pdf_obj *obj;
fz_rect rect;
fz_rect pagerect;
@@ -513,7 +514,7 @@ pdf_obj *pdf_load_name_tree(pdf_document *doc, char *which);
fz_link *pdf_load_link_annots(pdf_document *, pdf_obj *annots, fz_matrix page_ctm);
-pdf_annot *pdf_load_annots(pdf_document *, pdf_obj *annots, fz_matrix page_ctm);
+pdf_annot *pdf_load_annots(pdf_document *, pdf_obj *annots, pdf_page *page);
void pdf_update_annot(pdf_document *, pdf_annot *annot);
void pdf_free_annot(fz_context *ctx, pdf_annot *link);
@@ -583,6 +584,8 @@ int pdf_choice_widget_options(pdf_document *doc, fz_widget *tw, char *opts[]);
int pdf_choice_widget_is_multiselect(pdf_document *doc, fz_widget *tw);
int pdf_choice_widget_value(pdf_document *doc, fz_widget *tw, char *opts[]);
void pdf_choice_widget_set_value(pdf_document *doc, fz_widget *tw, int n, char *opts[]);
+pdf_annot *pdf_create_annot(pdf_document *doc, pdf_page *page, fz_annot_type type);
+void pdf_set_annot_appearance(pdf_document *doc, pdf_annot *annot, fz_display_list *disp_list);
void pdf_set_doc_event_callback(pdf_document *doc, fz_doc_event_cb *event_cb, void *data);
void pdf_event_issue_alert(pdf_document *doc, fz_alert_event *event);
diff --git a/pdf/mupdf.h b/pdf/mupdf.h
index e10a4982..27bd1644 100644
--- a/pdf/mupdf.h
+++ b/pdf/mupdf.h
@@ -78,6 +78,7 @@ void pdf_dict_put(pdf_obj *dict, pdf_obj *key, pdf_obj *val);
void pdf_dict_puts(pdf_obj *dict, const char *key, pdf_obj *val);
void pdf_dict_puts_drop(pdf_obj *dict, const char *key, pdf_obj *val);
void pdf_dict_putp(pdf_obj *dict, const char *key, pdf_obj *val);
+void pdf_dict_putp_drop(pdf_obj *dict, const char *key, pdf_obj *val);
void pdf_dict_del(pdf_obj *dict, pdf_obj *key);
void pdf_dict_dels(pdf_obj *dict, const char *key);
void pdf_sort_dict(pdf_obj *dict);
diff --git a/pdf/pdf_annot.c b/pdf/pdf_annot.c
index 4d0d0f84..b93fa258 100644
--- a/pdf/pdf_annot.c
+++ b/pdf/pdf_annot.c
@@ -353,7 +353,7 @@ pdf_transform_annot(pdf_annot *annot)
}
pdf_annot *
-pdf_load_annots(pdf_document *xref, pdf_obj *annots, fz_matrix page_ctm)
+pdf_load_annots(pdf_document *xref, pdf_obj *annots, pdf_page *page)
{
pdf_annot *annot, *head, *tail;
pdf_obj *obj, *ap, *as, *n, *rect;
@@ -400,9 +400,10 @@ pdf_load_annots(pdf_document *xref, pdf_obj *annots, fz_matrix page_ctm)
n = pdf_dict_get(n, as);
annot = fz_malloc_struct(ctx, pdf_annot);
+ annot->page = page;
annot->obj = pdf_keep_obj(obj);
annot->rect = pdf_to_rect(ctx, rect);
- annot->pagerect = fz_transform_rect(page_ctm, annot->rect);
+ annot->pagerect = fz_transform_rect(page->ctm, annot->rect);
annot->ap = NULL;
annot->type = pdf_field_type(xref, obj);
@@ -507,3 +508,127 @@ pdf_bound_annot(pdf_document *doc, pdf_annot *annot)
return annot->pagerect;
return fz_empty_rect;
}
+
+pdf_annot *
+pdf_create_annot(pdf_document *doc, pdf_page *page, fz_annot_type type)
+{
+ fz_context *ctx = doc->ctx;
+ pdf_annot *annot = NULL;
+ pdf_obj *annot_obj = pdf_new_dict(ctx, 0);
+
+ fz_var(annot);
+ fz_try(ctx)
+ {
+ fz_rect rect = {0.0, 0.0, 0.0, 0.0};
+ char *type_str = "";
+ pdf_obj *annot_arr = pdf_dict_gets(page->me, "Annots");
+ if (annot_arr == NULL)
+ {
+ annot_arr = pdf_new_array(ctx, 0);
+ pdf_dict_puts_drop(page->me, "Annots", annot_arr);
+ }
+
+ pdf_dict_puts_drop(annot_obj, "Type", pdf_new_name(ctx, "Annot"));
+
+ switch(type)
+ {
+ case FZ_ANNOT_STRIKEOUT:
+ type_str = "StrikeOut";
+ break;
+ }
+
+ pdf_dict_puts_drop(annot_obj, "Subtype", pdf_new_name(ctx, type_str));
+ pdf_dict_puts_drop(annot_obj, "Rect", pdf_new_rect(ctx, rect));
+
+ annot = fz_malloc_struct(ctx, pdf_annot);
+ annot->page = page;
+ annot->obj = pdf_keep_obj(annot_obj);
+ annot->rect = rect;
+ annot->pagerect = rect;
+ annot->ap = NULL;
+ annot->type = FZ_WIDGET_TYPE_NOT_WIDGET;
+
+ /*
+ Both annotation object and annotation structure are now created.
+ Insert the object in the hierarchy and the structure in the
+ page's array.
+ */
+ pdf_array_push(annot_arr, annot_obj);
+
+ /*
+ Linking must be done before any call that might throw because
+ pdf_free_annot below actually frees a list
+ */
+ annot->next = page->annots;
+ page->annots = annot;
+
+ doc->dirty = 1;
+ }
+ fz_always(ctx)
+ {
+ pdf_drop_obj(annot_obj);
+ }
+ fz_catch(ctx)
+ {
+ pdf_free_annot(ctx, annot);
+ fz_rethrow(ctx);
+ }
+
+ return annot;
+}
+
+void
+pdf_set_annot_appearance(pdf_document *doc, pdf_annot *annot, fz_display_list *disp_list)
+{
+ fz_context *ctx = doc->ctx;
+ fz_matrix ctm = fz_invert_matrix(annot->page->ctm);
+ fz_rect rect;
+ fz_matrix mat = fz_identity;
+ fz_device *dev = fz_new_bbox_device(ctx, &rect);
+
+ fz_try(ctx)
+ {
+ pdf_obj *ap_obj;
+
+ fz_run_display_list(disp_list, dev, ctm, fz_infinite_rect, NULL);
+ fz_free_device(dev);
+ dev = NULL;
+
+ pdf_dict_puts_drop(annot->obj, "Rect", pdf_new_rect(ctx, rect));
+
+ /* See if there is a current normal appearance */
+ ap_obj = pdf_dict_getp(annot->obj, "AP/N");
+ if (!pdf_is_stream(doc, pdf_to_num(annot->obj), pdf_to_gen(annot->obj)))
+ ap_obj = NULL;
+
+ if (ap_obj == NULL)
+ {
+ ap_obj = pdf_new_xobject(doc, rect, mat);
+ pdf_dict_putp_drop(annot->obj, "AP/N", ap_obj);
+ }
+ else
+ {
+ pdf_dict_puts_drop(ap_obj, "Rect", pdf_new_rect(ctx, rect));
+ pdf_dict_puts_drop(ap_obj, "Matrix", pdf_new_matrix(ctx, mat));
+ }
+
+ /* Remove annot reference to the xobject and don't recreate it
+ so that pdf_update_page counts it as dirty */
+ pdf_drop_xobject(ctx, annot->ap);
+ annot->ap = NULL;
+
+ annot->rect = rect;
+ annot->pagerect = fz_transform_rect(annot->page->ctm, rect);
+
+ dev = pdf_new_pdf_device(doc, ap_obj, pdf_dict_gets(ap_obj, "Resources"), mat);
+ fz_run_display_list(disp_list, dev, ctm, fz_infinite_rect, NULL);
+ fz_free_device(dev);
+
+ doc->dirty = 1;
+ }
+ fz_catch(ctx)
+ {
+ fz_free_device(dev);
+ fz_rethrow(ctx);
+ }
+}
diff --git a/pdf/pdf_form.c b/pdf/pdf_form.c
index 8fbebbc8..e92ba738 100644
--- a/pdf/pdf_form.c
+++ b/pdf/pdf_form.c
@@ -3,8 +3,6 @@
#define MATRIX_COEFS (6)
-#define FZ_WIDGET_TYPE_NOT_WIDGET (-1)
-
enum
{
Ff_Multiline = 1 << (13-1),
diff --git a/pdf/pdf_object.c b/pdf/pdf_object.c
index 9ebb4aec..8a2d71fc 100644
--- a/pdf/pdf_object.c
+++ b/pdf/pdf_object.c
@@ -1056,6 +1056,25 @@ pdf_dict_putp(pdf_obj *obj, const char *keys, pdf_obj *val)
}
void
+pdf_dict_putp_drop(pdf_obj *obj, const char *keys, pdf_obj *val)
+{
+ fz_context *ctx = obj->ctx;
+
+ fz_try(ctx)
+ {
+ pdf_dict_putp(obj, keys, val);
+ }
+ fz_always(ctx)
+ {
+ pdf_drop_obj(val);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+}
+
+void
pdf_dict_dels(pdf_obj *obj, const char *key)
{
RESOLVE(obj);
diff --git a/pdf/pdf_page.c b/pdf/pdf_page.c
index 93643e7c..a071732a 100644
--- a/pdf/pdf_page.c
+++ b/pdf/pdf_page.c
@@ -408,7 +408,7 @@ pdf_load_page(pdf_document *xref, int number)
if (obj)
{
page->links = pdf_load_link_annots(xref, obj, page->ctm);
- page->annots = pdf_load_annots(xref, obj, page->ctm);
+ page->annots = pdf_load_annots(xref, obj, page);
}
page->duration = pdf_to_real(pdf_dict_gets(pageobj, "Dur"));