pdf_obj *parse_pdf_array (char **start, char *end) { pdf_obj *result, *tmp1; #ifdef MEM_DEBUG MEM_START #endif skip_white(start, end); if (*((*start)++) != '[') return NULL; result = pdf_new_array (); skip_white(start, end); while (*start < end && **start != ']') { if ((tmp1 = parse_pdf_object (start, end)) == NULL) { pdf_release_obj (result); return NULL; }; pdf_add_array (result, tmp1); skip_white(start, end); } if (*start >= end) { pdf_release_obj (result); fprintf (stderr, "\nArray ended prematurely\n"); return NULL; } (*start)++; #ifdef MEM_DEBUG MEM_END #endif return result; }
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; }
/* It does write PDF objects. */ void CIDFont_flush (CIDFont *font) { if (font) { if (font->indirect) pdf_release_obj(font->indirect); font->indirect = NULL; if (font->fontdict) pdf_release_obj(font->fontdict); font->fontdict = NULL; if (font->descriptor) pdf_release_obj(font->descriptor); font->descriptor = NULL; } }
pdf_obj *parse_pdf_dict (char **start, char *end) { pdf_obj *result, *tmp1, *tmp2; char *save = *start; skip_white(start, end); if (*((*start)++) != '<' || *((*start)++) != '<') { *start = save; dump (*start, end); return NULL; } result = pdf_new_dict (); skip_white(start, end); while (*start < end && **start != '>') { if ((tmp1 = parse_pdf_name (start, end)) == NULL) { pdf_release_obj (result); { *start = save; dump (*start, end); return NULL; } }; if ((tmp2 = parse_pdf_object (start, end)) == NULL) { pdf_release_obj (result); pdf_release_obj (tmp1); { *start = save; dump (*start, end); return NULL; } } pdf_add_dict (result, tmp1, tmp2); skip_white(start, end); } if (*start >= end) { pdf_release_obj (result); *start = save; dump (*start, end); return NULL; } if (*((*start)++) == '>' && *((*start)++) == '>') { return result; } else { pdf_release_obj (result); fprintf (stderr, "\nDictionary object ended prematurely\n"); *start = save; dump (*start, end); return NULL; } }
static void pdf_flush_resource (pdf_res *res) { if (res) { if (res->reference) pdf_release_obj(res->reference); if (res->object) pdf_release_obj(res->object); res->reference = NULL; res->object = NULL; } }
static void Type0Font_flush (Type0Font *font) { if (font) { if (font->fontdict) pdf_release_obj(font->fontdict); font->fontdict = NULL; if (font->indirect) pdf_release_obj(font->indirect); font->indirect = NULL; if (font->descriptor) ERROR("%s: FontDescriptor unexpected for Type0 font.", TYPE0FONT_DEBUG_STR); font->descriptor = NULL; } }
static void pdf_flush_encoding (pdf_encoding *encoding) { ASSERT(encoding); if (encoding->resource) { pdf_release_obj(encoding->resource); encoding->resource = NULL; } if (encoding->tounicode) { pdf_release_obj(encoding->tounicode); encoding->tounicode = NULL; } return; }
static pdf_obj * JPEG_get_iccp (struct JPEG_info *j_info) { pdf_obj *icc_stream; struct JPEG_APPn_ICC *icc; int i, prev_id = 0, num_icc_seg = -1; icc_stream = pdf_new_stream(STREAM_COMPRESS); for (i = 0; i < j_info->num_appn; i++) { if (j_info->appn[i].marker != JM_APP2 || j_info->appn[i].app_sig != JS_APPn_ICC) continue; icc = (struct JPEG_APPn_ICC *) j_info->appn[i].app_data; if (num_icc_seg < 0 && prev_id == 0) { num_icc_seg = icc->num_chunks; /* ICC chunks are sorted? */ } else if (icc->seq_id != prev_id + 1 || num_icc_seg != icc->num_chunks || icc->seq_id > icc->num_chunks) { WARN("Invalid JPEG ICC chunk: %d (p:%d, n:%d)", icc->seq_id, prev_id, icc->num_chunks); pdf_release_obj(icc_stream); icc_stream = NULL; break; } pdf_add_stream(icc_stream, icc->chunk, icc->length); prev_id = icc->seq_id; num_icc_seg = icc->num_chunks; } return icc_stream; }
static void pdf_clean_encoding_struct (pdf_encoding *encoding) { int code; ASSERT(encoding); if (encoding->resource) ERROR("Object not flushed."); if (encoding->tounicode) pdf_release_obj(encoding->tounicode); if (encoding->ident) RELEASE(encoding->ident); if (encoding->enc_name) RELEASE(encoding->enc_name); encoding->ident = NULL; encoding->enc_name = NULL; for (code = 0; code < 256; code++) { if (encoding->glyphs[code]) RELEASE(encoding->glyphs[code]); encoding->glyphs[code] = NULL; } encoding->ident = NULL; encoding->enc_name = NULL; return; }
static void pdf_clean_resource (pdf_res *res) { if (res) { if (res->reference || res->object) WARN("Trying to release un-flushed object."); if (res->reference) pdf_release_obj(res->reference); if (res->object) pdf_release_obj(res->object); if (res->ident) RELEASE(res->ident); res->ident = NULL; res->category = -1; res->flags = 0; } }
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; }
/* 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; }
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 {
static int load_encoding_file (const char *filename) { FILE *fp; pdf_obj *enc_name = NULL; pdf_obj *encoding_array = NULL; char *wbuf; const char *p, *endptr; const char *enc_vec[256]; int code, fsize, enc_id; if (!filename) return -1; if (dpx_conf.verbose_level > 0) { MESG("(Encoding:%s", filename); } fp = DPXFOPEN(filename, DPX_RES_TYPE_ENC); if (!fp) return -1; /* * file_size do seek_end witout saving current position and * do rewind. */ fsize = file_size(fp); wbuf = NEW(fsize + 1, char); wbuf[fsize] = '\0'; fread(wbuf, sizeof(char), fsize, fp); DPXFCLOSE(fp); p = wbuf; endptr = wbuf + fsize; skip_white(&p, endptr); /* * Skip comment lines. */ while (p < endptr && p[0] == '%') { pdfparse_skip_line (&p, endptr); skip_white(&p, endptr); } if (p[0] == '/') enc_name = parse_pdf_name(&p, endptr); skip_white(&p, endptr); encoding_array = parse_pdf_array(&p, endptr, NULL); RELEASE(wbuf); if (!encoding_array) { if (enc_name) pdf_release_obj(enc_name); return -1; } for (code = 0; code < 256; code++) { enc_vec[code] = pdf_name_value(pdf_get_array(encoding_array, code)); } enc_id = pdf_encoding_new_encoding(enc_name ? pdf_name_value(enc_name) : NULL, filename, enc_vec, NULL, 0); if (enc_name) { if (dpx_conf.verbose_level > 1) MESG("[%s]", pdf_name_value(enc_name)); pdf_release_obj(enc_name); } pdf_release_obj(encoding_array); if (dpx_conf.verbose_level > 0) MESG(")"); return enc_id; }
int pdf_copy_clip (FILE *image_file, int pageNo, double x_user, double y_user) { pdf_obj *page_tree, *contents; int depth = 0, top = -1; const char *clip_path, *end_path; char *save_path, *temp; pdf_tmatrix M; double stack[6]; pdf_file *pf; pf = pdf_open(NULL, image_file); if (!pf) return -1; pdf_dev_currentmatrix(&M); pdf_invertmatrix(&M); M.e += x_user; M.f += y_user; page_tree = pdf_get_page_obj (pf, pageNo, NULL, NULL); if (!page_tree) { pdf_close(pf); return -1; } contents = pdf_get_page_content(page_tree); pdf_release_obj(page_tree); if (!contents) { pdf_close(pf); return -1; } pdf_doc_add_page_content(" ", 1); save_path = malloc(pdf_stream_length(contents) + 1); strncpy(save_path, (const char *) pdf_stream_dataptr(contents), pdf_stream_length(contents)); clip_path = save_path; end_path = clip_path + pdf_stream_length(contents); depth = 0; for (; clip_path < end_path; clip_path++) { int color_dimen = 0; /* silence uninitialized warning */ char *token; skip_white(&clip_path, end_path); if (clip_path == end_path) break; if (depth > 1) { if (*clip_path == 'q') depth++; if (*clip_path == 'Q') depth--; parse_ident(&clip_path, end_path); continue; } else if (*clip_path == '-' || *clip_path == '+' || *clip_path == '.' || isdigit((unsigned char)*clip_path)) { stack[++top] = strtod(clip_path, &temp); clip_path = temp; } else if (*clip_path == '[') { /* Ignore, but put a dummy value on the stack (in case of d operator) */ parse_pdf_array(&clip_path, end_path, pf); stack[++top] = 0; } else if (*clip_path == '/') { if (strncmp("/DeviceGray", clip_path, 11) == 0 || strncmp("/Indexed", clip_path, 8) == 0 || strncmp("/CalGray", clip_path, 8) == 0) { color_dimen = 1; continue; } else if (strncmp("/DeviceRGB", clip_path, 10) == 0 || strncmp("/CalRGB", clip_path, 7) == 0 || strncmp("/Lab", clip_path, 4) == 0) { color_dimen = 3; continue; } else if (strncmp("/DeviceCMYK", clip_path, 11) == 0) { color_dimen = 4; continue; } else { clip_path++; parse_ident(&clip_path, end_path); skip_white(&clip_path, end_path); token = parse_ident(&clip_path, end_path); if (strcmp(token, "gs") == 0) { continue; } return -1; } } else { int j; pdf_tmatrix T; pdf_coord p0, p1, p2, p3; token = parse_ident(&clip_path, end_path); for (j = 0; j < sizeof(pdf_operators) / sizeof(pdf_operators[0]); j++) if (strcmp(token, pdf_operators[j].token) == 0) break; if (j == sizeof(pdf_operators) / sizeof(pdf_operators[0])) { return -1; } switch (pdf_operators[j].opcode) { case 0: case -1: case -2: case -3: case -4: /* Just pop the stack and do nothing. */ top += pdf_operators[j].opcode; if (top < -1) return -1; break; case OP_SETCOLOR: top -= color_dimen; if (top < -1) return -1; break; case OP_CLOSEandCLIP: pdf_dev_closepath(); case OP_CLIP: #if 0 pdf_dev_clip(); #else pdf_dev_flushpath('W', PDF_FILL_RULE_NONZERO); #endif break; case OP_CONCATMATRIX: if (top < 5) return -1; T.f = stack[top--]; T.e = stack[top--]; T.d = stack[top--]; T.c = stack[top--]; T.b = stack[top--]; T.a = stack[top--]; pdf_concatmatrix(&M, &T); break; case OP_SETCOLORSPACE: /* Do nothing. */ break; case OP_RECTANGLE: if (top < 3) return -1; p1.y = stack[top--]; p1.x = stack[top--]; p0.y = stack[top--]; p0.x = stack[top--]; if (M.b == 0 && M.c == 0) { pdf_tmatrix M0; M0.a = M.a; M0.b = M.b; M0.c = M.c; M0.d = M.d; M0.e = 0; M0.f = 0; pdf_dev_transform(&p0, &M); pdf_dev_transform(&p1, &M0); pdf_dev_rectadd(p0.x, p0.y, p1.x, p1.y); } else { p2.x = p0.x + p1.x; p2.y = p0.y + p1.y; p3.x = p0.x; p3.y = p0.y + p1.y; p1.x += p0.x; p1.y = p0.y; pdf_dev_transform(&p0, &M); pdf_dev_transform(&p1, &M); pdf_dev_transform(&p2, &M); pdf_dev_transform(&p3, &M); pdf_dev_moveto(p0.x, p0.y); pdf_dev_lineto(p1.x, p1.y); pdf_dev_lineto(p2.x, p2.y); pdf_dev_lineto(p3.x, p3.y); pdf_dev_closepath(); } break; case OP_CURVETO: if (top < 5) return -1; p0.y = stack[top--]; p0.x = stack[top--]; pdf_dev_transform(&p0, &M); p1.y = stack[top--]; p1.x = stack[top--]; pdf_dev_transform(&p1, &M); p2.y = stack[top--]; p2.x = stack[top--]; pdf_dev_transform(&p2, &M); pdf_dev_curveto(p2.x, p2.y, p1.x, p1.y, p0.x, p0.y); break; case OP_CLOSEPATH: pdf_dev_closepath(); break; case OP_LINETO: if (top < 1) return -1; p0.y = stack[top--]; p0.x = stack[top--]; pdf_dev_transform(&p0, &M); pdf_dev_lineto(p0.x, p0.y); break; case OP_MOVETO: if (top < 1) return -1; p0.y = stack[top--]; p0.x = stack[top--]; pdf_dev_transform(&p0, &M); pdf_dev_moveto(p0.x, p0.y); break; case OP_NOOP: pdf_doc_add_page_content(" n", 2); break; case OP_GSAVE: depth++; break; case OP_GRESTORE: depth--; break; case OP_CURVETO1: if (top < 3) return -1; p0.y = stack[top--]; p0.x = stack[top--]; pdf_dev_transform(&p0, &M); p1.y = stack[top--]; p1.x = stack[top--]; pdf_dev_transform(&p1, &M); pdf_dev_vcurveto(p1.x, p1.y, p0.x, p0.y); break; case OP_CURVETO2: if (top < 3) return -1; p0.y = stack[top--]; p0.x = stack[top--]; pdf_dev_transform(&p0, &M); p1.y = stack[top--]; p1.x = stack[top--]; pdf_dev_transform(&p1, &M); pdf_dev_ycurveto(p1.x, p1.y, p0.x, p0.y); break; default: return -1; } } } free(save_path); pdf_release_obj(contents); pdf_close(pf); 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; }
static pdf_obj* pdf_get_page_content (pdf_obj* page) { pdf_obj *contents, *content_new; contents = pdf_deref_obj(pdf_lookup_dict(page, "Contents")); if (!contents) return NULL; if (pdf_obj_typeof(contents) == PDF_NULL) { /* empty page */ pdf_release_obj(contents); /* TODO: better don't include anything if the page is empty */ contents = pdf_new_stream(0); } else if (PDF_OBJ_ARRAYTYPE(contents)) { /* * Concatenate all content streams. */ pdf_obj *content_seg; int idx = 0; content_new = pdf_new_stream(STREAM_COMPRESS); for (;;) { content_seg = pdf_deref_obj(pdf_get_array(contents, idx)); if (!content_seg) break; else if (PDF_OBJ_NULLTYPE(content_seg)) { /* Silently ignore. */ } else if (!PDF_OBJ_STREAMTYPE(content_seg)) { WARN("Page content not a stream object. Broken PDF file?"); pdf_release_obj(content_seg); pdf_release_obj(content_new); pdf_release_obj(contents); return NULL; } else if (pdf_concat_stream(content_new, content_seg) < 0) { WARN("Could not handle content stream with multiple segments."); pdf_release_obj(content_seg); pdf_release_obj(content_new); pdf_release_obj(contents); return NULL; } pdf_release_obj(content_seg); idx++; } pdf_release_obj(contents); contents = content_new; } else { if (!PDF_OBJ_STREAMTYPE(contents)) { WARN("Page content not a stream object. Broken PDF file?"); pdf_release_obj(contents); return NULL; } /* Flate the contents if necessary. */ content_new = pdf_new_stream(STREAM_COMPRESS); if (pdf_concat_stream(content_new, contents) < 0) { WARN("Could not handle a content stream."); pdf_release_obj(contents); pdf_release_obj(content_new); return NULL; } pdf_release_obj(contents); contents = content_new; } return contents; }
static pdf_obj* pdf_get_page_obj (pdf_file *pf, int page_no, pdf_obj **ret_bbox, pdf_obj **ret_resources) { pdf_obj *page_tree; pdf_obj *bbox = NULL, *resources = NULL, *rotate = NULL; int page_idx; /* * Get Page Tree. */ page_tree = NULL; { pdf_obj *trailer, *catalog; pdf_obj *markinfo, *tmp; trailer = pdf_file_get_trailer(pf); if (pdf_lookup_dict(trailer, "Encrypt")) { WARN("This PDF document is encrypted."); pdf_release_obj(trailer); return NULL; } catalog = pdf_deref_obj(pdf_lookup_dict(trailer, "Root")); if (!PDF_OBJ_DICTTYPE(catalog)) { WARN("Can't read document catalog."); pdf_release_obj(trailer); if (catalog) pdf_release_obj(catalog); return NULL; } pdf_release_obj(trailer); markinfo = pdf_deref_obj(pdf_lookup_dict(catalog, "MarkInfo")); if (markinfo) { tmp = pdf_lookup_dict(markinfo, "Marked"); if (PDF_OBJ_BOOLEANTYPE(tmp) && pdf_boolean_value(tmp)) WARN("PDF file is tagged... Ignoring tags."); pdf_release_obj(markinfo); } page_tree = pdf_deref_obj(pdf_lookup_dict(catalog, "Pages")); pdf_release_obj(catalog); } if (!page_tree) { WARN("Page tree not found."); return NULL; } /* * Negative page numbers are counted from the back. */ { int count = pdf_number_value(pdf_lookup_dict(page_tree, "Count")); page_idx = page_no + (page_no >= 0 ? -1 : count); if (page_idx < 0 || page_idx >= count) { WARN("Page %ld does not exist.", page_no); pdf_release_obj(page_tree); return NULL; } page_no = page_idx+1; } /* * Seek correct page. Get Media/Crop Box. * Media box and resources can be inherited. */ { pdf_obj *kids_ref, *kids; pdf_obj *crop_box = NULL; pdf_obj *tmp; tmp = pdf_lookup_dict(page_tree, "Resources"); resources = tmp ? pdf_deref_obj(tmp) : pdf_new_dict(); while (1) { int kids_length, i; if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "MediaBox")))) { if (bbox) pdf_release_obj(bbox); bbox = tmp; } if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "BleedBox")))) { if (!rect_equal(tmp, bbox)) { if (bbox) pdf_release_obj(bbox); bbox = tmp; } else { pdf_release_obj(tmp); } } if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "TrimBox")))) { if (!rect_equal(tmp, bbox)) { if (bbox) pdf_release_obj(bbox); bbox = tmp; } else { pdf_release_obj(tmp); } } if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "ArtBox")))) { if (!rect_equal(tmp, bbox)) { if (bbox) pdf_release_obj(bbox); bbox = tmp; } else { pdf_release_obj(tmp); } } if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "CropBox")))) { if (crop_box) pdf_release_obj(crop_box); crop_box = tmp; } if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Rotate")))) { if (rotate) pdf_release_obj(rotate); rotate = tmp; } if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Resources")))) { #if 0 pdf_merge_dict(tmp, resources); #endif if (resources) pdf_release_obj(resources); resources = tmp; } kids_ref = pdf_lookup_dict(page_tree, "Kids"); if (!kids_ref) break; kids = pdf_deref_obj(kids_ref); kids_length = pdf_array_length(kids); for (i = 0; i < kids_length; i++) { int count; pdf_release_obj(page_tree); page_tree = pdf_deref_obj(pdf_get_array(kids, i)); tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Count")); if (tmp) { /* Pages object */ count = pdf_number_value(tmp); pdf_release_obj(tmp); } else { /* Page object */ count = 1; } if (page_idx < count) break; page_idx -= count; } pdf_release_obj(kids); if (i == kids_length) { WARN("Page %ld not found! Broken PDF file?", page_no); if (bbox) pdf_release_obj(bbox); if (crop_box) pdf_release_obj(crop_box); if (rotate) pdf_release_obj(rotate); pdf_release_obj(resources); pdf_release_obj(page_tree); return NULL; } } if (crop_box) { pdf_release_obj(bbox); bbox = crop_box; } } if (!bbox) { WARN("No BoundingBox information available."); pdf_release_obj(page_tree); pdf_release_obj(resources); if (rotate) pdf_release_obj(rotate); return NULL; } if (rotate) { if (pdf_number_value(rotate) != 0.0) WARN("<< /Rotate %d >> found. (Not supported yet)", (int)pdf_number_value(rotate)); pdf_release_obj(rotate); rotate = NULL; } if (ret_bbox != NULL) *ret_bbox = bbox; if (ret_resources != NULL) *ret_resources = resources; return page_tree; }
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; } } }
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); }
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; }
int png_include_image (pdf_ximage *ximage, FILE *png_file) { pdf_obj *stream; pdf_obj *stream_dict; pdf_obj *colorspace, *mask, *intent; png_bytep stream_data_ptr; int trans_type; ximage_info info; /* Libpng stuff */ png_structp png_ptr; png_infop png_info_ptr; png_byte bpc, color_type; png_uint_32 width, height, rowbytes; pdf_ximage_init_image_info(&info); stream = NULL; stream_dict = NULL; colorspace = mask = intent = NULL; rewind (png_file); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, warn); if (png_ptr == NULL || (png_info_ptr = png_create_info_struct (png_ptr)) == NULL) { WARN("%s: Creating Libpng read/info struct failed.", PNG_DEBUG_STR); if (png_ptr) png_destroy_read_struct(&png_ptr, NULL, NULL); return -1; } #if PNG_LIBPNG_VER >= 10603 /* ignore possibly incorrect CMF bytes */ png_set_option(png_ptr, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON); #endif /* Inititializing file IO. */ png_init_io (png_ptr, png_file); /* Read PNG info-header and get some info. */ png_read_info(png_ptr, png_info_ptr); color_type = png_get_color_type (png_ptr, png_info_ptr); width = png_get_image_width (png_ptr, png_info_ptr); height = png_get_image_height(png_ptr, png_info_ptr); bpc = png_get_bit_depth (png_ptr, png_info_ptr); /* Ask libpng to convert down to 8-bpc. */ if (bpc > 8) { if (pdf_get_version() < 5) { WARN("%s: 16-bpc PNG requires PDF version 1.5.", PNG_DEBUG_STR); png_set_strip_16(png_ptr); bpc = 8; } } /* Ask libpng to gamma-correct. * It is wrong to assume screen gamma value 2.2 but... * We do gamma correction here only when uncalibrated color space is used. */ if (!png_get_valid(png_ptr, png_info_ptr, PNG_INFO_iCCP) && !png_get_valid(png_ptr, png_info_ptr, PNG_INFO_sRGB) && !png_get_valid(png_ptr, png_info_ptr, PNG_INFO_cHRM) && png_get_valid(png_ptr, png_info_ptr, PNG_INFO_gAMA)) { double G = 1.0; png_get_gAMA (png_ptr, png_info_ptr, &G); png_set_gamma(png_ptr, 2.2, G); } trans_type = check_transparency(png_ptr, png_info_ptr); /* check_transparency() does not do updata_info() */ png_read_update_info(png_ptr, png_info_ptr); rowbytes = png_get_rowbytes(png_ptr, png_info_ptr); /* Values listed below will not be modified in the remaining process. */ info.width = width; info.height = height; info.bits_per_component = bpc; if (compat_mode) info.xdensity = info.ydensity = 72.0 / 100.0; else { png_uint_32 xppm = png_get_x_pixels_per_meter(png_ptr, png_info_ptr); png_uint_32 yppm = png_get_y_pixels_per_meter(png_ptr, png_info_ptr); if (xppm > 0) info.xdensity = 72.0 / 0.0254 / xppm; if (yppm > 0) info.ydensity = 72.0 / 0.0254 / yppm; } stream = pdf_new_stream (STREAM_COMPRESS); stream_dict = pdf_stream_dict(stream); stream_data_ptr = (png_bytep) NEW(rowbytes*height, png_byte); read_image_data(png_ptr, stream_data_ptr, height, rowbytes); /* Non-NULL intent means there is valid sRGB chunk. */ intent = get_rendering_intent(png_ptr, png_info_ptr); if (intent) pdf_add_dict(stream_dict, pdf_new_name("Intent"), intent); switch (color_type) { case PNG_COLOR_TYPE_PALETTE: colorspace = create_cspace_Indexed(png_ptr, png_info_ptr); switch (trans_type) { case PDF_TRANS_TYPE_BINARY: /* Color-key masking */ mask = create_ckey_mask(png_ptr, png_info_ptr); break; case PDF_TRANS_TYPE_ALPHA: /* Soft mask */ mask = create_soft_mask(png_ptr, png_info_ptr, stream_data_ptr, width, height); break; default: /* Nothing to be done here. * No tRNS chunk or image already composited with background color. */ break; } info.num_components = 1; break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_iCCP)) colorspace = create_cspace_ICCBased(png_ptr, png_info_ptr); else if (intent) { colorspace = create_cspace_sRGB(png_ptr, png_info_ptr); } else { colorspace = create_cspace_CalRGB(png_ptr, png_info_ptr); } if (!colorspace) colorspace = pdf_new_name("DeviceRGB"); switch (trans_type) { case PDF_TRANS_TYPE_BINARY: mask = create_ckey_mask(png_ptr, png_info_ptr); break; /* rowbytes changes 4 to 3 at here */ case PDF_TRANS_TYPE_ALPHA: mask = strip_soft_mask(png_ptr, png_info_ptr, stream_data_ptr, &rowbytes, width, height); break; default: mask = NULL; } info.num_components = 3; break; case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_GRAY_ALPHA: if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_iCCP)) colorspace = create_cspace_ICCBased(png_ptr, png_info_ptr); else if (intent) { colorspace = create_cspace_sRGB(png_ptr, png_info_ptr); } else { colorspace = create_cspace_CalGray(png_ptr, png_info_ptr); } if (!colorspace) colorspace = pdf_new_name("DeviceGray"); switch (trans_type) { case PDF_TRANS_TYPE_BINARY: mask = create_ckey_mask(png_ptr, png_info_ptr); break; case PDF_TRANS_TYPE_ALPHA: mask = strip_soft_mask(png_ptr, png_info_ptr, stream_data_ptr, &rowbytes, width, height); break; default: mask = NULL; } info.num_components = 1; break; default: WARN("%s: Unknown PNG colortype %d.", PNG_DEBUG_STR, color_type); } pdf_add_dict(stream_dict, pdf_new_name("ColorSpace"), colorspace); pdf_add_stream(stream, stream_data_ptr, rowbytes*height); RELEASE(stream_data_ptr); if (mask) { if (trans_type == PDF_TRANS_TYPE_BINARY) pdf_add_dict(stream_dict, pdf_new_name("Mask"), mask); else if (trans_type == PDF_TRANS_TYPE_ALPHA) { if (info.bits_per_component >= 8 && info.width > 64) { pdf_stream_set_predictor(mask, 2, info.width, info.bits_per_component, 1); } pdf_add_dict(stream_dict, pdf_new_name("SMask"), pdf_ref_obj(mask)); pdf_release_obj(mask); } else { WARN("%s: Unknown transparency type...???", PNG_DEBUG_STR); pdf_release_obj(mask); } } /* Finally read XMP Metadata * See, XMP Specification Part 3, Storage in Files * http://www.adobe.com/jp/devnet/xmp.html * * We require libpng version >= 1.6.14 since prior versions * of libpng had a bug that incorrectly treat the compression * flag of iTxt chunks. */ #if PNG_LIBPNG_VER >= 10614 if (pdf_get_version() >= 4) { png_textp text_ptr; pdf_obj *XMP_stream, *XMP_stream_dict; int i, num_text; int have_XMP = 0; num_text = png_get_text(png_ptr, png_info_ptr, &text_ptr, NULL); for (i = 0; i < num_text; i++) { if (!memcmp(text_ptr[i].key, "XML:com.adobe.xmp", 17)) { /* XMP found */ if (text_ptr[i].compression != PNG_ITXT_COMPRESSION_NONE || text_ptr[i].itxt_length == 0) WARN("%s: Invalid value(s) in iTXt chunk for XMP Metadata.", PNG_DEBUG_STR); else if (have_XMP) WARN("%s: Multiple XMP Metadata. Don't know how to treat it.", PNG_DEBUG_STR); else { /* We compress XMP metadata for included images here. * It is not recommended to compress XMP metadata for PDF documents but * we compress XMP metadata for included images here to avoid confusing * application programs that only want PDF document global XMP metadata * and scan for that. */ XMP_stream = pdf_new_stream(STREAM_COMPRESS); XMP_stream_dict = pdf_stream_dict(XMP_stream); pdf_add_dict(XMP_stream_dict, pdf_new_name("Type"), pdf_new_name("Metadata")); pdf_add_dict(XMP_stream_dict, pdf_new_name("Subtype"), pdf_new_name("XML")); pdf_add_stream(XMP_stream, text_ptr[i].text, text_ptr[i].itxt_length); pdf_add_dict(stream_dict, pdf_new_name("Metadata"), pdf_ref_obj(XMP_stream)); pdf_release_obj(XMP_stream); have_XMP = 1; } } } } #endif /* PNG_LIBPNG_VER */ png_read_end(png_ptr, NULL); /* Cleanup */ if (png_info_ptr) png_destroy_info_struct(png_ptr, &png_info_ptr); if (png_ptr) png_destroy_read_struct(&png_ptr, NULL, NULL); if (color_type != PNG_COLOR_TYPE_PALETTE && info.bits_per_component >= 8 && info.height > 64) { pdf_stream_set_predictor(stream, 15, info.width, info.bits_per_component, info.num_components); } pdf_ximage_set_image(ximage, &info, stream); return 0; }
long pdf_defineresource (const char *category, const char *resname, pdf_obj *object, int flags) { int res_id; struct res_cache *rc; int cat_id; pdf_res *res = NULL; ASSERT(category && object); cat_id = get_category(category); if (cat_id < 0) { ERROR("Unknown resource category: %s", category); return -1; } rc = &resources[cat_id]; if (resname) { for (res_id = 0; res_id < rc->count; res_id++) { res = &rc->resources[res_id]; if (!strcmp(resname, res->ident)) { WARN("Resource %s (category: %s) already defined...", resname, category); pdf_flush_resource(res); res->flags = flags; if (flags & PDF_RES_FLUSH_IMMEDIATE) { res->reference = pdf_ref_obj(object); pdf_release_obj(object); } else { res->object = object; } return (long) ((cat_id << 16)|(res_id)); } } } else { res_id = rc->count; } if (res_id == rc->count) { if (rc->count >= rc->capacity) { rc->capacity += CACHE_ALLOC_SIZE; rc->resources = RENEW(rc->resources, rc->capacity, pdf_res); } res = &rc->resources[res_id]; pdf_init_resource(res); if (resname && resname[0] != '\0') { res->ident = NEW(strlen(resname) + 1, char); strcpy(res->ident, resname); } res->category = cat_id; res->flags = flags; if (flags & PDF_RES_FLUSH_IMMEDIATE) { res->reference = pdf_ref_obj(object); pdf_release_obj(object); } else { res->object = object; } rc->count++; }
/* 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; }