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; }
pdf_obj * spc_lookup_object (const char *key) { pdf_obj *value = NULL; pdf_coord cp; int k; ASSERT(named_objects); if (!key) return NULL; for (k = 0; _rkeys[k] && strcmp(key, _rkeys[k]); k++); switch (k) { case K_OBJ__XPOS: cp.x = dvi_dev_xpos(); cp.y = 0.0; pdf_dev_transform(&cp, NULL); value = pdf_new_number(ROUND(cp.x, .01)); break; case K_OBJ__YPOS: cp.x = 0.0; cp.y = dvi_dev_ypos(); pdf_dev_transform(&cp, NULL); value = pdf_new_number(ROUND(cp.y, .01)); break; case K_OBJ__THISPAGE: value = pdf_doc_this_page(); break; case K_OBJ__PAGES: value = pdf_doc_page_tree(); break; case K_OBJ__NAMES: value = pdf_doc_names(); break; case K_OBJ__RESOURCES: value = pdf_doc_current_page_resources(); break; case K_OBJ__CATALOG: value = pdf_doc_catalog(); break; case K_OBJ__DOCINFO: value = pdf_doc_docinfo(); break; default: value = pdf_names_lookup_object(named_objects, key, strlen(key)); break; } /* spc_handler_pdfm_bead() in spc_pdfm.c controls NULL too. if (!value) { ERROR("Object reference %s not exist.", key); } */ return value; }
static pdf_obj * create_ckey_mask (png_structp png_ptr, png_infop info_ptr) { pdf_obj *colorkeys; png_byte color_type; png_bytep trans; int num_trans, i; png_color_16p colors; if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) || !png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &colors)) { WARN("%s: PNG does not have valid tRNS chunk!", PNG_DEBUG_STR); return NULL; } colorkeys = pdf_new_array(); color_type = png_get_color_type(png_ptr, info_ptr); switch (color_type) { case PNG_COLOR_TYPE_PALETTE: for (i = 0; i < num_trans; i++) { if (trans[i] == 0x00) { pdf_add_array(colorkeys, pdf_new_number(i)); pdf_add_array(colorkeys, pdf_new_number(i)); } else if (trans[i] != 0xff) { WARN("%s: You found a bug in pngimage.c.", PNG_DEBUG_STR); } } break; case PNG_COLOR_TYPE_RGB: pdf_add_array(colorkeys, pdf_new_number(colors->red)); pdf_add_array(colorkeys, pdf_new_number(colors->red)); pdf_add_array(colorkeys, pdf_new_number(colors->green)); pdf_add_array(colorkeys, pdf_new_number(colors->green)); pdf_add_array(colorkeys, pdf_new_number(colors->blue)); pdf_add_array(colorkeys, pdf_new_number(colors->blue)); break; case PNG_COLOR_TYPE_GRAY: pdf_add_array(colorkeys, pdf_new_number(colors->gray)); pdf_add_array(colorkeys, pdf_new_number(colors->gray)); break; default: WARN("%s: You found a bug in pngimage.c.", PNG_DEBUG_STR); pdf_release_obj(colorkeys); colorkeys = NULL; } return colorkeys; }
static void html_make_link_dict (char *name) { pdf_obj *color; if (!link_dict) { link_dict = pdf_new_dict(); pdf_add_dict(link_dict, pdf_new_name("Type"), pdf_new_name ("Annot")); pdf_add_dict(link_dict, pdf_new_name("Subtype"), pdf_new_name ("Link")); color = pdf_new_array (); pdf_add_array (color, pdf_new_number (0)); pdf_add_array (color, pdf_new_number (1)); pdf_add_array (color, pdf_new_number (1)); pdf_add_dict(link_dict, pdf_new_name("C"), color); if (name && *name == '#' && !(base_value)) { pdf_add_dict (link_dict, pdf_new_name("Dest"), pdf_new_string(name+1,strlen(name+1))); } else if (name) { /* Assume its a URL */ char *url; int len; pdf_obj *action; len = strlen(name)+1; if (base_value) len+=strlen(base_value); url = NEW (len, char); if (base_value) strcpy (url, base_value); else url[0] = 0; strcat (url, name); action = pdf_new_dict(); pdf_add_dict (action, pdf_new_name ("Type"), pdf_new_name ("Action")); pdf_add_dict (action, pdf_new_name ("S"), pdf_new_name ("URI")); pdf_add_dict (action, pdf_new_name ("URI"), pdf_new_string (url, len)); pdf_add_dict (link_dict, pdf_new_name ("A"), pdf_ref_obj (action)); pdf_release_obj (action); RELEASE (url); } pdf_doc_begin_annot (link_dict); } else {
/* * 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; }
/* 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; }
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; }
/* 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; }
/* bitdepth is always 8 (16 is not supported) */ static pdf_obj * strip_soft_mask (png_structp png_ptr, png_infop info_ptr, /* next two values will be modified. */ png_bytep image_data_ptr, png_uint_32p rowbytes_ptr, png_uint_32 width, png_uint_32 height) { pdf_obj *smask, *dict; png_byte color_type, bpc; png_bytep smask_data_ptr; png_uint_32 i; color_type = png_get_color_type(png_ptr, info_ptr); bpc = png_get_bit_depth (png_ptr, info_ptr); if (color_type & PNG_COLOR_MASK_COLOR) { int bps = (bpc == 8) ? 4 : 8; if (*rowbytes_ptr != bps*width*sizeof(png_byte)) { /* Something wrong */ WARN("%s: Inconsistent rowbytes value.", PNG_DEBUG_STR); return NULL; } } else { int bps = (bpc == 8) ? 2 : 4; if (*rowbytes_ptr != bps*width*sizeof(png_byte)) { /* Something wrong */ WARN("%s: Inconsistent rowbytes value.", PNG_DEBUG_STR); return NULL; } } smask = pdf_new_stream(STREAM_COMPRESS); dict = pdf_stream_dict(smask); 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(bpc)); smask_data_ptr = (png_bytep) NEW((bpc/8)*width*height, png_byte); switch (color_type) { case PNG_COLOR_TYPE_RGB_ALPHA: if (bpc == 8) { for (i = 0; i < width*height; i++) { memmove(image_data_ptr+(3*i), image_data_ptr+(4*i), 3); smask_data_ptr[i] = image_data_ptr[4*i+3]; } *rowbytes_ptr = 3*width*sizeof(png_byte); } else { for (i = 0; i < width*height; i++) { memmove(image_data_ptr+(6*i), image_data_ptr+(8*i), 6); smask_data_ptr[2*i] = image_data_ptr[8*i+6]; smask_data_ptr[2*i+1] = image_data_ptr[8*i+7]; } *rowbytes_ptr = 6*width*sizeof(png_byte); } break; case PNG_COLOR_TYPE_GRAY_ALPHA: if (bpc == 8) { for (i = 0; i < width*height; i++) { image_data_ptr[i] = image_data_ptr[2*i]; smask_data_ptr[i] = image_data_ptr[2*i+1]; } *rowbytes_ptr = width*sizeof(png_byte); } else { for (i = 0; i < width*height; i++) { image_data_ptr[2*i] = image_data_ptr[4*i]; image_data_ptr[2*i+1] = image_data_ptr[4*i+1]; smask_data_ptr[2*i] = image_data_ptr[4*i+2]; smask_data_ptr[2*i+1] = image_data_ptr[4*i+3]; } *rowbytes_ptr = 2*width*sizeof(png_byte); } break; default: WARN("You found a bug in pngimage.c!"); pdf_release_obj(smask); RELEASE(smask_data_ptr); return NULL; } pdf_add_stream(smask, smask_data_ptr, (bpc/8)*width*height); RELEASE(smask_data_ptr); return smask; }
static pdf_obj * make_param_Cal (png_byte color_type, double G, /* Gamma */ double xw, double yw, double xr, double yr, double xg, double yg, double xb, double yb) { pdf_obj *cal_param; pdf_obj *white_point, *matrix, *dev_gamma; double Xw, Yw, Zw; /* Yw = 1.0 */ double Xr, Xg, Xb, Yr, Yb, Yg, Zr, Zg, Zb; #ifndef ABS #define ABS(x) ((x) < 0 ? -(x) : (x)) #endif /* * TODO: Check validity * * Conversion found in * * com.sixlegs.image.png - Java package to read and display PNG images * Copyright (C) 1998, 1999, 2001 Chris Nokleberg * * http://www.sixlegs.com/software/png/ * */ { double zw, zr, zg, zb; double fr, fg, fb; double det; /* WhitePoint */ zw = 1 - (xw + yw); zr = 1 - (xr + yr); zg = 1 - (xg + yg); zb = 1 - (xb + yb); Xw = xw / yw; Yw = 1.0; Zw = zw / yw; /* Matrix */ det = xr * (yg * zb - zg * yb) - xg * (yr * zb - zr * yb) + xb * (yr * zg - zr * yg); if (ABS(det) < 1.0e-10) { WARN("Non invertible matrix: Maybe invalid value(s) specified in cHRM chunk."); return NULL; } fr = (Xw * (yg * zb - zg * yb) - xg * (zb - Zw * yb) + xb * (zg - Zw * yg)) / det; fg = (xr * (zb - Zw * yb) - Xw * (yr * zb - zr * yb) + xb * (yr * Zw - zr)) / det; fb = (xr * (yg * Zw - zg) - xg * (yr * Zw - zr) + Xw * (yr * zg - zr * yg)) / det; Xr = fr * xr; Yr = fr * yr; Zr = fr * zr; Xg = fg * xg; Yg = fg * yg; Zg = fg * zg; Xb = fb * xb; Yb = fb * yb; Zb = fb * zb; } if (G < 1.0e-2) { WARN("Unusual Gamma specified: 1.0 / %g", G); return NULL; } cal_param = pdf_new_dict(); /* White point is always required. */ white_point = pdf_new_array(); pdf_add_array(white_point, pdf_new_number(ROUND(Xw, 0.00001))); pdf_add_array(white_point, pdf_new_number(ROUND(Yw, 0.00001))); pdf_add_array(white_point, pdf_new_number(ROUND(Zw, 0.00001))); pdf_add_dict(cal_param, pdf_new_name("WhitePoint"), white_point); /* Matrix - default: Identity */ if (color_type & PNG_COLOR_MASK_COLOR) { if (G != 1.0) { dev_gamma = pdf_new_array(); pdf_add_array(dev_gamma, pdf_new_number(ROUND(G, 0.00001))); pdf_add_array(dev_gamma, pdf_new_number(ROUND(G, 0.00001))); pdf_add_array(dev_gamma, pdf_new_number(ROUND(G, 0.00001))); pdf_add_dict(cal_param, pdf_new_name("Gamma"), dev_gamma); } matrix = pdf_new_array(); pdf_add_array(matrix, pdf_new_number(ROUND(Xr, 0.00001))); pdf_add_array(matrix, pdf_new_number(ROUND(Yr, 0.00001))); pdf_add_array(matrix, pdf_new_number(ROUND(Zr, 0.00001))); pdf_add_array(matrix, pdf_new_number(ROUND(Xg, 0.00001))); pdf_add_array(matrix, pdf_new_number(ROUND(Yg, 0.00001))); pdf_add_array(matrix, pdf_new_number(ROUND(Zg, 0.00001))); pdf_add_array(matrix, pdf_new_number(ROUND(Xb, 0.00001))); pdf_add_array(matrix, pdf_new_number(ROUND(Yb, 0.00001))); pdf_add_array(matrix, pdf_new_number(ROUND(Zb, 0.00001))); pdf_add_dict (cal_param, pdf_new_name("Matrix"), matrix); } else { /* Gray */ if (G != 1.0) pdf_add_dict(cal_param, pdf_new_name("Gamma"), pdf_new_number(ROUND(G, 0.00001))); } return cal_param; }
pdf_obj *pdf_include_page(FILE *image_file, struct xform_info *p, char *res_name) { pdf_obj *trailer = NULL, *catalog = NULL, *page_tree = NULL; pdf_obj *kids_ref, *kids; pdf_obj *media_box = NULL, *crop_box = NULL, *resources = NULL, *contents = NULL, *contents_ref = NULL; pdf_obj *tmp1; #ifdef MEM_DEBUG MEM_START #endif if (!(trailer = pdf_open (image_file))) { fprintf (stderr, "\nCorrupt PDF file?\n"); } /* Now just lookup catalog location */ /* Deref catalog */ if (trailer && (catalog = pdf_deref_obj(pdf_lookup_dict (trailer,"Root"))) == NULL) { fprintf (stderr, "\nCatalog isn't where I expect it.\n"); } if (trailer) pdf_release_obj (trailer); /* Lookup page tree in catalog */ if (catalog) { page_tree = pdf_deref_obj (pdf_lookup_dict (catalog, "Pages")); /* Should be finished with catalog */ pdf_release_obj (catalog); } /* Media box and resources can be inherited so start looking for them here */ if (page_tree) { if ((tmp1 = pdf_lookup_dict (page_tree, "CropBox"))) crop_box = pdf_deref_obj (tmp1); if ((tmp1 = pdf_lookup_dict (page_tree, "MediaBox"))) media_box = pdf_deref_obj (tmp1); resources = pdf_deref_obj (pdf_lookup_dict (page_tree, "Resources")); if (resources == NULL) { resources = pdf_new_dict(); } while ((kids_ref = pdf_lookup_dict (page_tree, "Kids")) != NULL) { kids = pdf_deref_obj (kids_ref); pdf_release_obj (page_tree); page_tree = pdf_deref_obj (pdf_get_array(kids, 0)); pdf_release_obj (kids); /* Replace MediaBox if it's here */ tmp1 = pdf_deref_obj(pdf_lookup_dict (page_tree, "MediaBox")); if (tmp1 && media_box) pdf_release_obj (media_box); if (tmp1) media_box = tmp1; /* Do same for CropBox */ tmp1 = pdf_deref_obj(pdf_lookup_dict (page_tree, "CropBox")); if (tmp1 && crop_box) pdf_release_obj (crop_box); if (tmp1) crop_box = tmp1; /* Add resources if they're here */ tmp1 = pdf_deref_obj (pdf_lookup_dict (page_tree, "Resources")); if (tmp1) { pdf_merge_dict (tmp1, resources); pdf_release_obj (resources); resources = tmp1; } } /* At this point, page_tree contains the first page. media_box, crop_box, and resources should also be set. */ /* If there's a crop_box, replace media_box with crop_box. The rest of this routine assumes crop_box has been released */ if (crop_box) { pdf_release_obj (media_box); media_box = crop_box; crop_box = NULL; } /* This gets bit confusing. In the following code, media_box is the box the image is cropped to. The bounding box is the box the image is scaled to */ /* If user did not supply bounding box, use media_box (which may really be cropbox) as bounding box */ /* Set the crop box parameters in the xform_info structure */ p->c_llx = pdf_number_value (pdf_get_array (media_box, 0)); p->c_lly = pdf_number_value (pdf_get_array (media_box, 1)); p->c_urx = pdf_number_value (pdf_get_array (media_box, 2)); p->c_ury = pdf_number_value (pdf_get_array (media_box, 3)); /* Adjust scaling and clipping information as necessary */ pdf_scale_image (p); /* Set the media box to whatever pdf_scale_image() decided for the crop box (which may be unchanged) */ pdf_release_obj (media_box); media_box = pdf_new_array (); pdf_add_array (media_box, pdf_new_number (p->c_llx)); pdf_add_array (media_box, pdf_new_number (p->c_lly)); pdf_add_array (media_box, pdf_new_number (p->c_urx)); pdf_add_array (media_box, pdf_new_number (p->c_ury)); if ((contents = pdf_deref_obj(pdf_lookup_dict(page_tree,"Contents")))==NULL) { fprintf (stderr, "\nNo Contents found\n"); return NULL; } pdf_release_obj (page_tree); } /* Arrays of contents must be handled very differently (not implemented) */ if (contents && contents -> type != PDF_ARRAY) { doc_make_form_xobj (contents, media_box, p->user_bbox? p->u_llx: 0.0, p->user_bbox? p->u_lly: 0.0, 1.0, 1.0, resources, res_name); } else { fprintf (stderr, "\nIgnoring stream with with multiple segments\n"); contents = NULL; } if (contents) { contents_ref = pdf_ref_obj (contents); pdf_release_obj (contents); } pdf_close (); #ifdef MEM_DEBUG MEM_END #endif return (contents_ref); }
/* * The following routine returns copies, not the original object. */ pdf_obj * spc_lookup_reference (const char *key) { pdf_obj *value = NULL; pdf_coord cp; int k; ASSERT(named_objects); if (!key) return NULL; for (k = 0; _rkeys[k] && strcmp(key, _rkeys[k]); k++); switch (k) { /* xpos and ypos must be position in device space here. */ case K_OBJ__XPOS: cp.x = dvi_dev_xpos(); cp.y = 0.0; pdf_dev_transform(&cp, NULL); value = pdf_new_number(ROUND(cp.x, .01)); break; case K_OBJ__YPOS: cp.x = 0.0; cp.y = dvi_dev_ypos(); pdf_dev_transform(&cp, NULL); value = pdf_new_number(ROUND(cp.y, .01)); break; case K_OBJ__THISPAGE: value = pdf_doc_this_page_ref(); break; case K_OBJ__PREVPAGE: value = pdf_doc_prev_page_ref(); break; case K_OBJ__NEXTPAGE: value = pdf_doc_next_page_ref(); break; case K_OBJ__PAGES: value = pdf_ref_obj(pdf_doc_page_tree()); break; case K_OBJ__NAMES: value = pdf_ref_obj(pdf_doc_names()); break; case K_OBJ__RESOURCES: value = pdf_ref_obj(pdf_doc_current_page_resources()); break; case K_OBJ__CATALOG: value = pdf_ref_obj(pdf_doc_catalog()); break; case K_OBJ__DOCINFO: value = pdf_ref_obj(pdf_doc_docinfo()); break; default: if (ispageref(key)) value = pdf_doc_ref_page(atoi(key + 4)); else { value = pdf_names_lookup_reference(named_objects, key, strlen(key)); } break; } if (!value) { ERROR("Object reference %s not exist.", key); } return value; }
int jpeg_include_image (pdf_ximage *ximage, FILE *fp) { pdf_obj *stream; pdf_obj *stream_dict; pdf_obj *colorspace; int colortype; ximage_info info; struct JPEG_info j_info; if (!check_for_jpeg(fp)) { WARN("%s: Not a JPEG file?", JPEG_DEBUG_STR); rewind(fp); return -1; } /* File position is 2 here... */ pdf_ximage_init_image_info(&info); JPEG_info_init(&j_info); if (JPEG_scan_file(&j_info, fp) < 0) { WARN("%s: Not a JPEG file?", JPEG_DEBUG_STR); JPEG_info_clear(&j_info); return -1; } switch (j_info.num_components) { case 1: colortype = PDF_COLORSPACE_TYPE_GRAY; break; case 3: colortype = PDF_COLORSPACE_TYPE_RGB; break; case 4: colortype = PDF_COLORSPACE_TYPE_CMYK; break; default: WARN("%s: Unknown color space (num components: %d)", JPEG_DEBUG_STR, info.num_components); JPEG_info_clear(&j_info); return -1; } /* JPEG image use DCTDecode. */ stream = pdf_new_stream (0); stream_dict = pdf_stream_dict(stream); pdf_add_dict(stream_dict, pdf_new_name("Filter"), pdf_new_name("DCTDecode")); colorspace = NULL; if (j_info.flags & HAVE_APPn_ICC) { pdf_obj *icc_stream, *intent; icc_stream = JPEG_get_iccp(&j_info); if (!icc_stream) colorspace = NULL; else { int cspc_id; if (iccp_check_colorspace(colortype, pdf_stream_dataptr(icc_stream), pdf_stream_length (icc_stream)) < 0) colorspace = NULL; else { cspc_id = iccp_load_profile(NULL, /* noname */ pdf_stream_dataptr(icc_stream), pdf_stream_length (icc_stream)); if (cspc_id < 0) colorspace = NULL; else { colorspace = pdf_get_colorspace_reference(cspc_id); intent = iccp_get_rendering_intent(pdf_stream_dataptr(icc_stream), pdf_stream_length (icc_stream)); if (intent) pdf_add_dict(stream_dict, pdf_new_name("Intent"), intent); } } pdf_release_obj(icc_stream); } } /* No ICC or invalid ICC profile. */ if (!colorspace) { switch (colortype) { case PDF_COLORSPACE_TYPE_GRAY: colorspace = pdf_new_name("DeviceGray"); break; case PDF_COLORSPACE_TYPE_RGB: colorspace = pdf_new_name("DeviceRGB"); break; case PDF_COLORSPACE_TYPE_CMYK: colorspace = pdf_new_name("DeviceCMYK"); break; } } pdf_add_dict(stream_dict, pdf_new_name("ColorSpace"), colorspace); #define IS_ADOBE_CMYK(j) (((j).flags & HAVE_APPn_ADOBE) && (j).num_components == 4) if (IS_ADOBE_CMYK(j_info)) { pdf_obj *decode; int i; WARN("Adobe CMYK JPEG: Inverted color assumed."); decode = pdf_new_array(); for (i = 0; i < j_info.num_components; i++) { pdf_add_array(decode, pdf_new_number(1.0)); pdf_add_array(decode, pdf_new_number(0.0)); } pdf_add_dict(stream_dict, pdf_new_name("Decode"), decode); } /* Copy file */ JPEG_copy_stream(&j_info, stream, fp); info.width = j_info.width; info.height = j_info.height; info.bits_per_component = j_info.bits_per_component; info.num_components = j_info.num_components; jpeg_get_density(&j_info, &info.xdensity, &info.ydensity); pdf_ximage_set_image(ximage, &info, stream); JPEG_info_clear(&j_info); return 0; }
pdf_obj * CMap_create_stream (CMap *cmap) { pdf_obj *stream; pdf_obj *stream_dict; CIDSysInfo *csi; struct sbuf wbuf; struct rangeDef *ranges; unsigned char *codestr; int i, j, count = 0; if (!cmap || !CMap_is_valid(cmap)) { WARN("Invalid CMap"); return NULL; } if (cmap->type == CMAP_TYPE_IDENTITY) return NULL; stream = pdf_new_stream(STREAM_COMPRESS); stream_dict = pdf_stream_dict(stream); csi = CMap_get_CIDSysInfo(cmap); if (!csi) { csi = (cmap->type != CMAP_TYPE_TO_UNICODE) ? &CSI_IDENTITY : &CSI_UNICODE; } if (cmap->type != CMAP_TYPE_TO_UNICODE) { pdf_obj *csi_dict; csi_dict = pdf_new_dict(); pdf_add_dict(csi_dict, pdf_new_name("Registry"), pdf_new_string(csi->registry, strlen(csi->registry))); pdf_add_dict(csi_dict, pdf_new_name("Ordering"), pdf_new_string(csi->ordering, strlen(csi->ordering))); pdf_add_dict(csi_dict, pdf_new_name("Supplement"), pdf_new_number(csi->supplement)); pdf_add_dict(stream_dict, pdf_new_name("Type"), pdf_new_name("CMap")); pdf_add_dict(stream_dict, pdf_new_name("CMapName"), pdf_new_name(cmap->name)); pdf_add_dict(stream_dict, pdf_new_name("CIDSystemInfo"), csi_dict); if (cmap->wmode != 0) pdf_add_dict(stream_dict, pdf_new_name("WMode"), pdf_new_number(cmap->wmode)); } /* TODO: * Predefined CMaps need not to be embedded. */ if (cmap->useCMap) { ERROR("UseCMap found (not supported yet)..."); if (CMap_is_Identity(cmap->useCMap)) { /* not sure */ if (CMap_get_wmode(cmap) == 1) { pdf_add_dict(stream_dict, pdf_new_name("UseCMap"), pdf_new_name("Identity-V")); } else { pdf_add_dict(stream_dict, pdf_new_name("UseCMap"), pdf_new_name("Identity-H")); } } else { int res_id; pdf_obj *ucmap_ref; res_id = pdf_findresource("CMap", CMap_get_name(cmap->useCMap)); if (res_id >= 0) { ucmap_ref = pdf_get_resource_reference(res_id); } else { pdf_obj *ucmap_obj; ucmap_obj = CMap_create_stream(cmap->useCMap); if (!ucmap_obj) { ERROR("Uh ah. I cannot continue..."); } res_id = pdf_defineresource("CMap", CMap_get_name(cmap->useCMap), ucmap_obj, PDF_RES_FLUSH_IMMEDIATE); ucmap_ref = pdf_get_resource_reference(res_id); } pdf_add_dict(stream_dict, pdf_new_name("UseCMap"), ucmap_ref); } } #define WBUF_SIZE 40960 wbuf.buf = NEW(WBUF_SIZE, char); codestr = NEW(cmap->profile.maxBytesIn, unsigned char); memset(codestr, 0, cmap->profile.maxBytesIn); wbuf.curptr = wbuf.buf; wbuf.limptr = wbuf.buf + WBUF_SIZE - 2 * (cmap->profile.maxBytesIn + cmap->profile.maxBytesOut) + 16; /* Start CMap */ pdf_add_stream(stream, (const void *) CMAP_BEGIN, strlen(CMAP_BEGIN)); wbuf.curptr += sprintf(wbuf.curptr, "/CMapName "); write_name(&wbuf.curptr, wbuf.limptr, cmap->name); wbuf.curptr += sprintf(wbuf.curptr, " def\n"); wbuf.curptr += sprintf(wbuf.curptr, "/CMapType %d def\n" , cmap->type); if (cmap->wmode != 0 && cmap->type != CMAP_TYPE_TO_UNICODE) wbuf.curptr += sprintf(wbuf.curptr, "/WMode %d def\n", cmap->wmode); #define CMAP_CSI_FMT "/CIDSystemInfo <<\n\ /Registry (%s)\n\ /Ordering (%s)\n\ /Supplement %d\n\ >> def\n" wbuf.curptr += sprintf(wbuf.curptr, "/CIDSystemInfo <<\n"); wbuf.curptr += sprintf(wbuf.curptr, " /Registry "); write_string(&wbuf.curptr, wbuf.limptr, csi->registry); wbuf.curptr += sprintf(wbuf.curptr, "\n"); wbuf.curptr += sprintf(wbuf.curptr, " /Ordering "); write_string(&wbuf.curptr, wbuf.limptr, csi->ordering); wbuf.curptr += sprintf(wbuf.curptr, "\n"); wbuf.curptr += sprintf(wbuf.curptr, " /Supplement %d\n>> def\n", csi->supplement); pdf_add_stream(stream, wbuf.buf, (int)(wbuf.curptr - wbuf.buf)); wbuf.curptr = wbuf.buf; /* codespacerange */ ranges = cmap->codespace.ranges; wbuf.curptr += sprintf(wbuf.curptr, "%d begincodespacerange\n", cmap->codespace.num); for (i = 0; i < cmap->codespace.num; i++) { *(wbuf.curptr)++ = '<'; for (j = 0; j < ranges[i].dim; j++) { sputx(ranges[i].codeLo[j], &(wbuf.curptr), wbuf.limptr); } *(wbuf.curptr)++ = '>'; *(wbuf.curptr)++ = ' '; *(wbuf.curptr)++ = '<'; for (j = 0; j < ranges[i].dim; j++) { sputx(ranges[i].codeHi[j], &(wbuf.curptr), wbuf.limptr); } *(wbuf.curptr)++ = '>'; *(wbuf.curptr)++ = '\n'; } pdf_add_stream(stream, wbuf.buf, (int)(wbuf.curptr - wbuf.buf)); wbuf.curptr = wbuf.buf; pdf_add_stream(stream, "endcodespacerange\n", strlen("endcodespacerange\n")); /* CMap body */ if (cmap->mapTbl) { count = write_map(cmap->mapTbl, 0, codestr, 0, &wbuf, stream); /* Top node */ if (count > 0) { /* Flush */ char fmt_buf[32]; if (count > 100) ERROR("Unexpected error....: %d", count); sprintf(fmt_buf, "%d beginbfchar\n", count); pdf_add_stream(stream, fmt_buf, strlen(fmt_buf)); pdf_add_stream(stream, wbuf.buf, (int) (wbuf.curptr - wbuf.buf)); pdf_add_stream(stream, "endbfchar\n", strlen("endbfchar\n")); count = 0; wbuf.curptr = wbuf.buf; } } /* End CMap */ pdf_add_stream(stream, CMAP_END, strlen(CMAP_END)); RELEASE(codestr); RELEASE(wbuf.buf); return stream; }
int bmp_include_image (pdf_ximage *ximage, FILE *fp) { pdf_obj *stream, *stream_dict, *colorspace; ximage_info info; struct hdr_info hdr; int num_palette, flip; int i; pdf_ximage_init_image_info(&info); stream = stream_dict = colorspace = NULL; rewind(fp); if (read_header(fp, &hdr) < 0) return -1; get_density(&info.xdensity, &info.ydensity, &hdr); info.width = hdr.width; info.height = hdr.height; if (info.height < 0) { info.height = -info.height; flip = 0; } else { flip = 1; } if (hdr.bit_count < 24) { if (hdr.bit_count != 1 && hdr.bit_count != 4 && hdr.bit_count != 8) { WARN("Unsupported palette size: %ld", hdr.bit_count); return -1; } num_palette = (hdr.offset - hdr.hsize - DIB_FILE_HEADER_SIZE) / hdr.psize; info.bits_per_component = hdr.bit_count; info.num_components = 1; } else if (hdr.bit_count == 24) { /* full color */ num_palette = 1; /* dummy */ info.bits_per_component = 8; info.num_components = 3; } else { WARN("Unkown/Unsupported BMP bitCount value: %ld", hdr.bit_count); return -1; } if (info.width == 0 || info.height == 0 || num_palette < 1) { WARN("Invalid BMP file: width=%ld, height=%ld, #palette=%d", info.width, info.height, num_palette); return -1; } /* Start reading raster data */ stream = pdf_new_stream(STREAM_COMPRESS); stream_dict = pdf_stream_dict(stream); /* Color space: Indexed or DeviceRGB */ if (hdr.bit_count < 24) { pdf_obj *lookup; unsigned char *palette, bgrq[4]; palette = NEW(num_palette*3+1, unsigned char); for (i = 0; i < num_palette; i++) { if (fread(bgrq, 1, hdr.psize, fp) != hdr.psize) { WARN("Reading file failed..."); RELEASE(palette); return -1; } /* BGR data */ palette[3*i ] = bgrq[2]; palette[3*i+1] = bgrq[1]; palette[3*i+2] = bgrq[0]; } lookup = pdf_new_string(palette, num_palette*3); RELEASE(palette); colorspace = pdf_new_array(); pdf_add_array(colorspace, pdf_new_name("Indexed")); pdf_add_array(colorspace, pdf_new_name("DeviceRGB")); pdf_add_array(colorspace, pdf_new_number(num_palette-1)); pdf_add_array(colorspace, lookup); } else {
pdf_obj *start_png_image (FILE *file, char *res_name) { pdf_obj *result = NULL, *dict = NULL; png_structp png_ptr; png_infop info_ptr; unsigned long width, height; unsigned bit_depth, color_type; rewind (file); if (!(png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) || !(info_ptr = png_create_info_struct (png_ptr))) { fprintf (stderr, "\n\nLibpng failed to initialize\n"); if (png_ptr) png_destroy_read_struct(&png_ptr, NULL, NULL); return NULL; } png_init_io (png_ptr, file); /* png_set_sig_bytes (png_ptr, 0); */ /* Read PNG header */ png_read_info (png_ptr, info_ptr); { png_color_16 default_background; png_color_16p file_background; default_background.red=255; default_background.green=255; default_background.blue=255; default_background.gray=0; default_background.index = 0; width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); /* Convert paletted images to true color */ if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_expand(png_ptr); } /* Limit image component depth to 8 bits */ if (bit_depth == 16) { png_set_strip_16 (png_ptr); } if (png_get_bKGD(png_ptr, info_ptr, &file_background)) { png_set_background(png_ptr, file_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); } else { png_set_background(png_ptr, &default_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } } { /* Read the image in raw RGB format */ int i, rowbytes, pdf_bit_depth; png_bytep *rows; png_read_update_info(png_ptr, info_ptr); rows = NEW (height, png_bytep); rowbytes = png_get_rowbytes(png_ptr, info_ptr); rows[0] = NEW (rowbytes*height, png_byte); for (i=1; i<height; i++) { rows[i] = rows[0] + rowbytes * i; } png_read_image(png_ptr, rows); result = pdf_new_stream(STREAM_COMPRESS); dict = pdf_stream_dict(result); pdf_add_dict (dict, pdf_new_name ("Width"), pdf_new_number(width)); pdf_add_dict (dict, pdf_new_name ("Height"), pdf_new_number(height)); if (color_type == PNG_COLOR_TYPE_GRAY) { pdf_bit_depth = bit_depth; } else { pdf_bit_depth = 8; } pdf_add_dict (dict, pdf_new_name ("BitsPerComponent"), pdf_new_number(pdf_bit_depth)); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { pdf_add_dict (dict, pdf_new_name ("ColorSpace"), pdf_new_name ("DeviceGray")); } else{ pdf_add_dict (dict, pdf_new_name ("ColorSpace"), pdf_new_name ("DeviceRGB")); } pdf_add_stream (result, (char *)rows[0], rowbytes*height); RELEASE (rows[0]); RELEASE (rows); } { /* Cleanup */ if (info_ptr) png_destroy_info_struct(png_ptr, &info_ptr); if (png_ptr) png_destroy_read_struct(&png_ptr, NULL, NULL); } return result; }