summaryrefslogtreecommitdiff
path: root/source/pdf
diff options
context:
space:
mode:
authorPaul Gardiner <paulg.artifex@glidos.net>2013-07-29 11:43:57 +0100
committerPaul Gardiner <paulg.artifex@glidos.net>2013-07-29 11:43:57 +0100
commit0d6739f742310aee9e3aa8ca06895849d7e64648 (patch)
tree2dc2825397d8fa6307d1302056f81a3435318329 /source/pdf
parent9eb5dbcb3c884a1573d1a78b00dd345635fec0db (diff)
downloadmupdf-0d6739f742310aee9e3aa8ca06895849d7e64648.tar.xz
Add support for freetext annotations
This initial commit doesn't entirely complete the task: 1) There are a couple of ucs<->winansi conversions left out, 2) The text displayed by the appearance string can slightly overflow the annotation rectangle.
Diffstat (limited to 'source/pdf')
-rw-r--r--source/pdf/pdf-annot.c107
-rw-r--r--source/pdf/pdf-appearance.c100
-rw-r--r--source/pdf/pdf-form.c5
3 files changed, 209 insertions, 3 deletions
diff --git a/source/pdf/pdf-annot.c b/source/pdf/pdf-annot.c
index c21a62d4..c0254756 100644
--- a/source/pdf/pdf-annot.c
+++ b/source/pdf/pdf-annot.c
@@ -926,3 +926,110 @@ pdf_set_ink_annot_list(pdf_document *doc, pdf_annot *annot, fz_point *pts, int *
for (i = 0; i < 3; i++)
pdf_array_push_drop(col, pdf_new_real(doc, color[i]));
}
+
+static void find_free_font_name(pdf_obj *fdict, char *buf, int buf_size)
+{
+ int i;
+
+ /* Find a number X such that /FX doesn't occur as a key in fdict */
+ for (i = 0; 1; i++)
+ {
+ snprintf(buf, buf_size, "F%d", i);
+
+ if (!pdf_dict_gets(fdict, buf))
+ break;
+ }
+}
+
+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])
+{
+ fz_context *ctx = doc->ctx;
+ char nbuf[32];
+ pdf_obj *dr;
+ pdf_obj *form_fonts;
+ pdf_obj *font = NULL;
+ pdf_obj *ref;
+ pdf_font_desc *font_desc = NULL;
+ pdf_da_info da_info;
+ fz_buffer *fzbuf = NULL;
+ fz_matrix ctm;
+
+ fz_invert_matrix(&ctm, &annot->page->ctm);
+
+ dr = pdf_dict_gets(annot->page->me, "Resources");
+ if (!dr)
+ {
+ dr = pdf_new_dict(doc, 1);
+ pdf_dict_putp_drop(annot->page->me, "Resources", dr);
+ }
+
+ /* Ensure the resource dictionary includes a font dict */
+ form_fonts = pdf_dict_gets(dr, "Font");
+ if (!form_fonts)
+ {
+ form_fonts = pdf_new_dict(doc, 1);
+ pdf_dict_puts_drop(dr, "Font", form_fonts);
+ /* form_fonts is still valid if execution continues past the above call */
+ }
+
+ fz_var(fzbuf);
+ fz_var(font);
+ fz_try(ctx)
+ {
+ unsigned char *da_str;
+ int da_len;
+ fz_rect bounds;
+
+ find_free_font_name(form_fonts, nbuf, sizeof(nbuf));
+
+ font = pdf_new_dict(doc, 5);
+ ref = pdf_new_ref(doc, font);
+ pdf_dict_puts_drop(form_fonts, nbuf, ref);
+
+ pdf_dict_puts_drop(font, "Type", pdf_new_name(doc, "Font"));
+ pdf_dict_puts_drop(font, "Subtype", pdf_new_name(doc, "Type1"));
+ pdf_dict_puts_drop(font, "BaseFont", pdf_new_name(doc, font_name));
+ pdf_dict_puts_drop(font, "Encoding", pdf_new_name(doc, "WinAnsiEncoding"));
+
+ memcpy(da_info.col, color, sizeof(float)*3);
+ da_info.col_size = 3;
+ da_info.font_name = nbuf;
+ da_info.font_size = font_size;
+
+ fzbuf = fz_new_buffer(ctx, 0);
+ pdf_fzbuf_print_da(ctx, fzbuf, &da_info);
+
+ da_len = fz_buffer_storage(ctx, fzbuf, &da_str);
+ pdf_dict_puts_drop(annot->obj, "DA", pdf_new_string(doc, (char *)da_str, da_len));
+
+ /* FIXME: should convert to WinAnsiEncoding */
+ pdf_dict_puts_drop(annot->obj, "Contents", pdf_new_string(doc, text, strlen(text)));
+
+ font_desc = pdf_load_font(doc, NULL, font, 0);
+ pdf_measure_text(ctx, font_desc, (unsigned char *)text, strlen(text), &bounds);
+
+ bounds.x0 *= font_size;
+ bounds.x1 *= font_size;
+ bounds.y0 *= font_size;
+ bounds.y1 *= font_size;
+
+ bounds.x0 += pos->x;
+ bounds.x1 += pos->x;
+ bounds.y0 += pos->y;
+ bounds.y1 += pos->y;
+ fz_transform_rect(&bounds, &ctm);
+
+ pdf_dict_puts_drop(annot->obj, "Rect", pdf_new_rect(doc, &bounds));
+ update_rect(ctx, annot);
+ }
+ fz_always(ctx)
+ {
+ pdf_drop_obj(font);
+ fz_drop_buffer(ctx, fzbuf);
+ pdf_drop_font(ctx, font_desc);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+}
diff --git a/source/pdf/pdf-appearance.c b/source/pdf/pdf-appearance.c
index ffddddc6..e7c3190d 100644
--- a/source/pdf/pdf-appearance.c
+++ b/source/pdf/pdf-appearance.c
@@ -1,5 +1,9 @@
#include "mupdf/pdf.h"
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_ADVANCES_H
+
#define MATRIX_COEFS (6)
#define STRIKE_HEIGHT (0.375f)
#define UNDERLINE_HEIGHT (0.075f)
@@ -1545,15 +1549,16 @@ void pdf_set_ink_appearance(pdf_document *doc, pdf_annot *annot)
fz_stroke_state *stroke = NULL;
fz_device *dev = NULL;
fz_display_list *strike_list = NULL;
+ fz_colorspace *cs = NULL;
fz_var(path);
fz_var(stroke);
fz_var(dev);
fz_var(strike_list);
+ fz_var(cs);
fz_try(ctx)
{
fz_rect rect = fz_empty_rect;
- fz_colorspace *cs;
float color[4];
float width;
pdf_obj *list;
@@ -1622,6 +1627,7 @@ void pdf_set_ink_appearance(pdf_document *doc, pdf_annot *annot)
}
fz_always(ctx)
{
+ fz_drop_colorspace(ctx, cs);
fz_free_device(dev);
fz_drop_stroke_state(ctx, stroke);
fz_free_path(ctx, path);
@@ -1632,3 +1638,95 @@ void pdf_set_ink_appearance(pdf_document *doc, pdf_annot *annot)
fz_rethrow(ctx);
}
}
+
+static fz_text *layout_text(fz_context *ctx, font_info *font_rec, char *str, float x, float y)
+{
+ fz_matrix tm;
+ fz_font *font = font_rec->font->font;
+ fz_text *text;
+ int mask = FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM;
+
+ fz_scale(&tm, font_rec->da_rec.font_size, font_rec->da_rec.font_size);
+ text = fz_new_text(ctx, font, &tm, 0);
+
+ fz_try(ctx)
+ {
+
+ while (*str)
+ {
+ FT_Fixed adv;
+
+ /* FIXME: convert str from utf8 to WinAnsi */
+ int gid = FT_Get_Char_Index(font->ft_face, *str);
+ fz_add_text(ctx, text, gid, *str, x, y);
+
+ FT_Get_Advance(font->ft_face, gid, mask, &adv);
+ x += ((float)adv) * font_rec->da_rec.font_size / ((FT_Face)font->ft_face)->units_per_EM;
+
+ str++;
+ }
+ }
+ fz_catch(ctx)
+ {
+ fz_free_text(ctx, text);
+ fz_rethrow(ctx);
+ }
+
+ return text;
+}
+
+void pdf_update_free_text_annot_appearance(pdf_document *doc, pdf_annot *annot)
+{
+ fz_context *ctx = doc->ctx;
+ const fz_matrix *page_ctm = &annot->page->ctm;
+ pdf_obj *obj = annot->obj;
+ pdf_obj *dr = pdf_dict_getp(annot->page->me, "Resources");
+ fz_display_list *dlist = NULL;
+ fz_device *dev = NULL;
+ font_info font_rec;
+ fz_text *text = NULL;
+ fz_colorspace *cs = NULL;
+
+ memset(&font_rec, 0, sizeof(font_rec));
+
+ fz_var(dlist);
+ fz_var(dev);
+ fz_var(text);
+ fz_var(cs);
+ fz_try(ctx)
+ {
+ char *contents = pdf_to_str_buf(pdf_dict_gets(obj, "Contents"));
+ char *da = pdf_to_str_buf(pdf_dict_gets(obj, "DA"));
+ fz_rect rect = annot->rect;
+
+ get_font_info(doc, dr, da, &font_rec);
+
+ switch (font_rec.da_rec.col_size)
+ {
+ case 1: cs = fz_device_gray(doc->ctx); break;
+ case 3: cs = fz_device_rgb(doc->ctx); break;
+ case 4: cs = fz_device_cmyk(doc->ctx); break;
+ }
+
+ fz_transform_rect(&rect, page_ctm);
+ text = layout_text(ctx, &font_rec, contents, rect.x0, rect.y0);
+
+ dlist = fz_new_display_list(ctx);
+ dev = fz_new_list_device(ctx, dlist);
+ fz_fill_text(dev, text, page_ctm, cs, font_rec.da_rec.col, 1.0f);
+
+ pdf_set_annot_appearance(doc, annot, &annot->rect, dlist);
+ }
+ fz_always(ctx)
+ {
+ fz_free_device(dev);
+ fz_drop_display_list(ctx, dlist);
+ font_info_fin(ctx, &font_rec);
+ fz_free_text(ctx, text);
+ fz_drop_colorspace(ctx, cs);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+}
diff --git a/source/pdf/pdf-form.c b/source/pdf/pdf-form.c
index f6e2f721..1ba2cd82 100644
--- a/source/pdf/pdf-form.c
+++ b/source/pdf/pdf-form.c
@@ -1,7 +1,5 @@
#include "mupdf/pdf.h"
-#define SMALL_FLOAT (0.00001)
-
enum
{
F_Invisible = 1 << (1-1),
@@ -474,6 +472,9 @@ void pdf_update_appearance(pdf_document *doc, pdf_annot *annot)
break;
}
break;
+ case FZ_ANNOT_FREETEXT:
+ pdf_update_free_text_annot_appearance(doc, annot);
+ break;
case FZ_ANNOT_STRIKEOUT:
case FZ_ANNOT_UNDERLINE:
case FZ_ANNOT_HIGHLIGHT: