3 #define TEXT_ANNOT_SIZE (25.0)
5 static const char *annot_type_str(fz_annot_type type)
9 case FZ_ANNOT_TEXT: return "Text";
10 case FZ_ANNOT_LINK: return "Link";
11 case FZ_ANNOT_FREETEXT: return "FreeText";
12 case FZ_ANNOT_LINE: return "Line";
13 case FZ_ANNOT_SQUARE: return "Square";
14 case FZ_ANNOT_CIRCLE: return "Circle";
15 case FZ_ANNOT_POLYGON: return "Polygon";
16 case FZ_ANNOT_POLYLINE: return "PolyLine";
17 case FZ_ANNOT_HIGHLIGHT: return "Highlight";
18 case FZ_ANNOT_UNDERLINE: return "Underline";
19 case FZ_ANNOT_SQUIGGLY: return "Squiggly";
20 case FZ_ANNOT_STRIKEOUT: return "StrikeOut";
21 case FZ_ANNOT_STAMP: return "Stamp";
22 case FZ_ANNOT_CARET: return "Caret";
23 case FZ_ANNOT_INK: return "Ink";
24 case FZ_ANNOT_POPUP: return "Popup";
25 case FZ_ANNOT_FILEATTACHMENT: return "FileAttachment";
26 case FZ_ANNOT_SOUND: return "Sound";
27 case FZ_ANNOT_MOVIE: return "Movie";
28 case FZ_ANNOT_WIDGET: return "Widget";
29 case FZ_ANNOT_SCREEN: return "Screen";
30 case FZ_ANNOT_PRINTERMARK: return "PrinterMark";
31 case FZ_ANNOT_TRAPNET: return "TrapNet";
32 case FZ_ANNOT_WATERMARK: return "Watermark";
33 case FZ_ANNOT_3D: return "3D";
39 pdf_update_annot(pdf_document *doc, pdf_annot *annot)
41 pdf_obj *obj, *ap, *as, *n;
42 fz_context *ctx = doc->ctx;
44 if (doc->update_appearance)
45 doc->update_appearance(doc, annot);
49 ap = pdf_dict_gets(obj, "AP");
50 as = pdf_dict_gets(obj, "AS");
54 pdf_hotspot *hp = &doc->hotspot;
58 if (hp->num == pdf_to_num(obj)
59 && hp->gen == pdf_to_gen(obj)
60 && (hp->state & HOTSPOT_POINTER_DOWN))
62 n = pdf_dict_gets(ap, "D"); /* down state */
66 n = pdf_dict_gets(ap, "N"); /* normal state */
68 /* lookup current state in sub-dictionary */
69 if (!pdf_is_stream(doc, pdf_to_num(n), pdf_to_gen(n)))
70 n = pdf_dict_get(n, as);
72 pdf_drop_xobject(ctx, annot->ap);
75 if (pdf_is_stream(doc, pdf_to_num(n), pdf_to_gen(n)))
79 annot->ap = pdf_load_xobject(doc, n);
80 pdf_transform_annot(annot);
81 annot->ap_iteration = annot->ap->iteration;
85 fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
86 fz_warn(ctx, "ignoring broken annotation");
93 pdf_create_annot(pdf_document *doc, pdf_page *page, fz_annot_type type)
95 fz_context *ctx = doc->ctx;
96 pdf_annot *annot = NULL;
97 pdf_obj *annot_obj = pdf_new_dict(doc, 0);
98 pdf_obj *ind_obj = NULL;
105 fz_rect rect = {0.0, 0.0, 0.0, 0.0};
106 const char *type_str = annot_type_str(type);
107 pdf_obj *annot_arr = pdf_dict_gets(page->me, "Annots");
108 if (annot_arr == NULL)
110 annot_arr = pdf_new_array(doc, 0);
111 pdf_dict_puts_drop(page->me, "Annots", annot_arr);
114 pdf_dict_puts_drop(annot_obj, "Type", pdf_new_name(doc, "Annot"));
116 pdf_dict_puts_drop(annot_obj, "Subtype", pdf_new_name(doc, type_str));
117 pdf_dict_puts_drop(annot_obj, "Rect", pdf_new_rect(doc, &rect));
119 /* Make printable as default */
120 pdf_dict_puts_drop(annot_obj, "F", pdf_new_int(doc, F_Print));
122 annot = fz_malloc_struct(ctx, pdf_annot);
125 annot->pagerect = rect;
127 annot->widget_type = PDF_WIDGET_TYPE_NOT_WIDGET;
128 annot->annot_type = type;
131 Both annotation object and annotation structure are now created.
132 Insert the object in the hierarchy and the structure in the
135 ind_obj_num = pdf_create_object(doc);
136 pdf_update_object(doc, ind_obj_num, annot_obj);
137 ind_obj = pdf_new_indirect(doc, ind_obj_num, 0);
138 pdf_array_push(annot_arr, ind_obj);
139 annot->obj = pdf_keep_obj(ind_obj);
142 Linking must be done after any call that might throw because
143 pdf_free_annot below actually frees a list. Put the new annot
144 at the end of the list, so that it will be drawn last.
146 *page->annot_tailp = annot;
147 page->annot_tailp = &annot->next;
153 pdf_drop_obj(annot_obj);
154 pdf_drop_obj(ind_obj);
158 pdf_free_annot(ctx, annot);
166 pdf_delete_annot(pdf_document *doc, pdf_page *page, pdf_annot *annot)
168 fz_context *ctx = doc->ctx;
169 pdf_annot **annotptr;
170 pdf_obj *old_annot_arr;
176 /* Remove annot from page's list */
177 for (annotptr = &page->annots; *annotptr; annotptr = &(*annotptr)->next)
179 if (*annotptr == annot)
183 /* Check the passed annotation was of this page */
184 if (*annotptr == NULL)
187 *annotptr = annot->next;
188 /* If the removed annotation was the last in the list adjust the end pointer */
189 if (*annotptr == NULL)
190 page->annot_tailp = annotptr;
192 /* Stick it in the deleted list */
193 annot->next = page->deleted_annots;
194 page->deleted_annots = annot;
196 pdf_drop_xobject(ctx, annot->ap);
199 /* Recreate the "Annots" array with this annot removed */
200 old_annot_arr = pdf_dict_gets(page->me, "Annots");
204 int i, n = pdf_array_len(old_annot_arr);
205 annot_arr = pdf_new_array(doc, n?(n-1):0);
209 for (i = 0; i < n; i++)
211 pdf_obj *obj = pdf_array_get(old_annot_arr, i);
213 if (obj != annot->obj)
214 pdf_array_push(annot_arr, obj);
217 if (pdf_is_indirect(old_annot_arr))
218 pdf_update_object(doc, pdf_to_num(old_annot_arr), annot_arr);
220 pdf_dict_puts(page->me, "Annots", annot_arr);
222 if (pdf_is_indirect(annot->obj))
223 pdf_delete_object(doc, pdf_to_num(annot->obj));
227 pdf_drop_obj(annot_arr);
235 pdf_drop_obj(annot->obj);
241 pdf_set_markup_annot_quadpoints(pdf_document *doc, pdf_annot *annot, fz_point *qp, int n)
244 pdf_obj *arr = pdf_new_array(doc, n*2);
247 fz_invert_matrix(&ctm, &annot->page->ctm);
249 pdf_dict_puts_drop(annot->obj, "QuadPoints", arr);
251 for (i = 0; i < n; i++)
256 fz_transform_point(&pt, &ctm);
257 r = pdf_new_real(doc, pt.x);
258 pdf_array_push_drop(arr, r);
259 r = pdf_new_real(doc, pt.y);
260 pdf_array_push_drop(arr, r);
264 static void update_rect(fz_context *ctx, pdf_annot *annot)
266 pdf_to_rect(ctx, pdf_dict_gets(annot->obj, "Rect"), &annot->rect);
267 annot->pagerect = annot->rect;
268 fz_transform_rect(&annot->pagerect, &annot->page->ctm);
272 pdf_set_ink_annot_list(pdf_document *doc, pdf_annot *annot, fz_point *pts, int *counts, int ncount, float color[3], float thickness)
274 fz_context *ctx = doc->ctx;
276 pdf_obj *list = pdf_new_array(doc, ncount);
281 fz_invert_matrix(&ctm, &annot->page->ctm);
283 pdf_dict_puts_drop(annot->obj, "InkList", list);
285 for (i = 0; i < ncount; i++)
288 pdf_obj *arc = pdf_new_array(doc, counts[i]);
290 pdf_array_push_drop(list, arc);
292 for (j = 0; j < counts[i]; j++)
294 fz_point pt = pts[k];
296 fz_transform_point(&pt, &ctm);
298 if (i == 0 && j == 0)
300 rect.x0 = rect.x1 = pt.x;
301 rect.y0 = rect.y1 = pt.y;
305 fz_include_point_in_rect(&rect, &pt);
308 pdf_array_push_drop(arc, pdf_new_real(doc, pt.x));
309 pdf_array_push_drop(arc, pdf_new_real(doc, pt.y));
315 Expand the rectangle by thickness all around. We cannot use
316 fz_expand_rect because the rectangle might be empty in the
321 rect.x0 -= thickness;
322 rect.y0 -= thickness;
323 rect.x1 += thickness;
324 rect.y1 += thickness;
327 pdf_dict_puts_drop(annot->obj, "Rect", pdf_new_rect(doc, &rect));
328 update_rect(ctx, annot);
330 bs = pdf_new_dict(doc, 1);
331 pdf_dict_puts_drop(annot->obj, "BS", bs);
332 pdf_dict_puts_drop(bs, "W", pdf_new_real(doc, thickness));
334 col = pdf_new_array(doc, 3);
335 pdf_dict_puts_drop(annot->obj, "C", col);
336 for (i = 0; i < 3; i++)
337 pdf_array_push_drop(col, pdf_new_real(doc, color[i]));
340 static void find_free_font_name(pdf_obj *fdict, char *buf, int buf_size)
344 /* Find a number X such that /FX doesn't occur as a key in fdict */
347 snprintf(buf, buf_size, "F%d", i);
349 if (!pdf_dict_gets(fdict, buf))
354 void pdf_set_text_annot_position(pdf_document *doc, pdf_annot *annot, fz_point pt)
360 fz_invert_matrix(&ctm, &annot->page->ctm);
362 rect.x1 = pt.x + TEXT_ANNOT_SIZE;
364 rect.y1 = pt.y + TEXT_ANNOT_SIZE;
365 fz_transform_rect(&rect, &ctm);
367 pdf_dict_puts_drop(annot->obj, "Rect", pdf_new_rect(doc, &rect));
369 flags = pdf_to_int(pdf_dict_gets(annot->obj, "F"));
370 flags |= (F_NoZoom|F_NoRotate);
371 pdf_dict_puts_drop(annot->obj, "F", pdf_new_int(doc, flags));
373 update_rect(doc->ctx, annot);
376 void pdf_set_annot_contents(pdf_document *doc, pdf_annot *annot, char *text)
378 pdf_dict_puts_drop(annot->obj, "Contents", pdf_new_string(doc, text, strlen(text)));
381 char *pdf_annot_contents(pdf_document *doc, pdf_annot *annot)
383 return pdf_to_str_buf(pdf_dict_getp(annot->obj, "Contents"));
386 void pdf_set_free_text_details(pdf_document *doc, pdf_annot *annot, fz_point *pos, char *text, char *font_name, float font_size, float color[3])
388 fz_context *ctx = doc->ctx;
392 pdf_obj *font = NULL;
394 pdf_font_desc *font_desc = NULL;
396 fz_buffer *fzbuf = NULL;
400 fz_invert_matrix(&ctm, &annot->page->ctm);
402 dr = pdf_dict_gets(annot->page->me, "Resources");
405 dr = pdf_new_dict(doc, 1);
406 pdf_dict_putp_drop(annot->page->me, "Resources", dr);
409 /* Ensure the resource dictionary includes a font dict */
410 form_fonts = pdf_dict_gets(dr, "Font");
413 form_fonts = pdf_new_dict(doc, 1);
414 pdf_dict_puts_drop(dr, "Font", form_fonts);
415 /* form_fonts is still valid if execution continues past the above call */
422 unsigned char *da_str;
426 find_free_font_name(form_fonts, nbuf, sizeof(nbuf));
428 font = pdf_new_dict(doc, 5);
429 ref = pdf_new_ref(doc, font);
430 pdf_dict_puts_drop(form_fonts, nbuf, ref);
432 pdf_dict_puts_drop(font, "Type", pdf_new_name(doc, "Font"));
433 pdf_dict_puts_drop(font, "Subtype", pdf_new_name(doc, "Type1"));
434 pdf_dict_puts_drop(font, "BaseFont", pdf_new_name(doc, font_name));
435 pdf_dict_puts_drop(font, "Encoding", pdf_new_name(doc, "WinAnsiEncoding"));
437 memcpy(da_info.col, color, sizeof(float)*3);
438 da_info.col_size = 3;
439 da_info.font_name = nbuf;
440 da_info.font_size = font_size;
442 fzbuf = fz_new_buffer(ctx, 0);
443 pdf_fzbuf_print_da(ctx, fzbuf, &da_info);
445 da_len = fz_buffer_storage(ctx, fzbuf, &da_str);
446 pdf_dict_puts_drop(annot->obj, "DA", pdf_new_string(doc, (char *)da_str, da_len));
448 /* FIXME: should convert to WinAnsiEncoding */
449 pdf_dict_puts_drop(annot->obj, "Contents", pdf_new_string(doc, text, strlen(text)));
451 font_desc = pdf_load_font(doc, NULL, font, 0);
452 pdf_measure_text(ctx, font_desc, (unsigned char *)text, strlen(text), &bounds);
455 fz_transform_point(&page_pos, &ctm);
457 bounds.x0 *= font_size;
458 bounds.x1 *= font_size;
459 bounds.y0 *= font_size;
460 bounds.y1 *= font_size;
462 bounds.x0 += page_pos.x;
463 bounds.x1 += page_pos.x;
464 bounds.y0 += page_pos.y;
465 bounds.y1 += page_pos.y;
467 pdf_dict_puts_drop(annot->obj, "Rect", pdf_new_rect(doc, &bounds));
468 update_rect(ctx, annot);
473 fz_drop_buffer(ctx, fzbuf);
474 pdf_drop_font(ctx, font_desc);