diff options
author | Paul Gardiner <paulg.artifex@glidos.net> | 2013-07-29 11:43:57 +0100 |
---|---|---|
committer | Paul Gardiner <paulg.artifex@glidos.net> | 2013-07-29 11:43:57 +0100 |
commit | 0d6739f742310aee9e3aa8ca06895849d7e64648 (patch) | |
tree | 2dc2825397d8fa6307d1302056f81a3435318329 /source/pdf | |
parent | 9eb5dbcb3c884a1573d1a78b00dd345635fec0db (diff) | |
download | mupdf-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.c | 107 | ||||
-rw-r--r-- | source/pdf/pdf-appearance.c | 100 | ||||
-rw-r--r-- | source/pdf/pdf-form.c | 5 |
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: |