pdf_obj * pdf_to_utf8_name(fz_context *ctx, pdf_document *doc, pdf_obj *src) { char *buf = pdf_to_utf8(ctx, doc, src); pdf_obj *dst = pdf_new_name(ctx, doc, buf); fz_free(ctx, buf); return dst; }
/* Approximated sRGB */ static pdf_obj * create_cspace_sRGB (png_structp png_ptr, png_infop info_ptr) { pdf_obj *colorspace; pdf_obj *cal_param; png_byte color_type; color_type = png_get_color_type(png_ptr, info_ptr); /* Parameters taken from PNG spec. section 4.2.2.3. */ cal_param = make_param_Cal(color_type, 2.2, 0.3127, 0.329, 0.64, 0.33, 0.3, 0.6, 0.15, 0.06); if (!cal_param) return NULL; colorspace = pdf_new_array(); switch (color_type) { case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: case PNG_COLOR_TYPE_PALETTE: pdf_add_array(colorspace, pdf_new_name("CalRGB")); break; case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_GRAY_ALPHA: pdf_add_array(colorspace, pdf_new_name("CalGray")); break; } pdf_add_array(colorspace, cal_param); return colorspace; }
/* * sRGB: * * If sRGB chunk is present, cHRM and gAMA chunk must be ignored. * */ static pdf_obj * get_rendering_intent (png_structp png_ptr, png_infop info_ptr) { pdf_obj *intent; int srgb_intent; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB) && png_get_sRGB (png_ptr, info_ptr, &srgb_intent)) { switch (srgb_intent) { case PNG_sRGB_INTENT_SATURATION: intent = pdf_new_name("Saturation"); break; case PNG_sRGB_INTENT_PERCEPTUAL: intent = pdf_new_name("Perceptual"); break; case PNG_sRGB_INTENT_ABSOLUTE: intent = pdf_new_name("AbsoluteColorimetric"); break; case PNG_sRGB_INTENT_RELATIVE: intent = pdf_new_name("RelativeColorimetric"); break; default: WARN("%s: Invalid value in PNG sRGB chunk: %d", PNG_DEBUG_STR, srgb_intent); intent = NULL; } } else intent = NULL; return intent; }
/* Creates the PDF Encoding entry for the encoding. * If baseenc is non-null, it is used as BaseEncoding entry. */ static pdf_obj * create_encoding_resource (pdf_encoding *encoding, pdf_encoding *baseenc) { pdf_obj *differences; ASSERT(encoding); ASSERT(!encoding->resource); differences = make_encoding_differences(encoding->glyphs, baseenc ? baseenc->glyphs : NULL, encoding->is_used); if (differences) { pdf_obj *resource = pdf_new_dict(); if (baseenc) pdf_add_dict(resource, pdf_new_name("BaseEncoding"), pdf_link_obj(baseenc->resource)); pdf_add_dict(resource, pdf_new_name("Differences"), differences); return resource; } else { /* Fix a bug with the MinionPro package using MnSymbol fonts * in its virtual fonts: * * Some font may have font_id even if no character is used. * For example, suppose that a virtual file A.vf uses two * other fonts, B and C. Even if only characters of B are used * in a DVI document, C will have font_id too. * In this case, both baseenc and differences can be NULL. * * Actually these fonts will be ignored in pdffont.c. */ return baseenc ? pdf_link_obj(baseenc->resource) : NULL; } }
static pdf_obj * create_soft_mask (png_structp png_ptr, png_infop info_ptr, png_bytep image_data_ptr, png_uint_32 width, png_uint_32 height) { pdf_obj *smask, *dict; png_bytep smask_data_ptr; png_bytep trans; int num_trans; png_uint_32 i; if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) || !png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL)) { WARN("%s: PNG does not have valid tRNS chunk but tRNS is requested.", PNG_DEBUG_STR); return NULL; } smask = pdf_new_stream(STREAM_COMPRESS); dict = pdf_stream_dict(smask); smask_data_ptr = (png_bytep) NEW(width*height, png_byte); pdf_add_dict(dict, pdf_new_name("Type"), pdf_new_name("XObject")); pdf_add_dict(dict, pdf_new_name("Subtype"), pdf_new_name("Image")); pdf_add_dict(dict, pdf_new_name("Width"), pdf_new_number(width)); pdf_add_dict(dict, pdf_new_name("Height"), pdf_new_number(height)); pdf_add_dict(dict, pdf_new_name("ColorSpace"), pdf_new_name("DeviceGray")); pdf_add_dict(dict, pdf_new_name("BitsPerComponent"), pdf_new_number(8)); for (i = 0; i < width*height; i++) { png_byte idx = image_data_ptr[i]; smask_data_ptr[i] = (idx < num_trans) ? trans[idx] : 0xff; } pdf_add_stream(smask, (char *)smask_data_ptr, width*height); RELEASE(smask_data_ptr); return smask; }
static void pdf_flush_font (pdf_font *font) { char *fontname, *uniqueTag; if (!font) { return; } if (font->resource && font->reference) { if (font->subtype != PDF_FONT_FONTTYPE_TYPE3) { if (pdf_font_get_flag(font, PDF_FONT_FLAG_NOEMBED)) { pdf_add_dict(font->resource, pdf_new_name("BaseFont"), pdf_new_name(font->fontname)); if (font->descriptor) { pdf_add_dict(font->descriptor, pdf_new_name("FontName"), pdf_new_name(font->fontname)); } } else { if (!font->fontname) { ERROR("Undefined in fontname... (%s)", font->ident); } fontname = NEW(7+strlen(font->fontname)+1, char); uniqueTag = pdf_font_get_uniqueTag(font); sprintf(fontname, "%6s+%s", uniqueTag, font->fontname); pdf_add_dict(font->resource, pdf_new_name("BaseFont"), pdf_new_name(fontname)); if (font->descriptor) { pdf_add_dict(font->descriptor, pdf_new_name("FontName"), pdf_new_name(fontname)); } RELEASE(fontname); } if (font->descriptor) { pdf_add_dict(font->resource, pdf_new_name("FontDescriptor"), pdf_ref_obj(font->descriptor)); } } } if (font->resource) pdf_release_obj(font->resource); if (font->descriptor) pdf_release_obj(font->descriptor); if (font->reference) pdf_release_obj(font->reference); font->reference = NULL; font->resource = NULL; font->descriptor = NULL; return; }
pdf_obj * pdfout_data_scalar_to_pdf_name (fz_context *ctx, pdf_document *doc, pdfout_data *scalar) { const char *s = scalar_get_string (ctx, scalar); return pdf_new_name (ctx, doc, s); }
void pdf_set_annot_icon_name(fz_context *ctx, pdf_annot *annot, const char *name) { pdf_document *doc = annot->page->doc; check_allowed_subtypes(ctx, annot, PDF_NAME_Name, icon_name_subtypes); pdf_dict_put_drop(ctx, annot->obj, PDF_NAME_Name, pdf_new_name(ctx, doc, name)); }
pdf_obj * pdf_parse_stm_obj(pdf_document *doc, fz_stream *file, pdf_lexbuf *buf) { pdf_token tok; fz_context *ctx = file->ctx; tok = pdf_lex(file, buf); switch (tok) { case PDF_TOK_OPEN_ARRAY: return pdf_parse_array(doc, file, buf); case PDF_TOK_OPEN_DICT: return pdf_parse_dict(doc, file, buf); case PDF_TOK_NAME: return pdf_new_name(doc, buf->scratch); break; case PDF_TOK_REAL: return pdf_new_real(doc, buf->f); break; case PDF_TOK_STRING: return pdf_new_string(doc, buf->scratch, buf->len); break; case PDF_TOK_TRUE: return pdf_new_bool(doc, 1); break; case PDF_TOK_FALSE: return pdf_new_bool(doc, 0); break; case PDF_TOK_NULL: return pdf_new_null(doc); break; case PDF_TOK_INT: return pdf_new_int(doc, buf->i); break; default: fz_throw(ctx, FZ_ERROR_GENERIC, "unknown token in object stream"); } return NULL; /* Stupid MSVC */ }
void pdf_new_page_label (pdf_file_handle pdf_file, int page_index, int base, int count, char style, char *prefix) { struct pdf_obj *label_dict; char style_str [2] = { style, '\0' }; if (! pdf_file->page_label_tree) { pdf_file->page_label_tree = pdf_new_name_tree (pdf_file, 1); } label_dict = pdf_new_obj (PT_DICTIONARY); if (style) pdf_set_dict_entry (label_dict, "S", pdf_new_name (style_str)); if (prefix) pdf_set_dict_entry (label_dict, "P", pdf_new_string (prefix)); if (base > 1) pdf_set_dict_entry (label_dict, "St", pdf_new_integer (base)); pdf_add_number_tree_element (pdf_file->page_label_tree, page_index, label_dict); }
pdf_obj * pdf_to_utf8_name(pdf_document *doc, pdf_obj *src) { char *buf = pdf_to_utf8(doc, src); pdf_obj *dst = pdf_new_name(doc, buf); fz_free(doc->ctx, buf); return dst; }
void Type0Font_set_ToUnicode (Type0Font *font, pdf_obj *cmap_ref) { ASSERT(font); pdf_add_dict(font->fontdict, pdf_new_name("ToUnicode"), cmap_ref); }
/* * Set up Indexed ColorSpace for color-type PALETTE: * * PNG allows only RGB color for base color space. If gAMA and/or cHRM * chunk is available, we can use CalRGB color space instead of DeviceRGB * for base color space. * */ static pdf_obj * create_cspace_Indexed (png_structp png_ptr, png_infop info_ptr) { pdf_obj *colorspace; pdf_obj *base, *lookup; png_byte *data_ptr; png_colorp plte; int num_plte, i; if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE) || !png_get_PLTE(png_ptr, info_ptr, &plte, &num_plte)) { WARN("%s: PNG does not have valid PLTE chunk.", PNG_DEBUG_STR); return NULL; } /* Order is important. */ colorspace = pdf_new_array (); pdf_add_array(colorspace, pdf_new_name("Indexed")); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) base = create_cspace_ICCBased(png_ptr, info_ptr); else { if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) base = create_cspace_sRGB(png_ptr, info_ptr); else base = create_cspace_CalRGB(png_ptr, info_ptr); } if (!base) base = pdf_new_name("DeviceRGB"); pdf_add_array(colorspace, base); pdf_add_array(colorspace, pdf_new_number(num_plte-1)); data_ptr = NEW(num_plte*3, png_byte); for (i = 0; i < num_plte; i++) { data_ptr[3*i] = plte[i].red; data_ptr[3*i+1] = plte[i].green; data_ptr[3*i+2] = plte[i].blue; } lookup = pdf_new_string(data_ptr, num_plte*3); RELEASE(data_ptr); pdf_add_array(colorspace, lookup); return colorspace; }
pdf_page * pdf_create_page(pdf_document *doc, fz_rect mediabox, int res, int rotate) { pdf_page *page = NULL; pdf_obj *pageobj; float userunit = 1; fz_context *ctx = doc->ctx; fz_matrix ctm, tmp; fz_rect realbox; page = fz_malloc_struct(ctx, pdf_page); fz_try(ctx) { page->resources = NULL; page->contents = NULL; page->transparency = 0; page->links = NULL; page->annots = NULL; page->me = pageobj = pdf_new_dict(doc, 4); pdf_dict_puts_drop(pageobj, "Type", pdf_new_name(doc, "Page")); page->mediabox.x0 = fz_min(mediabox.x0, mediabox.x1) * userunit; page->mediabox.y0 = fz_min(mediabox.y0, mediabox.y1) * userunit; page->mediabox.x1 = fz_max(mediabox.x0, mediabox.x1) * userunit; page->mediabox.y1 = fz_max(mediabox.y0, mediabox.y1) * userunit; pdf_dict_puts_drop(pageobj, "MediaBox", pdf_new_rect(doc, &page->mediabox)); /* Snap page->rotate to 0, 90, 180 or 270 */ if (page->rotate < 0) page->rotate = 360 - ((-page->rotate) % 360); if (page->rotate >= 360) page->rotate = page->rotate % 360; page->rotate = 90*((page->rotate + 45)/90); if (page->rotate > 360) page->rotate = 0; pdf_dict_puts_drop(pageobj, "Rotate", pdf_new_int(doc, page->rotate)); fz_pre_rotate(fz_scale(&ctm, 1, -1), -page->rotate); realbox = page->mediabox; fz_transform_rect(&realbox, &ctm); fz_pre_scale(fz_translate(&tmp, -realbox.x0, -realbox.y0), userunit, userunit); fz_concat(&ctm, &ctm, &tmp); page->ctm = ctm; /* Do not create a Contents, as an empty Contents dict is not * valid. See Bug 694712 */ } fz_catch(ctx) { pdf_drop_obj(page->me); fz_free(ctx, page); fz_rethrow_message(ctx, "Failed to create page"); } return page; }
static pdf_obj * create_cspace_ICCBased (png_structp png_ptr, png_infop info_ptr) { pdf_obj *colorspace; int csp_id, colortype; png_byte color_type; png_charp name; int compression_type; /* Manual page for libpng does not * clarify whether profile data is inflated by libpng. */ #if PNG_LIBPNG_VER_MINOR < 5 png_charp profile; #else png_bytep profile; #endif png_uint_32 proflen; if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP) || !png_get_iCCP(png_ptr, info_ptr, &name, &compression_type, &profile, &proflen)) return NULL; color_type = png_get_color_type(png_ptr, info_ptr); if (color_type & PNG_COLOR_MASK_COLOR) { colortype = PDF_COLORSPACE_TYPE_RGB; #if 0 alternate = create_cspace_CalRGB(png_ptr, info_ptr); #endif } else { colortype = PDF_COLORSPACE_TYPE_GRAY; #if 0 alternate = create_cspace_CalGray(png_ptr, info_ptr); #endif } #if 0 if (alternate) pdf_add_dict(dict, pdf_new_name("Alternate"), alternate); #endif if (iccp_check_colorspace(colortype, profile, proflen) < 0) colorspace = NULL; else { csp_id = iccp_load_profile(name, profile, proflen); if (csp_id < 0) { colorspace = NULL; } else { colorspace = pdf_get_colorspace_reference(csp_id); } } /* Rendering intent ... */ return colorspace; }
int jp2_include_image (pdf_ximage *ximage, FILE *fp) { int smask = 0; pdf_obj *stream, *stream_dict; ximage_info info; if (pdf_check_version(1, 5) < 0) { WARN("JPEG 2000 support requires PDF version >= 1.5.\n"); return -1; } pdf_ximage_init_image_info(&info); stream = stream_dict = NULL; rewind(fp); if (scan_file(&info, &smask, fp) < 0) { WARN("JPEG2000: Reading JPEG 2000 file failed."); return -1; } stream = pdf_new_stream(0); stream_dict = pdf_stream_dict(stream); pdf_add_dict(stream_dict, pdf_new_name("Filter"), pdf_new_name("JPXDecode")); if (smask) pdf_add_dict(stream_dict, pdf_new_name("SMaskInData"), pdf_new_number(1)); /* Read whole file */ { int nb_read; rewind(fp); while ((nb_read = fread(work_buffer, sizeof(char), WORK_BUFFER_SIZE, fp)) > 0) pdf_add_stream(stream, work_buffer, nb_read); } pdf_ximage_set_image(ximage, &info, stream); return 0; }
int jp2_include_image (pdf_ximage *ximage, FILE *fp) { unsigned pdf_version; pdf_obj *stream, *stream_dict; ximage_info info; pdf_version = pdf_get_version(); if (pdf_version < 5) { WARN("JPEG 2000 support requires PDF version >= 1.5 (Current setting 1.%d)\n", pdf_version); return -1; } pdf_ximage_init_image_info(&info); stream = stream_dict = NULL; rewind(fp); if (scan_file(&info, fp) < 0) { WARN("Reading JPEG 2000 file failed."); return -1; } stream = pdf_new_stream(0); stream_dict = pdf_stream_dict(stream); pdf_add_dict(stream_dict, pdf_new_name("Filter"), pdf_new_name("JPXDecode")); /* Read whole file */ { long nb_read; rewind(fp); while ((nb_read = fread(work_buffer, sizeof(char), WORK_BUFFER_SIZE, fp)) > 0) pdf_add_stream(stream, work_buffer, nb_read); } pdf_ximage_set_image(ximage, &info, stream); return 0; }
static pdf_obj * hash_to_pdf_dict (fz_context *ctx, pdf_document *doc, pdfout_data *hash, int *page) { pdf_obj *dict_obj = pdf_new_dict (ctx, doc, 3); int len = pdfout_data_hash_len (ctx, hash); for (int j = 0; j < len; ++j) { char *key, *value; int value_len; pdfout_data_hash_get_key_value (ctx, hash, &key, &value, &value_len, j); if (streq (key, "page")) *page = pdfout_strtoint_null (ctx, value); else if (streq (key, "prefix")) { pdf_obj *string = pdfout_utf8_to_str_obj (ctx, doc, value, value_len); pdf_dict_puts_drop (ctx, dict_obj, "P", string); } else if (streq (key, "first")) { int first = pdfout_strtoint_null (ctx, value); pdf_dict_puts_drop (ctx, dict_obj, "St", pdf_new_int (ctx, doc, first)); } else if (streq (key, "style")) { const char *name; if (streq (value, "arabic")) name = "D"; else if (streq (value, "Roman")) name = "R"; else if (streq (value, "roman")) name = "r"; else if (streq (value, "Letters")) name = "A"; else if (streq (value, "letters")) name = "a"; else abort (); pdf_obj *name_obj = pdf_new_name (ctx, doc, name); pdf_dict_puts_drop (ctx, dict_obj, "S", name_obj); } } return dict_obj; }
static pdf_obj *start_new_destpage(fz_context *ctx,double width_pts,double height_pts) { pdf_obj *pageobj; pdf_obj *mbox; pageobj=pdf_new_dict(ctx,2); pdf_dict_puts(pageobj,"Type",pdf_new_name(ctx,"Page")); mbox=pdf_new_array(ctx,4); pdf_array_push(mbox,pdf_new_real(ctx,0.)); pdf_array_push(mbox,pdf_new_real(ctx,0.)); pdf_array_push(mbox,pdf_new_real(ctx,width_pts)); pdf_array_push(mbox,pdf_new_real(ctx,height_pts)); pdf_dict_puts(pageobj,"MediaBox",mbox); return(pageobj); }
/* Creates a PDF Differences array for the encoding, based on the * base encoding baseenc (if not NULL). Only character codes which * are actually used in the document are considered. */ static pdf_obj * make_encoding_differences (char **enc_vec, char **baseenc, const char *is_used) { pdf_obj *differences = NULL; int code, count = 0; int skipping = 1; ASSERT(enc_vec); /* * Write all entries (except .notdef) if baseenc is unknown. * If is_used is given, write only used entries. */ differences = pdf_new_array(); for (code = 0; code < 256; code++) { /* We skip NULL (= ".notdef"). Any character code mapped to ".notdef" * glyph should not be used in the document. */ if ((is_used && !is_used[code]) || !enc_vec[code]) skipping = 1; else if (!baseenc || !baseenc[code] || strcmp(baseenc[code], enc_vec[code]) != 0) { /* * Difference found. */ if (skipping) pdf_add_array(differences, pdf_new_number(code)); pdf_add_array(differences, pdf_new_name(enc_vec[code])); skipping = 0; count++; } else skipping = 1; } /* * No difference found. Some PDF viewers can't handle differences without * any differences. We return NULL. */ if (count == 0) { pdf_release_obj(differences); differences = NULL; } return differences; }
pdf_obj * Type0Font_get_resource (Type0Font *font) { ASSERT(font); /* * This looks somewhat strange. */ if (!font->indirect) { pdf_obj *array; array = pdf_new_array(); pdf_add_array(array, CIDFont_get_resource(font->descendant)); pdf_add_dict(font->fontdict, pdf_new_name("DescendantFonts"), array); font->indirect = pdf_ref_obj(font->fontdict); } return pdf_link_obj(font->indirect); }
static pdf_obj * create_cspace_CalGray (png_structp png_ptr, png_infop info_ptr) { pdf_obj *colorspace; pdf_obj *cal_param; double xw, yw, xr, yr, xg, yg, xb, yb; double G; if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_cHRM) || !png_get_cHRM(png_ptr, info_ptr, &xw, &yw, &xr, &yr, &xg, &yg, &xb, &yb)) return NULL; if (xw <= 0.0 || yw < 1.0e-10 || xr < 0.0 || yr < 0.0 || xg < 0.0 || yg < 0.0 || xb < 0.0 || yb < 0.0) { WARN("%s: Invalid cHRM chunk parameters found.", PNG_DEBUG_STR); return NULL; } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA) && png_get_gAMA (png_ptr, info_ptr, &G)) { if (G < 1.0e-2) { WARN("%s: Unusual Gamma value: 1.0 / %g", PNG_DEBUG_STR, G); return NULL; } G = 1.0 / G; /* Gamma is inverted. */ } else { G = DPX_PNG_DEFAULT_GAMMA; } cal_param = make_param_Cal(PNG_COLOR_TYPE_GRAY, G, xw, yw, xr, yr, xg, yg, xb, yb); if (!cal_param) return NULL; colorspace = pdf_new_array(); pdf_add_array(colorspace, pdf_new_name("CalGray")); pdf_add_array(colorspace, cal_param); return colorspace; }
pdf_obj * pdf_parse_dict(pdf_document *doc, fz_stream *file, pdf_lexbuf *buf) { pdf_obj *dict; pdf_obj *key = NULL; pdf_obj *val = NULL; pdf_token tok; int a, b; fz_context *ctx = file->ctx; dict = pdf_new_dict(doc, 8); fz_var(key); fz_var(val); fz_try(ctx) { while (1) { tok = pdf_lex(file, buf); skip: if (tok == PDF_TOK_CLOSE_DICT) break; /* for BI .. ID .. EI in content streams */ if (tok == PDF_TOK_KEYWORD && !strcmp(buf->scratch, "ID")) break; if (tok != PDF_TOK_NAME) fz_throw(ctx, FZ_ERROR_GENERIC, "invalid key in dict"); key = pdf_new_name(doc, buf->scratch); tok = pdf_lex(file, buf); switch (tok) { case PDF_TOK_OPEN_ARRAY: /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1643 */ fz_try(ctx) { val = pdf_parse_array(doc, file, buf); } fz_catch(ctx) { fz_warn(ctx, "ignoring broken array for '%s'", pdf_to_name(key)); pdf_drop_obj(key); val = key = NULL; do tok = pdf_lex(file, buf); while (tok != PDF_TOK_CLOSE_DICT && tok != PDF_TOK_CLOSE_ARRAY && tok != PDF_TOK_EOF && tok != PDF_TOK_OPEN_ARRAY && tok != PDF_TOK_OPEN_DICT); if (tok == PDF_TOK_CLOSE_DICT) goto skip; if (tok == PDF_TOK_CLOSE_ARRAY) continue; fz_throw(ctx, FZ_ERROR_GENERIC, "cannot make sense of broken array after all"); } break; case PDF_TOK_OPEN_DICT: val = pdf_parse_dict(doc, file, buf); break; case PDF_TOK_NAME: val = pdf_new_name(doc, buf->scratch); break; case PDF_TOK_REAL: val = pdf_new_real(doc, buf->f); break; case PDF_TOK_STRING: val = pdf_new_string(doc, buf->scratch, buf->len); break; case PDF_TOK_TRUE: val = pdf_new_bool(doc, 1); break; case PDF_TOK_FALSE: val = pdf_new_bool(doc, 0); break; case PDF_TOK_NULL: val = pdf_new_null(doc); break; case PDF_TOK_INT: /* 64-bit to allow for numbers > INT_MAX and overflow */ a = buf->i; tok = pdf_lex(file, buf); if (tok == PDF_TOK_CLOSE_DICT || tok == PDF_TOK_NAME || (tok == PDF_TOK_KEYWORD && !strcmp(buf->scratch, "ID"))) { val = pdf_new_int(doc, a); pdf_dict_put(dict, key, val); pdf_drop_obj(val); val = NULL; pdf_drop_obj(key); key = NULL; goto skip; } if (tok == PDF_TOK_INT) { b = buf->i; tok = pdf_lex(file, buf); if (tok == PDF_TOK_R) { val = pdf_new_indirect(doc, a, b); break; } } fz_throw(ctx, FZ_ERROR_GENERIC, "invalid indirect reference in dict"); default: fz_throw(ctx, FZ_ERROR_GENERIC, "unknown token in dict"); } pdf_dict_put(dict, key, val); pdf_drop_obj(val); val = NULL; pdf_drop_obj(key); key = NULL; } } fz_catch(ctx) { pdf_drop_obj(dict); pdf_drop_obj(key); pdf_drop_obj(val); fz_rethrow_message(ctx, "cannot parse dict"); } return dict; }
/* ximage here is the result. DONT USE IT FOR PASSING OPTIONS! */ int pdf_include_page (pdf_ximage *ximage, FILE *image_file, const char *ident, load_options options) { pdf_file *pf; xform_info info; pdf_obj *contents = NULL, *catalog; pdf_obj *page = NULL, *resources = NULL, *markinfo = NULL; pf = pdf_open(ident, image_file); if (!pf) return -1; if (pdf_file_get_version(pf) > pdf_get_version()) { WARN("Trying to include PDF file which has newer version number " \ "than output PDF: 1.%d.", pdf_get_version()); } pdf_ximage_init_form_info(&info); if (options.page_no == 0) options.page_no = 1; page = pdf_doc_get_page(pf, options.page_no, options.bbox_type, &info.bbox, &resources); if(!page) goto error_silent; catalog = pdf_file_get_catalog(pf); markinfo = pdf_deref_obj(pdf_lookup_dict(catalog, "MarkInfo")); if (markinfo) { pdf_obj *tmp = pdf_deref_obj(pdf_lookup_dict(markinfo, "Marked")); pdf_release_obj(markinfo); if (!PDF_OBJ_BOOLEANTYPE(tmp)) { if (tmp) pdf_release_obj(tmp); goto error; } else if (pdf_boolean_value(tmp)) { WARN("PDF file is tagged... Ignoring tags."); } pdf_release_obj(tmp); } contents = pdf_deref_obj(pdf_lookup_dict(page, "Contents")); pdf_release_obj(page); page = NULL; /* * Handle page content stream. */ { pdf_obj *content_new; if (!contents) { /* * Empty page */ content_new = pdf_new_stream(0); /* TODO: better don't include anything if the page is empty */ } else if (PDF_OBJ_STREAMTYPE(contents)) { /* * We must import the stream because its dictionary * may contain indirect references. */ content_new = pdf_import_object(contents); } else if (PDF_OBJ_ARRAYTYPE(contents)) { /* * Concatenate all content streams. */ int idx, len = pdf_array_length(contents); content_new = pdf_new_stream(STREAM_COMPRESS); for (idx = 0; idx < len; idx++) { pdf_obj *content_seg = pdf_deref_obj(pdf_get_array(contents, idx)); if (!PDF_OBJ_STREAMTYPE(content_seg) || pdf_concat_stream(content_new, content_seg) < 0) { pdf_release_obj(content_seg); pdf_release_obj(content_new); goto error; } pdf_release_obj(content_seg); } } else { goto error; } if (contents) pdf_release_obj(contents); contents = content_new; } /* * Add entries to contents stream dictionary. */ { pdf_obj *contents_dict, *bbox, *matrix; contents_dict = pdf_stream_dict(contents); pdf_add_dict(contents_dict, pdf_new_name("Type"), pdf_new_name("XObject")); pdf_add_dict(contents_dict, pdf_new_name("Subtype"), pdf_new_name("Form")); pdf_add_dict(contents_dict, pdf_new_name("FormType"), pdf_new_number(1.0)); bbox = pdf_new_array(); pdf_add_array(bbox, pdf_new_number(info.bbox.llx)); pdf_add_array(bbox, pdf_new_number(info.bbox.lly)); pdf_add_array(bbox, pdf_new_number(info.bbox.urx)); pdf_add_array(bbox, pdf_new_number(info.bbox.ury)); pdf_add_dict(contents_dict, pdf_new_name("BBox"), bbox); matrix = pdf_new_array(); pdf_add_array(matrix, pdf_new_number(1.0)); pdf_add_array(matrix, pdf_new_number(0.0)); pdf_add_array(matrix, pdf_new_number(0.0)); pdf_add_array(matrix, pdf_new_number(1.0)); pdf_add_array(matrix, pdf_new_number(0.0)); pdf_add_array(matrix, pdf_new_number(0.0)); pdf_add_dict(contents_dict, pdf_new_name("Matrix"), matrix); pdf_add_dict(contents_dict, pdf_new_name("Resources"), pdf_import_object(resources)); pdf_release_obj(resources); } pdf_close(pf); pdf_ximage_set_form(ximage, &info, contents); return 0; error: WARN("Cannot parse document. Broken PDF file?"); error_silent: if (resources) pdf_release_obj(resources); if (markinfo) pdf_release_obj(markinfo); if (page) pdf_release_obj(page); if (contents) pdf_release_obj(contents); pdf_close(pf); return -1; }
static void add_ToUnicode (Type0Font *font) { pdf_obj *tounicode; CIDFont *cidfont; CIDSysInfo *csi; char *fontname; /* * ToUnicode CMap: * * ToUnicode CMaps are usually not required for standard character * collections such as Adobe-Japan1. Identity-H is used for UCS * ordering CID-keyed fonts. External resource must be loaded for * others. */ cidfont = font->descendant; if (!cidfont) { ERROR("%s: No descendant CID-keyed font.", TYPE0FONT_DEBUG_STR); return; } if (CIDFont_is_ACCFont(cidfont)) { /* No need to embed ToUnicode */ return; } else if (CIDFont_is_UCSFont(cidfont)) { /* * Old version of dvipdfmx mistakenly used Adobe-Identity as Unicode. */ tounicode = pdf_read_ToUnicode_file("Adobe-Identity-UCS2"); if (!tounicode) { /* This should work */ tounicode = pdf_new_name("Identity-H"); } pdf_add_dict(font->fontdict, pdf_new_name("ToUnicode"), tounicode); return; } tounicode = NULL; csi = CIDFont_get_CIDSysInfo(cidfont); fontname = CIDFont_get_fontname(cidfont); if (CIDFont_get_embedding(cidfont)) { fontname += 7; /* FIXME */ } if (!strcmp(csi->registry, "Adobe") && !strcmp(csi->ordering, "Identity")) { switch (CIDFont_get_subtype(cidfont)) { case CIDFONT_TYPE2: /* PLEASE FIX THIS */ tounicode = Type0Font_create_ToUnicode_stream(font); break; default: if (CIDFont_get_flag(cidfont, CIDFONT_FLAG_TYPE1C)) { /* FIXME */ tounicode = Type0Font_create_ToUnicode_stream(font); } else if (CIDFont_get_flag(cidfont, CIDFONT_FLAG_TYPE1)) { /* FIXME */ /* Font loader will create ToUnicode and set. */ return; } else { tounicode = Type0Font_try_load_ToUnicode_stream(font, fontname); } break; } } else { char *cmap_base = NEW(strlen(csi->registry) + strlen(csi->ordering) + 2, char); sprintf(cmap_base, "%s-%s", csi->registry, csi->ordering); tounicode = Type0Font_try_load_ToUnicode_stream(font, cmap_base); RELEASE(cmap_base); } if (tounicode) { pdf_add_dict(font->fontdict, pdf_new_name("ToUnicode"), tounicode); } else { WARN("Failed to load ToUnicode CMap for font \"%s\"", fontname); } return; }
static void reset_field(pdf_document *doc, pdf_obj *field) { fz_context *ctx = doc->ctx; /* Set V to DV whereever DV is present, and delete V where DV is not. * FIXME: we assume for now that V has not been set unequal * to DV higher in the hierarchy than "field". * * At the bottom of the hierarchy we may find widget annotations * that aren't also fields, but DV and V will not be present in their * dictionaries, and attempts to remove V will be harmless. */ pdf_obj *dv = pdf_dict_gets(field, "DV"); pdf_obj *kids = pdf_dict_gets(field, "Kids"); if (dv) pdf_dict_puts(field, "V", dv); else pdf_dict_dels(field, "V"); if (kids == NULL) { /* The leaves of the tree are widget annotations * In some cases we need to update the appearance state; * in others we need to mark the field as dirty so that * the appearance stream will be regenerated. */ switch (pdf_field_type(doc, field)) { case PDF_WIDGET_TYPE_RADIOBUTTON: case PDF_WIDGET_TYPE_CHECKBOX: { pdf_obj *leafv = pdf_get_inheritable(doc, field, "V"); if (leafv) pdf_keep_obj(leafv); else leafv = pdf_new_name(doc, "Off"); fz_try(ctx) { pdf_dict_puts(field, "AS", leafv); } fz_always(ctx) { pdf_drop_obj(leafv); } fz_catch(ctx) { fz_rethrow(ctx); } } break; case PDF_WIDGET_TYPE_PUSHBUTTON: break; default: pdf_field_mark_dirty(doc, field); break; } } doc->dirty = 1; }
int pdf_font_load_pkfont (pdf_font *font) { pdf_obj *fontdict; char *usedchars; char *ident; unsigned dpi; FILE *fp; double point_size, pix2charu; int opcode, code, firstchar, lastchar, prev; pdf_obj *charprocs, *procset, *encoding, *tmp_array; double widths[256]; pdf_rect bbox; char charavail[256]; #if ENABLE_GLYPHENC int encoding_id; char **enc_vec; #endif /* ENABLE_GLYPHENC */ int error = 0; if (!pdf_font_is_in_use(font)) { return 0; } ident = pdf_font_get_ident(font); point_size = pdf_font_get_param(font, PDF_FONT_PARAM_POINT_SIZE); usedchars = pdf_font_get_usedchars(font); #if ENABLE_GLYPHENC encoding_id = pdf_font_get_encoding(font); if (encoding_id < 0) enc_vec = NULL; else { enc_vec = pdf_encoding_get_encoding(encoding_id); } #endif /* ENABLE_GLYPHENC */ ASSERT(ident && usedchars && point_size > 0.0); dpi = truedpi(ident, point_size, base_dpi); { char *fontfile = pdf_font_get_fontfile (font); if (fontfile) fp = MFOPEN(fontfile, FOPEN_RBIN_MODE); else fp = dpx_open_pk_font_at(ident, dpi); } if (!fp) { ERROR("Could not find/open PK font file: %s (at %udpi)", ident, dpi); } memset(charavail, 0, 256); charprocs = pdf_new_dict(); /* Include bitmap as 72dpi image: * There seems to be problems in "scaled" bitmap glyph * rendering in several viewers. */ pix2charu = 72. * 1000. / ((double) base_dpi) / point_size; bbox.llx = bbox.lly = HUGE_VAL; bbox.urx = bbox.ury = -HUGE_VAL; while ((opcode = fgetc(fp)) >= 0 && opcode != PK_POST) { if (opcode < 240) { struct pk_header_ pkh; error = read_pk_char_header(&pkh, opcode, fp); if (error) ERROR("Error in reading PK character header."); else if (charavail[pkh.chrcode & 0xff]) WARN("More than two bitmap image for single glyph?: font=\"%s\" code=0x%02x", ident, pkh.chrcode); if (!usedchars[pkh.chrcode & 0xff]) do_skip(fp, pkh.pkt_len); else { char *charname; pdf_obj *charproc; unsigned char *pkt_ptr; size_t bytesread; double charwidth; /* Charwidth in PDF units */ charwidth = ROUND(1000.0 * pkh.wd / (((double) (1<<20))*pix2charu), 0.1); widths[pkh.chrcode & 0xff] = charwidth; /* Update font BBox info */ bbox.llx = MIN(bbox.llx, -pkh.bm_hoff); bbox.lly = MIN(bbox.lly, pkh.bm_voff - pkh.bm_ht); bbox.urx = MAX(bbox.urx, pkh.bm_wd - pkh.bm_hoff); bbox.ury = MAX(bbox.ury, pkh.bm_voff); pkt_ptr = NEW(pkh.pkt_len, unsigned char); if ((bytesread = fread(pkt_ptr, 1, pkh.pkt_len, fp))!= pkh.pkt_len) { ERROR("Only %ld bytes PK packet read. (expected %ld bytes)", bytesread, pkh.pkt_len); } charproc = create_pk_CharProc_stream(&pkh, charwidth, pkt_ptr, bytesread); RELEASE(pkt_ptr); if (!charproc) ERROR("Unpacking PK character data failed."); #if ENABLE_GLYPHENC if (encoding_id >= 0 && enc_vec) { charname = (char *) enc_vec[pkh.chrcode & 0xff]; if (!charname) { WARN("\".notdef\" glyph used in font (code=0x%02x): %s", pkh.chrcode, ident); charname = work_buffer; pk_char2name(charname, pkh.chrcode); } } else #endif /* ENABLE_GLYPHENC */ { charname = work_buffer; pk_char2name(charname, pkh.chrcode); } pdf_add_dict(charprocs, pdf_new_name(charname), pdf_ref_obj(charproc)); /* _FIXME_ */ pdf_release_obj(charproc); } charavail[pkh.chrcode & 0xff] = 1; } else { /* A command byte */ switch (opcode) { case PK_NO_OP: break; case PK_XXX1: do_skip(fp, get_unsigned_byte(fp)); break; case PK_XXX2: do_skip(fp, get_unsigned_pair(fp)); break; case PK_XXX3: do_skip(fp, get_unsigned_triple(fp)); break; case PK_XXX4: do_skip(fp, get_unsigned_quad(fp)); break; case PK_YYY: do_skip(fp, 4); break; case PK_PRE: do_preamble(fp); break; } } }
static int CIDFont_base_open (CIDFont *font, const char *name, CIDSysInfo *cmap_csi, cid_opt *opt) { pdf_obj *fontdict, *descriptor; char *fontname = NULL; int idx; ASSERT(font); for (idx = 0; cid_basefont[idx].fontname != NULL; idx++) { if (!strcmp(name, cid_basefont[idx].fontname) || (strlen(name) == strlen(cid_basefont[idx].fontname) - strlen("-Acro") && !strncmp(name, cid_basefont[idx].fontname, strlen(cid_basefont[idx].fontname)-strlen("-Acro"))) ) break; } if (cid_basefont[idx].fontname == NULL) return -1; fontname = NEW(strlen(name)+12, char); memset(fontname, 0, strlen(name)+12); strcpy(fontname, name); switch (opt->style) { case FONT_STYLE_BOLD: strcat(fontname, ",Bold"); break; case FONT_STYLE_ITALIC: strcat(fontname, ",Italic"); break; case FONT_STYLE_BOLDITALIC: strcat(fontname, ",BoldItalic"); break; } { const char *start; const char *end; start = cid_basefont[idx].fontdict; end = start + strlen(start); fontdict = parse_pdf_dict(&start, end, NULL); start = cid_basefont[idx].descriptor; end = start + strlen(start); descriptor = parse_pdf_dict(&start, end, NULL); ASSERT(fontdict && descriptor); } font->fontname = fontname; font->flags |= FONT_FLAG_BASEFONT; { char *registry, *ordering; int supplement; pdf_obj *tmp; tmp = pdf_lookup_dict(fontdict, "CIDSystemInfo"); ASSERT( tmp && pdf_obj_typeof(tmp) == PDF_DICT ); registry = pdf_string_value(pdf_lookup_dict(tmp, "Registry")); ordering = pdf_string_value(pdf_lookup_dict(tmp, "Ordering")); supplement = pdf_number_value(pdf_lookup_dict(tmp, "Supplement")); if (cmap_csi) { /* NULL for accept any */ if (strcmp(registry, cmap_csi->registry) || strcmp(ordering, cmap_csi->ordering)) ERROR("Inconsistent CMap used for CID-keyed font %s.", cid_basefont[idx].fontname); else if (supplement < cmap_csi->supplement) { WARN("CMap has higher supplement number than CIDFont: %s", fontname); WARN("Some chracters may not be displayed or printed."); } } font->csi = NEW(1, CIDSysInfo); font->csi->registry = NEW(strlen(registry)+1, char); font->csi->ordering = NEW(strlen(ordering)+1, char); strcpy(font->csi->registry, registry); strcpy(font->csi->ordering, ordering); font->csi->supplement = supplement; } { pdf_obj *tmp; char *type; tmp = pdf_lookup_dict(fontdict, "Subtype"); ASSERT( tmp != NULL && pdf_obj_typeof(tmp) == PDF_NAME ); type = pdf_name_value(tmp); if (!strcmp(type, "CIDFontType0")) font->subtype = CIDFONT_TYPE0; else if (!strcmp(type, "CIDFontType2")) font->subtype = CIDFONT_TYPE2; else { ERROR("Unknown CIDFontType \"%s\"", type); } } if (cidoptflags & CIDFONT_FORCE_FIXEDPITCH) { if (pdf_lookup_dict(fontdict, "W")) { pdf_remove_dict(fontdict, "W"); } if (pdf_lookup_dict(fontdict, "W2")) { pdf_remove_dict(fontdict, "W2"); } } pdf_add_dict(fontdict, pdf_new_name("Type"), pdf_new_name("Font")); pdf_add_dict(fontdict, pdf_new_name("BaseFont"), pdf_new_name(fontname)); pdf_add_dict(descriptor, pdf_new_name("Type"), pdf_new_name("FontDescriptor")); pdf_add_dict(descriptor, pdf_new_name("FontName"), pdf_new_name(fontname)); font->fontdict = fontdict; font->descriptor = descriptor; opt->embed = 0; return 0; }
pdf_obj * pdf_parse_array(pdf_document *doc, fz_stream *file, pdf_lexbuf *buf) { pdf_obj *ary = NULL; pdf_obj *obj = NULL; int a = 0, b = 0, n = 0; pdf_token tok; fz_context *ctx = file->ctx; pdf_obj *op = NULL; fz_var(obj); ary = pdf_new_array(doc, 4); fz_try(ctx) { while (1) { tok = pdf_lex(file, buf); if (tok != PDF_TOK_INT && tok != PDF_TOK_R) { if (n > 0) { obj = pdf_new_int(doc, a); pdf_array_push(ary, obj); pdf_drop_obj(obj); obj = NULL; } if (n > 1) { obj = pdf_new_int(doc, b); pdf_array_push(ary, obj); pdf_drop_obj(obj); obj = NULL; } n = 0; } if (tok == PDF_TOK_INT && n == 2) { obj = pdf_new_int(doc, a); pdf_array_push(ary, obj); pdf_drop_obj(obj); obj = NULL; a = b; n --; } switch (tok) { case PDF_TOK_CLOSE_ARRAY: op = ary; goto end; case PDF_TOK_INT: if (n == 0) a = buf->i; if (n == 1) b = buf->i; n ++; break; case PDF_TOK_R: if (n != 2) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot parse indirect reference in array"); obj = pdf_new_indirect(doc, a, b); pdf_array_push(ary, obj); pdf_drop_obj(obj); obj = NULL; n = 0; break; case PDF_TOK_OPEN_ARRAY: obj = pdf_parse_array(doc, file, buf); pdf_array_push(ary, obj); pdf_drop_obj(obj); obj = NULL; break; case PDF_TOK_OPEN_DICT: obj = pdf_parse_dict(doc, file, buf); pdf_array_push(ary, obj); pdf_drop_obj(obj); obj = NULL; break; case PDF_TOK_NAME: obj = pdf_new_name(doc, buf->scratch); pdf_array_push(ary, obj); pdf_drop_obj(obj); obj = NULL; break; case PDF_TOK_REAL: obj = pdf_new_real(doc, buf->f); pdf_array_push(ary, obj); pdf_drop_obj(obj); obj = NULL; break; case PDF_TOK_STRING: obj = pdf_new_string(doc, buf->scratch, buf->len); pdf_array_push(ary, obj); pdf_drop_obj(obj); obj = NULL; break; case PDF_TOK_TRUE: obj = pdf_new_bool(doc, 1); pdf_array_push(ary, obj); pdf_drop_obj(obj); obj = NULL; break; case PDF_TOK_FALSE: obj = pdf_new_bool(doc, 0); pdf_array_push(ary, obj); pdf_drop_obj(obj); obj = NULL; break; case PDF_TOK_NULL: obj = pdf_new_null(doc); pdf_array_push(ary, obj); pdf_drop_obj(obj); obj = NULL; break; default: fz_throw(ctx, FZ_ERROR_GENERIC, "cannot parse token in array"); } } end: {} } fz_catch(ctx) { pdf_drop_obj(obj); pdf_drop_obj(ary); fz_rethrow_message(ctx, "cannot parse array"); } return op; }
pdf_obj * pdf_parse_ind_obj(pdf_document *doc, fz_stream *file, pdf_lexbuf *buf, int *onum, int *ogen, int *ostmofs) { pdf_obj *obj = NULL; int num = 0, gen = 0, stm_ofs; pdf_token tok; int a, b; fz_context *ctx = file->ctx; fz_var(obj); tok = pdf_lex(file, buf); if (tok != PDF_TOK_INT) fz_throw(ctx, FZ_ERROR_GENERIC, "expected object number"); num = buf->i; tok = pdf_lex(file, buf); if (tok != PDF_TOK_INT) fz_throw(ctx, FZ_ERROR_GENERIC, "expected generation number (%d ? obj)", num); gen = buf->i; tok = pdf_lex(file, buf); if (tok != PDF_TOK_OBJ) fz_throw(ctx, FZ_ERROR_GENERIC, "expected 'obj' keyword (%d %d ?)", num, gen); tok = pdf_lex(file, buf); switch (tok) { case PDF_TOK_OPEN_ARRAY: obj = pdf_parse_array(doc, file, buf); break; case PDF_TOK_OPEN_DICT: obj = pdf_parse_dict(doc, file, buf); break; case PDF_TOK_NAME: obj = pdf_new_name(doc, buf->scratch); break; case PDF_TOK_REAL: obj = pdf_new_real(doc, buf->f); break; case PDF_TOK_STRING: obj = pdf_new_string(doc, buf->scratch, buf->len); break; case PDF_TOK_TRUE: obj = pdf_new_bool(doc, 1); break; case PDF_TOK_FALSE: obj = pdf_new_bool(doc, 0); break; case PDF_TOK_NULL: obj = pdf_new_null(doc); break; case PDF_TOK_INT: a = buf->i; tok = pdf_lex(file, buf); if (tok == PDF_TOK_STREAM || tok == PDF_TOK_ENDOBJ) { obj = pdf_new_int(doc, a); goto skip; } if (tok == PDF_TOK_INT) { b = buf->i; tok = pdf_lex(file, buf); if (tok == PDF_TOK_R) { obj = pdf_new_indirect(doc, a, b); break; } } fz_throw(ctx, FZ_ERROR_GENERIC, "expected 'R' keyword (%d %d R)", num, gen); case PDF_TOK_ENDOBJ: obj = pdf_new_null(doc); goto skip; default: fz_throw(ctx, FZ_ERROR_GENERIC, "syntax error in object (%d %d R)", num, gen); } fz_try(ctx) { tok = pdf_lex(file, buf); } fz_catch(ctx) { pdf_drop_obj(obj); fz_rethrow_message(ctx, "cannot parse indirect object (%d %d R)", num, gen); } skip: if (tok == PDF_TOK_STREAM) { int c = fz_read_byte(file); while (c == ' ') c = fz_read_byte(file); if (c == '\r') { c = fz_peek_byte(file); if (c != '\n') fz_warn(ctx, "line feed missing after stream begin marker (%d %d R)", num, gen); else fz_read_byte(file); } stm_ofs = fz_tell(file); } else if (tok == PDF_TOK_ENDOBJ) { stm_ofs = 0; } else { fz_warn(ctx, "expected 'endobj' or 'stream' keyword (%d %d R)", num, gen); stm_ofs = 0; } if (onum) *onum = num; if (ogen) *ogen = gen; if (ostmofs) *ostmofs = stm_ofs; return obj; }