/* CCITT Group 4 filter may reduce file size. */ static pdf_obj * create_pk_CharProc_stream (struct pk_header_ *pkh, double chrwid, unsigned char *pkt_ptr, long pkt_len) { pdf_obj *stream; /* charproc */ long llx, lly, urx, ury; int len, error = 0; llx = -pkh->bm_hoff; lly = pkh->bm_voff - pkh->bm_ht; urx = pkh->bm_wd - pkh->bm_hoff; ury = pkh->bm_voff; stream = pdf_new_stream(STREAM_COMPRESS); /* * The following line is a "metric" for the PDF reader: * * PDF Reference Reference, 4th ed., p.385. * * The wx (first operand of d1) must be consistent with the corresponding * width in the font's Widths array. The format string of sprint() must be * consistent with write_number() in pdfobj.c. */ len = pdf_sprint_number(work_buffer, chrwid); len += sprintf (work_buffer + len, " 0 %ld %ld %ld %ld d1\n", llx, lly, urx, ury); pdf_add_stream(stream, work_buffer, len); /* * Acrobat dislike transformation [0 0 0 0 dx dy]. * PDF Reference, 4th ed., p.147, says, * * Use of a noninvertible matrix when painting graphics objects can result in * unpredictable behavior. * * but it does not forbid use of such transformation. */ if (pkh->bm_wd != 0 && pkh->bm_ht != 0 && pkt_len > 0) { /* Scale and translate origin to lower left corner for raster data */ len = sprintf (work_buffer, "q\n%ld 0 0 %ld %ld %ld cm\n", pkh->bm_wd, pkh->bm_ht, llx, lly); pdf_add_stream(stream, work_buffer, len); len = sprintf (work_buffer, "BI\n/W %ld\n/H %ld\n/IM true\n/BPC 1\nID ", pkh->bm_wd, pkh->bm_ht); pdf_add_stream(stream, work_buffer, len); /* Add bitmap data */ if (pkh->dyn_f == 14) /* bitmap */ error = pk_decode_bitmap(stream, pkh->bm_wd, pkh->bm_ht, pkh->dyn_f, pkh->run_color, pkt_ptr, pkt_len); else error = pk_decode_packed(stream, pkh->bm_wd, pkh->bm_ht, pkh->dyn_f, pkh->run_color, pkt_ptr, pkt_len); len = sprintf (work_buffer, "\nEI\nQ"); pdf_add_stream(stream, work_buffer, len); } /* Otherwise we embed an empty stream :-( */ return stream; }
static void send_out (unsigned char *rowptr, long rowbytes, pdf_obj *stream) #endif { pdf_add_stream(stream, (void *)rowptr, rowbytes); #if DEBUG == 2 { long i, n, len = (wd + 7) / 8; int c; fputc('|', stderr); for (n = 0; n < len; n++) { c = rowptr[n]; for (i = 0; i < 8; i++) { if (n * 8 + i == wd) break; if (c & 1 << (7 - i)) fputc(' ', stderr); else fputc('*', stderr); } } fputc('|', stderr); fputc('\n', stderr); } #endif /* DEBUG2 */ }
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 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 int concat_stream (pdf_obj *dst, pdf_obj *src) { const char *stream_data; long stream_length; pdf_obj *stream_dict; pdf_obj *filter; if (!PDF_OBJ_STREAMTYPE(dst) || !PDF_OBJ_STREAMTYPE(src)) ERROR("Invalid type."); stream_data = pdf_stream_dataptr(src); stream_length = pdf_stream_length (src); stream_dict = pdf_stream_dict (src); if (pdf_lookup_dict(stream_dict, "DecodeParms")) { WARN("DecodeParams not supported."); return -1; } filter = pdf_lookup_dict(stream_dict, "Filter"); if (!filter) { pdf_add_stream(dst, stream_data, stream_length); return 0; #if HAVE_ZLIB } else { char *filter_name; if (PDF_OBJ_NAMETYPE(filter)) { filter_name = pdf_name_value(filter); if (filter_name && !strcmp(filter_name, "FlateDecode")) return add_stream_flate(dst, stream_data, stream_length); else { WARN("DecodeFilter \"%s\" not supported.", filter_name); return -1; } } else if (PDF_OBJ_ARRAYTYPE(filter)) { if (pdf_array_length(filter) > 1) { WARN("Multiple DecodeFilter not supported."); return -1; } else { filter_name = pdf_name_value(pdf_get_array(filter, 0)); if (filter_name && !strcmp(filter_name, "FlateDecode")) return add_stream_flate(dst, stream_data, stream_length); else { WARN("DecodeFilter \"%s\" not supported.", filter_name); return -1; } } } else ERROR("Broken PDF file?"); #endif /* HAVE_ZLIB */ } return -1; }
static int add_stream_flate (pdf_obj *dst, const void *data, long len) { z_stream z; Bytef wbuf[WBUF_SIZE]; z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; z.next_in = (z_const Bytef *) data; z.avail_in = len; z.next_out = (Bytef *) wbuf; z.avail_out = WBUF_SIZE; if (inflateInit(&z) != Z_OK) { WARN("inflateInit() failed."); return -1; } for (;;) { int status; status = inflate(&z, Z_NO_FLUSH); if (status == Z_STREAM_END) break; else if (status != Z_OK) { WARN("inflate() failed. Broken PDF file?"); inflateEnd(&z); return -1; } if (z.avail_out == 0) { pdf_add_stream(dst, wbuf, WBUF_SIZE); z.next_out = wbuf; z.avail_out = WBUF_SIZE; } } if (WBUF_SIZE - z.avail_out > 0) pdf_add_stream(dst, wbuf, WBUF_SIZE - z.avail_out); return (inflateEnd(&z) == Z_OK ? 0 : -1); }
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; }
pdf_obj * pdf_new_xobject(fz_context *ctx, pdf_document *doc, fz_rect bbox, fz_matrix matrix, pdf_obj *res, fz_buffer *contents) { pdf_obj *ind = NULL; pdf_obj *form = pdf_new_dict(ctx, doc, 5); fz_try(ctx) { pdf_dict_put(ctx, form, PDF_NAME(Type), PDF_NAME(XObject)); pdf_dict_put(ctx, form, PDF_NAME(Subtype), PDF_NAME(Form)); pdf_dict_put_rect(ctx, form, PDF_NAME(BBox), bbox); pdf_dict_put_matrix(ctx, form, PDF_NAME(Matrix), matrix); if (res) pdf_dict_put(ctx, form, PDF_NAME(Resources), res); ind = pdf_add_stream(ctx, doc, contents, form, 0); } fz_always(ctx) pdf_drop_obj(ctx, form); fz_catch(ctx) fz_rethrow(ctx); return ind; }
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; }
int pdf_add_portfolio_entry(fz_context *ctx, pdf_document *doc, const char *name, int name_len, const char *desc, int desc_len, const char *filename, int filename_len, const char *unifile, int unifile_len, fz_buffer *buf) { int entry, len; pdf_obj *ef, *f, *params, *s; pdf_obj *key; pdf_obj *val = NULL; fz_var(val); if (!doc) fz_throw(ctx, FZ_ERROR_GENERIC, "Bad pdf_add_portfolio_entry call"); if (doc->portfolio == NULL) load_portfolio(ctx, doc); key = pdf_new_string(ctx, doc, name, name_len); fz_try(ctx) { val = pdf_new_dict(ctx, doc, 6); pdf_dict_put_drop(ctx, val, PDF_NAME_CI, pdf_new_dict(ctx, doc, 4)); pdf_dict_put_drop(ctx, val, PDF_NAME_EF, (ef = pdf_new_dict(ctx, doc, 4))); pdf_dict_put_drop(ctx, val, PDF_NAME_F, pdf_new_string(ctx, doc, filename, filename_len)); pdf_dict_put_drop(ctx, val, PDF_NAME_UF, pdf_new_string(ctx, doc, unifile, unifile_len)); pdf_dict_put_drop(ctx, val, PDF_NAME_Desc, pdf_new_string(ctx, doc, desc, desc_len)); pdf_dict_put_drop(ctx, val, PDF_NAME_Type, PDF_NAME_Filespec); pdf_dict_put_drop(ctx, ef, PDF_NAME_F, (f = pdf_add_stream(ctx, doc, buf, NULL, 0))); len = fz_buffer_storage(ctx, buf, NULL); pdf_dict_put_drop(ctx, f, PDF_NAME_DL, pdf_new_int(ctx, doc, len)); pdf_dict_put_drop(ctx, f, PDF_NAME_Length, pdf_new_int(ctx, doc, len)); pdf_dict_put_drop(ctx, f, PDF_NAME_Params, (params = pdf_new_dict(ctx, doc, 4))); pdf_dict_put_drop(ctx, params, PDF_NAME_Size, pdf_new_int(ctx, doc, len)); s = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root, PDF_NAME_Collection, NULL); if (s == NULL) { s = pdf_new_dict(ctx, doc, 4); pdf_dict_putl_drop(ctx, pdf_trailer(ctx, doc), s, PDF_NAME_Root, PDF_NAME_Collection, NULL); } s = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root, PDF_NAME_Names, PDF_NAME_EmbeddedFiles, NULL); if (s == NULL) { s = pdf_new_dict(ctx, doc, 4); pdf_dict_putl_drop(ctx, pdf_trailer(ctx, doc), s, PDF_NAME_Root, PDF_NAME_Names, PDF_NAME_EmbeddedFiles, NULL); } entry = pdf_name_tree_insert(ctx, doc, s, key, val); } fz_always(ctx) { pdf_drop_obj(ctx, key); pdf_drop_obj(ctx, val); } fz_catch(ctx) fz_rethrow(ctx); return entry; }
/* 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; }
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; }
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; }
static int write_map (mapDef *mtab, int count, unsigned char *codestr, int depth, struct sbuf *wbuf, pdf_obj *stream) { int c, i, block_length; mapDef *mtab1; /* Must be greater than 1 */ #define BLOCK_LEN_MIN 2 struct { int start, count; } blocks[256/BLOCK_LEN_MIN+1]; int num_blocks = 0; for (c = 0; c < 256; c++) { codestr[depth] = (unsigned char) (c & 0xff); if (LOOKUP_CONTINUE(mtab[c].flag)) { mtab1 = mtab[c].next; count = write_map(mtab1, count, codestr, depth + 1, wbuf, stream); } else { if (MAP_DEFINED(mtab[c].flag)) { switch (MAP_TYPE(mtab[c].flag)) { case MAP_IS_CID: case MAP_IS_CODE: block_length = block_count(mtab, c); if (block_length >= BLOCK_LEN_MIN) { blocks[num_blocks].start = c; blocks[num_blocks].count = block_length; num_blocks++; c += block_length; } else { *(wbuf->curptr)++ = '<'; for (i = 0; i <= depth; i++) sputx(codestr[i], &(wbuf->curptr), wbuf->limptr); *(wbuf->curptr)++ = '>'; *(wbuf->curptr)++ = ' '; *(wbuf->curptr)++ = '<'; for (i = 0; i < mtab[c].len; i++) sputx(mtab[c].code[i], &(wbuf->curptr), wbuf->limptr); *(wbuf->curptr)++ = '>'; *(wbuf->curptr)++ = '\n'; count++; } break; case MAP_IS_NAME: ERROR("%s: Unexpected error...", CMAP_DEBUG_STR); break; case MAP_IS_NOTDEF: break; default: ERROR("%s: Unknown mapping type: %d", CMAP_DEBUG_STR, MAP_TYPE(mtab[c].flag)); } } } /* Flush if necessary */ if (count >= 100 || wbuf->curptr >= wbuf->limptr ) { 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)); wbuf->curptr = wbuf->buf; pdf_add_stream(stream, "endbfchar\n", strlen("endbfchar\n")); count = 0; } } if (num_blocks > 0) { char fmt_buf[32]; if (count > 0) { 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)); wbuf->curptr = wbuf->buf; pdf_add_stream(stream, "endbfchar\n", strlen("endbfchar\n")); count = 0; } sprintf(fmt_buf, "%d beginbfrange\n", num_blocks); pdf_add_stream(stream, fmt_buf, strlen(fmt_buf)); for (i = 0; i < num_blocks; i++) { int j; c = blocks[i].start; *(wbuf->curptr)++ = '<'; for (j = 0; j < depth; j++) sputx(codestr[j], &(wbuf->curptr), wbuf->limptr); sputx((unsigned char)c, &(wbuf->curptr), wbuf->limptr); *(wbuf->curptr)++ = '>'; *(wbuf->curptr)++ = ' '; *(wbuf->curptr)++ = '<'; for (j = 0; j < depth; j++) sputx(codestr[j], &(wbuf->curptr), wbuf->limptr); sputx((unsigned char)(c + blocks[i].count), &(wbuf->curptr), wbuf->limptr); *(wbuf->curptr)++ = '>'; *(wbuf->curptr)++ = ' '; *(wbuf->curptr)++ = '<'; for (j = 0; j < mtab[c].len; j++) sputx(mtab[c].code[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, "endbfrange\n", strlen("endbfrange\n")); } return count; }
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; }