static int find_destination_pages(fz_context *ctx, pdf_obj *current, int page_num, pdf_obj **dest_pages, int *index) { if(!strcmp(pdf_to_name(ctx, pdf_dict_gets(ctx, current, "Type")), "Page")) { return(--page_num); } if(!strcmp(pdf_to_name(ctx, pdf_dict_gets(ctx, current, "Type")), "Pages")) { pdf_obj *kids = pdf_dict_gets(ctx, current, "Kids"); pdf_obj *count_obj = pdf_dict_gets(ctx, current, "Count"); if(!pdf_is_array(ctx, kids) || !pdf_is_int(ctx, count_obj)) return(-2); int count = pdf_to_int(ctx, count_obj); int i; for(i = 0; i < count; i++) { pdf_obj *current_kid = pdf_array_get(ctx, kids, i); page_num = find_destination_pages(ctx, current_kid, page_num, dest_pages, index); if(page_num == -1) { *index = i; *dest_pages = current; return(-2); } else if(page_num == -2) { return(-2); // just return, preserve index and dest_pages } } return(page_num); } return(page_num); }
pdfout_data * pdfout_data_scalar_from_pdf (fz_context *ctx, pdf_obj *obj) { const char *s; if (pdf_is_null (ctx, obj)) return pdfout_data_scalar_new (ctx, "null", strlen ("null")); else if (pdf_is_bool (ctx, obj)) { if (pdf_to_bool (ctx, obj)) s = "true"; else s = "false"; return pdfout_data_scalar_new (ctx, s, strlen (s)); } else if (pdf_is_name (ctx, obj)) { s = pdf_to_name (ctx, obj); return pdfout_data_scalar_new (ctx, s, strlen (s)); } else if (pdf_is_string (ctx, obj)) { int len; char *str = pdfout_str_obj_to_utf8 (ctx, obj, &len); pdfout_data *result = pdfout_data_scalar_new (ctx, str, len); free (str); return result; } else if (pdf_is_int (ctx, obj)) { int n = pdf_to_int (ctx, obj); char buf[200]; int len = pdfout_snprintf (ctx, buf, "%d", n); return pdfout_data_scalar_new (ctx, buf, len); } else if (pdf_is_real (ctx, obj)) { float f = pdf_to_real (ctx, obj); char buf[200]; int len = pdfout_snprintf (ctx, buf, "%g", f); return pdfout_data_scalar_new (ctx, buf, len); } else abort(); }
static void gathershadings(int page, pdf_obj *pageref, pdf_obj *pageobj, pdf_obj *dict) { int i, n; n = pdf_dict_len(dict); for (i = 0; i < n; i++) { pdf_obj *shade; pdf_obj *type; int k; shade = pdf_dict_get_val(dict, i); if (!pdf_is_dict(shade)) { fz_warn(ctx, "not a shading dict (%d %d R)", pdf_to_num(shade), pdf_to_gen(shade)); continue; } type = pdf_dict_gets(shade, "ShadingType"); if (!pdf_is_int(type) || pdf_to_int(type) < 1 || pdf_to_int(type) > 7) { fz_warn(ctx, "not a shading type (%d %d R)", pdf_to_num(shade), pdf_to_gen(shade)); type = NULL; } for (k = 0; k < shadings; k++) if (!pdf_objcmp(shading[k].u.shading.obj, shade)) break; if (k < shadings) continue; shading = fz_resize_array(ctx, shading, shadings+1, sizeof(struct info)); shadings++; shading[shadings - 1].page = page; shading[shadings - 1].pageref = pageref; shading[shadings - 1].pageobj = pageobj; shading[shadings - 1].u.shading.obj = shade; shading[shadings - 1].u.shading.type = type; } }
pdfout_data * pdfout_page_labels_get (fz_context *ctx, pdf_document *doc) { pdf_obj *trailer = pdf_trailer (ctx, doc); pdf_obj *labels_obj = pdf_dict_getp (ctx, trailer, "Root/PageLabels"); pdf_obj *array = pdf_dict_gets (ctx, labels_obj, "Nums"); if (array && pdf_is_array (ctx, array) == false) pdfout_throw (ctx, "Nums is not an array"); int length = pdf_array_len (ctx, array); pdfout_data *labels = pdfout_data_array_new (ctx); for (int i = 0; i < length / 2; ++i) { pdf_obj *object = pdf_array_get (ctx, array, 2 * i); if (pdf_is_int (ctx, object) == false) pdfout_throw (ctx, "key in number tree not an int"); pdfout_data *hash = pdfout_data_hash_new (ctx); int page = pdf_to_int (ctx, object); if (page < 0) pdfout_throw (ctx, "key in number tree is < 0"); push_int_key (ctx, hash, "page", page); pdf_obj *dict = pdf_array_get (ctx, array, 2 * i + 1); if (pdf_is_dict (ctx, dict) == false) pdfout_throw (ctx, "value in number tree not a dict"); parse_dict (ctx, dict, hash); pdfout_data_array_push (ctx, labels, hash); } return labels; }
pdf_font_desc * pdf_load_type3_font(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict) { char buf[256]; char *estrings[256]; pdf_font_desc *fontdesc = NULL; pdf_obj *encoding; pdf_obj *widths; pdf_obj *charprocs; pdf_obj *obj; int first, last; int i, k, n; fz_rect bbox; fz_matrix matrix; fz_font *font; fz_var(fontdesc); /* Make a new type3 font entry in the document */ if (doc->num_type3_fonts == doc->max_type3_fonts) { int new_max = doc->max_type3_fonts * 2; if (new_max == 0) new_max = 4; doc->type3_fonts = fz_resize_array(ctx, doc->type3_fonts, new_max, sizeof(*doc->type3_fonts)); doc->max_type3_fonts = new_max; } fz_try(ctx) { obj = pdf_dict_get(ctx, dict, PDF_NAME_Name); if (pdf_is_name(ctx, obj)) fz_strlcpy(buf, pdf_to_name(ctx, obj), sizeof buf); else fz_strlcpy(buf, "Unnamed-T3", sizeof buf); fontdesc = pdf_new_font_desc(ctx); obj = pdf_dict_get(ctx, dict, PDF_NAME_FontMatrix); pdf_to_matrix(ctx, obj, &matrix); obj = pdf_dict_get(ctx, dict, PDF_NAME_FontBBox); fz_transform_rect(pdf_to_rect(ctx, obj, &bbox), &matrix); font = fz_new_type3_font(ctx, buf, &matrix); fontdesc->font = font; fontdesc->size += sizeof(fz_font) + 256 * (sizeof(fz_buffer*) + sizeof(float)); fz_set_font_bbox(ctx, font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* Encoding */ for (i = 0; i < 256; i++) estrings[i] = NULL; encoding = pdf_dict_get(ctx, dict, PDF_NAME_Encoding); if (!encoding) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing Encoding"); } if (pdf_is_name(ctx, encoding)) pdf_load_encoding(estrings, pdf_to_name(ctx, encoding)); if (pdf_is_dict(ctx, encoding)) { pdf_obj *base, *diff, *item; base = pdf_dict_get(ctx, encoding, PDF_NAME_BaseEncoding); if (pdf_is_name(ctx, base)) pdf_load_encoding(estrings, pdf_to_name(ctx, base)); diff = pdf_dict_get(ctx, encoding, PDF_NAME_Differences); if (pdf_is_array(ctx, diff)) { n = pdf_array_len(ctx, diff); k = 0; for (i = 0; i < n; i++) { item = pdf_array_get(ctx, diff, i); if (pdf_is_int(ctx, item)) k = pdf_to_int(ctx, item); if (pdf_is_name(ctx, item) && k >= 0 && k < nelem(estrings)) estrings[k++] = pdf_to_name(ctx, item); } } } fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1); fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding); pdf_load_to_unicode(ctx, doc, fontdesc, estrings, NULL, pdf_dict_get(ctx, dict, PDF_NAME_ToUnicode)); /* Widths */ pdf_set_default_hmtx(ctx, fontdesc, 0); first = pdf_to_int(ctx, pdf_dict_get(ctx, dict, PDF_NAME_FirstChar)); last = pdf_to_int(ctx, pdf_dict_get(ctx, dict, PDF_NAME_LastChar)); if (first < 0 || last > 255 || first > last) first = last = 0; widths = pdf_dict_get(ctx, dict, PDF_NAME_Widths); if (!widths) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing Widths"); } for (i = first; i <= last; i++) { float w = pdf_to_real(ctx, pdf_array_get(ctx, widths, i - first)); w = font->t3matrix.a * w * 1000; font->t3widths[i] = w * 0.001f; pdf_add_hmtx(ctx, fontdesc, i, i, w); } pdf_end_hmtx(ctx, fontdesc); /* Resources -- inherit page resources if the font doesn't have its own */ font->t3freeres = pdf_t3_free_resources; font->t3resources = pdf_dict_get(ctx, dict, PDF_NAME_Resources); if (!font->t3resources) font->t3resources = rdb; if (font->t3resources) pdf_keep_obj(ctx, font->t3resources); if (!font->t3resources) fz_warn(ctx, "no resource dictionary for type 3 font!"); font->t3doc = doc; font->t3run = pdf_run_glyph_func; /* CharProcs */ charprocs = pdf_dict_get(ctx, dict, PDF_NAME_CharProcs); if (!charprocs) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing CharProcs"); } for (i = 0; i < 256; i++) { if (estrings[i]) { obj = pdf_dict_gets(ctx, charprocs, estrings[i]); if (pdf_is_stream(ctx, obj)) { font->t3procs[i] = pdf_load_stream(ctx, obj); fz_trim_buffer(ctx, font->t3procs[i]); fontdesc->size += fz_buffer_storage(ctx, font->t3procs[i], NULL); fontdesc->size += 0; // TODO: display list size calculation } } } } fz_catch(ctx) { pdf_drop_font(ctx, fontdesc); fz_rethrow(ctx); } doc->type3_fonts[doc->num_type3_fonts++] = fz_keep_font(ctx, font); return fontdesc; }
/* * Load CMap stream in PDF file */ pdf_cmap * pdf_load_embedded_cmap(pdf_document *doc, pdf_obj *stmobj) { fz_stream *file = NULL; pdf_cmap *cmap = NULL; pdf_cmap *usecmap; pdf_obj *wmode; pdf_obj *obj = NULL; fz_context *ctx = doc->ctx; int phase = 0; fz_var(phase); fz_var(obj); fz_var(file); fz_var(cmap); if (pdf_obj_marked(stmobj)) fz_throw(ctx, FZ_ERROR_GENERIC, "Recursion in embedded cmap"); if ((cmap = pdf_find_item(ctx, pdf_free_cmap_imp, stmobj)) != NULL) { return cmap; } fz_try(ctx) { file = pdf_open_stream(doc, pdf_to_num(stmobj), pdf_to_gen(stmobj)); phase = 1; cmap = pdf_load_cmap(ctx, file); phase = 2; fz_close(file); file = NULL; wmode = pdf_dict_gets(stmobj, "WMode"); if (pdf_is_int(wmode)) pdf_set_cmap_wmode(ctx, cmap, pdf_to_int(wmode)); obj = pdf_dict_gets(stmobj, "UseCMap"); if (pdf_is_name(obj)) { usecmap = pdf_load_system_cmap(ctx, pdf_to_name(obj)); pdf_set_usecmap(ctx, cmap, usecmap); pdf_drop_cmap(ctx, usecmap); } else if (pdf_is_indirect(obj)) { phase = 3; pdf_mark_obj(obj); usecmap = pdf_load_embedded_cmap(doc, obj); pdf_unmark_obj(obj); phase = 4; pdf_set_usecmap(ctx, cmap, usecmap); pdf_drop_cmap(ctx, usecmap); } pdf_store_item(ctx, stmobj, cmap, pdf_cmap_size(ctx, cmap)); } fz_catch(ctx) { if (file) fz_close(file); if (cmap) pdf_drop_cmap(ctx, cmap); if (phase < 1) fz_rethrow_message(ctx, "cannot open cmap stream (%d %d R)", pdf_to_num(stmobj), pdf_to_gen(stmobj)); else if (phase < 2) fz_rethrow_message(ctx, "cannot parse cmap stream (%d %d R)", pdf_to_num(stmobj), pdf_to_gen(stmobj)); else if (phase < 3) fz_rethrow_message(ctx, "cannot load system usecmap '%s'", pdf_to_name(obj)); else { if (phase == 3) pdf_unmark_obj(obj); fz_rethrow_message(ctx, "cannot load embedded usecmap (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj)); } } return cmap; }
static void pdf_process_extgstate(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, pdf_obj *dict) { pdf_obj *obj; obj = pdf_dict_get(ctx, dict, PDF_NAME_LW); if (pdf_is_number(ctx, obj) && proc->op_w) proc->op_w(ctx, proc, pdf_to_real(ctx, obj)); obj = pdf_dict_get(ctx, dict, PDF_NAME_LC); if (pdf_is_int(ctx, obj) && proc->op_J) proc->op_J(ctx, proc, fz_clampi(pdf_to_int(ctx, obj), 0, 2)); obj = pdf_dict_get(ctx, dict, PDF_NAME_LJ); if (pdf_is_int(ctx, obj) && proc->op_j) proc->op_j(ctx, proc, fz_clampi(pdf_to_int(ctx, obj), 0, 2)); obj = pdf_dict_get(ctx, dict, PDF_NAME_ML); if (pdf_is_number(ctx, obj) && proc->op_M) proc->op_M(ctx, proc, pdf_to_real(ctx, obj)); obj = pdf_dict_get(ctx, dict, PDF_NAME_D); if (pdf_is_array(ctx, obj) && proc->op_d) { pdf_obj *dash_array = pdf_array_get(ctx, obj, 0); pdf_obj *dash_phase = pdf_array_get(ctx, obj, 1); proc->op_d(ctx, proc, dash_array, pdf_to_real(ctx, dash_phase)); } obj = pdf_dict_get(ctx, dict, PDF_NAME_RI); if (pdf_is_name(ctx, obj) && proc->op_ri) proc->op_ri(ctx, proc, pdf_to_name(ctx, obj)); obj = pdf_dict_get(ctx, dict, PDF_NAME_FL); if (pdf_is_number(ctx, obj) && proc->op_i) proc->op_i(ctx, proc, pdf_to_real(ctx, obj)); obj = pdf_dict_get(ctx, dict, PDF_NAME_Font); if (pdf_is_array(ctx, obj) && proc->op_Tf) { pdf_obj *font_ref = pdf_array_get(ctx, obj, 0); pdf_obj *font_size = pdf_array_get(ctx, obj, 1); pdf_font_desc *font = load_font_or_hail_mary(ctx, csi->doc, csi->rdb, font_ref, 0, csi->cookie); fz_try(ctx) proc->op_Tf(ctx, proc, "ExtGState", font, pdf_to_real(ctx, font_size)); fz_always(ctx) pdf_drop_font(ctx, font); fz_catch(ctx) fz_rethrow(ctx); } /* transfer functions */ obj = pdf_dict_get(ctx, dict, PDF_NAME_TR2); if (pdf_is_name(ctx, obj)) if (!pdf_name_eq(ctx, obj, PDF_NAME_Identity) && !pdf_name_eq(ctx, obj, PDF_NAME_Default)) fz_warn(ctx, "ignoring transfer function"); if (!obj) /* TR is ignored in the presence of TR2 */ { pdf_obj *tr = pdf_dict_get(ctx, dict, PDF_NAME_TR); if (pdf_is_name(ctx, tr)) if (!pdf_name_eq(ctx, tr, PDF_NAME_Identity)) fz_warn(ctx, "ignoring transfer function"); } /* transparency state */ obj = pdf_dict_get(ctx, dict, PDF_NAME_CA); if (pdf_is_number(ctx, obj) && proc->op_gs_CA) proc->op_gs_CA(ctx, proc, pdf_to_real(ctx, obj)); obj = pdf_dict_get(ctx, dict, PDF_NAME_ca); if (pdf_is_number(ctx, obj) && proc->op_gs_ca) proc->op_gs_ca(ctx, proc, pdf_to_real(ctx, obj)); obj = pdf_dict_get(ctx, dict, PDF_NAME_BM); if (pdf_is_array(ctx, obj)) obj = pdf_array_get(ctx, obj, 0); if (pdf_is_name(ctx, obj) && proc->op_gs_BM) proc->op_gs_BM(ctx, proc, pdf_to_name(ctx, obj)); obj = pdf_dict_get(ctx, dict, PDF_NAME_SMask); if (proc->op_gs_SMask) { if (pdf_is_dict(ctx, obj)) { pdf_xobject *xobj; pdf_obj *group, *s, *bc, *tr; float softmask_bc[FZ_MAX_COLORS]; fz_colorspace *colorspace; int colorspace_n = 1; int k, luminosity; fz_var(xobj); group = pdf_dict_get(ctx, obj, PDF_NAME_G); if (!group) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot load softmask xobject (%d 0 R)", pdf_to_num(ctx, obj)); xobj = pdf_load_xobject(ctx, csi->doc, group); fz_try(ctx) { colorspace = pdf_xobject_colorspace(ctx, xobj); if (colorspace) { colorspace_n = fz_colorspace_n(ctx, colorspace); fz_drop_colorspace(ctx, colorspace); } /* Default background color is black. */ for (k = 0; k < colorspace_n; k++) softmask_bc[k] = 0; /* Which in CMYK means not all zeros! This should really be * a test for subtractive color spaces, but this will have * to do for now. */ if (colorspace == fz_device_cmyk(ctx)) softmask_bc[3] = 1.0; bc = pdf_dict_get(ctx, obj, PDF_NAME_BC); if (pdf_is_array(ctx, bc)) { for (k = 0; k < colorspace_n; k++) softmask_bc[k] = pdf_to_real(ctx, pdf_array_get(ctx, bc, k)); } s = pdf_dict_get(ctx, obj, PDF_NAME_S); if (pdf_name_eq(ctx, s, PDF_NAME_Luminosity)) luminosity = 1; else luminosity = 0; tr = pdf_dict_get(ctx, obj, PDF_NAME_TR); if (tr && !pdf_name_eq(ctx, tr, PDF_NAME_Identity)) fz_warn(ctx, "ignoring transfer function"); proc->op_gs_SMask(ctx, proc, xobj, csi->rdb, softmask_bc, luminosity); } fz_always(ctx) { pdf_drop_xobject(ctx, xobj); } fz_catch(ctx) { fz_rethrow(ctx); } } else if (pdf_is_name(ctx, obj) && pdf_name_eq(ctx, obj, PDF_NAME_None)) { proc->op_gs_SMask(ctx, proc, NULL, NULL, NULL, 0); } }
fz_link_dest pdf_parse_link_dest(pdf_document *xref, pdf_obj *dest) { fz_link_dest ld; pdf_obj *obj; int l_from_2 = 0; int b_from_3 = 0; int r_from_4 = 0; int t_from_5 = 0; int t_from_3 = 0; int t_from_2 = 0; int z_from_4 = 0; dest = resolve_dest(xref, dest); if (dest == NULL || !pdf_is_array(dest)) { ld.kind = FZ_LINK_NONE; return ld; } obj = pdf_array_get(dest, 0); if (pdf_is_int(obj)) ld.ld.gotor.page = pdf_to_int(obj); else ld.ld.gotor.page = pdf_lookup_page_number(xref, obj); ld.kind = FZ_LINK_GOTO; ld.ld.gotor.flags = 0; ld.ld.gotor.lt.x = 0; ld.ld.gotor.lt.y = 0; ld.ld.gotor.rb.x = 0; ld.ld.gotor.rb.y = 0; ld.ld.gotor.file_spec = NULL; ld.ld.gotor.new_window = 0; obj = pdf_array_get(dest, 1); if (!pdf_is_name(obj)) return ld; if (!strcmp("XYZ", pdf_to_name(obj))) { l_from_2 = t_from_3 = z_from_4 = 1; ld.ld.gotor.flags |= fz_link_flag_r_is_zoom; } else if ((!strcmp("Fit", pdf_to_name(obj))) || (!strcmp("FitB", pdf_to_name(obj)))) { ld.ld.gotor.flags |= fz_link_flag_fit_h; ld.ld.gotor.flags |= fz_link_flag_fit_v; } else if ((!strcmp("FitH", pdf_to_name(obj))) || (!strcmp("FitBH", pdf_to_name(obj)))) { t_from_2 = 1; ld.ld.gotor.flags |= fz_link_flag_fit_h; } else if ((!strcmp("FitV", pdf_to_name(obj))) || (!strcmp("FitBV", pdf_to_name(obj)))) { l_from_2 = 1; ld.ld.gotor.flags |= fz_link_flag_fit_v; } else if (!strcmp("FitR", pdf_to_name(obj))) { l_from_2 = b_from_3 = r_from_4 = t_from_5 = 1; ld.ld.gotor.flags |= fz_link_flag_fit_h; ld.ld.gotor.flags |= fz_link_flag_fit_v; } if (l_from_2) { obj = pdf_array_get(dest, 2); if (pdf_is_int(obj)) { ld.ld.gotor.flags |= fz_link_flag_l_valid; ld.ld.gotor.lt.x = pdf_to_int(obj); } else if (pdf_is_real(obj)) { ld.ld.gotor.flags |= fz_link_flag_l_valid; ld.ld.gotor.lt.x = pdf_to_real(obj); } } if (b_from_3) { obj = pdf_array_get(dest, 3); if (pdf_is_int(obj)) { ld.ld.gotor.flags |= fz_link_flag_b_valid; ld.ld.gotor.rb.y = pdf_to_int(obj); } else if (pdf_is_real(obj)) { ld.ld.gotor.flags |= fz_link_flag_b_valid; ld.ld.gotor.rb.y = pdf_to_real(obj); } } if (r_from_4) { obj = pdf_array_get(dest, 4); if (pdf_is_int(obj)) { ld.ld.gotor.flags |= fz_link_flag_r_valid; ld.ld.gotor.rb.x = pdf_to_int(obj); } else if (pdf_is_real(obj)) { ld.ld.gotor.flags |= fz_link_flag_r_valid; ld.ld.gotor.rb.x = pdf_to_real(obj); } } if (t_from_5 || t_from_3 || t_from_2) { if (t_from_5) obj = pdf_array_get(dest, 5); else if (t_from_3) obj = pdf_array_get(dest, 3); else obj = pdf_array_get(dest, 2); if (pdf_is_int(obj)) { ld.ld.gotor.flags |= fz_link_flag_t_valid; ld.ld.gotor.lt.y = pdf_to_int(obj); } else if (pdf_is_real(obj)) { ld.ld.gotor.flags |= fz_link_flag_t_valid; ld.ld.gotor.lt.y = pdf_to_real(obj); } } if (z_from_4) { obj = pdf_array_get(dest, 4); if (pdf_is_int(obj)) { ld.ld.gotor.flags |= fz_link_flag_r_valid; ld.ld.gotor.rb.x = pdf_to_int(obj); } else if (pdf_is_real(obj)) { ld.ld.gotor.flags |= fz_link_flag_r_valid; ld.ld.gotor.rb.x = pdf_to_real(obj); } } /* Duplicate the values out for the sake of stupid clients */ if ((ld.ld.gotor.flags & (fz_link_flag_l_valid | fz_link_flag_r_valid)) == fz_link_flag_l_valid) ld.ld.gotor.rb.x = ld.ld.gotor.lt.x; if ((ld.ld.gotor.flags & (fz_link_flag_l_valid | fz_link_flag_r_valid | fz_link_flag_r_is_zoom)) == fz_link_flag_r_valid) ld.ld.gotor.lt.x = ld.ld.gotor.rb.x; if ((ld.ld.gotor.flags & (fz_link_flag_t_valid | fz_link_flag_b_valid)) == fz_link_flag_t_valid) ld.ld.gotor.rb.y = ld.ld.gotor.lt.y; if ((ld.ld.gotor.flags & (fz_link_flag_t_valid | fz_link_flag_b_valid)) == fz_link_flag_b_valid) ld.ld.gotor.lt.y = ld.ld.gotor.rb.y; return ld; }
int pdf_repair_obj(fz_context *ctx, pdf_document *doc, pdf_lexbuf *buf, fz_off_t *stmofsp, int *stmlenp, pdf_obj **encrypt, pdf_obj **id, pdf_obj **page, fz_off_t *tmpofs, pdf_obj **root) { fz_stream *file = doc->file; pdf_token tok; int stm_len; *stmofsp = 0; if (stmlenp) *stmlenp = -1; stm_len = 0; /* On entry to this function, we know that we've just seen * '<int> <int> obj'. We expect the next thing we see to be a * pdf object. Regardless of the type of thing we meet next * we only need to fully parse it if it is a dictionary. */ tok = pdf_lex(ctx, file, buf); if (tok == PDF_TOK_OPEN_DICT) { pdf_obj *dict, *obj; fz_try(ctx) { dict = pdf_parse_dict(ctx, doc, file, buf); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); /* Don't let a broken object at EOF overwrite a good one */ if (file->eof) fz_rethrow(ctx); /* Silently swallow the error */ dict = pdf_new_dict(ctx, NULL, 2); } /* We must be careful not to try to resolve any indirections * here. We have just read dict, so we know it to be a non * indirected dictionary. Before we look at any values that * we get back from looking up in it, we need to check they * aren't indirected. */ if (encrypt || id || root) { obj = pdf_dict_get(ctx, dict, PDF_NAME_Type); if (!pdf_is_indirect(ctx, obj) && pdf_name_eq(ctx, obj, PDF_NAME_XRef)) { if (encrypt) { obj = pdf_dict_get(ctx, dict, PDF_NAME_Encrypt); if (obj) { pdf_drop_obj(ctx, *encrypt); *encrypt = pdf_keep_obj(ctx, obj); } } if (id) { obj = pdf_dict_get(ctx, dict, PDF_NAME_ID); if (obj) { pdf_drop_obj(ctx, *id); *id = pdf_keep_obj(ctx, obj); } } if (root) *root = pdf_keep_obj(ctx, pdf_dict_get(ctx, dict, PDF_NAME_Root)); } } obj = pdf_dict_get(ctx, dict, PDF_NAME_Length); if (!pdf_is_indirect(ctx, obj) && pdf_is_int(ctx, obj)) stm_len = pdf_to_int(ctx, obj); if (doc->file_reading_linearly && page) { obj = pdf_dict_get(ctx, dict, PDF_NAME_Type); if (!pdf_is_indirect(ctx, obj) && pdf_name_eq(ctx, obj, PDF_NAME_Page)) { pdf_drop_obj(ctx, *page); *page = pdf_keep_obj(ctx, dict); } } pdf_drop_obj(ctx, dict); }
static fz_image * pdf_load_image_imp(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask) { fz_image *image = NULL; pdf_obj *obj, *res; int w, h, bpc, n; int imagemask; int interpolate; int indexed; fz_image *mask = NULL; /* explicit mask/soft mask image */ int use_colorkey = 0; fz_colorspace *colorspace = NULL; float decode[FZ_MAX_COLORS * 2]; int colorkey[FZ_MAX_COLORS * 2]; int stride; int i; fz_compressed_buffer *buffer; /* special case for JPEG2000 images */ if (pdf_is_jpx_image(ctx, dict)) return pdf_load_jpx_imp(ctx, doc, rdb, dict, cstm, forcemask); w = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(Width), PDF_NAME(W))); h = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(Height), PDF_NAME(H))); bpc = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(BitsPerComponent), PDF_NAME(BPC))); if (bpc == 0) bpc = 8; imagemask = pdf_to_bool(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(ImageMask), PDF_NAME(IM))); interpolate = pdf_to_bool(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(Interpolate), PDF_NAME(I))); indexed = 0; use_colorkey = 0; if (imagemask) bpc = 1; if (w <= 0) fz_throw(ctx, FZ_ERROR_GENERIC, "image width is zero (or less)"); if (h <= 0) fz_throw(ctx, FZ_ERROR_GENERIC, "image height is zero (or less)"); if (bpc <= 0) fz_throw(ctx, FZ_ERROR_GENERIC, "image depth is zero (or less)"); if (bpc > 16) fz_throw(ctx, FZ_ERROR_GENERIC, "image depth is too large: %d", bpc); if (w > (1 << 16)) fz_throw(ctx, FZ_ERROR_GENERIC, "image is too wide"); if (h > (1 << 16)) fz_throw(ctx, FZ_ERROR_GENERIC, "image is too high"); fz_var(mask); fz_var(image); fz_var(colorspace); fz_try(ctx) { obj = pdf_dict_geta(ctx, dict, PDF_NAME(ColorSpace), PDF_NAME(CS)); if (obj && !imagemask && !forcemask) { /* colorspace resource lookup is only done for inline images */ if (pdf_is_name(ctx, obj)) { res = pdf_dict_get(ctx, pdf_dict_get(ctx, rdb, PDF_NAME(ColorSpace)), obj); if (res) obj = res; } colorspace = pdf_load_colorspace(ctx, obj); indexed = fz_colorspace_is_indexed(ctx, colorspace); n = fz_colorspace_n(ctx, colorspace); } else { n = 1; } obj = pdf_dict_geta(ctx, dict, PDF_NAME(Decode), PDF_NAME(D)); if (obj) { for (i = 0; i < n * 2; i++) decode[i] = pdf_array_get_real(ctx, obj, i); } else if (fz_colorspace_is_lab(ctx, colorspace) || fz_colorspace_is_lab_icc(ctx, colorspace)) { decode[0] = 0; decode[1] = 100; decode[2] = -128; decode[3] = 127; decode[4] = -128; decode[5] = 127; } else { float maxval = indexed ? (1 << bpc) - 1 : 1; for (i = 0; i < n * 2; i++) decode[i] = i & 1 ? maxval : 0; } obj = pdf_dict_geta(ctx, dict, PDF_NAME(SMask), PDF_NAME(Mask)); if (pdf_is_dict(ctx, obj)) { /* Not allowed for inline images or soft masks */ if (cstm) fz_warn(ctx, "Ignoring invalid inline image soft mask"); else if (forcemask) fz_warn(ctx, "Ignoring recursive image soft mask"); else { mask = pdf_load_image_imp(ctx, doc, rdb, obj, NULL, 1); obj = pdf_dict_get(ctx, obj, PDF_NAME(Matte)); if (pdf_is_array(ctx, obj)) { use_colorkey = 1; for (i = 0; i < n; i++) colorkey[i] = pdf_array_get_real(ctx, obj, i) * 255; } } } else if (pdf_is_array(ctx, obj)) { use_colorkey = 1; for (i = 0; i < n * 2; i++) { if (!pdf_is_int(ctx, pdf_array_get(ctx, obj, i))) { fz_warn(ctx, "invalid value in color key mask"); use_colorkey = 0; } colorkey[i] = pdf_array_get_int(ctx, obj, i); } } /* Do we load from a ref, or do we load an inline stream? */ if (cstm == NULL) { /* Just load the compressed image data now and we can decode it on demand. */ buffer = pdf_load_compressed_stream(ctx, doc, pdf_to_num(ctx, dict)); image = fz_new_image_from_compressed_buffer(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, use_colorkey ? colorkey : NULL, buffer, mask); image->invert_cmyk_jpeg = 0; } else { /* Inline stream */ stride = (w * n * bpc + 7) / 8; image = fz_new_image_from_compressed_buffer(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, use_colorkey ? colorkey : NULL, NULL, mask); image->invert_cmyk_jpeg = 0; pdf_load_compressed_inline_image(ctx, doc, dict, stride * h, cstm, indexed, (fz_compressed_image *)image); } } fz_always(ctx) { fz_drop_colorspace(ctx, colorspace); fz_drop_image(ctx, mask); } fz_catch(ctx) { fz_drop_image(ctx, image); fz_rethrow(ctx); } return image; }
static pdf_image * pdf_load_image_imp(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask) { fz_stream *stm = NULL; pdf_image *image = NULL; pdf_obj *obj, *res; int w, h, bpc, n; int imagemask; int interpolate; int indexed; fz_image *mask = NULL; /* explicit mask/soft mask image */ int usecolorkey; int i; fz_context *ctx = xref->ctx; fz_var(stm); fz_var(mask); image = fz_malloc_struct(ctx, pdf_image); fz_try(ctx) { /* special case for JPEG2000 images */ if (pdf_is_jpx_image(ctx, dict)) { pdf_load_jpx(xref, dict, image, forcemask); if (forcemask) { fz_pixmap *mask_pixmap; if (image->n != 2) fz_throw(ctx, "soft mask must be grayscale"); mask_pixmap = fz_alpha_from_gray(ctx, image->tile, 1); fz_drop_pixmap(ctx, image->tile); image->tile = mask_pixmap; } break; /* Out of fz_try */ } w = pdf_to_int(pdf_dict_getsa(dict, "Width", "W")); h = pdf_to_int(pdf_dict_getsa(dict, "Height", "H")); bpc = pdf_to_int(pdf_dict_getsa(dict, "BitsPerComponent", "BPC")); if (bpc == 0) bpc = 8; imagemask = pdf_to_bool(pdf_dict_getsa(dict, "ImageMask", "IM")); interpolate = pdf_to_bool(pdf_dict_getsa(dict, "Interpolate", "I")); indexed = 0; usecolorkey = 0; mask = NULL; if (imagemask) bpc = 1; if (w <= 0) fz_throw(ctx, "image width is zero (or less)"); if (h <= 0) fz_throw(ctx, "image height is zero (or less)"); if (bpc <= 0) fz_throw(ctx, "image depth is zero (or less)"); if (bpc > 16) fz_throw(ctx, "image depth is too large: %d", bpc); if (w > (1 << 16)) fz_throw(ctx, "image is too wide"); if (h > (1 << 16)) fz_throw(ctx, "image is too high"); obj = pdf_dict_getsa(dict, "ColorSpace", "CS"); if (obj && !imagemask && !forcemask) { /* colorspace resource lookup is only done for inline images */ if (pdf_is_name(obj)) { res = pdf_dict_get(pdf_dict_gets(rdb, "ColorSpace"), obj); if (res) obj = res; } image->base.colorspace = pdf_load_colorspace(xref, obj); if (!strcmp(image->base.colorspace->name, "Indexed")) indexed = 1; n = image->base.colorspace->n; } else { n = 1; } obj = pdf_dict_getsa(dict, "Decode", "D"); if (obj) { for (i = 0; i < n * 2; i++) image->decode[i] = pdf_to_real(pdf_array_get(obj, i)); } else { float maxval = indexed ? (1 << bpc) - 1 : 1; for (i = 0; i < n * 2; i++) image->decode[i] = i & 1 ? maxval : 0; } obj = pdf_dict_getsa(dict, "SMask", "Mask"); if (pdf_is_dict(obj)) { /* Not allowed for inline images or soft masks */ if (cstm) fz_warn(ctx, "Ignoring invalid inline image soft mask"); else if (forcemask) fz_warn(ctx, "Ignoring recursive image soft mask"); else mask = (fz_image *)pdf_load_image_imp(xref, rdb, obj, NULL, 1); } else if (pdf_is_array(obj)) { usecolorkey = 1; for (i = 0; i < n * 2; i++) { if (!pdf_is_int(pdf_array_get(obj, i))) { fz_warn(ctx, "invalid value in color key mask"); usecolorkey = 0; } image->colorkey[i] = pdf_to_int(pdf_array_get(obj, i)); } } /* Now, do we load a ref, or do we load the actual thing? */ FZ_INIT_STORABLE(&image->base, 1, pdf_free_image); image->base.get_pixmap = pdf_image_get_pixmap; image->base.w = w; image->base.h = h; image->base.bpc = bpc; image->n = n; image->interpolate = interpolate; image->imagemask = imagemask; image->usecolorkey = usecolorkey; image->base.mask = mask; if (!cstm) { /* Just load the compressed image data now and we can * decode it on demand. */ int num = pdf_to_num(dict); int gen = pdf_to_gen(dict); image->buffer = pdf_load_compressed_stream(xref, num, gen); break; /* Out of fz_try */ } /* We need to decompress the image now */ if (cstm) { int stride = (w * image->n * image->base.bpc + 7) / 8; stm = pdf_open_inline_stream(xref, dict, stride * h, cstm, NULL); } else { stm = pdf_open_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); } image->tile = decomp_image_from_stream(ctx, stm, image, cstm != NULL, indexed, 0, 0, 0); } fz_catch(ctx) { pdf_free_image(ctx, (fz_storable *) image); fz_rethrow(ctx); } return image; }
char * pdf_parse_link_dest(fz_context *ctx, pdf_document *doc, pdf_obj *dest) { pdf_obj *obj; char buf[256]; const char *ld; int page; int x, y; dest = resolve_dest(ctx, doc, dest); if (dest == NULL) { fz_warn(ctx, "undefined link destination"); return NULL; } if (pdf_is_name(ctx, dest)) { ld = pdf_to_name(ctx, dest); return fz_strdup(ctx, ld); } else if (pdf_is_string(ctx, dest)) { ld = pdf_to_str_buf(ctx, dest); return fz_strdup(ctx, ld); } obj = pdf_array_get(ctx, dest, 0); if (pdf_is_int(ctx, obj)) page = pdf_to_int(ctx, obj); else { fz_try(ctx) page = pdf_lookup_page_number(ctx, doc, obj); fz_catch(ctx) page = -1; } x = y = 0; obj = pdf_array_get(ctx, dest, 1); if (pdf_name_eq(ctx, obj, PDF_NAME_XYZ)) { x = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2)); y = pdf_to_int(ctx, pdf_array_get(ctx, dest, 3)); } else if (pdf_name_eq(ctx, obj, PDF_NAME_FitR)) { x = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2)); y = pdf_to_int(ctx, pdf_array_get(ctx, dest, 5)); } else if (pdf_name_eq(ctx, obj, PDF_NAME_FitH) || pdf_name_eq(ctx, obj, PDF_NAME_FitBH)) y = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2)); else if (pdf_name_eq(ctx, obj, PDF_NAME_FitV) || pdf_name_eq(ctx, obj, PDF_NAME_FitBV)) x = pdf_to_int(ctx, pdf_array_get(ctx, dest, 2)); if (page >= 0) { if (x != 0 || y != 0) fz_snprintf(buf, sizeof buf, "#%d,%d,%d", page + 1, x, y); else fz_snprintf(buf, sizeof buf, "#%d", page + 1); return fz_strdup(ctx, buf); } return NULL; }
/* * Load CMap stream in PDF file */ pdf_cmap * pdf_load_embedded_cmap(fz_context *ctx, pdf_document *doc, pdf_obj *stmobj) { fz_stream *file = NULL; pdf_cmap *cmap = NULL; pdf_cmap *usecmap = NULL; pdf_obj *obj; fz_var(file); fz_var(cmap); fz_var(usecmap); if (pdf_obj_marked(ctx, stmobj)) fz_throw(ctx, FZ_ERROR_GENERIC, "Recursion in embedded cmap"); if ((cmap = pdf_find_item(ctx, pdf_drop_cmap_imp, stmobj)) != NULL) return cmap; fz_try(ctx) { file = pdf_open_stream(ctx, stmobj); cmap = pdf_load_cmap(ctx, file); obj = pdf_dict_get(ctx, stmobj, PDF_NAME_WMode); if (pdf_is_int(ctx, obj)) pdf_set_cmap_wmode(ctx, cmap, pdf_to_int(ctx, obj)); obj = pdf_dict_get(ctx, stmobj, PDF_NAME_UseCMap); if (pdf_is_name(ctx, obj)) { usecmap = pdf_load_system_cmap(ctx, pdf_to_name(ctx, obj)); pdf_set_usecmap(ctx, cmap, usecmap); } else if (pdf_is_indirect(ctx, obj)) { if (pdf_mark_obj(ctx, obj)) fz_throw(ctx, FZ_ERROR_GENERIC, "recursive CMap"); fz_try(ctx) usecmap = pdf_load_embedded_cmap(ctx, doc, obj); fz_always(ctx) pdf_unmark_obj(ctx, obj); fz_catch(ctx) fz_rethrow(ctx); pdf_set_usecmap(ctx, cmap, usecmap); } pdf_store_item(ctx, stmobj, cmap, pdf_cmap_size(ctx, cmap)); } fz_always(ctx) { fz_drop_stream(ctx, file); pdf_drop_cmap(ctx, usecmap); } fz_catch(ctx) { pdf_drop_cmap(ctx, cmap); fz_rethrow(ctx); } return cmap; }
static fz_image * pdf_load_image_imp(pdf_document *doc, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask) { fz_stream *stm = NULL; fz_image *image = NULL; pdf_obj *obj, *res; int w, h, bpc, n; int imagemask; int interpolate; int indexed; fz_image *mask = NULL; /* explicit mask/soft mask image */ int usecolorkey = 0; fz_colorspace *colorspace = NULL; float decode[FZ_MAX_COLORS * 2]; int colorkey[FZ_MAX_COLORS * 2]; int stride; int i; fz_context *ctx = doc->ctx; fz_compressed_buffer *buffer; fz_var(stm); fz_var(mask); fz_var(image); fz_var(colorspace); fz_try(ctx) { /* special case for JPEG2000 images */ if (pdf_is_jpx_image(ctx, dict)) { // image = pdf_load_jpx(doc, dict, forcemask); // // if (forcemask) // { // fz_pixmap *mask_pixmap; // if (image->n != 2) // { // fz_pixmap *gray; // fz_irect bbox; // fz_warn(ctx, "soft mask should be grayscale"); // gray = fz_new_pixmap_with_bbox(ctx, fz_device_gray(ctx), fz_pixmap_bbox(ctx, image->tile, &bbox)); // fz_convert_pixmap(ctx, gray, image->tile); // fz_drop_pixmap(ctx, image->tile); // image->tile = gray; // } // mask_pixmap = fz_alpha_from_gray(ctx, image->tile, 1); // fz_drop_pixmap(ctx, image->tile); // image->tile = mask_pixmap; // } break; /* Out of fz_try */ } w = pdf_to_int(pdf_dict_getsa(dict, "Width", "W")); h = pdf_to_int(pdf_dict_getsa(dict, "Height", "H")); bpc = pdf_to_int(pdf_dict_getsa(dict, "BitsPerComponent", "BPC")); if (bpc == 0) bpc = 8; imagemask = pdf_to_bool(pdf_dict_getsa(dict, "ImageMask", "IM")); interpolate = pdf_to_bool(pdf_dict_getsa(dict, "Interpolate", "I")); indexed = 0; usecolorkey = 0; if (imagemask) bpc = 1; if (w <= 0) fz_throw(ctx, FZ_ERROR_GENERIC, "image width is zero (or less)"); if (h <= 0) fz_throw(ctx, FZ_ERROR_GENERIC, "image height is zero (or less)"); if (bpc <= 0) fz_throw(ctx, FZ_ERROR_GENERIC, "image depth is zero (or less)"); if (bpc > 16) fz_throw(ctx, FZ_ERROR_GENERIC, "image depth is too large: %d", bpc); if (w > (1 << 16)) fz_throw(ctx, FZ_ERROR_GENERIC, "image is too wide"); if (h > (1 << 16)) fz_throw(ctx, FZ_ERROR_GENERIC, "image is too high"); obj = pdf_dict_getsa(dict, "ColorSpace", "CS"); if (obj && !imagemask && !forcemask) { /* colorspace resource lookup is only done for inline images */ if (pdf_is_name(obj)) { res = pdf_dict_get(pdf_dict_gets(rdb, "ColorSpace"), obj); if (res) obj = res; } colorspace = pdf_load_colorspace(doc, obj); indexed = fz_colorspace_is_indexed(colorspace); n = colorspace->n; } else { n = 1; } obj = pdf_dict_getsa(dict, "Decode", "D"); if (obj) { for (i = 0; i < n * 2; i++) decode[i] = pdf_to_real(pdf_array_get(obj, i)); } else { float maxval = indexed ? (1 << bpc) - 1 : 1; for (i = 0; i < n * 2; i++) decode[i] = i & 1 ? maxval : 0; } obj = pdf_dict_getsa(dict, "SMask", "Mask"); if (pdf_is_dict(obj)) { /* Not allowed for inline images or soft masks */ if (cstm) fz_warn(ctx, "Ignoring invalid inline image soft mask"); else if (forcemask) fz_warn(ctx, "Ignoring recursive image soft mask"); else { mask = pdf_load_image_imp(doc, rdb, obj, NULL, 1); obj = pdf_dict_gets(obj, "Matte"); if (pdf_is_array(obj)) { usecolorkey = 1; for (i = 0; i < n; i++) colorkey[i] = pdf_to_real(pdf_array_get(obj, i)) * 255; } } } else if (pdf_is_array(obj)) { usecolorkey = 1; for (i = 0; i < n * 2; i++) { if (!pdf_is_int(pdf_array_get(obj, i))) { fz_warn(ctx, "invalid value in color key mask"); usecolorkey = 0; } colorkey[i] = pdf_to_int(pdf_array_get(obj, i)); } } /* Do we load from a ref, or do we load an inline stream? */ if (cstm == NULL) { /* Just load the compressed image data now and we can * decode it on demand. */ int num = pdf_to_num(dict); int gen = pdf_to_gen(dict); buffer = pdf_load_compressed_stream(doc, num, gen); image = fz_new_image(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, usecolorkey ? colorkey : NULL, buffer, mask); } else { /* Inline stream */ stride = (w * n * bpc + 7) / 8; image = fz_new_image(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, usecolorkey ? colorkey : NULL, NULL, mask); pdf_load_compressed_inline_image(doc, dict, stride * h, cstm, indexed, image); } } fz_catch(ctx) { fz_drop_colorspace(ctx, colorspace); fz_drop_image(ctx, mask); fz_drop_image(ctx, image); fz_rethrow(ctx); } return image; }
static fz_image * pdf_load_image_imp(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask) { fz_stream *stm = NULL; fz_image *image = NULL; pdf_obj *obj, *res; int w, h, bpc, n; int imagemask; int interpolate; int indexed; fz_image *mask = NULL; /* explicit mask/soft mask image */ int usecolorkey = 0; fz_colorspace *colorspace = NULL; float decode[FZ_MAX_COLORS * 2]; int colorkey[FZ_MAX_COLORS * 2]; int i; fz_context *ctx = xref->ctx; fz_var(stm); fz_var(mask); fz_var(image); fz_var(colorspace); fz_try(ctx) { /* special case for JPEG2000 images */ if (pdf_is_jpx_image(ctx, dict)) { image = pdf_load_jpx(xref, dict, forcemask); if (forcemask) { fz_pixmap *mask_pixmap; if (image->n != 2) { /* SumatraPDF: ignore invalid JPX softmasks */ fz_warn(ctx, "soft mask must be grayscale"); mask_pixmap = fz_new_pixmap(ctx, NULL, image->tile->w, image->tile->h); fz_clear_pixmap_with_value(ctx, mask_pixmap, 255); } else mask_pixmap = fz_alpha_from_gray(ctx, image->tile, 1); fz_drop_pixmap(ctx, image->tile); image->tile = mask_pixmap; } break; /* Out of fz_try */ } w = pdf_to_int(pdf_dict_getsa(dict, "Width", "W")); h = pdf_to_int(pdf_dict_getsa(dict, "Height", "H")); bpc = pdf_to_int(pdf_dict_getsa(dict, "BitsPerComponent", "BPC")); if (bpc == 0) bpc = 8; imagemask = pdf_to_bool(pdf_dict_getsa(dict, "ImageMask", "IM")); interpolate = pdf_to_bool(pdf_dict_getsa(dict, "Interpolate", "I")); indexed = 0; usecolorkey = 0; mask = NULL; if (imagemask) bpc = 1; if (w <= 0) fz_throw(ctx, "image width is zero (or less)"); if (h <= 0) fz_throw(ctx, "image height is zero (or less)"); if (bpc <= 0) fz_throw(ctx, "image depth is zero (or less)"); if (bpc > 16) fz_throw(ctx, "image depth is too large: %d", bpc); if (w > (1 << 16)) fz_throw(ctx, "image is too wide"); if (h > (1 << 16)) fz_throw(ctx, "image is too high"); obj = pdf_dict_getsa(dict, "ColorSpace", "CS"); if (obj && !imagemask && !forcemask) { /* colorspace resource lookup is only done for inline images */ if (pdf_is_name(obj)) { res = pdf_dict_get(pdf_dict_gets(rdb, "ColorSpace"), obj); if (res) obj = res; } colorspace = pdf_load_colorspace(xref, obj); if (!strcmp(colorspace->name, "Indexed")) indexed = 1; n = colorspace->n; } else { n = 1; } obj = pdf_dict_getsa(dict, "Decode", "D"); if (obj) { for (i = 0; i < n * 2; i++) decode[i] = pdf_to_real(pdf_array_get(obj, i)); } else { float maxval = indexed ? (1 << bpc) - 1 : 1; for (i = 0; i < n * 2; i++) decode[i] = i & 1 ? maxval : 0; } obj = pdf_dict_getsa(dict, "SMask", "Mask"); if (pdf_is_dict(obj)) { /* Not allowed for inline images or soft masks */ if (cstm) fz_warn(ctx, "Ignoring invalid inline image soft mask"); else if (forcemask) fz_warn(ctx, "Ignoring recursive image soft mask"); else mask = pdf_load_image_imp(xref, rdb, obj, NULL, 1); } else if (pdf_is_array(obj)) { usecolorkey = 1; for (i = 0; i < n * 2; i++) { if (!pdf_is_int(pdf_array_get(obj, i))) { fz_warn(ctx, "invalid value in color key mask"); usecolorkey = 0; } colorkey[i] = pdf_to_int(pdf_array_get(obj, i)); } } /* Now, do we load a ref, or do we load the actual thing? */ if (!cstm) { /* Just load the compressed image data now and we can * decode it on demand. */ int num = pdf_to_num(dict); int gen = pdf_to_gen(dict); fz_compressed_buffer *buffer = pdf_load_compressed_stream(xref, num, gen); image = fz_new_image(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, usecolorkey ? colorkey : NULL, buffer, mask); break; /* Out of fz_try */ } /* We need to decompress the image now */ if (cstm) { int stride = (w * n * bpc + 7) / 8; stm = pdf_open_inline_stream(xref, dict, stride * h, cstm, NULL); } else { stm = pdf_open_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); } image = fz_new_image(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, usecolorkey ? colorkey : NULL, NULL, mask); image->tile = fz_decomp_image_from_stream(ctx, stm, image, cstm != NULL, indexed, 0, 0); } fz_catch(ctx) { /* SumatraPDF: fix memory leak */ if (!image) fz_drop_colorspace(ctx, colorspace); else fz_drop_image(ctx, image); fz_rethrow(ctx); } /* cf. http://bugs.ghostscript.com/show_bug.cgi?id=693517 */ fz_try(ctx) { obj = pdf_dict_getp(dict, "SMask/Matte"); if (pdf_is_array(obj) && image->mask) { assert(!image->usecolorkey); image->usecolorkey = 2; for (i = 0; i < n; i++) image->colorkey[i] = pdf_to_int(pdf_array_get(obj, i)); } } fz_catch(ctx) { fz_drop_image(ctx, image); fz_rethrow(ctx); } return image; }
pdf_font_desc * pdf_load_type3_font(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict) { char buf[256]; char *estrings[256]; pdf_font_desc *fontdesc = NULL; pdf_obj *encoding; pdf_obj *widths; pdf_obj *charprocs; pdf_obj *obj; int first, last; int i, k, n; fz_rect bbox; fz_matrix matrix; fz_context *ctx = xref->ctx; fz_var(fontdesc); fz_try(ctx) { obj = pdf_dict_gets(dict, "Name"); if (pdf_is_name(obj)) fz_strlcpy(buf, pdf_to_name(obj), sizeof buf); else sprintf(buf, "Unnamed-T3"); fontdesc = pdf_new_font_desc(ctx); obj = pdf_dict_gets(dict, "FontMatrix"); pdf_to_matrix(ctx, obj, &matrix); obj = pdf_dict_gets(dict, "FontBBox"); fz_transform_rect(pdf_to_rect(ctx, obj, &bbox), &matrix); fontdesc->font = fz_new_type3_font(ctx, buf, &matrix); fontdesc->size += sizeof(fz_font) + 256 * (sizeof(fz_buffer*) + sizeof(float)); fz_set_font_bbox(ctx, fontdesc->font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* Encoding */ for (i = 0; i < 256; i++) estrings[i] = NULL; encoding = pdf_dict_gets(dict, "Encoding"); if (!encoding) { fz_throw(ctx, "syntaxerror: Type3 font missing Encoding"); } if (pdf_is_name(encoding)) pdf_load_encoding(estrings, pdf_to_name(encoding)); if (pdf_is_dict(encoding)) { pdf_obj *base, *diff, *item; base = pdf_dict_gets(encoding, "BaseEncoding"); if (pdf_is_name(base)) pdf_load_encoding(estrings, pdf_to_name(base)); diff = pdf_dict_gets(encoding, "Differences"); if (pdf_is_array(diff)) { n = pdf_array_len(diff); k = 0; for (i = 0; i < n; i++) { item = pdf_array_get(diff, i); if (pdf_is_int(item)) k = pdf_to_int(item); if (pdf_is_name(item) && k >= 0 && k < nelem(estrings)) estrings[k++] = pdf_to_name(item); } } } fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1); fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding); pdf_load_to_unicode(xref, fontdesc, estrings, NULL, pdf_dict_gets(dict, "ToUnicode")); /* Widths */ pdf_set_default_hmtx(ctx, fontdesc, 0); first = pdf_to_int(pdf_dict_gets(dict, "FirstChar")); last = pdf_to_int(pdf_dict_gets(dict, "LastChar")); if (first < 0 || last > 255 || first > last) first = last = 0; widths = pdf_dict_gets(dict, "Widths"); if (!widths) { fz_throw(ctx, "syntaxerror: Type3 font missing Widths"); } for (i = first; i <= last; i++) { float w = pdf_to_real(pdf_array_get(widths, i - first)); w = fontdesc->font->t3matrix.a * w * 1000; fontdesc->font->t3widths[i] = w * 0.001f; pdf_add_hmtx(ctx, fontdesc, i, i, w); } pdf_end_hmtx(ctx, fontdesc); /* Resources -- inherit page resources if the font doesn't have its own */ fontdesc->font->t3freeres = pdf_t3_free_resources; fontdesc->font->t3resources = pdf_dict_gets(dict, "Resources"); if (!fontdesc->font->t3resources) fontdesc->font->t3resources = rdb; if (fontdesc->font->t3resources) pdf_keep_obj(fontdesc->font->t3resources); if (!fontdesc->font->t3resources) fz_warn(ctx, "no resource dictionary for type 3 font!"); fontdesc->font->t3doc = xref; fontdesc->font->t3run = pdf_run_glyph_func; /* CharProcs */ charprocs = pdf_dict_gets(dict, "CharProcs"); if (!charprocs) { fz_throw(ctx, "syntaxerror: Type3 font missing CharProcs"); } for (i = 0; i < 256; i++) { if (estrings[i]) { obj = pdf_dict_gets(charprocs, estrings[i]); if (pdf_is_stream(xref, pdf_to_num(obj), pdf_to_gen(obj))) { fontdesc->font->t3procs[i] = pdf_load_stream(xref, pdf_to_num(obj), pdf_to_gen(obj)); fontdesc->size += fontdesc->font->t3procs[i]->cap; fontdesc->size += 0; // TODO: display list size calculation } } } } fz_catch(ctx) { if (fontdesc) pdf_drop_font(ctx, fontdesc); fz_throw(ctx, "cannot load type3 font (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } return fontdesc; }
static void gatherpatterns(int page, pdf_obj *pageref, pdf_obj *pageobj, pdf_obj *dict) { int i, n; n = pdf_dict_len(dict); for (i = 0; i < n; i++) { pdf_obj *patterndict; pdf_obj *type; pdf_obj *paint = NULL; pdf_obj *tiling = NULL; pdf_obj *shading = NULL; int k; patterndict = pdf_dict_get_val(dict, i); if (!pdf_is_dict(patterndict)) { fz_warn(ctx, "not a pattern dict (%d %d R)", pdf_to_num(patterndict), pdf_to_gen(patterndict)); continue; } type = pdf_dict_gets(patterndict, "PatternType"); if (!pdf_is_int(type) || pdf_to_int(type) < 1 || pdf_to_int(type) > 2) { fz_warn(ctx, "not a pattern type (%d %d R)", pdf_to_num(patterndict), pdf_to_gen(patterndict)); type = NULL; } if (pdf_to_int(type) == 1) { paint = pdf_dict_gets(patterndict, "PaintType"); if (!pdf_is_int(paint) || pdf_to_int(paint) < 1 || pdf_to_int(paint) > 2) { fz_warn(ctx, "not a pattern paint type (%d %d R)", pdf_to_num(patterndict), pdf_to_gen(patterndict)); paint = NULL; } tiling = pdf_dict_gets(patterndict, "TilingType"); if (!pdf_is_int(tiling) || pdf_to_int(tiling) < 1 || pdf_to_int(tiling) > 3) { fz_warn(ctx, "not a pattern tiling type (%d %d R)", pdf_to_num(patterndict), pdf_to_gen(patterndict)); tiling = NULL; } } else { shading = pdf_dict_gets(patterndict, "Shading"); } for (k = 0; k < patterns; k++) if (!pdf_objcmp(pattern[k].u.pattern.obj, patterndict)) break; if (k < patterns) continue; pattern = fz_resize_array(ctx, pattern, patterns+1, sizeof(struct info)); patterns++; pattern[patterns - 1].page = page; pattern[patterns - 1].pageref = pageref; pattern[patterns - 1].pageobj = pageobj; pattern[patterns - 1].u.pattern.obj = patterndict; pattern[patterns - 1].u.pattern.type = type; pattern[patterns - 1].u.pattern.paint = paint; pattern[patterns - 1].u.pattern.tiling = tiling; pattern[patterns - 1].u.pattern.shading = shading; } }
pdf_font_desc * pdf_load_type3_font(pdf_document *doc, pdf_obj *rdb, pdf_obj *dict) { char buf[256]; char *estrings[256]; pdf_font_desc *fontdesc = NULL; pdf_obj *encoding; pdf_obj *widths; pdf_obj *charprocs; pdf_obj *obj; int first, last; int i, k, n; fz_rect bbox; fz_matrix matrix; fz_context *ctx = doc->ctx; fz_var(fontdesc); /* Make a new type3 font entry in the document */ if (doc->num_type3_fonts == doc->max_type3_fonts) { int new_max = doc->max_type3_fonts * 2; if (new_max == 0) new_max = 4; doc->type3_fonts = fz_resize_array(doc->ctx, doc->type3_fonts, new_max, sizeof(*doc->type3_fonts)); doc->max_type3_fonts = new_max; } fz_try(ctx) { obj = pdf_dict_gets(dict, "Name"); if (pdf_is_name(obj)) fz_strlcpy(buf, pdf_to_name(obj), sizeof buf); else sprintf(buf, "Unnamed-T3"); fontdesc = pdf_new_font_desc(ctx); obj = pdf_dict_gets(dict, "FontMatrix"); pdf_to_matrix(ctx, obj, &matrix); obj = pdf_dict_gets(dict, "FontBBox"); fz_transform_rect(pdf_to_rect(ctx, obj, &bbox), &matrix); fontdesc->font = fz_new_type3_font(ctx, buf, &matrix); fontdesc->size += sizeof(fz_font) + 256 * (sizeof(fz_buffer*) + sizeof(float)); fz_set_font_bbox(ctx, fontdesc->font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* SumatraPDF: expose Type3 FontDescriptor flags */ fontdesc->flags = pdf_to_int(pdf_dict_gets(pdf_dict_gets(dict, "FontDescriptor"), "Flags")); /* Encoding */ for (i = 0; i < 256; i++) estrings[i] = NULL; encoding = pdf_dict_gets(dict, "Encoding"); if (!encoding) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing Encoding"); } if (pdf_is_name(encoding)) pdf_load_encoding(estrings, pdf_to_name(encoding)); if (pdf_is_dict(encoding)) { pdf_obj *base, *diff, *item; base = pdf_dict_gets(encoding, "BaseEncoding"); if (pdf_is_name(base)) pdf_load_encoding(estrings, pdf_to_name(base)); diff = pdf_dict_gets(encoding, "Differences"); if (pdf_is_array(diff)) { n = pdf_array_len(diff); k = 0; for (i = 0; i < n; i++) { item = pdf_array_get(diff, i); if (pdf_is_int(item)) k = pdf_to_int(item); if (pdf_is_name(item) && k >= 0 && k < nelem(estrings)) estrings[k++] = pdf_to_name(item); } } } fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1); fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding); pdf_load_to_unicode(doc, fontdesc, estrings, NULL, pdf_dict_gets(dict, "ToUnicode")); /* SumatraPDF: trying to match Adobe Reader's behavior */ if (!(fontdesc->flags & PDF_FD_SYMBOLIC) && fontdesc->cid_to_ucs_len >= 128) for (i = 32; i < 128; i++) if (fontdesc->cid_to_ucs[i] == '?' || fontdesc->cid_to_ucs[i] == '\0') fontdesc->cid_to_ucs[i] = i; /* Widths */ pdf_set_default_hmtx(ctx, fontdesc, 0); first = pdf_to_int(pdf_dict_gets(dict, "FirstChar")); last = pdf_to_int(pdf_dict_gets(dict, "LastChar")); /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1966 */ if (first >= 256 && last - first < 256) { fz_warn(ctx, "ignoring out-of-bound values for FirstChar/LastChar: %d/%d", first, last); last -= first; first = 0; } if (first < 0 || last > 255 || first > last) first = last = 0; widths = pdf_dict_gets(dict, "Widths"); if (!widths) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing Widths"); } for (i = first; i <= last; i++) { float w = pdf_to_real(pdf_array_get(widths, i - first)); w = fontdesc->font->t3matrix.a * w * 1000; fontdesc->font->t3widths[i] = w * 0.001f; pdf_add_hmtx(ctx, fontdesc, i, i, w); } pdf_end_hmtx(ctx, fontdesc); /* Resources -- inherit page resources if the font doesn't have its own */ fontdesc->font->t3freeres = pdf_t3_free_resources; fontdesc->font->t3resources = pdf_dict_gets(dict, "Resources"); if (!fontdesc->font->t3resources) fontdesc->font->t3resources = rdb; if (fontdesc->font->t3resources) pdf_keep_obj(fontdesc->font->t3resources); if (!fontdesc->font->t3resources) fz_warn(ctx, "no resource dictionary for type 3 font!"); fontdesc->font->t3doc = doc; fontdesc->font->t3run = pdf_run_glyph_func; /* CharProcs */ charprocs = pdf_dict_gets(dict, "CharProcs"); if (!charprocs) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing CharProcs"); } for (i = 0; i < 256; i++) { if (estrings[i]) { /* SumatraPDF: don't reject fonts with few broken glyphs */ fz_try(ctx) { obj = pdf_dict_gets(charprocs, estrings[i]); if (pdf_is_stream(doc, pdf_to_num(obj), pdf_to_gen(obj))) { fontdesc->font->t3procs[i] = pdf_load_stream(doc, pdf_to_num(obj), pdf_to_gen(obj)); fontdesc->size += fontdesc->font->t3procs[i]->cap; fontdesc->size += 0; // TODO: display list size calculation } } fz_catch(ctx) { fz_warn(ctx, "failed to get data for type 3 glyph '%s'", estrings[i]); } } } } fz_catch(ctx) { if (fontdesc) pdf_drop_font(ctx, fontdesc); fz_rethrow_message(ctx, "cannot load type3 font (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } doc->type3_fonts[doc->num_type3_fonts++] = fz_keep_font(ctx, fontdesc->font); return fontdesc; }
static pdf_font_desc * pdf_load_simple_font(pdf_document *xref, pdf_obj *dict) { pdf_obj *descriptor; pdf_obj *encoding; pdf_obj *widths; unsigned short *etable = NULL; pdf_font_desc *fontdesc = NULL; char *subtype; FT_Face face; FT_CharMap cmap; int symbolic; int kind; char *basefont; char *estrings[256]; char ebuffer[256][32]; int i, k, n; int fterr; fz_context *ctx = xref->ctx; fz_var(fontdesc); fz_var(etable); basefont = pdf_to_name(pdf_dict_gets(dict, "BaseFont")); /* Load font file */ fz_try(ctx) { fontdesc = pdf_new_font_desc(ctx); descriptor = pdf_dict_gets(dict, "FontDescriptor"); if (descriptor) pdf_load_font_descriptor(fontdesc, xref, descriptor, NULL, basefont); else pdf_load_builtin_font(ctx, fontdesc, basefont); /* Some chinese documents mistakenly consider WinAnsiEncoding to be codepage 936 */ if (descriptor && pdf_is_string(pdf_dict_gets(descriptor, "FontName")) && !pdf_dict_gets(dict, "ToUnicode") && !strcmp(pdf_to_name(pdf_dict_gets(dict, "Encoding")), "WinAnsiEncoding") && pdf_to_int(pdf_dict_gets(descriptor, "Flags")) == 4) { char *cp936fonts[] = { "\xCB\xCE\xCC\xE5", "SimSun,Regular", "\xBA\xDA\xCC\xE5", "SimHei,Regular", "\xBF\xAC\xCC\xE5_GB2312", "SimKai,Regular", "\xB7\xC2\xCB\xCE_GB2312", "SimFang,Regular", "\xC1\xA5\xCA\xE9", "SimLi,Regular", NULL }; for (i = 0; cp936fonts[i]; i += 2) if (!strcmp(basefont, cp936fonts[i])) break; if (cp936fonts[i]) { fz_warn(ctx, "workaround for S22PDF lying about chinese font encodings"); pdf_drop_font(ctx, fontdesc); fontdesc = pdf_new_font_desc(ctx); pdf_load_font_descriptor(fontdesc, xref, descriptor, "Adobe-GB1", cp936fonts[i+1]); fontdesc->encoding = pdf_load_system_cmap(ctx, "GBK-EUC-H"); fontdesc->to_unicode = pdf_load_system_cmap(ctx, "Adobe-GB1-UCS2"); fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-GB1-UCS2"); face = fontdesc->font->ft_face; kind = ft_kind(face); goto skip_encoding; } } face = fontdesc->font->ft_face; kind = ft_kind(face); /* Encoding */ symbolic = fontdesc->flags & 4; if (face->num_charmaps > 0) cmap = face->charmaps[0]; else cmap = NULL; for (i = 0; i < face->num_charmaps; i++) { FT_CharMap test = face->charmaps[i]; if (kind == TYPE1) { if (test->platform_id == 7) cmap = test; } if (kind == TRUETYPE) { if (test->platform_id == 1 && test->encoding_id == 0) cmap = test; if (test->platform_id == 3 && test->encoding_id == 1) cmap = test; if (symbolic && test->platform_id == 3 && test->encoding_id == 0) cmap = test; } } if (cmap) { fterr = FT_Set_Charmap(face, cmap); if (fterr) fz_warn(ctx, "freetype could not set cmap: %s", ft_error_string(fterr)); } else fz_warn(ctx, "freetype could not find any cmaps"); etable = fz_malloc_array(ctx, 256, sizeof(unsigned short)); fontdesc->size += 256 * sizeof(unsigned short); for (i = 0; i < 256; i++) { estrings[i] = NULL; etable[i] = 0; } encoding = pdf_dict_gets(dict, "Encoding"); if (encoding) { if (pdf_is_name(encoding)) pdf_load_encoding(estrings, pdf_to_name(encoding)); if (pdf_is_dict(encoding)) { pdf_obj *base, *diff, *item; base = pdf_dict_gets(encoding, "BaseEncoding"); if (pdf_is_name(base)) pdf_load_encoding(estrings, pdf_to_name(base)); else if (!fontdesc->is_embedded && !symbolic) pdf_load_encoding(estrings, "StandardEncoding"); diff = pdf_dict_gets(encoding, "Differences"); if (pdf_is_array(diff)) { n = pdf_array_len(diff); k = 0; for (i = 0; i < n; i++) { item = pdf_array_get(diff, i); if (pdf_is_int(item)) k = pdf_to_int(item); if (pdf_is_name(item) && k >= 0 && k < nelem(estrings)) estrings[k++] = pdf_to_name(item); } } } } /* start with the builtin encoding */ for (i = 0; i < 256; i++) etable[i] = ft_char_index(face, i); fz_lock(ctx, FZ_LOCK_FREETYPE); /* built-in and substitute fonts may be a different type than what the document expects */ subtype = pdf_to_name(pdf_dict_gets(dict, "Subtype")); if (!strcmp(subtype, "Type1")) kind = TYPE1; else if (!strcmp(subtype, "MMType1")) kind = TYPE1; else if (!strcmp(subtype, "TrueType")) kind = TRUETYPE; else if (!strcmp(subtype, "CIDFontType0")) kind = TYPE1; else if (!strcmp(subtype, "CIDFontType2")) kind = TRUETYPE; /* encode by glyph name where we can */ if (kind == TYPE1) { for (i = 0; i < 256; i++) { if (estrings[i]) { etable[i] = FT_Get_Name_Index(face, estrings[i]); if (etable[i] == 0) { int aglcode = pdf_lookup_agl(estrings[i]); const char **dupnames = pdf_lookup_agl_duplicates(aglcode); while (*dupnames) { etable[i] = FT_Get_Name_Index(face, (char*)*dupnames); if (etable[i]) break; dupnames++; } } } } } /* encode by glyph name where we can */ if (kind == TRUETYPE) { /* Unicode cmap */ if (!symbolic && face->charmap && face->charmap->platform_id == 3) { for (i = 0; i < 256; i++) { if (estrings[i]) { int aglcode = pdf_lookup_agl(estrings[i]); if (!aglcode) etable[i] = FT_Get_Name_Index(face, estrings[i]); else etable[i] = ft_char_index(face, aglcode); } } } /* MacRoman cmap */ else if (!symbolic && face->charmap && face->charmap->platform_id == 1) { for (i = 0; i < 256; i++) { if (estrings[i]) { k = lookup_mre_code(estrings[i]); if (k <= 0) etable[i] = FT_Get_Name_Index(face, estrings[i]); else etable[i] = ft_char_index(face, k); } } } /* Symbolic cmap */ else if (!face->charmap || face->charmap->encoding != FT_ENCODING_MS_SYMBOL) { for (i = 0; i < 256; i++) { if (estrings[i]) { etable[i] = FT_Get_Name_Index(face, estrings[i]); if (etable[i] == 0) etable[i] = ft_char_index(face, i); } } } } /* try to reverse the glyph names from the builtin encoding */ for (i = 0; i < 256; i++) { if (etable[i] && !estrings[i]) { if (FT_HAS_GLYPH_NAMES(face)) { fterr = FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32); if (fterr) fz_warn(ctx, "freetype get glyph name (gid %d): %s", etable[i], ft_error_string(fterr)); if (ebuffer[i][0]) estrings[i] = ebuffer[i]; } else { estrings[i] = (char*) pdf_win_ansi[i]; /* discard const */ } } } /* symbolic Type 1 fonts with an implicit encoding and non-standard glyph names */ if (kind == TYPE1 && symbolic) { for (i = 0; i < 256; i++) if (etable[i] && estrings[i] && !pdf_lookup_agl(estrings[i])) estrings[i] = (char*) pdf_standard[i]; } fz_unlock(ctx, FZ_LOCK_FREETYPE); fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1); fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding); fontdesc->cid_to_gid_len = 256; fontdesc->cid_to_gid = etable; fz_try(ctx) { pdf_load_to_unicode(xref, fontdesc, estrings, NULL, pdf_dict_gets(dict, "ToUnicode")); } fz_catch(ctx) { fz_warn(ctx, "cannot load ToUnicode CMap"); } skip_encoding: /* Widths */ pdf_set_default_hmtx(ctx, fontdesc, fontdesc->missing_width); widths = pdf_dict_gets(dict, "Widths"); if (widths) { int first, last; first = pdf_to_int(pdf_dict_gets(dict, "FirstChar")); last = pdf_to_int(pdf_dict_gets(dict, "LastChar")); if (first < 0 || last > 255 || first > last) first = last = 0; for (i = 0; i < last - first + 1; i++) { int wid = pdf_to_int(pdf_array_get(widths, i)); pdf_add_hmtx(ctx, fontdesc, i + first, i + first, wid); } } else { fz_lock(ctx, FZ_LOCK_FREETYPE); fterr = FT_Set_Char_Size(face, 1000, 1000, 72, 72); if (fterr) fz_warn(ctx, "freetype set character size: %s", ft_error_string(fterr)); for (i = 0; i < 256; i++) { pdf_add_hmtx(ctx, fontdesc, i, i, ft_width(ctx, fontdesc, i)); } fz_unlock(ctx, FZ_LOCK_FREETYPE); } pdf_end_hmtx(ctx, fontdesc); } fz_catch(ctx) { if (fontdesc && etable != fontdesc->cid_to_gid) fz_free(ctx, etable); pdf_drop_font(ctx, fontdesc); fz_throw(ctx, "cannot load simple font (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } return fontdesc; }
char * pdf_parse_link_dest(fz_context *ctx, pdf_document *doc, pdf_obj *dest) { pdf_obj *obj, *pageobj; fz_rect mediabox; fz_matrix pagectm; const char *ld; int page, x, y, h; dest = resolve_dest(ctx, doc, dest); if (dest == NULL) { fz_warn(ctx, "undefined link destination"); return NULL; } if (pdf_is_name(ctx, dest)) { ld = pdf_to_name(ctx, dest); return fz_strdup(ctx, ld); } else if (pdf_is_string(ctx, dest)) { ld = pdf_to_str_buf(ctx, dest); return fz_strdup(ctx, ld); } pageobj = pdf_array_get(ctx, dest, 0); if (pdf_is_int(ctx, pageobj)) { page = pdf_to_int(ctx, pageobj); pageobj = pdf_lookup_page_obj(ctx, doc, page); } else { fz_try(ctx) page = pdf_lookup_page_number(ctx, doc, pageobj); fz_catch(ctx) page = -1; } if (page < 0) return NULL; obj = pdf_array_get(ctx, dest, 1); if (obj) { /* Link coords use a coordinate space that does not seem to respect Rotate or UserUnit. */ /* All we need to do is figure out the page height to flip the coordinate space. */ pdf_page_obj_transform(ctx, pageobj, &mediabox, &pagectm); mediabox = fz_transform_rect(mediabox, pagectm); h = mediabox.y1 - mediabox.y0; if (pdf_name_eq(ctx, obj, PDF_NAME(XYZ))) { x = pdf_array_get_int(ctx, dest, 2); y = h - pdf_array_get_int(ctx, dest, 3); } else if (pdf_name_eq(ctx, obj, PDF_NAME(FitR))) { x = pdf_array_get_int(ctx, dest, 2); y = h - pdf_array_get_int(ctx, dest, 5); } else if (pdf_name_eq(ctx, obj, PDF_NAME(FitH)) || pdf_name_eq(ctx, obj, PDF_NAME(FitBH))) { x = 0; y = h - pdf_array_get_int(ctx, dest, 2); } else if (pdf_name_eq(ctx, obj, PDF_NAME(FitV)) || pdf_name_eq(ctx, obj, PDF_NAME(FitBV))) { x = pdf_array_get_int(ctx, dest, 2); y = 0; } else { x = 0; y = 0; } return fz_asprintf(ctx, "#%d,%d,%d", page + 1, x, y); } return fz_asprintf(ctx, "#%d", page + 1); }