static int make_fake_doc(pdfapp_t *app) { fz_context *ctx = app->ctx; pdf_document *pdf = NULL; fz_buffer *contents = NULL; pdf_obj *page_obj = NULL; fz_var(contents); fz_var(page_obj); fz_try(ctx) { fz_rect mediabox = { 0, 0, app->winw, app->winh }; int i; pdf = pdf_create_document(ctx); contents = fz_new_buffer(ctx, 100); fz_append_printf(ctx, contents, "1 0 0 RG %g w 0 0 m %g %g l 0 %g m %g 0 l s\n", fz_min(mediabox.x1, mediabox.y1) / 20, mediabox.x1, mediabox.y1, mediabox.y1, mediabox.x1); /* Create enough copies of our blank(ish) page so that the * page number is preserved if and when a subsequent load * works. */ page_obj = pdf_add_page(ctx, pdf, &mediabox, 0, NULL, contents); for (i = 0; i < app->pagecount; i++) pdf_insert_page(ctx, pdf, -1, page_obj); } fz_always(ctx) { pdf_drop_obj(ctx, page_obj); fz_drop_buffer(ctx, contents); } fz_catch(ctx) { fz_drop_document(ctx, (fz_document *) pdf); return 1; } app->doc = (fz_document*)pdf; return 0; }
void fz_drop_font(fz_context *ctx, fz_font *font) { int fterr; int i, drop; fz_lock(ctx, FZ_LOCK_ALLOC); drop = (font && --font->refs == 0); fz_unlock(ctx, FZ_LOCK_ALLOC); if (!drop) return; if (font->t3procs) { if (font->t3resources) font->t3freeres(font->t3doc, font->t3resources); for (i = 0; i < 256; i++) { if (font->t3procs[i]) fz_drop_buffer(ctx, font->t3procs[i]); if (font->t3lists[i]) fz_free_display_list(ctx, font->t3lists[i]); } fz_free(ctx, font->t3procs); fz_free(ctx, font->t3lists); fz_free(ctx, font->t3widths); fz_free(ctx, font->t3flags); } if (font->ft_face) { fz_lock(ctx, FZ_LOCK_FREETYPE); fterr = FT_Done_Face((FT_Face)font->ft_face); fz_unlock(ctx, FZ_LOCK_FREETYPE); if (fterr) fz_warn(ctx, "freetype finalizing face: %s", ft_error_string(fterr)); fz_drop_freetype(ctx); } fz_free(ctx, font->ft_file); fz_free(ctx, font->ft_data); fz_free(ctx, font->bbox_table); fz_free(ctx, font->width_table); fz_free(ctx, font); }
void pdfapp_open_progressive(pdfapp_t *app, char *filename, int reload, int bps) { fz_context *ctx = app->ctx; char *password = ""; pdf_document *idoc; fz_try(ctx) { fz_register_document_handlers(ctx); if (app->layout_css) { fz_buffer *buf = fz_read_file(ctx, app->layout_css); fz_set_user_css(ctx, fz_string_from_buffer(ctx, buf)); fz_drop_buffer(ctx, buf); } fz_set_use_document_css(ctx, app->layout_use_doc_css); #ifdef HAVE_CURL if (!strncmp(filename, "http://", 7) || !strncmp(filename, "https://", 8)) { app->stream = fz_stream_from_curl(ctx, filename, pdfapp_more_data, app); while (1) { fz_try(ctx) { fz_seek(ctx, app->stream, 0, SEEK_SET); app->doc = fz_open_document_with_stream(ctx, filename, app->stream); } fz_catch(ctx) { if (fz_caught(ctx) == FZ_ERROR_TRYLATER) { pdfapp_warn(app, "not enough data to open yet"); continue; } fz_rethrow(ctx); } break; } } else #endif if (bps == 0)
static void svg_dev_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, fz_colorspace *colorspace, float *color, float alpha) { svg_device *sdev = (svg_device*)dev; fz_output *out; fz_matrix local_ctm = *ctm; fz_matrix scale = { 0 }; int mask = sdev->id++; scale.a = 1.0f / image->w; scale.d = 1.0f / image->h; fz_concat(&local_ctm, &scale, ctm); out = start_def(ctx, sdev); fz_printf(ctx, out, "<mask id=\"ma%d\"><image", mask); fz_printf(ctx, out, " width=\"%dpx\" height=\"%dpx\" xlink:href=\"data:", image->w, image->h); switch (image->buffer == NULL ? FZ_IMAGE_JPX : image->buffer->params.type) { case FZ_IMAGE_JPEG: fz_printf(ctx, out, "image/jpeg;base64,"); send_data_base64(ctx, out, image->buffer->buffer); break; case FZ_IMAGE_PNG: fz_printf(ctx, out, "image/png;base64,"); send_data_base64(ctx, out, image->buffer->buffer); break; default: { fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, image, image->w, image->h); fz_printf(ctx, out, "image/png;base64,"); send_data_base64(ctx, out, buf); fz_drop_buffer(ctx, buf); break; } } fz_printf(ctx, out, "\"/></mask>\n"); out = end_def(ctx, sdev); fz_printf(ctx, out, "<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\"", image->w, image->h); svg_dev_fill_color(ctx, sdev, colorspace, color, alpha); svg_dev_ctm(ctx, sdev, &local_ctm); fz_printf(ctx, out, " mask=\"url(#ma%d)\"/>\n", mask); }
static void svg_dev_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha) { svg_device *sdev = (svg_device*)dev; fz_output *out = sdev->out; fz_rect rect; fz_irect bbox; fz_pixmap *pix; fz_buffer *buf = NULL; fz_var(buf); if (dev->container_len == 0) return; fz_round_rect(&bbox, fz_intersect_rect(fz_bound_shade(ctx, shade, ctm, &rect), &dev->container[dev->container_len-1].scissor)); if (fz_is_empty_irect(&bbox)) return; pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), &bbox); fz_clear_pixmap(ctx, pix); fz_try(ctx) { fz_paint_shade(ctx, shade, ctm, pix, &bbox); buf = fz_new_buffer_from_pixmap_as_png(ctx, pix); if (alpha != 1.0f) fz_printf(ctx, out, "<g opacity=\"%g\">", alpha); fz_printf(ctx, out, "<image x=\"%dpx\" y=\"%dpx\" width=\"%dpx\" height=\"%dpx\" xlink:href=\"data:image/png;base64,", pix->x, pix->y, pix->w, pix->h); send_data_base64(ctx, out, buf); fz_printf(ctx, out, "\"/>\n"); if (alpha != 1.0f) fz_printf(ctx, out, "</g>"); } fz_always(ctx) { fz_drop_buffer(ctx, buf); fz_drop_pixmap(ctx, pix); } fz_catch(ctx) { fz_rethrow(ctx); } }
static fz_css_rule * html_load_css(fz_context *ctx, fz_archive *zip, const char *base_uri, fz_css_rule *css, fz_xml *root) { fz_xml *html, *head, *node; fz_buffer *buf; char path[2048]; fz_var(buf); html = fz_xml_find(root, "html"); head = fz_xml_find_down(html, "head"); for (node = fz_xml_down(head); node; node = fz_xml_next(node)) { if (fz_xml_is_tag(node, "link")) { char *rel = fz_xml_att(node, "rel"); if (rel && !fz_strcasecmp(rel, "stylesheet")) { char *type = fz_xml_att(node, "type"); if ((type && !strcmp(type, "text/css")) || !type) { char *href = fz_xml_att(node, "href"); if (href) { fz_strlcpy(path, base_uri, sizeof path); fz_strlcat(path, "/", sizeof path); fz_strlcat(path, href, sizeof path); fz_urldecode(path); fz_cleanname(path); buf = NULL; fz_try(ctx) { buf = fz_read_archive_entry(ctx, zip, path); fz_write_buffer_byte(ctx, buf, 0); css = fz_parse_css(ctx, css, (char*)buf->data, path); } fz_always(ctx) fz_drop_buffer(ctx, buf); fz_catch(ctx) fz_warn(ctx, "ignoring stylesheet %s", path); } } }
static void svg_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha) { svg_device *sdev = (svg_device*)dev; fz_output *out = sdev->out; fz_compressed_buffer *buffer; fz_matrix local_ctm = *ctm; fz_matrix scale = { 0 }; scale.a = 1.0f / image->w; scale.d = 1.0f / image->h; fz_concat(&local_ctm, &scale, ctm); if (alpha != 1.0f) fz_printf(ctx, out, "<g opacity=\"%g\">", alpha); fz_printf(ctx, out, "<image"); svg_dev_ctm(ctx, sdev, &local_ctm); buffer = fz_compressed_image_buffer(ctx, image); fz_printf(ctx, out, " width=\"%dpx\" height=\"%dpx\" xlink:href=\"data:", image->w, image->h); switch (buffer == NULL ? FZ_IMAGE_JPX : buffer->params.type) { case FZ_IMAGE_JPEG: fz_printf(ctx, out, "image/jpeg;base64,"); send_data_base64(ctx, out, buffer->buffer); break; case FZ_IMAGE_PNG: fz_printf(ctx, out, "image/png;base64,"); send_data_base64(ctx, out, buffer->buffer); break; default: { fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, image); fz_printf(ctx, out, "image/png;base64,"); send_data_base64(ctx, out, buf); fz_drop_buffer(ctx, buf); break; } } fz_printf(ctx, out, "\"/>\n"); if (alpha != 1.0f) fz_printf(ctx, out, "</g>"); }
static fz_document * svg_open_document_with_stream(fz_context *ctx, fz_stream *file) { fz_buffer *buf; fz_document *doc; buf = fz_read_all(ctx, file, 0); fz_try(ctx) { fz_write_buffer_byte(ctx, buf, 0); doc = svg_open_document_with_buffer(ctx, buf); } fz_always(ctx) fz_drop_buffer(ctx, buf); fz_catch(ctx) fz_rethrow(ctx); return doc; }
static char *get_string_or_stream(pdf_document *doc, pdf_obj *obj) { fz_context *ctx = doc->ctx; int len = 0; char *buf = NULL; fz_buffer *strmbuf = NULL; char *text = NULL; fz_var(strmbuf); fz_var(text); fz_try(ctx) { if (pdf_is_string(obj)) { len = pdf_to_str_len(obj); buf = pdf_to_str_buf(obj); } else if (pdf_is_stream(doc, pdf_to_num(obj), pdf_to_gen(obj))) { strmbuf = pdf_load_stream(doc, pdf_to_num(obj), pdf_to_gen(obj)); len = fz_buffer_storage(ctx, strmbuf, (unsigned char **)&buf); } if (buf) { text = fz_malloc(ctx, len+1); memcpy(text, buf, len); text[len] = 0; } } fz_always(ctx) { fz_drop_buffer(ctx, strmbuf); } fz_catch(ctx) { fz_free(ctx, text); fz_rethrow(ctx); } return text; }
static void free_resources(fz_context *ctx, fz_font *font) { int i; if (font->t3resources) { font->t3freeres(font->t3doc, font->t3resources); font->t3resources = NULL; } if (font->t3procs) { for (i = 0; i < 256; i++) if (font->t3procs[i]) fz_drop_buffer(ctx, font->t3procs[i]); } fz_free(ctx, font->t3procs); font->t3procs = NULL; }
static int new_stream_object(pdf_document *xref,fz_context *ctx,char *buf) { int ref; pdf_obj *obj,*len; fz_buffer *fzbuf; ref = pdf_create_object(xref); obj = pdf_new_dict(ctx,1); len=pdf_new_int(ctx,strlen(buf)); pdf_dict_puts(obj,"Length",len); pdf_drop_obj(len); pdf_update_object(xref,ref,obj); pdf_drop_obj(obj); fzbuf=fz_new_buffer(ctx,strlen(buf)); fz_write_buffer(ctx,fzbuf,(unsigned char *)buf,strlen(buf)); pdf_update_stream(xref,ref,fzbuf); fz_drop_buffer(ctx,fzbuf); return(ref); }
/* Return a newly allocated UTF-8 string with the text for a given selection. crlf: If true, write "\r\n" style line endings (otherwise "\n" only). */ char * fz_copy_selection(fz_context *ctx, fz_stext_page *page, fz_point a, fz_point b, int crlf) { struct callbacks cb; fz_buffer *buffer; unsigned char *s; buffer = fz_new_buffer(ctx, 1024); cb.on_char = on_copy_char; cb.on_line = crlf ? on_copy_line_crlf : on_copy_line_lf; cb.arg = buffer; fz_enumerate_selection(ctx, page, a, b, &cb); fz_terminate_buffer(ctx, buffer); fz_buffer_extract(ctx, buffer, &s); /* take over the data */ fz_drop_buffer(ctx, buffer); return (char*)s; }
static xps_part * xps_new_part(fz_context *ctx, xps_document *doc, char *name, fz_buffer *data) { xps_part *part; part = fz_malloc_struct(ctx, xps_part); fz_try(ctx) { part->name = fz_strdup(ctx, name); part->data = data; /* take ownership of buffer */ } fz_catch(ctx) { fz_drop_buffer(ctx, data); fz_free(ctx, part); fz_rethrow(ctx); } return part; }
static void pdf_write_ch_widget_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect, fz_rect *bbox, fz_matrix *matrix, pdf_obj **res) { int ff = pdf_field_flags(ctx, annot->obj); if (ff & PDF_CH_FIELD_IS_COMBO) { /* TODO: Pop-down arrow */ pdf_write_tx_widget_appearance(ctx, annot, buf, rect, bbox, matrix, res, pdf_field_value(ctx, annot->obj), 0); } else { fz_buffer *text = fz_new_buffer(ctx, 1024); fz_try(ctx) { pdf_obj *opt = pdf_dict_get(ctx, annot->obj, PDF_NAME(Opt)); int i = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(TI)); int n = pdf_array_len(ctx, opt); /* TODO: Scrollbar */ /* TODO: Highlight selected items */ if (i < 0) i = 0; for (; i < n; ++i) { pdf_obj *val = pdf_array_get(ctx, opt, i); if (pdf_is_array(ctx, val)) fz_append_string(ctx, text, pdf_array_get_text_string(ctx, val, 1)); else fz_append_string(ctx, text, pdf_to_text_string(ctx, val)); fz_append_byte(ctx, text, '\n'); } pdf_write_tx_widget_appearance(ctx, annot, buf, rect, bbox, matrix, res, fz_string_from_buffer(ctx, text), PDF_TX_FIELD_IS_MULTILINE); } fz_always(ctx) fz_drop_buffer(ctx, text); fz_catch(ctx) fz_rethrow(ctx); } }
static epub_chapter * epub_parse_chapter(fz_context *ctx, epub_document *doc, const char *path) { fz_archive *zip = doc->zip; fz_buffer *buf; epub_chapter *ch; char base_uri[2048]; fz_dirname(base_uri, path, sizeof base_uri); buf = fz_read_archive_entry(ctx, zip, path); fz_write_buffer_byte(ctx, buf, 0); ch = fz_malloc_struct(ctx, epub_chapter); ch->box = fz_parse_html(ctx, doc->set, zip, base_uri, buf, fz_user_css(ctx)); ch->next = NULL; fz_drop_buffer(ctx, buf); return ch; }
static int make_fake_doc(pdfapp_t *app) { fz_context *ctx = app->ctx; pdf_document *pdf = NULL; fz_buffer *contents = NULL; fz_try(ctx) { fz_rect mediabox = { 0, 0, app->winw, app->winh }; pdf_obj *page_obj; int i; contents = fz_new_buffer(ctx, 100); pdf = pdf_create_document(ctx); app->doc = (fz_document*)pdf; fz_buffer_printf(ctx, contents, "1 0 0 rg %f w 0 0 m %f %f l 0 %f m %f 0 l\n", fz_min(mediabox.x1, mediabox.y1) / 4, mediabox.x1, mediabox.y1, mediabox.y1, mediabox.x1); /* Create enough copies of our blank(ish) page so that the * page number is preserved if and when a subsequent load * works. */ page_obj = pdf_add_page(ctx, pdf, &mediabox, 0, contents, NULL); for (i = 0; i < app->pagecount; i++) pdf_insert_page(ctx, pdf, -1, page_obj); pdf_drop_obj(ctx, page_obj); } fz_always(ctx) { fz_drop_buffer(ctx, contents); } fz_catch(ctx) { fz_rethrow(ctx); } return 0; }
fz_buffer * fz_read_all(fz_stream *stm, int initial) { fz_buffer *buf = NULL; int n; fz_context *ctx = stm->ctx; try { if (initial < 1024) initial = 1024; buf = fz_new_buffer(ctx, initial+1); while (1) { if (buf->len == buf->cap) fz_grow_buffer(ctx, buf); if (buf->len >= MIN_BOMB && buf->len / 200 > initial) { throw("compression bomb detected"); } n = fz_read(stm, buf->data + buf->len, buf->cap - buf->len); if (n == 0) break; buf->len += n; } } catch(...) { fz_drop_buffer(ctx, buf); throw(""); } fz_trim_buffer(ctx, buf); return buf; }
static fz_document * htdoc_open_document_with_stream(fz_context *ctx, fz_stream *file) { html_document *doc; fz_buffer *buf; doc = fz_malloc_struct(ctx, html_document); doc->super.close = htdoc_close_document; doc->super.layout = htdoc_layout; doc->super.count_pages = htdoc_count_pages; doc->super.load_page = htdoc_load_page; doc->zip = fz_open_directory(ctx, "."); doc->set = fz_new_html_font_set(ctx); buf = fz_read_all(ctx, file, 0); fz_write_buffer_byte(ctx, buf, 0); doc->box = fz_parse_html(ctx, doc->set, doc->zip, ".", buf, fz_user_css(ctx)); fz_drop_buffer(ctx, buf); return (fz_document*)doc; }
static void epub_parse_ncx(fz_context *ctx, epub_document *doc, const char *path) { fz_archive *zip = doc->zip; fz_buffer *buf; fz_xml *ncx; char base_uri[2048]; unsigned char *data; size_t len; fz_dirname(base_uri, path, sizeof base_uri); buf = fz_read_archive_entry(ctx, zip, path); fz_write_buffer_byte(ctx, buf, 0); len = fz_buffer_storage(ctx, buf, &data); ncx = fz_parse_xml(ctx, data, len, 0); fz_drop_buffer(ctx, buf); doc->outline = epub_parse_ncx_imp(ctx, doc, fz_xml_find_down(ncx, "navMap"), base_uri); fz_drop_xml(ctx, ncx); }
static void do_copy_region(fz_rect *screen_sel, int xofs, int yofs) { fz_buffer *buf; fz_rect page_sel; xofs -= page_tex.x; yofs -= page_tex.y; page_sel.x0 = screen_sel->x0 - xofs; page_sel.y0 = screen_sel->y0 - yofs; page_sel.x1 = screen_sel->x1 - xofs; page_sel.y1 = screen_sel->y1 - yofs; fz_transform_rect(&page_sel, &page_inv_ctm); #ifdef _WIN32 buf = fz_new_buffer_from_page(ctx, page, &page_sel, 1, NULL); #else buf = fz_new_buffer_from_page(ctx, page, &page_sel, 0, NULL); #endif glfwSetClipboardString(window, fz_string_from_buffer(ctx, buf)); fz_drop_buffer(ctx, buf); }
static fz_page * cbz_load_page(fz_context *ctx, fz_document *doc_, int number) { cbz_document *doc = (cbz_document*)doc_; cbz_page *page = NULL; fz_buffer *buf = NULL; if (number < 0 || number >= doc->page_count) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot load page %d", number); fz_var(page); if (doc->arch) buf = fz_read_archive_entry(ctx, doc->arch, doc->page[number]); if (!buf) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot load cbz page"); fz_try(ctx) { page = fz_new_derived_page(ctx, cbz_page); page->super.bound_page = cbz_bound_page; page->super.run_page_contents = cbz_run_page; page->super.drop_page = cbz_drop_page; page->image = fz_new_image_from_buffer(ctx, buf); } fz_always(ctx) { fz_drop_buffer(ctx, buf); } fz_catch(ctx) { fz_drop_page(ctx, (fz_page*)page); fz_rethrow(ctx); } return (fz_page*)page; }
static void generate_image(fz_context *ctx, fz_pool *pool, fz_archive *zip, const char *base_uri, fz_html *box, const char *src) { fz_image *img = NULL; fz_buffer *buf = NULL; char path[2048]; fz_html *flow = box; while (flow->type != BOX_FLOW) flow = flow->up; fz_strlcpy(path, base_uri, sizeof path); fz_strlcat(path, "/", sizeof path); fz_strlcat(path, src, sizeof path); fz_urldecode(path); fz_cleanname(path); fz_var(buf); fz_var(img); fz_try(ctx) { buf = fz_read_archive_entry(ctx, zip, path); img = fz_new_image_from_buffer(ctx, buf); add_flow_image(ctx, pool, flow, &box->style, img); } fz_always(ctx) { fz_drop_buffer(ctx, buf); fz_drop_image(ctx, img); } fz_catch(ctx) { const char *alt = "[image]"; fz_warn(ctx, "html: cannot add image src='%s'", src); add_flow_word(ctx, pool, flow, &box->style, alt, alt + 7); } }
static pdf_font_desc * load_cid_font(pdf_document *xref, pdf_obj *dict, pdf_obj *encoding, pdf_obj *to_unicode) { pdf_obj *widths; pdf_obj *descriptor; pdf_font_desc *fontdesc = NULL; FT_Face face; int kind; char collection[256]; char *basefont; int i, k, fterr; pdf_obj *obj; int dw; fz_context *ctx = xref->ctx; fz_var(fontdesc); fz_try(ctx) { /* Get font name and CID collection */ basefont = pdf_to_name(pdf_dict_gets(dict, "BaseFont")); { pdf_obj *cidinfo; char tmpstr[64]; int tmplen; cidinfo = pdf_dict_gets(dict, "CIDSystemInfo"); if (!cidinfo) fz_throw(ctx, "cid font is missing info"); obj = pdf_dict_gets(cidinfo, "Registry"); tmplen = fz_mini(sizeof tmpstr - 1, pdf_to_str_len(obj)); memcpy(tmpstr, pdf_to_str_buf(obj), tmplen); tmpstr[tmplen] = '\0'; fz_strlcpy(collection, tmpstr, sizeof collection); fz_strlcat(collection, "-", sizeof collection); obj = pdf_dict_gets(cidinfo, "Ordering"); tmplen = fz_mini(sizeof tmpstr - 1, pdf_to_str_len(obj)); memcpy(tmpstr, pdf_to_str_buf(obj), tmplen); tmpstr[tmplen] = '\0'; fz_strlcat(collection, tmpstr, sizeof collection); } /* Load font file */ fontdesc = pdf_new_font_desc(ctx); descriptor = pdf_dict_gets(dict, "FontDescriptor"); if (!descriptor) fz_throw(ctx, "syntaxerror: missing font descriptor"); pdf_load_font_descriptor(fontdesc, xref, descriptor, collection, basefont); face = fontdesc->font->ft_face; kind = ft_kind(face); /* Encoding */ if (pdf_is_name(encoding)) { if (!strcmp(pdf_to_name(encoding), "Identity-H")) fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 2); else if (!strcmp(pdf_to_name(encoding), "Identity-V")) fontdesc->encoding = pdf_new_identity_cmap(ctx, 1, 2); else fontdesc->encoding = pdf_load_system_cmap(ctx, pdf_to_name(encoding)); } else if (pdf_is_indirect(encoding)) { fontdesc->encoding = pdf_load_embedded_cmap(xref, encoding); } else { fz_throw(ctx, "syntaxerror: font missing encoding"); } fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding); pdf_set_font_wmode(ctx, fontdesc, pdf_cmap_wmode(ctx, fontdesc->encoding)); if (kind == TRUETYPE) { pdf_obj *cidtogidmap; cidtogidmap = pdf_dict_gets(dict, "CIDToGIDMap"); if (pdf_is_indirect(cidtogidmap)) { fz_buffer *buf; buf = pdf_load_stream(xref, pdf_to_num(cidtogidmap), pdf_to_gen(cidtogidmap)); fontdesc->cid_to_gid_len = (buf->len) / 2; fontdesc->cid_to_gid = fz_malloc_array(ctx, fontdesc->cid_to_gid_len, sizeof(unsigned short)); fontdesc->size += fontdesc->cid_to_gid_len * sizeof(unsigned short); for (i = 0; i < fontdesc->cid_to_gid_len; i++) fontdesc->cid_to_gid[i] = (buf->data[i * 2] << 8) + buf->data[i * 2 + 1]; fz_drop_buffer(ctx, buf); } /* if truetype font is external, cidtogidmap should not be identity */ /* so we map from cid to unicode and then map that through the (3 1) */ /* unicode cmap to get a glyph id */ else if (fontdesc->font->ft_substitute) { fterr = FT_Select_Charmap(face, ft_encoding_unicode); if (fterr) { fz_throw(ctx, "fonterror: no unicode cmap when emulating CID font: %s", ft_error_string(fterr)); } if (!strcmp(collection, "Adobe-CNS1")) fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-CNS1-UCS2"); else if (!strcmp(collection, "Adobe-GB1")) fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-GB1-UCS2"); else if (!strcmp(collection, "Adobe-Japan1")) fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-Japan1-UCS2"); else if (!strcmp(collection, "Adobe-Japan2")) fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-Japan2-UCS2"); else if (!strcmp(collection, "Adobe-Korea1")) fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-Korea1-UCS2"); } } pdf_load_to_unicode(xref, fontdesc, NULL, collection, to_unicode); /* Horizontal */ dw = 1000; obj = pdf_dict_gets(dict, "DW"); if (obj) dw = pdf_to_int(obj); pdf_set_default_hmtx(ctx, fontdesc, dw); widths = pdf_dict_gets(dict, "W"); if (widths) { int c0, c1, w, n, m; n = pdf_array_len(widths); for (i = 0; i < n; ) { c0 = pdf_to_int(pdf_array_get(widths, i)); obj = pdf_array_get(widths, i + 1); if (pdf_is_array(obj)) { m = pdf_array_len(obj); for (k = 0; k < m; k++) { w = pdf_to_int(pdf_array_get(obj, k)); pdf_add_hmtx(ctx, fontdesc, c0 + k, c0 + k, w); } i += 2; } else { c1 = pdf_to_int(obj); w = pdf_to_int(pdf_array_get(widths, i + 2)); pdf_add_hmtx(ctx, fontdesc, c0, c1, w); i += 3; } } } pdf_end_hmtx(ctx, fontdesc); /* Vertical */ if (pdf_cmap_wmode(ctx, fontdesc->encoding) == 1) { int dw2y = 880; int dw2w = -1000; obj = pdf_dict_gets(dict, "DW2"); if (obj) { dw2y = pdf_to_int(pdf_array_get(obj, 0)); dw2w = pdf_to_int(pdf_array_get(obj, 1)); } pdf_set_default_vmtx(ctx, fontdesc, dw2y, dw2w); widths = pdf_dict_gets(dict, "W2"); if (widths) { int c0, c1, w, x, y, n; n = pdf_array_len(widths); for (i = 0; i < n; ) { c0 = pdf_to_int(pdf_array_get(widths, i)); obj = pdf_array_get(widths, i + 1); if (pdf_is_array(obj)) { int m = pdf_array_len(obj); for (k = 0; k * 3 < m; k ++) { w = pdf_to_int(pdf_array_get(obj, k * 3 + 0)); x = pdf_to_int(pdf_array_get(obj, k * 3 + 1)); y = pdf_to_int(pdf_array_get(obj, k * 3 + 2)); pdf_add_vmtx(ctx, fontdesc, c0 + k, c0 + k, x, y, w); } i += 2; } else { c1 = pdf_to_int(obj); w = pdf_to_int(pdf_array_get(widths, i + 2)); x = pdf_to_int(pdf_array_get(widths, i + 3)); y = pdf_to_int(pdf_array_get(widths, i + 4)); pdf_add_vmtx(ctx, fontdesc, c0, c1, x, y, w); i += 5; } } } pdf_end_vmtx(ctx, fontdesc); } } fz_catch(ctx) { pdf_drop_font(ctx, fontdesc); fz_throw(ctx, "cannot load cid font (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } return fontdesc; }
static void pdf_load_jpx(pdf_document *xref, pdf_obj *dict, pdf_image *image, int forcemask) { fz_buffer *buf = NULL; fz_colorspace *colorspace = NULL; fz_pixmap *img = NULL; pdf_obj *obj; fz_context *ctx = xref->ctx; int indexed = 0; fz_var(img); fz_var(buf); fz_var(colorspace); buf = pdf_load_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); /* FIXME: We can't handle decode arrays for indexed images currently */ fz_try(ctx) { obj = pdf_dict_gets(dict, "ColorSpace"); if (obj) { colorspace = pdf_load_colorspace(xref, obj); indexed = !strcmp(colorspace->name, "Indexed"); } img = fz_load_jpx(ctx, buf->data, buf->len, colorspace, indexed); if (img && colorspace == NULL) colorspace = fz_keep_colorspace(ctx, img->colorspace); fz_drop_buffer(ctx, buf); buf = NULL; obj = pdf_dict_getsa(dict, "SMask", "Mask"); if (pdf_is_dict(obj)) { if (forcemask) fz_warn(ctx, "Ignoring recursive JPX soft mask"); else image->base.mask = (fz_image *)pdf_load_image_imp(xref, NULL, obj, NULL, 1); } obj = pdf_dict_getsa(dict, "Decode", "D"); if (obj && !indexed) { float decode[FZ_MAX_COLORS * 2]; int i; for (i = 0; i < img->n * 2; i++) decode[i] = pdf_to_real(pdf_array_get(obj, i)); fz_decode_tile(img, decode); } } fz_catch(ctx) { if (colorspace) fz_drop_colorspace(ctx, colorspace); fz_drop_buffer(ctx, buf); fz_drop_pixmap(ctx, img); fz_rethrow(ctx); } FZ_INIT_STORABLE(&image->base, 1, pdf_free_image); image->base.get_pixmap = pdf_image_get_pixmap; image->base.w = img->w; image->base.h = img->h; image->base.bpc = 8; image->base.colorspace = colorspace; image->buffer = NULL; image->tile = img; image->n = img->n; image->interpolate = 0; image->imagemask = 0; image->usecolorkey = 0; }
static void pdf_clean_type3(fz_context *ctx, pdf_document *doc, pdf_obj *obj, pdf_obj *orig_res, fz_cookie *cookie, int sanitize, int ascii) { pdf_processor *proc_buffer = NULL; pdf_processor *proc_filter = NULL; pdf_obj *res = NULL; pdf_obj *ref; pdf_obj *charprocs; int i, l; fz_var(res); fz_var(proc_buffer); fz_var(proc_filter); fz_try(ctx) { res = pdf_dict_get(ctx, obj, PDF_NAME(Resources)); if (res) orig_res = res; res = NULL; res = pdf_new_dict(ctx, doc, 1); charprocs = pdf_dict_get(ctx, obj, PDF_NAME(CharProcs)); l = pdf_dict_len(ctx, charprocs); for (i = 0; i < l; i++) { pdf_obj *val = pdf_dict_get_val(ctx, charprocs, i); fz_buffer *buffer = fz_new_buffer(ctx, 1024); fz_try(ctx) { proc_buffer = pdf_new_buffer_processor(ctx, buffer, ascii); if (sanitize) { proc_filter = pdf_new_filter_processor(ctx, doc, proc_buffer, orig_res, res); pdf_process_contents(ctx, proc_filter, doc, orig_res, val, cookie); pdf_close_processor(ctx, proc_filter); } else { pdf_process_contents(ctx, proc_filter, doc, orig_res, val, cookie); } pdf_close_processor(ctx, proc_buffer); pdf_update_stream(ctx, doc, val, buffer, 0); } fz_always(ctx) { pdf_drop_processor(ctx, proc_filter); pdf_drop_processor(ctx, proc_buffer); fz_drop_buffer(ctx, buffer); } fz_catch(ctx) { fz_rethrow(ctx); } } /* ProcSet - no cleaning possible. Inherit this from the old dict. */ pdf_dict_put(ctx, res, PDF_NAME(ProcSet), pdf_dict_get(ctx, orig_res, PDF_NAME(ProcSet))); ref = pdf_add_object(ctx, doc, res); pdf_dict_put_drop(ctx, obj, PDF_NAME(Resources), ref); } fz_always(ctx) { pdf_drop_obj(ctx, res); } fz_catch(ctx) { fz_rethrow(ctx); } }
/* Performs the same task as pdf_clean_page_contents, but with an optional text filter function. text_filter: Function to assess whether a given character should be kept (return 0) or removed (return 1). after_text: Function called after each text object is closed to allow other output to be sent. arg: Opaque value to be passed to callback functions. */ void pdf_filter_page_contents(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_cookie *cookie, pdf_page_contents_process_fn *proc_fn, pdf_text_filter_fn *text_filter, pdf_after_text_object_fn *after_text, void *proc_arg, int sanitize, int ascii) { pdf_processor *proc_buffer = NULL; pdf_processor *proc_filter = NULL; pdf_obj *new_obj = NULL; pdf_obj *new_ref = NULL; pdf_obj *res = NULL; pdf_obj *obj; pdf_obj *contents; pdf_obj *resources; fz_buffer *buffer; fz_var(new_obj); fz_var(new_ref); fz_var(res); fz_var(proc_buffer); fz_var(proc_filter); buffer = fz_new_buffer(ctx, 1024); fz_try(ctx) { contents = pdf_page_contents(ctx, page); resources = pdf_page_resources(ctx, page); proc_buffer = pdf_new_buffer_processor(ctx, buffer, ascii); if (sanitize) { res = pdf_new_dict(ctx, doc, 1); proc_filter = pdf_new_filter_processor_with_text_filter(ctx, doc, proc_buffer, resources, res, text_filter, after_text, proc_arg); pdf_process_contents(ctx, proc_filter, doc, resources, contents, cookie); pdf_close_processor(ctx, proc_filter); } else { res = pdf_keep_obj(ctx, resources); pdf_process_contents(ctx, proc_buffer, doc, resources, contents, cookie); } pdf_close_processor(ctx, proc_buffer); /* Deal with page content stream. */ if (pdf_is_array(ctx, contents)) { /* create a new object to replace the array */ new_obj = pdf_new_dict(ctx, doc, 1); new_ref = pdf_add_object(ctx, doc, new_obj); contents = new_ref; pdf_dict_put(ctx, page->obj, PDF_NAME(Contents), contents); } else { pdf_dict_del(ctx, contents, PDF_NAME(Filter)); pdf_dict_del(ctx, contents, PDF_NAME(DecodeParms)); } pdf_update_stream(ctx, doc, contents, buffer, 0); /* Now deal with resources. The spec allows for Type3 fonts and form * XObjects to omit a resource dictionary and look in the parent. * Avoid that by flattening here as part of the cleaning. This could * conceivably cause changes in rendering, but we don't care. */ /* ExtGState */ obj = pdf_dict_get(ctx, res, PDF_NAME(ExtGState)); if (obj) { int i, l; l = pdf_dict_len(ctx, obj); for (i = 0; i < l; i++) { pdf_obj *o = pdf_dict_get(ctx, pdf_dict_get_val(ctx, obj, i), PDF_NAME(SMask)); if (!o) continue; o = pdf_dict_get(ctx, o, PDF_NAME(G)); if (!o) continue; /* Transparency group XObject */ pdf_clean_stream_object(ctx, doc, o, resources, cookie, 1, text_filter, after_text, proc_arg, sanitize, ascii); } } /* Pattern */ obj = pdf_dict_get(ctx, res, PDF_NAME(Pattern)); if (obj) { int i, l; l = pdf_dict_len(ctx, obj); for (i = 0; i < l; i++) { pdf_obj *pat_res; pdf_obj *pat = pdf_dict_get_val(ctx, obj, i); if (!pat) continue; pat_res = pdf_dict_get(ctx, pat, PDF_NAME(Resources)); if (pat_res == NULL) pat_res = resources; if (pdf_dict_get_int(ctx, pat, PDF_NAME(PatternType)) == 1) pdf_clean_stream_object(ctx, doc, pat, pat_res, cookie, 0, text_filter, after_text, proc_arg, sanitize, ascii); } } /* XObject */ obj = pdf_dict_get(ctx, res, PDF_NAME(XObject)); if (obj) { int i, l; l = pdf_dict_len(ctx, obj); for (i = 0; i < l; i++) { pdf_obj *xobj_res; pdf_obj *xobj = pdf_dict_get_val(ctx, obj, i); if (!xobj) continue; xobj_res = pdf_dict_get(ctx, xobj, PDF_NAME(Resources)); if (xobj_res == NULL) xobj_res = resources; if (pdf_name_eq(ctx, PDF_NAME(Form), pdf_dict_get(ctx, xobj, PDF_NAME(Subtype)))) pdf_clean_stream_object(ctx, doc, xobj, xobj_res, cookie, 1, text_filter, after_text, proc_arg, sanitize, ascii); } } /* Font */ obj = pdf_dict_get(ctx, res, PDF_NAME(Font)); if (obj) { int i, l; l = pdf_dict_len(ctx, obj); for (i = 0; i < l; i++) { pdf_obj *o = pdf_dict_get_val(ctx, obj, i); if (!o) continue; if (pdf_name_eq(ctx, PDF_NAME(Type3), pdf_dict_get(ctx, o, PDF_NAME(Subtype)))) pdf_clean_type3(ctx, doc, o, resources, cookie, sanitize, ascii); } } /* ProcSet - no cleaning possible. Inherit this from the old dict. */ obj = pdf_dict_get(ctx, resources, PDF_NAME(ProcSet)); if (obj) pdf_dict_put(ctx, res, PDF_NAME(ProcSet), obj); /* ColorSpace - no cleaning possible. */ /* Properties - no cleaning possible. */ if (proc_fn) (*proc_fn)(ctx, buffer, res, proc_arg); /* Update resource dictionary */ if (sanitize) { pdf_dict_put(ctx, page->obj, PDF_NAME(Resources), res); } } fz_always(ctx) { pdf_drop_processor(ctx, proc_filter); pdf_drop_processor(ctx, proc_buffer); fz_drop_buffer(ctx, buffer); pdf_drop_obj(ctx, new_obj); pdf_drop_obj(ctx, new_ref); pdf_drop_obj(ctx, res); } fz_catch(ctx) { fz_rethrow(ctx); } }
static void savefont(pdf_obj *dict, int num) { char namebuf[1024]; fz_buffer *buf; pdf_obj *stream = NULL; pdf_obj *obj; char *ext = ""; fz_output *out; char *fontname = "font"; size_t len; unsigned char *data; obj = pdf_dict_get(ctx, dict, PDF_NAME_FontName); if (obj) fontname = pdf_to_name(ctx, obj); obj = pdf_dict_get(ctx, dict, PDF_NAME_FontFile); if (obj) { stream = obj; ext = "pfa"; } obj = pdf_dict_get(ctx, dict, PDF_NAME_FontFile2); if (obj) { stream = obj; ext = "ttf"; } obj = pdf_dict_get(ctx, dict, PDF_NAME_FontFile3); if (obj) { stream = obj; obj = pdf_dict_get(ctx, obj, PDF_NAME_Subtype); if (obj && !pdf_is_name(ctx, obj)) fz_throw(ctx, FZ_ERROR_GENERIC, "invalid font descriptor subtype"); if (pdf_name_eq(ctx, obj, PDF_NAME_Type1C)) ext = "cff"; else if (pdf_name_eq(ctx, obj, PDF_NAME_CIDFontType0C)) ext = "cid"; else if (pdf_name_eq(ctx, obj, PDF_NAME_OpenType)) ext = "otf"; else fz_throw(ctx, FZ_ERROR_GENERIC, "unhandled font type '%s'", pdf_to_name(ctx, obj)); } if (!stream) { fz_warn(ctx, "unhandled font type"); return; } buf = pdf_load_stream(ctx, doc, pdf_to_num(ctx, stream)); len = fz_buffer_storage(ctx, buf, &data); fz_try(ctx) { snprintf(namebuf, sizeof(namebuf), "%s-%04d.%s", fontname, num, ext); printf("extracting font %s\n", namebuf); out = fz_new_output_with_path(ctx, namebuf, 0); fz_try(ctx) fz_write(ctx, out, data, len); fz_always(ctx) fz_drop_output(ctx, out); fz_catch(ctx) fz_rethrow(ctx); } fz_always(ctx) fz_drop_buffer(ctx, buf); fz_catch(ctx) fz_rethrow(ctx); }
fz_font * xps_lookup_font(fz_context *ctx, xps_document *doc, char *base_uri, char *font_uri, char *style_att) { char partname[1024]; char fakename[1024]; char *subfont; int subfontid = 0; xps_part *part; fz_font *font; xps_resolve_url(ctx, doc, partname, base_uri, font_uri, sizeof partname); subfont = strrchr(partname, '#'); if (subfont) { subfontid = atoi(subfont + 1); *subfont = 0; } /* Make a new part name for font with style simulation applied */ fz_strlcpy(fakename, partname, sizeof fakename); if (style_att) { if (!strcmp(style_att, "BoldSimulation")) fz_strlcat(fakename, "#Bold", sizeof fakename); else if (!strcmp(style_att, "ItalicSimulation")) fz_strlcat(fakename, "#Italic", sizeof fakename); else if (!strcmp(style_att, "BoldItalicSimulation")) fz_strlcat(fakename, "#BoldItalic", sizeof fakename); } font = xps_lookup_font_imp(ctx, doc, fakename); if (!font) { fz_buffer *buf = NULL; fz_var(buf); fz_try(ctx) { part = xps_read_part(ctx, doc, partname); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); fz_warn(ctx, "cannot find font resource part '%s'", partname); return NULL; } /* deobfuscate if necessary */ if (strstr(part->name, ".odttf")) xps_deobfuscate_font_resource(ctx, doc, part); if (strstr(part->name, ".ODTTF")) xps_deobfuscate_font_resource(ctx, doc, part); fz_try(ctx) { buf = fz_new_buffer_from_data(ctx, part->data, part->size); /* part->data is now owned by buf */ part->data = NULL; font = fz_new_font_from_buffer(ctx, NULL, buf, subfontid, 1); } fz_always(ctx) { fz_drop_buffer(ctx, buf); xps_drop_part(ctx, doc, part); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); fz_warn(ctx, "cannot load font resource '%s'", partname); return NULL; } if (style_att) { font->ft_bold = !!strstr(style_att, "Bold"); font->ft_italic = !!strstr(style_att, "Italic"); } xps_select_best_font_encoding(ctx, doc, font); xps_insert_font(ctx, doc, fakename, font); }
/* * Read and interleave split parts from a ZIP file. */ xps_part * xps_read_part(fz_context *ctx, xps_document *doc, char *partname) { fz_archive *zip = doc->zip; fz_buffer *buf, *tmp; char path[2048]; unsigned char *data; int size; int count; char *name; int seen_last; name = partname; if (name[0] == '/') name ++; /* All in one piece */ if (fz_has_archive_entry(ctx, zip, name)) { buf = fz_read_archive_entry(ctx, zip, name); } /* Assemble all the pieces */ else { buf = fz_new_buffer(ctx, 512); seen_last = 0; for (count = 0; !seen_last; ++count) { sprintf(path, "%s/[%d].piece", name, count); if (fz_has_archive_entry(ctx, zip, path)) { tmp = fz_read_archive_entry(ctx, zip, path); fz_append_buffer(ctx, buf, tmp); fz_drop_buffer(ctx, tmp); } else { sprintf(path, "%s/[%d].last.piece", name, count); if (fz_has_archive_entry(ctx, zip, path)) { tmp = fz_read_archive_entry(ctx, zip, path); fz_append_buffer(ctx, buf, tmp); fz_drop_buffer(ctx, tmp); seen_last = 1; } else { fz_drop_buffer(ctx, buf); fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find all pieces for part '%s'", partname); } } } } fz_write_buffer_byte(ctx, buf, 0); /* zero-terminate */ /* take over the data */ data = buf->data; /* size doesn't include the added zero-terminator */ size = buf->len - 1; fz_free(ctx, buf); return xps_new_part(ctx, doc, partname, data, size); }
void xps_parse_glyphs(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, char *base_uri, xps_resource *dict, fz_xml *root) { fz_device *dev = doc->dev; fz_xml *node; char *fill_uri; char *opacity_mask_uri; char *bidi_level_att; char *fill_att; char *font_size_att; char *font_uri_att; char *origin_x_att; char *origin_y_att; char *is_sideways_att; char *indices_att; char *unicode_att; char *style_att; char *transform_att; char *clip_att; char *opacity_att; char *opacity_mask_att; char *navigate_uri_att; fz_xml *transform_tag = NULL; fz_xml *clip_tag = NULL; fz_xml *fill_tag = NULL; fz_xml *opacity_mask_tag = NULL; char *fill_opacity_att = NULL; xps_part *part; fz_font *font; char partname[1024]; char fakename[1024]; char *subfont; float font_size = 10; int subfontid = 0; int is_sideways = 0; int bidi_level = 0; fz_text *text; fz_rect area; fz_matrix local_ctm = *ctm; /* * Extract attributes and extended attributes. */ bidi_level_att = fz_xml_att(root, "BidiLevel"); fill_att = fz_xml_att(root, "Fill"); font_size_att = fz_xml_att(root, "FontRenderingEmSize"); font_uri_att = fz_xml_att(root, "FontUri"); origin_x_att = fz_xml_att(root, "OriginX"); origin_y_att = fz_xml_att(root, "OriginY"); is_sideways_att = fz_xml_att(root, "IsSideways"); indices_att = fz_xml_att(root, "Indices"); unicode_att = fz_xml_att(root, "UnicodeString"); style_att = fz_xml_att(root, "StyleSimulations"); transform_att = fz_xml_att(root, "RenderTransform"); clip_att = fz_xml_att(root, "Clip"); opacity_att = fz_xml_att(root, "Opacity"); opacity_mask_att = fz_xml_att(root, "OpacityMask"); navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri"); for (node = fz_xml_down(root); node; node = fz_xml_next(node)) { if (fz_xml_is_tag(node, "Glyphs.RenderTransform")) transform_tag = fz_xml_down(node); if (fz_xml_is_tag(node, "Glyphs.OpacityMask")) opacity_mask_tag = fz_xml_down(node); if (fz_xml_is_tag(node, "Glyphs.Clip")) clip_tag = fz_xml_down(node); if (fz_xml_is_tag(node, "Glyphs.Fill")) fill_tag = fz_xml_down(node); } fill_uri = base_uri; opacity_mask_uri = base_uri; xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL); xps_resolve_resource_reference(ctx, doc, dict, &clip_att, &clip_tag, NULL); xps_resolve_resource_reference(ctx, doc, dict, &fill_att, &fill_tag, &fill_uri); xps_resolve_resource_reference(ctx, doc, dict, &opacity_mask_att, &opacity_mask_tag, &opacity_mask_uri); /* * Check that we have all the necessary information. */ if (!font_size_att || !font_uri_att || !origin_x_att || !origin_y_att) { fz_warn(ctx, "missing attributes in glyphs element"); return; } if (!indices_att && !unicode_att) return; /* nothing to draw */ if (is_sideways_att) is_sideways = !strcmp(is_sideways_att, "true"); if (bidi_level_att) bidi_level = atoi(bidi_level_att); /* * Find and load the font resource */ xps_resolve_url(ctx, doc, partname, base_uri, font_uri_att, sizeof partname); subfont = strrchr(partname, '#'); if (subfont) { subfontid = atoi(subfont + 1); *subfont = 0; } /* Make a new part name for font with style simulation applied */ fz_strlcpy(fakename, partname, sizeof fakename); if (style_att) { if (!strcmp(style_att, "BoldSimulation")) fz_strlcat(fakename, "#Bold", sizeof fakename); else if (!strcmp(style_att, "ItalicSimulation")) fz_strlcat(fakename, "#Italic", sizeof fakename); else if (!strcmp(style_att, "BoldItalicSimulation")) fz_strlcat(fakename, "#BoldItalic", sizeof fakename); } font = xps_lookup_font(ctx, doc, fakename); if (!font) { fz_buffer *buf = NULL; fz_var(buf); fz_try(ctx) { part = xps_read_part(ctx, doc, partname); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); fz_warn(ctx, "cannot find font resource part '%s'", partname); return; } /* deobfuscate if necessary */ if (strstr(part->name, ".odttf")) xps_deobfuscate_font_resource(ctx, doc, part); if (strstr(part->name, ".ODTTF")) xps_deobfuscate_font_resource(ctx, doc, part); fz_try(ctx) { buf = fz_new_buffer_from_data(ctx, part->data, part->size); /* part->data is now owned by buf */ part->data = NULL; font = fz_new_font_from_buffer(ctx, NULL, buf, subfontid, 1); } fz_always(ctx) { fz_drop_buffer(ctx, buf); xps_drop_part(ctx, doc, part); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); fz_warn(ctx, "cannot load font resource '%s'", partname); return; } if (style_att) { font->ft_bold = !!strstr(style_att, "Bold"); font->ft_italic = !!strstr(style_att, "Italic"); } xps_select_best_font_encoding(ctx, doc, font); xps_insert_font(ctx, doc, fakename, font); }