/* Finish the pattern definition. */ PDFLIB_API void PDFLIB_CALL PDF_end_pattern(PDF *p) { static const char fn[] = "PDF_end_pattern"; long length; PDF_TRACE(("%s\t(pdf[%p]);\n", fn, (void *) p)); if (PDF_SANITY_CHECK_FAILED(p)) return; PDF_CHECK_SCOPE(p, fn, pdf_state_pattern); /* check whether PDF_save() and PDF_restore() calls are balanced */ if (p->sl > 0) pdf_error(p, PDF_RuntimeError, "Unmatched save level at end of pattern"); pdf_end_text(p); p->contents = c_none; if (p->compresslevel) pdf_compress_end(p); length = pdf_tell(p) - p->start_contents_pos; pdf_end_stream(p); pdf_end_obj(p); /* pattern */ pdf_begin_obj(p, p->contents_length_id); /* Length object */ pdf_printf(p, "%ld\n", length); pdf_end_obj(p); pdf_begin_obj(p, p->res_id); /* Resource object */ pdf_begin_dict(p); /* Resource dict */ pdf_write_page_procsets(p); /* ProcSet resources */ pdf_write_page_fonts(p); /* Font resources */ pdf_write_page_colorspaces(p); /* Color space resources */ pdf_write_page_pattern(p); /* Pattern resources */ pdf_write_xobjects(p); /* XObject resources */ pdf_end_dict(p); /* resource dict */ pdf_end_obj(p); /* resource object */ PDF_POP_STATE(p, fn); if (p->flush & PDF_FLUSH_PAGE) pdf_flush_stream(p); }
static void pdf_write_pnode(PDF *p, id node_id, id parent_id, id *kids, int n_kids, int n_pages) { pdf_begin_obj(p, node_id); pdf_begin_dict(p); pdf_puts(p, "/Type/Pages\n"); pdf_printf(p, "/Count %d\n", n_pages); if (parent_id != BAD_ID) pdf_printf(p, "/Parent %d 0 R\n", parent_id); pdf_puts(p, "/Kids["); do { pdf_printf(p, "%ld 0 R", *kids++); pdf_putc(p, PDF_NEWLINE); } while (--n_kids > 0); pdf_puts(p, "]"); pdf_end_dict(p); pdf_end_obj(p); }
void write_pdfstream(PDF pdf, image_dict * idict) { pdf_begin_obj(pdf, img_objnum(idict), OBJSTM_NEVER); pdf_begin_dict(pdf); if (!img_notype(idict)) { pdf_dict_add_name(pdf, "Type", "XObject"); pdf_dict_add_name(pdf, "Subtype", "Form"); pdf_dict_add_int(pdf, "FormType", 1); } if (!img_nobbox(idict)) { pdf_add_name(pdf, "BBox"); pdf_begin_array(pdf); pdf_add_real(pdf, sp2bp(img_bbox(idict)[0])); pdf_add_real(pdf, sp2bp(img_bbox(idict)[1])); pdf_add_real(pdf, sp2bp(img_bbox(idict)[2])); pdf_add_real(pdf, sp2bp(img_bbox(idict)[3])); pdf_end_array(pdf); } if (img_attr(idict) != NULL && strlen(img_attr(idict)) > 0) { pdf_printf(pdf, "\n%s\n", img_attr(idict)); } if (!img_nolength(idict)) { pdf_dict_add_streaminfo(pdf); } pdf_end_dict(pdf); pdf_begin_stream(pdf); if (img_pdfstream_stream(idict) != NULL) { pdf_out_block(pdf, (const char *) img_pdfstream_stream(idict), img_pdfstream_size(idict)); } pdf_end_stream(pdf); pdf_end_obj(pdf); }
void pdf_end_contents_section(PDF *p) { long length; if (p->contents == c_none) return; pdf_end_text(p); p->contents = c_none; pdf_compress_end(p); /* Contents object */ length = pdf_tell(p) - p->start_contents_pos; pdf_end_stream(p); pdf_end_obj(p); pdf_begin_obj(p, p->contents_length_id); /* Length object */ pdf_printf(p, "%ld\n", length); pdf_end_obj(p); }
/* Write all pending document information up to the xref table and trailer */ static void pdf_wrapup_document(PDF *p) { static const char bin2hex[] = PDF_STRING_0123456789ABCDEF; long pos; id i; id pages_id; unsigned char digest[MD5_DIGEST_LENGTH]; pdf_write_info(p); pdf_write_doc_fonts(p); /* font objects */ pdf_write_doc_colorspaces(p); /* color space resources */ pages_id = pdf_make_tree(p, BAD_ID, p->pnodes, p->pages+1, p->current_page); pdf_begin_obj(p, p->root_id); /* Catalog or Root object */ pdf_begin_dict(p); pdf_puts(p, "/Type/Catalog\n"); /* * specify the open action (display of the first page) * default = retain: top of the first page at default zoom level */ if (p->open_action == fitpage) { pdf_printf(p, "/OpenAction[%ld 0 R/Fit]\n", p->pages[1]); } else if (p->open_action == fitwidth) { pdf_printf(p, "/OpenAction[%ld 0 R/FitH]\n", p->pages[1]); } else if (p->open_action == fitheight) { pdf_printf(p, "/OpenAction[%ld 0 R/FitV 0]\n", p->pages[1]); } else if (p->open_action == fitbbox) { pdf_printf(p, "/OpenAction[%ld 0 R/FitB]\n", p->pages[1]); } /* * specify the document's open mode * default = open_none: open document with neither bookmarks nor * thumbnails visible */ if (p->open_mode == open_bookmarks) { pdf_printf(p, "/PageMode/UseOutlines\n"); } else if (p->open_mode == open_thumbnails) { pdf_printf(p, "/PageMode/UseThumbs\n"); } else if (p->open_mode == open_fullscreen) { pdf_printf(p, "/PageMode/FullScreen\n"); } if (p->base) { pdf_printf(p, "/URI<</Base", p->base); pdf_quote_string(p, p->base); pdf_printf(p, ">>\n", p->base); } /* Pages object */ pdf_printf(p, "/Pages %ld 0 R\n", pages_id); pdf_write_outline_root(p); pdf_end_dict(p); /* Catalog */ pdf_end_obj(p); pdf_write_outlines(p); #ifdef DEBUG if (p->debug['s']) { fprintf(stderr, "PDF document statistics:\n"); fprintf(stderr, " %d pages\n", p->current_page); fprintf(stderr, " %d fonts\n", p->fonts_number); fprintf(stderr, " %d xobjects\n", p->xobjects_number); fprintf(stderr, " %ld objects\n", p->currentobj + 1); } #endif /* Don't write any object after this check! */ for (i = 1; i <= p->currentobj; i++) { if (p->file_offset[i] == BAD_ID) { pdf_error(p, PDF_NonfatalError, "Object %ld allocated but not used", i); pdf_begin_obj(p, i); pdf_end_obj(p); } } pos = pdf_tell(p); /* xref table */ pdf_puts(p, "xref\n"); pdf_printf(p, "0 %ld\n", p->currentobj + 1); pdf_puts(p, "0000000000 65535 f \n"); for (i = 1; i <= p->currentobj; i++) { pdf_printf(p, "%010ld 00000 n \n", p->file_offset[i]); } pdf_puts(p, "trailer\n"); pdf_begin_dict(p); /* trailer */ pdf_printf(p, "/Size %ld\n", p->currentobj + 1); pdf_printf(p, "/Info %ld 0 R\n", p->info_id); pdf_printf(p, "/Root %ld 0 R\n", p->root_id); /* put some more data into the MD5 digest */ MD5_Update(p->md5, (unsigned char *) &pos, sizeof pos); MD5_Update(p->md5, (unsigned char *) p, sizeof (PDF)); if (p->filename && strcmp(p->filename, "-") != 0) MD5_Update(p->md5, (unsigned char *) p->filename, strlen(p->filename)); /* write the digest to the ID array */ MD5_Final(digest, p->md5); pdf_puts(p, "/ID[<"); for (i = 0; i < MD5_DIGEST_LENGTH; ++i) { pdf_putc(p, bin2hex[digest[i] >> 4]); pdf_putc(p, bin2hex[digest[i] & 0x0F]); } pdf_puts(p, "><"); for (i = 0; i < MD5_DIGEST_LENGTH; ++i) { pdf_putc(p, bin2hex[digest[i] >> 4]); pdf_putc(p, bin2hex[digest[i] & 0x0F]); } pdf_puts(p, ">]\n"); pdf_end_dict(p); /* trailer */ pdf_puts(p, "startxref\n"); pdf_printf(p, "%ld\n", pos); pdf_puts(p, "%%EOF\n"); }
PDFLIB_API void PDFLIB_CALL PDF_end_page(PDF *p) { static const char fn[] = "PDF_end_page"; int index; PDF_TRACE(("%s\t(pdf[%p]);\n", fn, (void *) p)); if (PDF_SANITY_CHECK_FAILED(p)) return; PDF_CHECK_SCOPE(p, fn, pdf_state_page); /* check whether PDF_save() and PDF_restore() calls are balanced */ if (p->sl > 0) pdf_error(p, PDF_RuntimeError, "Unmatched save level at end of page"); /* restore text parameter and color defaults for out-of-page usage. */ pdf_init_tstate(p); pdf_init_cstate(p); pdf_end_contents_section(p); /* Page object */ pdf_begin_obj(p, p->pages[p->current_page]); pdf_begin_dict(p); pdf_puts(p, "/Type/Page\n"); pdf_printf(p, "/Parent %ld 0 R\n", pdf_get_pnode_id(p)); p->res_id = pdf_alloc_id(p); pdf_printf(p, "/Resources %ld 0 R\n", p->res_id); pdf_printf(p, "/MediaBox[0 0 %f %f]\n", p->width, p->height); if (p->CropBox.llx != (float) 0 || p->CropBox.lly != (float) 0 || p->CropBox.urx != (float) 0 || p->CropBox.ury != (float) 0 ) { if (p->CropBox.urx <= p->CropBox.llx || p->CropBox.ury <= p->CropBox.lly) pdf_error(p, PDF_ValueError, "Illegal CropBox dimensions"); pdf_printf(p, "/CropBox[%f %f %f %f]\n", p->CropBox.llx, p->CropBox.lly, p->CropBox.urx, p->CropBox.ury); } if (p->BleedBox.llx != (float) 0 || p->BleedBox.lly != (float) 0 || p->BleedBox.urx != (float) 0 || p->BleedBox.ury != (float) 0 ) { if (p->BleedBox.urx <= p->BleedBox.llx || p->BleedBox.ury <= p->BleedBox.lly) pdf_error(p, PDF_ValueError, "Illegal BleedBox dimensions"); pdf_printf(p, "/BleedBox[%f %f %f %f]\n", p->BleedBox.llx, p->BleedBox.lly, p->BleedBox.urx, p->BleedBox.ury); } if (p->TrimBox.llx != (float) 0 || p->TrimBox.lly != (float) 0 || p->TrimBox.urx != (float) 0 || p->TrimBox.ury != (float) 0 ) { if (p->TrimBox.urx <= p->TrimBox.llx || p->TrimBox.ury <= p->TrimBox.lly) pdf_error(p, PDF_ValueError, "Illegal TrimBox dimensions"); pdf_printf(p, "/TrimBox[%f %f %f %f]\n", p->TrimBox.llx, p->TrimBox.lly, p->TrimBox.urx, p->TrimBox.ury); } if (p->ArtBox.llx != (float) 0 || p->ArtBox.lly != (float) 0 || p->ArtBox.urx != (float) 0 || p->ArtBox.ury != (float) 0 ) { if (p->ArtBox.urx <= p->ArtBox.llx || p->ArtBox.ury <= p->ArtBox.lly) pdf_error(p, PDF_ValueError, "Illegal ArtBox dimensions"); pdf_printf(p, "/ArtBox[%f %f %f %f]\n", p->ArtBox.llx, p->ArtBox.lly, p->ArtBox.urx, p->ArtBox.ury); } /* * The duration can be placed in the transition dictionary (/D) * or in the page dictionary (/Dur). We put it here so it can * be used without setting a transition effect. */ if (p->duration > 0) pdf_printf(p, "/Dur %f\n", p->duration); pdf_write_page_transition(p); pdf_puts(p, "/Contents["); for (index = 0; index < p->next_content; index++) { pdf_printf(p, "%ld 0 R", p->contents_ids[index]); pdf_putc(p, (char) (index + 1 % 8 ? PDF_SPACE : PDF_NEWLINE)); } pdf_puts(p, "]\n"); /* Thumbnail image */ if (p->thumb_id != BAD_ID) pdf_printf(p, "/Thumb %ld 0 R\n", p->thumb_id); pdf_write_annots_root(p); pdf_end_dict(p); /* Page object */ pdf_end_obj(p); pdf_write_page_annots(p); /* Annotation dicts */ pdf_begin_obj(p, p->res_id); /* resource object */ pdf_begin_dict(p); /* resource dict */ pdf_write_page_procsets(p); /* ProcSet resources */ pdf_write_page_fonts(p); /* Font resources */ pdf_write_page_colorspaces(p); /* Color space resources */ pdf_write_page_pattern(p); /* Pattern resources */ pdf_write_xobjects(p); /* XObject resources */ pdf_end_dict(p); /* resource dict */ pdf_end_obj(p); /* resource object */ pdf_cleanup_page(p); PDF_SET_STATE(p, fn, pdf_state_document); if (p->flush & PDF_FLUSH_PAGE) pdf_flush_stream(p); }
static int l_immediateobj(lua_State * L) { int n, first_arg = 1; int k; lstring buf; const_lstring st1,st2, st3; const char *st1_s = NULL; st1.s = st2.s = st3.s = NULL; check_o_mode(static_pdf, "immediateobj()", 1 << OMODE_PDF, true); if (global_shipping_mode != NOT_SHIPPING) luaL_error(L, "pdf.immediateobj() can not be used with \\latelua"); n = lua_gettop(L); if ((n > 0) && (lua_type(L, 1) == LUA_TNUMBER)) { first_arg++; k = (int) lua_tointeger(L, 1); check_obj_type(static_pdf, obj_type_obj, k); if (is_obj_scheduled(static_pdf, k) || obj_data_ptr(static_pdf, k) != 0) luaL_error(L, "pdf.immediateobj() object in use"); } else { static_pdf->obj_count++; k = pdf_create_obj(static_pdf, obj_type_obj, static_pdf->obj_ptr + 1); } pdf_last_obj = k; switch (n - first_arg + 1) { case 0: luaL_error(L, "pdf.immediateobj() needs at least one argument"); break; case 1: if (!lua_isstring(L, first_arg)) /* or number */ luaL_error(L, "pdf.immediateobj() 1st argument must be string"); pdf_begin_obj(static_pdf, k, OBJSTM_ALWAYS); st1.s = lua_tolstring(L, first_arg, &st1.l); pdf_out_block(static_pdf, st1.s, st1.l); pdf_end_obj(static_pdf); break; case 2: case 3: if (lua_type(L,first_arg) != LUA_TSTRING) luaL_error(L, "pdf.immediateobj() 1st argument must be string"); if (!lua_isstring(L, first_arg + 1)) /* or number */ luaL_error(L, "pdf.immediateobj() 2nd argument must be string"); st1_s = lua_tostring(L, first_arg); st2.s = lua_tolstring(L, first_arg + 1, &st2.l); if (lua_key_eq(st1_s, file)) { if (n == first_arg + 2) luaL_error(L, "pdf.immediateobj() 3rd argument forbidden in file mode"); pdf_begin_obj(static_pdf, k, OBJSTM_ALWAYS); buf.s = fread_to_buf(L, st2.s, &buf.l); pdf_out_block(static_pdf, (const char *) buf.s, buf.l); xfree(buf.s); pdf_end_obj(static_pdf); } else { pdf_begin_obj(static_pdf, k, OBJSTM_NEVER); /* not an object stream candidate! */ pdf_begin_dict(static_pdf); if (n == first_arg + 2) { /* write attr text */ if (!lua_isstring(L, first_arg + 2)) /* or number (maybe only string as it's an attr) */ luaL_error(L, "pdf.immediateobj() 3rd argument must be string"); st3.s = lua_tolstring(L, first_arg + 2, &st3.l); pdf_out_block(static_pdf, st3.s, st3.l); if (st3.s[st3.l - 1] != '\n') pdf_out(static_pdf, '\n'); } pdf_dict_add_streaminfo(static_pdf); pdf_end_dict(static_pdf); pdf_begin_stream(static_pdf); if (lua_key_eq(st1_s, stream)) { pdf_out_block(static_pdf, st2.s, st2.l); } else if (lua_key_eq(st1_s, streamfile)) { buf.s = fread_to_buf(L, st2.s, &buf.l); pdf_out_block(static_pdf, (const char *) buf.s, buf.l); xfree(buf.s); } else luaL_error(L, "pdf.immediateobj() invalid argument"); pdf_end_stream(static_pdf); pdf_end_obj(static_pdf); } break; default: luaL_error(L, "pdf.immediateobj() allows max. 3 arguments"); } lua_pushinteger(L, k); return 1; }
static int table_obj(lua_State * L) { const char *type; int k, obj_compression; int compress_level = -1; /* unset */ int os_threshold = OBJSTM_ALWAYS; /* default: put non-stream objects into object streams */ int saved_compress_level = static_pdf->compress_level; const_lstring attr, st; lstring buf; int immediate = 0; /* default: not immediate */ attr.s = st.s = NULL; attr.l = 0; assert(lua_istable(L, 1)); /* t */ lua_key_rawgeti(type); if (lua_isnil(L, -1)) /* !vs t */ luaL_error(L, "pdf.obj(): object \"type\" missing"); if (lua_type(L,-1) != LUA_TSTRING) /* !vs t */ luaL_error(L, "pdf.obj(): object \"type\" must be string"); type = lua_tostring(L, -1); if (! (lua_key_eq(type, raw) || lua_key_eq(type, stream))) { luaL_error(L, "pdf.obj(): \"%s\" is not a valid object type", type); /* i vs t */ } lua_pop(L, 1); /* t */ lua_key_rawgeti(immediate); if (!lua_isnil(L, -1)) { /* b? t */ if (!lua_isboolean(L, -1)) /* !b t */ luaL_error(L, "pdf.obj(): \"immediate\" must be boolean"); immediate = lua_toboolean(L, -1); /* 0 or 1 */ } lua_pop(L, 1); /* t */ /* is a reserved object referenced by "objnum"? */ lua_key_rawgeti(objnum); if (!lua_isnil(L, -1)) { /* vi? t */ if (lua_type(L,-1) != LUA_TNUMBER) /* !vi t */ luaL_error(L, "pdf.obj(): \"objnum\" must be integer"); k = (int) lua_tointeger(L, -1); /* vi t */ check_obj_type(static_pdf, obj_type_obj, k); if (is_obj_scheduled(static_pdf, k) || obj_data_ptr(static_pdf, k) != 0) luaL_error(L, "pdf.obj() object in use"); } else { static_pdf->obj_count++; k = pdf_create_obj(static_pdf, obj_type_obj, static_pdf->obj_ptr + 1); } pdf_last_obj = k; if (immediate == 0) { obj_data_ptr(static_pdf, k) = pdf_get_mem(static_pdf, pdfmem_obj_size); init_obj_obj(static_pdf, k); } lua_pop(L, 1); /* t */ /* get optional "attr" (allowed only for stream case) */ lua_key_rawgeti(attr); if (!lua_isnil(L, -1)) { /* attr-s? t */ if (! lua_key_eq(type, stream)) luaL_error(L, "pdf.obj(): \"attr\" key not allowed for non-stream object"); if (!lua_isstring(L, -1)) /* or number */ /* !attr-s t */ luaL_error(L, "pdf.obj(): object \"attr\" must be string"); if (immediate == 1) { attr.s = lua_tolstring(L, -1, &attr.l); /* attr-s t */ lua_pop(L, 1); /* t */ } else obj_obj_stream_attr(static_pdf, k) = luaL_ref(Luas, LUA_REGISTRYINDEX); /* t */ } else { lua_pop(L, 1); /* t */ } /* get optional "compresslevel" (allowed only for stream case) */ lua_key_rawgeti(compresslevel); if (!lua_isnil(L, -1)) { /* vi? t */ if (lua_key_eq(type, raw)) luaL_error(L, "pdf.obj(): \"compresslevel\" key not allowed for raw object"); if (lua_type(L, -1) != LUA_TNUMBER) /* !vi t */ luaL_error(L, "pdf.obj(): \"compresslevel\" must be integer"); compress_level = (int) lua_tointeger(L, -1); /* vi t */ if (compress_level > 9) luaL_error(L, "pdf.obj(): \"compresslevel\" must be <= 9"); else if (compress_level < 0) luaL_error(L, "pdf.obj(): \"compresslevel\" must be >= 0"); if (immediate == 0) obj_obj_pdfcompresslevel(static_pdf, k) = compress_level; } lua_pop(L, 1); /* t */ /* get optional "objcompression" (allowed only for non-stream case) */ lua_key_rawgeti(objcompression); if (!lua_isnil(L, -1)) { /* b? t */ if (lua_key_eq(type, stream)) luaL_error(L, "pdf.obj(): \"objcompression\" key not allowed for stream object"); if (!lua_isboolean(L, -1)) /* !b t */ luaL_error(L, "pdf.obj(): \"objcompression\" must be boolean"); obj_compression = lua_toboolean(L, -1); /* 0 or 1 */ /* OBJSTM_NEVER: never into object stream; OBJSTM_ALWAYS: depends then on \pdfobjcompresslevel */ if (obj_compression > 0) os_threshold = OBJSTM_ALWAYS; else os_threshold = OBJSTM_NEVER; if (immediate == 0) obj_obj_objstm_threshold(static_pdf, k) = os_threshold; } lua_pop(L, 1); /* t */ /* now the object contents for all cases are handled */ lua_key_rawgeti(string); lua_key_rawgeti_n(file,-2); if (!lua_isnil(L, -1) && !lua_isnil(L, -2)) /* file-s? string-s? t */ luaL_error(L, "pdf.obj(): \"string\" and \"file\" must not be given together"); if (lua_isnil(L, -1) && lua_isnil(L, -2)) /* nil nil t */ luaL_error(L, "pdf.obj(): no \"string\" or \"file\" given"); if (lua_key_eq(type, raw)) { if (immediate == 1) pdf_begin_obj(static_pdf, k, os_threshold); if (!lua_isnil(L, -2)) { /* file-s? string-s? t */ /* from string */ lua_pop(L, 1); /* string-s? t */ if (!lua_isstring(L, -1)) /* or number */ /* !string-s t */ luaL_error(L, "pdf.obj(): \"string\" must be string for raw object"); if (immediate == 1) { st.s = lua_tolstring(L, -1, &st.l); pdf_out_block(static_pdf, st.s, st.l); } else obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX); /* t */ } else { /* from file */ if (lua_type(L, -1) != LUA_TSTRING) /* !file-s nil t */ luaL_error(L, "pdf.obj(): \"file\" name must be string for raw object"); if (immediate == 1) { st.s = lua_tolstring(L, -1, &st.l); /* file-s nil t */ buf.s = fread_to_buf(L, st.s, &buf.l); pdf_out_block(static_pdf, (const char *) buf.s, buf.l); /* already in pdf_end_obj: if (buf.s[buf.l - 1] != '\n') pdf_out(static_pdf, '\n'); */ xfree(buf.s); } else { set_obj_obj_is_file(static_pdf, k); obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX); /* nil t */ } } if (immediate == 1) pdf_end_obj(static_pdf); } else { if (immediate == 1) { pdf_begin_obj(static_pdf, k, OBJSTM_NEVER); /* 0 = not an object stream candidate! */ pdf_begin_dict(static_pdf); if (attr.s != NULL) { pdf_out_block(static_pdf, attr.s, attr.l); if (attr.s[attr.l - 1] != '\n') pdf_out(static_pdf, '\n'); } if (compress_level > -1) static_pdf->compress_level = compress_level; pdf_dict_add_streaminfo(static_pdf); pdf_end_dict(static_pdf); pdf_begin_stream(static_pdf); } else { set_obj_obj_is_stream(static_pdf, k); if (compress_level > -1) obj_obj_pdfcompresslevel(static_pdf, k) = compress_level; } if (!lua_isnil(L, -2)) { /* file-s? string-s? t */ /* from string */ lua_pop(L, 1); /* string-s? t */ if (!lua_isstring(L, -1)) /* or number */ /* !string-s t */ luaL_error(L, "pdf.obj(): \"string\" must be string for stream object"); if (immediate == 1) { st.s = lua_tolstring(L, -1, &st.l); /* string-s t */ pdf_out_block(static_pdf, st.s, st.l); } else obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX); /* t */ } else { /* from file */ if (lua_type(L, -1) != LUA_TSTRING) /* !file-s nil t */ luaL_error(L, "pdf.obj(): \"file\" name must be string for stream object"); if (immediate == 1) { st.s = lua_tolstring(L, -1, &st.l); /* file-s nil t */ buf.s = fread_to_buf(L, st.s, &buf.l); pdf_out_block(static_pdf, (const char *) buf.s, buf.l); xfree(buf.s); } else { set_obj_obj_is_file(static_pdf, k); obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX); /* nil t */ } } if (immediate == 1) { pdf_end_stream(static_pdf); pdf_end_obj(static_pdf); } } static_pdf->compress_level = saved_compress_level; return k; }
void pdf_write_page_annots(PDF *p) { pdf_annot *ann; long length, start_pos; id length_id; PDF_data_source src; for (ann = p->annots; ann != NULL; ann = ann->next) { pdf_begin_obj(p, ann->obj_id); /* Annotation object */ pdf_begin_dict(p); /* Annotation dict */ pdf_puts(p, "/Type/Annot\n"); switch (ann->type) { case ann_text: pdf_puts(p, "/Subtype/Text\n"); pdf_printf(p, "/Rect[%f %f %f %f]\n", ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury); pdf_write_border_style(p, ann); if (ann->open) pdf_puts(p, "/Open true\n"); if (ann->icon != icon_text_note) /* note is default */ pdf_printf(p, "/Name/%s\n", pdf_icon_names[ann->icon]); /* Contents key is required, but may be empty */ pdf_puts(p, "/Contents"); if (ann->contents) { pdf_quote_string(p, ann->contents); pdf_putc(p, PDF_NEWLINE); } else pdf_puts(p, "()\n"); /* empty contents is OK */ /* title is optional */ if (ann->title) { pdf_puts(p, "/T"); pdf_quote_string(p, ann->title); pdf_putc(p, PDF_NEWLINE); } break; case ann_locallink: pdf_puts(p, "/Subtype/Link\n"); pdf_printf(p, "/Rect[%f %f %f %f]\n", ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury); pdf_write_border_style(p, ann); /* preallocate page object id for a later page */ if (ann->dest.page > p->current_page) { while (ann->dest.page >= p->pages_capacity) pdf_grow_pages(p); /* if this page has already been used as a link target * it will already have an object id. */ if (p->pages[ann->dest.page] == BAD_ID) p->pages[ann->dest.page] = pdf_alloc_id(p); } if (ann->dest.type == retain) { pdf_printf(p, "/Dest[%ld 0 R/XYZ null null 0]\n", p->pages[ann->dest.page]); } else if (ann->dest.type == fitpage) { pdf_printf(p, "/Dest[%ld 0 R/Fit]\n", p->pages[ann->dest.page]); } else if (ann->dest.type == fitwidth) { pdf_printf(p, "/Dest[%ld 0 R/FitH 0]\n", p->pages[ann->dest.page]); } else if (ann->dest.type == fitheight) { pdf_printf(p, "/Dest[%ld 0 R/FitV 0]\n", p->pages[ann->dest.page]); } else if (ann->dest.type == fitbbox) { pdf_printf(p, "/Dest[%ld 0 R/FitB]\n", p->pages[ann->dest.page]); } break; case ann_pdflink: pdf_puts(p, "/Subtype/Link\n"); pdf_printf(p, "/Rect[%f %f %f %f]\n", ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury); pdf_write_border_style(p, ann); pdf_puts(p, "/A"); pdf_begin_dict(p); /* A dict */ pdf_puts(p, "/Type/Action/S/GoToR\n"); if (ann->dest.type == retain) { pdf_printf(p, "/D[%d 0 R/XYZ null null 0]\n", ann->dest.page-1); /* zero-based */ } else if (ann->dest.type == fitpage) { /* zero-based */ pdf_printf(p, "/D[%d 0 R/Fit]\n", ann->dest.page-1); } else if (ann->dest.type == fitwidth) { /* Trick: we don't know the height of a future page yet, * so we use a "large" value for top which will do for * most pages. If it doesn't work, not much harm is done. */ /* zero-based */ pdf_printf(p, "/D[%d 0 R/FitH 2000]\n", ann->dest.page-1); } else if (ann->dest.type == fitheight) { /* zero-based */ pdf_printf(p, "/D[%d 0 R/FitV 0]\n", ann->dest.page-1); } else if (ann->dest.type == fitbbox) { /* zero-based */ pdf_printf(p, "/D[%d 0 R/FitB]\n", ann->dest.page-1); } pdf_puts(p, "/F"); pdf_begin_dict(p); /* F dict */ pdf_puts(p, "/Type/FileSpec\n"); pdf_printf(p, "/F("); pdf_puts(p, ann->filename); pdf_puts(p,")\n"); pdf_end_dict(p); /* F dict */ pdf_end_dict(p); /* A dict */ break; case ann_launchlink: pdf_puts(p, "/Subtype/Link\n"); pdf_printf(p, "/Rect[%f %f %f %f]\n", ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury); pdf_write_border_style(p, ann); pdf_puts(p, "/A"); pdf_begin_dict(p); /* A dict */ pdf_puts(p, "/Type/Action/S/Launch\n"); pdf_puts(p, "/F"); pdf_begin_dict(p); /* F dict */ pdf_puts(p, "/Type/FileSpec\n"); pdf_printf(p, "/F("); pdf_puts(p, ann->filename); pdf_puts(p,")\n"); pdf_end_dict(p); /* F dict */ pdf_end_dict(p); /* A dict */ break; case ann_weblink: pdf_puts(p, "/Subtype/Link\n"); pdf_printf(p, "/Rect[%f %f %f %f]\n", ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury); pdf_write_border_style(p, ann); pdf_printf(p, "/A<</S/URI/URI("); pdf_puts(p, ann->filename); pdf_puts(p, ")>>\n"); break; case ann_attach: pdf_puts(p, "/Subtype/FileAttachment\n"); pdf_printf(p, "/Rect[%f %f %f %f]\n", ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury); pdf_write_border_style(p, ann); if (ann->icon != icon_file_pushpin) /* pushpin is default */ pdf_printf(p, "/Name/%s\n", pdf_icon_names[ann->icon]); if (ann->title) { pdf_puts(p, "/T"); pdf_quote_string(p, ann->title); pdf_putc(p, PDF_NEWLINE); } if (ann->contents) { pdf_puts(p, "/Contents"); pdf_quote_string(p, ann->contents); pdf_putc(p, PDF_NEWLINE); } /* the icon is too small without these flags (=28) */ pdf_printf(p, "/F %d\n", pdf_ann_flag_print | pdf_ann_flag_nozoom | pdf_ann_flag_norotate); pdf_puts(p, "/FS"); pdf_begin_dict(p); /* FS dict */ pdf_puts(p, "/Type/FileSpec\n"); pdf_printf(p, "/F("); pdf_puts(p, ann->filename); pdf_puts(p, ")\n"); /* alloc id for the actual embedded file stream */ ann->obj_id = pdf_alloc_id(p); pdf_printf(p, "/EF<</F %ld 0 R>>\n", ann->obj_id); pdf_end_dict(p); /* FS dict */ break; default: pdf_error(p, PDF_SystemError, "Unknown annotation type %d", ann->type); } pdf_end_dict(p); /* Annotation dict */ pdf_end_obj(p); /* Annotation object */ } /* Write the actual embedded files with preallocated ids */ for (ann = p->annots; ann != NULL; ann = ann->next) { if (ann->type != ann_attach) continue; pdf_begin_obj(p, ann->obj_id); /* EmbeddedFile */ pdf_puts(p, "<</Type/EmbeddedFile\n"); if (ann->mimetype) pdf_printf(p, "/Subtype (%s)\n", ann->mimetype); if (p->compresslevel) pdf_puts(p, "/Filter/FlateDecode\n"); length_id = pdf_alloc_id(p); pdf_printf(p, "/Length %ld 0 R\n", length_id); pdf_end_dict(p); /* F dict */ pdf_begin_stream(p); /* Embedded file stream */ start_pos = pdf_tell(p); /* write the file in the PDF */ src.private_data = (void *) ann->filename; src.init = pdf_data_source_file_init; src.fill = pdf_data_source_file_fill; src.terminate = pdf_data_source_file_terminate; src.length = (long) 0; src.offset = (long) 0; pdf_compress(p, &src); length = pdf_tell(p) - start_pos; pdf_end_stream(p); /* Embedded file stream */ pdf_end_obj(p); /* EmbeddedFile object */ pdf_begin_obj(p, length_id); /* Length object */ pdf_printf(p, "%ld\n", length); pdf_end_obj(p); /* Length object */ if (p->flush & PDF_FLUSH_CONTENT) pdf_flush_stream(p); } }
void pdf_write_doc_colorspaces(PDF *p) { int i; pdf_csresource *cs; for (i = 0; i < p->colorspaces_number; i++) { cs = &p->colorspaces[i]; pdf_begin_obj(p, cs->obj_id); /* color space resource */ /* Separation color space, or pattern based on separation */ if (cs->cs == Separation || (cs->cs == PatternCS && cs->alternate.cs == Separation)) { const char *name; if (cs->cs == PatternCS) { pdf_printf(p, "[/Pattern"); /* pattern color space */ name = p->colorspaces[cs->alternate.val.sep.cs].name; } else name = cs->name; pdf_puts(p, "[/Separation/"); pdf_puts(p, name); /* this is already quoted */ pdf_puts(p, "\n"); if (cs->alternate.cs == DeviceGray) { pdf_puts(p, "/DeviceGray<<\n"); pdf_puts(p, "/Range[0 1]\n"); pdf_printf(p, "/C0[0]\n"); pdf_printf(p, "/C1[%f]\n", cs->alternate.val.gray); } else if (cs->alternate.cs == DeviceRGB) { pdf_puts(p, "/DeviceRGB<<\n"); pdf_puts(p, "/Range[0 1 0 1 0 1]\n"); pdf_printf(p, "/C0[0 0 0]\n"); pdf_printf(p, "/C1[%f %f %f]\n", cs->alternate.val.rgb.r, cs->alternate.val.rgb.g, cs->alternate.val.rgb.b); } else if (cs->alternate.cs == DeviceCMYK) { pdf_puts(p, "/DeviceCMYK<<\n"); pdf_puts(p, "/Range[0 1 0 1 0 1 0 1]\n"); pdf_printf(p, "/C0[0 0 0 0]\n"); pdf_printf(p, "/C1[%f %f %f %f]\n", cs->alternate.val.cmyk.c, cs->alternate.val.cmyk.m, cs->alternate.val.cmyk.y, cs->alternate.val.cmyk.k); } else if (cs->alternate.cs != Separation) pdf_error(p, PDF_SystemError, "Unknown alternate color space in pdf_write_doc_colorspaces"); pdf_puts(p, "/FunctionType 2\n"); pdf_puts(p, "/Domain[0 1]\n"); pdf_puts(p, "/N 1\n"); pdf_end_dict(p); /* alternate color space */ pdf_puts(p, "]\n"); /* separation color space */ if (cs->cs == PatternCS) pdf_puts(p, "]\n"); /* pattern color space */ /* Pattern color space based on simple color space */ } else if (cs->cs == PatternCS) { pdf_printf(p, "[/Pattern/%s]\n", pdf_colorspace_names[cs->alternate.cs]); } else { pdf_error(p, PDF_SystemError, "Unknown base or alternate color space in pdf_write_doc_colorspaces"); } pdf_end_obj(p); /* color space resource */ } }
void pdf_put_image(PDF *p, int im, pdf_bool firststrip) { id length_id; long length; pdf_image *image; int i; image = &p->images[im]; /* york: how to check? see also F-imagecolor! switch (image->colorspace) { case ImageMask: case DeviceGray: case Indexed: case DeviceRGB: case DeviceCMYK: break; default: pdf_error(p, PDF_SystemError, "Unknown color space"); break; } */ /* Images may also be written to the output before the first page */ if (PDF_GET_STATE(p) == pdf_state_page) pdf_end_contents_section(p); /* Image object */ image->no = pdf_new_xobject(p, image_xobject, NEW_ID); pdf_begin_dict(p); /* XObject */ pdf_puts(p, "/Type/XObject\n"); pdf_puts(p, "/Subtype/Image\n"); pdf_printf(p,"/Width %d\n", (int) image->width); pdf_printf(p,"/Height %d\n", (int) image->height); pdf_printf(p,"/BitsPerComponent %d\n", image->bpc); /* * Transparency handling */ /* Masking by color: single transparent color value */ if (image->transparent) { if (image->colorspace == Indexed || image->colorspace == DeviceGray) pdf_printf(p,"/Mask[%d %d]\n", (int) image->transval[0], (int) image->transval[0]); else if (image->colorspace == DeviceRGB) pdf_printf(p,"/Mask[%d %d %d %d %d %d]\n", (int) image->transval[0], (int) image->transval[0], (int) image->transval[1], (int) image->transval[1], (int) image->transval[2], (int) image->transval[2]); else if (image->colorspace == DeviceCMYK) pdf_printf(p,"/Mask[%d %d %d %d %d %d %d %d]\n", (int) image->transval[0], (int) image->transval[0], (int) image->transval[1], (int) image->transval[1], (int) image->transval[2], (int) image->transval[2], (int) image->transval[3], (int) image->transval[3]); else pdf_error(p, PDF_SystemError, "Unknown color space with transparency"); /* Masking by position: separate bitmap mask */ } else if (image->mask != -1) { pdf_printf(p, "/Mask %ld 0 R\n", p->xobjects[p->images[image->mask].no].obj_id); } switch (image->colorspace) { case ImageMask: pdf_puts(p, "/ImageMask true\n"); break; case Indexed: if (firststrip) image->colormap_id = pdf_alloc_id(p); pdf_puts(p, "/ColorSpace[/Indexed/DeviceRGB "); pdf_printf(p, "%d %ld 0 R]\n", image->palette_size - 1, image->colormap_id); break; default: /* colorize the image with a spot color */ if (image->colorspace >= LastCS) { /* TODO: reconsider spot color numbering scheme */ int spot = image->colorspace - LastCS; p->colorspaces[spot].used_on_current_page = pdf_true; pdf_printf(p, "/ColorSpace %ld 0 R\n", p->colorspaces[spot].obj_id); /* the following is tricky: /Separation color space * always works as a subtractive color space. The * image, however, is Grayscale, and therefore * additive. */ if (firststrip) { image->invert = !image->invert; } } else { pdf_printf(p, "/ColorSpace/%s\n", pdf_colorspace_names[image->colorspace]); } break; } /* special case: referenced image data instead of direct data */ if (image->reference != pdf_ref_direct) { if (image->compression != none) { pdf_printf(p, "/FFilter[/%s]\n", pdf_filter_names[image->compression]); } if (image->compression == ccitt) { pdf_puts(p, "/FDecodeParms[<<"); if ((int) image->width != 1728) /* CCITT default width */ pdf_printf(p, "/Columns %d", (int) image->width); pdf_printf(p, "/Rows %d", (int) image->height); /* write CCITT parameters if required */ if (image->params) pdf_puts(p, image->params); pdf_puts(p, ">>]\n"); } if (image->reference == pdf_ref_file) { /* LATER: make image file name platform-neutral: * Change : to / on the Mac * Change \ to / on Windows */ pdf_printf(p, "/F(%s)/Length 0", image->filename); } else if (image->reference == pdf_ref_url) { pdf_printf(p, "/F<</FS/URL/F(%s)>>/Length 0", image->filename); } pdf_end_dict(p); /* XObject */ pdf_begin_stream(p); /* dummy image data */ pdf_end_stream(p); /* dummy image data */ if (PDF_GET_STATE(p) == pdf_state_page) pdf_begin_contents_section(p); pdf_end_obj(p); /* XObject */ return; } /* * Now the (more common) handling of actual image * data to be included in the PDF output. */ /* do we need a filter (either ASCII or decompression)? */ if (p->debug['a']) { pdf_puts(p, "/Filter[/ASCIIHexDecode"); if (image->compression != none) pdf_printf(p, "/%s", pdf_filter_names[image->compression]); pdf_puts(p, "]\n"); } else { /* force compression if not a recognized precompressed image format */ if (!image->use_raw && p->compresslevel) image->compression = flate; if (image->compression != none) pdf_printf(p, "/Filter[/%s]\n", pdf_filter_names[image->compression]); } /* prepare precompressed (raw) image data */ if (image->use_raw) { pdf_printf(p, "/DecodeParms[%s<<", (p->debug['a'] ? "null" : "")); /* write EarlyChange or CCITT parameters if required */ if (image->params) pdf_puts(p, image->params); if (image->compression == flate || image->compression == lzw) { if (image->predictor != pred_default) { pdf_printf(p, "/Predictor %d", (int) image->predictor); pdf_printf(p, "/Columns %d", (int) image->width); if (image->bpc != 8) pdf_printf(p, "/BitsPerComponent %d", image->bpc); if (image->colorspace < LastCS) { switch (image->colorspace) { case Indexed: case ImageMask: case DeviceGray: /* 1 is default */ break; case DeviceRGB: pdf_puts(p, "/Colors 3"); break; case DeviceCMYK: pdf_puts(p, "/Colors 4"); break; default: pdf_error(p, PDF_SystemError, "Unknown colorspace (%d)", (int )image->colorspace); break; } } } } if (image->compression == ccitt) { if ((int) image->width != 1728) /* CCITT default width */ pdf_printf(p, "/Columns %d", (int) image->width); pdf_printf(p, "/Rows %d", (int) image->height); } pdf_puts(p, ">>]\n"); /* DecodeParms dict and array */ } if (image->invert) { pdf_puts(p, "/Decode[1 0"); for (i = 1; i < image->components; i++) pdf_puts(p, " 1 0"); pdf_puts(p, "]\n"); } /* Write the actual image data */ length_id = pdf_alloc_id(p); pdf_printf(p,"/Length %ld 0 R\n", length_id); pdf_end_dict(p); /* XObject */ pdf_begin_stream(p); /* image data */ p->start_contents_pos = pdf_tell(p); /* image data */ if (p->debug['a']) pdf_ASCIIHexEncode(p, &image->src); else { if (image->use_raw) pdf_copy(p, &image->src); else pdf_compress(p, &image->src); } length = pdf_tell(p) - p->start_contents_pos; pdf_end_stream(p); /* image data */ pdf_end_obj(p); /* XObject */ pdf_begin_obj(p, length_id); /* Length object */ pdf_printf(p,"%ld\n", length); pdf_end_obj(p); if (p->flush & PDF_FLUSH_CONTENT) pdf_flush_stream(p); /* Image data done */ /* * Write colormap information for indexed color spaces */ if (firststrip && image->colorspace == Indexed) { pdf_begin_obj(p, image->colormap_id); /* colormap object */ pdf_begin_dict(p); if (p->debug['a']) pdf_puts(p, "/Filter[/ASCIIHexDecode]\n"); else if (p->compresslevel) pdf_puts(p, "/Filter[/FlateDecode]\n"); /* Length of colormap object */ length_id = pdf_alloc_id(p); pdf_printf(p,"/Length %ld 0 R\n", length_id); pdf_end_dict(p); pdf_begin_stream(p); /* colormap data */ p->start_contents_pos = pdf_tell(p); if (image->components != 1) { pdf_error(p, PDF_SystemError, "Bogus indexed colorspace (%d color components)", image->components); } image->src.init = pdf_noop; image->src.fill = pdf_data_source_buf_fill; image->src.terminate = pdf_noop; image->src.buffer_start = (unsigned char *) image->colormap; image->src.buffer_length= (size_t) (image->palette_size * 3); image->src.bytes_available = 0; image->src.next_byte = NULL; /* Write colormap data */ if (p->debug['a']) pdf_ASCIIHexEncode(p, &image->src); else { pdf_compress(p, &image->src); } length = pdf_tell(p) - p->start_contents_pos; pdf_end_stream(p); /* Colormap data */ pdf_end_obj(p); /* Colormap object */ pdf_begin_obj(p, length_id); /* Length object for colormap */ pdf_printf(p, "%ld\n", length); pdf_end_obj(p); /* Length object for colormap */ } if (PDF_GET_STATE(p) == pdf_state_page) pdf_begin_contents_section(p); if (p->flush & PDF_FLUSH_CONTENT) pdf_flush_stream(p); }