diff options
Diffstat (limited to 'Build/source/texk/dvipdfm/pdfdoc.c')
-rw-r--r-- | Build/source/texk/dvipdfm/pdfdoc.c | 1296 |
1 files changed, 0 insertions, 1296 deletions
diff --git a/Build/source/texk/dvipdfm/pdfdoc.c b/Build/source/texk/dvipdfm/pdfdoc.c deleted file mode 100644 index 67810a2084e..00000000000 --- a/Build/source/texk/dvipdfm/pdfdoc.c +++ /dev/null @@ -1,1296 +0,0 @@ -/* $Header$ - - This is dvipdfm, a DVI to PDF translator. - Copyright (C) 1998, 1999 by Mark A. Wicks - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - The author may be contacted via the e-mail address - - mwicks@kettering.edu -*/ - - -#include <stdio.h> -#include <stdlib.h> -#include <time.h> -#include "system.h" -#include "config.h" -#include "mem.h" -#include "error.h" -#include "mfileio.h" -#include "numbers.h" -#include "dvi.h" -#include "pdflimits.h" -#include "pdfobj.h" -#include "pdfdev.h" -#include "pdfdoc.h" -#include "pdfspecial.h" - -#ifdef HAVE_LIBPNG -#include "thumbnail.h" -#endif - -static pdf_obj *catalog = NULL; -static pdf_obj *docinfo = NULL; -static pdf_obj *page_tree = NULL, *page_tree_ref = NULL; - -int outline_depth=0; -static struct -{ - int kid_count; - pdf_obj *entry; -} outline[MAX_OUTLINE_DEPTH]; - - -static pdf_obj *current_page_resources = NULL; -static pdf_obj *this_page_contents = NULL; -static pdf_obj *glob_page_bop, *glob_page_eop; -static pdf_obj *coord_xform_stream = NULL, *coord_xform_ref = NULL; -static pdf_obj *this_page_bop = NULL; -static pdf_obj *this_page_beads = NULL; -static pdf_obj *this_page_annots = NULL; -static pdf_obj *this_page_xobjects = NULL, *this_page_fonts = NULL; -static pdf_obj *tmp1; - -static unsigned long page_count = 0; -static struct pages { - pdf_obj *page_dict; - pdf_obj *page_ref; -} *pages = NULL; -static unsigned long max_pages = 0; - -static void start_page_tree (void); -static void create_catalog (void); -static void start_current_page_resources (void); -static void finish_page_tree(void); -static void start_name_tree(void); -static void finish_dests_tree(void); -static void finish_pending_xobjects(void); -static void start_articles(void); - -static unsigned char verbose = 0, debug=0; - -void pdf_doc_set_verbose(void) -{ - if (verbose < 255) - verbose += 1; -} - -void pdf_doc_set_debug(void) -{ - debug = 1; -} - -static void resize_pages (unsigned long newsize) -{ - unsigned long i; - if (newsize > max_pages) { - pages = RENEW (pages, newsize, struct pages); - for (i=max_pages; i<newsize; i++) { - pages[i].page_dict = NULL; - pages[i].page_ref = NULL; - } - max_pages = newsize; - } -} - -static pdf_obj *type_name, *page_name, *pages_name, *contents_name, *annots_name, - *resources_name, *bead_name, *count_name, *kids_name, *parent_name, - *mediabox_name, *limits_name, *thumb_name; - -static void make_short_cuts(void) -{ -#ifdef MEM_DEBUG -MEM_START -#endif - /* Define some shorthand for names that will conserve memory (and time) - (similar to the latex \@ne trick */ - type_name = pdf_new_name("Type"); - page_name = pdf_new_name("Page"); - pages_name = pdf_new_name("Pages"); - count_name = pdf_new_name("Count"); - kids_name = pdf_new_name("Kids"); - parent_name = pdf_new_name("Parent"); - contents_name = pdf_new_name("Contents"); - annots_name = pdf_new_name("Annots"); - resources_name = pdf_new_name ("Resources"); - bead_name = pdf_new_name ("B"); - mediabox_name = pdf_new_name ("MediaBox"); - limits_name = pdf_new_name ("Limits"); - thumb_name = pdf_new_name ("Thumb"); -#ifdef MEM_DEBUG -MEM_END -#endif -} -static void release_short_cuts(void) -{ - /* Release those shorthand name we created */ - pdf_release_obj (type_name); - pdf_release_obj (page_name); - pdf_release_obj (pages_name); - pdf_release_obj (count_name); - pdf_release_obj (kids_name); - pdf_release_obj (parent_name); - pdf_release_obj (contents_name); - pdf_release_obj (annots_name); - pdf_release_obj (resources_name); - pdf_release_obj (bead_name); - pdf_release_obj (mediabox_name); - pdf_release_obj (limits_name); - pdf_release_obj (thumb_name); -} - -static void start_page_tree (void) -{ - if (debug) { - fprintf (stderr, "(start_page_tree)"); - } - /* Create empty page tree */ - page_tree = pdf_new_dict(); - page_tree_ref = pdf_ref_obj (page_tree); - /* Both page_tree and page_tree_ref are kept open until the - document is closed. This allows the user to write to page_tree - if he so choses. */ - /* Link /Pages into the catalog - and poing it to indirect reference since we - haven't built the tree yet */ - glob_page_bop = pdf_new_stream(0); - glob_page_eop = pdf_new_stream(0); - coord_xform_stream = pdf_new_stream(0); - coord_xform_ref = pdf_ref_obj (coord_xform_stream); - return; -} - -void pdf_doc_bop (char *string, unsigned length) -{ - if (length > 0) - pdf_add_stream (glob_page_bop, string, length); -} - -void pdf_doc_this_bop (char *string, unsigned length) -{ - if (this_page_bop == NULL) - this_page_bop = pdf_new_stream (STREAM_COMPRESS); - if (length > 0) - pdf_add_stream (this_page_bop, string, length); -} - -void pdf_doc_set_origin (double x, double y) -{ - int len; - static char first = 1; - if (first) { - sprintf (work_buffer, "%g 0 0 %g %g %g cm\n", - dvi_tell_mag()*pdf_dev_scale(), dvi_tell_mag()*pdf_dev_scale(), - x, y); - len = strlen (work_buffer); - pdf_add_stream (coord_xform_stream, work_buffer, len); - first = 0; - } -} - - -void pdf_doc_eop (char *string, unsigned length) -{ - if (length > 0) - pdf_add_stream (glob_page_eop, string, length); -} - -static void start_outline_tree (void) -{ - if (debug) { - fprintf (stderr, "(start_outline_tree)"); - } - /* Create empty outline tree */ - outline[outline_depth].entry = pdf_new_dict(); - outline[outline_depth].kid_count = 0; - return; -} - -static pdf_obj *names_dict; - -static void start_name_tree (void) -{ - if (debug) { - fprintf (stderr, "(start_name_tree)"); - } - names_dict = pdf_new_dict (); -} - -static char *asn_date (void) -{ - long tz_offset; - static char date_string[24]; - time_t current_time; - struct tm *bd_time; - if (debug) { - fprintf (stderr, "(asn_date)"); - } - time(¤t_time); - bd_time = localtime(¤t_time); - -#ifdef HAVE_TM_GMTOFF /* Preferred way to get time zone offset */ - tz_offset = bd_time->tm_gmtoff; -#else -#ifdef HAVE_TIMEZONE /* Plan B --- use external variable 'timezone' - /* (may not provide correct offset for daylight savings time) */ - tz_offset = - timezone; -#else /* Last resort --- without more information, set offset to zero */ - tz_offset = 0l; -#endif /* HAVE_TIMEZONE */ -#endif /* HAVE_TM_GMTOFF */ - - if (tz_offset == 0l) { - sprintf (date_string, "D:%04d%02d%02d%02d%02d%02dZ00'00'", - bd_time -> tm_year+1900, bd_time -> tm_mon+1, bd_time -> tm_mday, - bd_time -> tm_hour, bd_time -> tm_min, bd_time -> tm_sec); - } else { - sprintf (date_string, "D:%04d%02d%02d%02d%02d%02d%c%02ld'%02ld'", - bd_time -> tm_year+1900, bd_time -> tm_mon+1, bd_time -> tm_mday, - bd_time -> tm_hour, bd_time -> tm_min, bd_time -> tm_sec, - (tz_offset>0)? '+':'-', labs(tz_offset)/3600, (labs(tz_offset)/60)%60); - } - return date_string; -} - -#define BANNER "dvipdfm %s, Copyright \251 1998, by Mark A. Wicks" -static void create_docinfo (void) -{ - /* Create an empty Info entry and make it - be the root object */ - if (debug) { - fprintf (stderr, "(create_docinfo)"); - } - docinfo = pdf_new_dict (); - pdf_set_info (docinfo); - return; -} - -static void finish_docinfo(void) -{ - char *time_string, *banner; - banner = NEW (strlen(BANNER)+20,char); - sprintf(banner, BANNER, VERSION); - pdf_add_dict (docinfo, - pdf_new_name ("Producer"), - pdf_new_string (banner, strlen (banner))); - RELEASE (banner); - time_string = asn_date(); - pdf_add_dict (docinfo, - pdf_new_name ("CreationDate"), - pdf_new_string (time_string, strlen (time_string))); - pdf_release_obj (docinfo); - return; -} - -void pdf_doc_merge_with_docinfo (pdf_obj *dictionary) -{ - pdf_merge_dict (docinfo, dictionary); -} - -void pdf_doc_merge_with_catalog (pdf_obj *dictionary) -{ - pdf_merge_dict (catalog, dictionary); -} - -static void create_catalog (void) -{ - if (debug) { - fprintf (stderr, "(create_catalog)"); - } - catalog = pdf_new_dict (); - pdf_set_root (catalog); - /* Create /Type attribute */ - pdf_add_dict (catalog, - pdf_link_obj (type_name), - pdf_new_name("Catalog")); - /* Create only those parts of the page tree required for the catalog. - That way, the rest of the page tree can be finished at any time */ - start_page_tree(); - /* Likewise for outline tree */ - start_outline_tree (); - start_name_tree(); - start_articles(); - return; -} - -static void start_current_page_resources (void) -{ - /* work on resources to put in Pages */ - if (debug) { - fprintf (stderr, "(start_current_page_resources)"); - } - current_page_resources = pdf_new_dict (); - tmp1 = pdf_new_array (); - pdf_add_array (tmp1, pdf_new_name ("PDF")); - pdf_add_array (tmp1, pdf_new_name ("Text")); - pdf_add_array (tmp1, pdf_new_name ("ImageC")); - pdf_add_dict (current_page_resources, - pdf_new_name ("ProcSet"), - tmp1); - return; -} - -void pdf_doc_add_to_page_fonts (const char *name, pdf_obj - *resource) -{ -#ifdef MEM_DEBUG - MEM_START; -#endif - - if (debug) { - fprintf (stderr, "(pdf_doc_add_to_page_fonts)"); - } - if (this_page_fonts == NULL) - this_page_fonts = pdf_new_dict(); - pdf_add_dict (this_page_fonts, - pdf_new_name (name), resource); -#ifdef MEM_DEBUG -MEM_END -#endif -} - -void pdf_doc_add_to_page_xobjects (const char *name, pdf_obj - *resource) -{ - if (debug) { - fprintf (stderr, "(pdf_doc_add_to_page_xojects)"); - } - if (this_page_xobjects == NULL) - this_page_xobjects = pdf_new_dict (); - pdf_add_dict (this_page_xobjects, - pdf_new_name (name), - resource); -} - - -void pdf_doc_add_to_page_resources (const char *name, pdf_obj *resource) -{ - if (debug) { - fprintf (stderr, "(pdf_doc_add_to_page_resources)"); - } - pdf_add_dict (current_page_resources, - pdf_new_name (name), - resource); -} - -void pdf_doc_add_to_page_annots (pdf_obj *annot) -{ - if (debug) { - fprintf (stderr, "(pdf_doc_add_to_page_annots)"); - } - if (this_page_annots == NULL) - this_page_annots = pdf_new_array (); - pdf_add_array (this_page_annots, - annot); -} - -static pdf_obj *page_subtree (struct pages *pages, unsigned long npages, - pdf_obj *parent_ref) -{ -#define PAGE_CLUSTER 4 - pdf_obj *self, *self_ref, *kid_array; - self = pdf_new_dict(); - /* This is a slight kludge which allow the subtree - dictionary generated by this routine to be merged with the - real page_tree dictionary, while keeping the indirect - object references right */ - if (parent_ref == NULL) - self_ref = pdf_ref_obj (page_tree); - else - self_ref = pdf_ref_obj (self); - pdf_add_dict (self, pdf_link_obj (type_name), - pdf_link_obj (pages_name)); - pdf_add_dict (self, pdf_link_obj (count_name), - pdf_new_number((double) npages)); - kid_array = pdf_new_array(); - pdf_add_dict (self, pdf_link_obj (kids_name), - kid_array); - if (parent_ref != NULL) { - pdf_add_dict (self, pdf_link_obj(parent_name), - parent_ref); - } - if (npages > 0 && npages <= PAGE_CLUSTER) { - int i; - for (i=0; i<npages; i++) { - pdf_add_array (kid_array, pdf_link_obj(pages[i].page_ref)); - pdf_add_dict (pages[i].page_dict, pdf_link_obj (parent_name), - pdf_link_obj(self_ref)); - pdf_release_obj (pages[i].page_dict); - pdf_release_obj (pages[i].page_ref); - pages[i].page_dict = NULL; - pages[i].page_ref = NULL; - } - } else if (npages > 0) { - int i; - for (i=0; i<PAGE_CLUSTER; i++) { - pdf_obj *subtree; - unsigned long start, end; - start = (i*npages)/PAGE_CLUSTER; - end = ((i+1)*npages)/PAGE_CLUSTER; - if (end-start>1) { - subtree = page_subtree (pages+start, end-start, pdf_link_obj(self_ref)); - pdf_add_array (kid_array, pdf_ref_obj (subtree)); - pdf_release_obj (subtree); - } - else { - pdf_add_array (kid_array, pdf_link_obj(pages[start].page_ref)); - pdf_add_dict (pages[start].page_dict, pdf_link_obj(parent_name), - pdf_link_obj (self_ref)); - pdf_release_obj (pages[start].page_dict); - pdf_release_obj (pages[start].page_ref); - pages[start].page_dict = NULL; - pages[start].page_ref = NULL; - } - } - } - pdf_release_obj (self_ref); - return self; -} - -static void finish_page_tree(void) -{ - pdf_obj *subtree; - if (debug) { - fprintf (stderr, "(finish_page_tree)"); - } - - subtree = page_subtree (pages, page_count, NULL); - pdf_merge_dict (page_tree, subtree); - pdf_release_obj (subtree); - /* Generate media box at root of page tree and let the - other pages inherit it */ - { - tmp1 = pdf_new_array (); - pdf_add_array (tmp1, pdf_new_number (0)); - pdf_add_array (tmp1, pdf_new_number (0)); - pdf_add_array (tmp1, pdf_new_number (ROUND(dev_page_width(),1.0))); - pdf_add_array (tmp1, pdf_new_number (ROUND(dev_page_height(),1.0))); - pdf_add_dict (page_tree, pdf_link_obj (mediabox_name), tmp1); - } - pdf_release_obj (page_tree); - pdf_add_dict (catalog, - pdf_link_obj (pages_name), - pdf_link_obj (page_tree_ref)); - pdf_release_obj (page_tree_ref); - RELEASE (pages); - pdf_add_stream (glob_page_bop, "\n", 1); - pdf_release_obj (glob_page_bop); - pdf_add_stream (glob_page_eop, "\n", 1); - pdf_release_obj (glob_page_eop); - pdf_release_obj (coord_xform_stream); - pdf_release_obj (coord_xform_ref); - return; -} - -void pdf_doc_change_outline_depth(int new_depth) -{ - int i; - if (debug) { - fprintf (stderr, "(change_outline_depth)"); - } - if (outline_depth >= MAX_OUTLINE_DEPTH -1) - ERROR ("Outline is too deep."); - if (new_depth == outline_depth) - /* Nothing to do */ - return; - if (new_depth > outline_depth+1) - ERROR ("Can't increase outline depth by more than one at a time\n"); - if (outline[outline_depth].entry == NULL) - ERROR ("change_outline_depth: Fix me, I'm broke. This shouldn't happen!"); - /* Terminate all entries above this depth */ - for (i=outline_depth-1; i>=new_depth; i--) { - pdf_add_dict (outline[i].entry, - pdf_new_name ("Last"), - pdf_ref_obj (outline[i+1].entry)); - if (i > 0) - tmp1 = pdf_new_number (-outline[i].kid_count); - else - tmp1 = pdf_new_number (outline[i].kid_count); - - pdf_add_dict (outline[i].entry, - pdf_link_obj (count_name), - tmp1); - } - /* Flush out all entries above this depth */ - for (i=new_depth+1; i<=outline_depth; i++) { - pdf_release_obj (outline[i].entry); - outline[i].entry = NULL; - outline[i].kid_count = 0; - } - outline_depth = new_depth; -} - -static void finish_outline(void) -{ - if (debug) - fprintf (stderr, "(finish_outline)"); - /* Link it into the catalog */ - /* Point /Outline attribute to indirect reference */ - pdf_doc_change_outline_depth (0); - pdf_add_dict (catalog, - pdf_new_name ("Outlines"), - pdf_ref_obj(outline[outline_depth].entry)); - pdf_release_obj (outline[0].entry); - outline[0].entry = NULL; -} - - -void pdf_doc_add_outline (pdf_obj *dict) -{ - pdf_obj *new_entry; - if (outline_depth < 1) - ERROR ("Can't add to outline at depth < 1"); - new_entry = pdf_new_dict (); - pdf_merge_dict (new_entry, dict); - /* Caller doesn't know we don't actually use the dictionary, - so he *gave* dict to us. We have to free it */ - pdf_release_obj (dict); - /* Tell it where its parent is */ - pdf_add_dict (new_entry, - pdf_link_obj (parent_name), - pdf_ref_obj (outline[outline_depth-1].entry)); - /* Give mom and dad the good news */ - outline[outline_depth-1].kid_count += 1; - - /* Is this the first entry at this depth? */ - if (outline[outline_depth].entry == NULL) { - /* Is so, tell the parent we are first born */ - pdf_add_dict (outline[outline_depth-1].entry, - pdf_new_name ("First"), - pdf_ref_obj (new_entry)); - } - else { - /* Point us back to sister */ - pdf_add_dict (new_entry, - pdf_new_name ("Prev"), - pdf_ref_obj (outline[outline_depth].entry)); - /* Point our elder sister toward us */ - pdf_add_dict (outline[outline_depth].entry, - pdf_new_name ("Next"), - pdf_ref_obj (new_entry)); - /* Bye-Bye sis */ - pdf_release_obj (outline[outline_depth].entry); - } - outline[outline_depth].entry = new_entry; - /* Just born, so don't have any kids */ - outline[outline_depth].kid_count = 0; -} - -struct dests -{ - char *name; - unsigned length; - pdf_obj *array; -}; -typedef struct dests dest_entry; -static dest_entry *dests = NULL; -unsigned long max_dests = 0; - -static int CDECL cmp_dest (const void *d1, const void *d2) -{ - unsigned length; - int tmp; - length = MIN (((dest_entry *) d1) -> length, ((dest_entry *) d2) -> - length); - if ((tmp = memcmp (((dest_entry *) d1) -> name, ((dest_entry *) d2) - -> name, length)) != 0) - return tmp; - if (((dest_entry *) d1) -> length == ((dest_entry *) d2) -> length) - return 0; - return (((dest_entry *) d1) -> length < ((dest_entry *) d2) -> length ? -1 : 1 ); -} - -static pdf_obj *name_subtree (dest_entry *dests, unsigned long ndests) -{ -#define CLUSTER 4 - pdf_obj *result, *name_array, *limit_array, *kid_array; - result = pdf_new_dict(); - limit_array = pdf_new_array(); - pdf_add_dict (result, pdf_link_obj(limits_name), limit_array); - pdf_add_array (limit_array, pdf_new_string(dests[0].name, - dests[0].length)); - pdf_add_array (limit_array, pdf_new_string(dests[ndests-1].name, - dests[ndests-1].length)); - if (ndests > 0 && ndests <= CLUSTER) { - int i; - name_array = pdf_new_array(); - pdf_add_dict (result, pdf_new_name ("Names"), - name_array); - for (i=0; i<ndests; i++) { - pdf_add_array (name_array, pdf_new_string (dests[i].name, - dests[i].length)); - RELEASE (dests[i].name); - pdf_add_array (name_array, dests[i].array); - } - } else if (ndests > 0) { - int i; - kid_array = pdf_new_array(); - pdf_add_dict (result, pdf_link_obj (kids_name), kid_array); - for (i=0; i<CLUSTER; i++) { - pdf_obj *subtree; - unsigned long start, end; - start = (i*ndests)/CLUSTER; - end = ((i+1)*ndests)/CLUSTER; - subtree = name_subtree (dests+start, end-start); - pdf_add_array (kid_array, pdf_ref_obj (subtree)); - pdf_release_obj (subtree); - } - } - return result; -} - -static unsigned long number_dests = 0; - -static void finish_dests_tree (void) -{ - pdf_obj *kid; - if (number_dests > 0) { - /* Sort before writing any /Dests entries */ - qsort(dests, number_dests, sizeof(dests[0]), cmp_dest); - kid = name_subtree (dests, number_dests); - /* Each entry in dests has been assigned to another object, so - we can free the entire array without freeing the entries. */ - RELEASE (dests); - pdf_add_dict (names_dict, - pdf_new_name ("Dests"), - pdf_ref_obj (kid)); - pdf_release_obj (kid); - } -} - -void pdf_doc_add_dest (char *name, unsigned length, pdf_obj *array_ref) -{ -#ifdef MEM_DEBUG -MEM_START -#endif - if (number_dests >= max_dests) { - max_dests += DESTS_ALLOC_SIZE; - dests = RENEW (dests, max_dests, dest_entry); - } - dests[number_dests].name = NEW (length, char); - memcpy (dests[number_dests].name, name, length); - dests[number_dests].length = length; - dests[number_dests].array = array_ref; - number_dests++; -#ifdef MEM_DEBUG -MEM_END -#endif - return; -} - -struct articles -{ - char *name; - pdf_obj *info; - pdf_obj *first; - pdf_obj *last; - pdf_obj *this; -}; - -typedef struct articles article_entry; -static article_entry articles[MAX_ARTICLES]; -static unsigned long number_articles = 0; - -static pdf_obj *articles_array; -static void start_articles (void) -{ - articles_array = pdf_new_array(); -} - -void pdf_doc_start_article (char *name, pdf_obj *info) -{ - if (number_articles >= MAX_ARTICLES) { - ERROR ("pdf_doc_add_article: Too many articles\n"); - } - if (name == NULL || strlen (name) == 0) - ERROR ("pdf_doc_start_article called null name"); - articles[number_articles].name = NEW (strlen(name)+1, char); - strcpy (articles[number_articles].name, name); - articles[number_articles].info = info; - articles[number_articles].first = NULL; - articles[number_articles].last = NULL; - /* Start dictionary for this article even though we can't finish it - until we get the first bead */ - articles[number_articles].this = pdf_new_dict(); - number_articles++; - return; -} - -void pdf_doc_add_bead (char *article_name, pdf_obj *partial_dict) -{ - /* partial_dict should have P (Page) and R (Rect) already filled in */ - /* See if the specified article exists */ - int i; - for (i=0; i<number_articles; i++) { - if (!strcmp (articles[i].name, article_name)) - break; - } - if (i == number_articles) { - fprintf (stderr, "Bead specified thread that doesn't exist\n"); - return; - } - /* Is this the first bead? */ - if (articles[i].last == NULL) { - articles[i].first = pdf_link_obj (partial_dict); - /* Add pointer to its first object */ - pdf_add_dict (articles[i].this, - pdf_new_name ("F"), - pdf_ref_obj (articles[i].first)); - /* Next add pointer to its Info dictionary */ - pdf_add_dict (articles[i].this, - pdf_new_name ("I"), - pdf_ref_obj (articles[i].info)); - /* Point first bead to parent article */ - pdf_add_dict (partial_dict, - pdf_new_name ("T"), - pdf_ref_obj (articles[i].this)); - /* Ship it out and forget it */ - pdf_add_array (articles_array, pdf_ref_obj (articles[i].this)); - pdf_release_obj (articles[i].this); - articles[i].this = NULL; - } else { - /* Link it in... */ - /* Point last object to this one */ - pdf_add_dict (articles[i].last, - pdf_new_name ("N"), - pdf_ref_obj (partial_dict)); - /* Point this one to last */ - pdf_add_dict (partial_dict, - pdf_new_name ("V"), - pdf_ref_obj (articles[i].last)); - pdf_release_obj (articles[i].last); - } - articles[i].last = partial_dict; - if (this_page_beads == NULL) - this_page_beads = pdf_new_array(); - pdf_add_array (this_page_beads, - pdf_ref_obj (partial_dict)); -} - -void finish_articles(void) -{ - int i; - pdf_add_dict (catalog, - pdf_new_name ("Threads"), - pdf_ref_obj (articles_array)); - pdf_release_obj (articles_array); - for (i=0; i<number_articles; i++) { - if (articles[i].last == NULL) { - fprintf (stderr, "Article started, but no beads\n"); - break; - } - /* Close the loop */ - pdf_add_dict (articles[i].last, - pdf_new_name ("N"), - pdf_ref_obj (articles[i].first)); - pdf_add_dict (articles[i].first, - pdf_new_name ("V"), - pdf_ref_obj (articles[i].last)); - pdf_release_obj (articles[i].first); - pdf_release_obj (articles[i].last); - pdf_release_obj (articles[i].info); - RELEASE (articles[i].name); - } -} - -#ifdef HAVE_LIBPNG -static char thumbnail_opt = 0; -static char *thumb_basename = NULL; - -void pdf_doc_enable_thumbnails(void) -{ - thumbnail_opt = 1; -} - -#endif - -void pdf_doc_finish_page () -{ -#ifdef MEM_DEBUG -MEM_START -#endif - if (debug) { - fprintf (stderr, "(pdf_doc_finish_page)"); - } - finish_pending_xobjects(); - /* Flush this page */ - /* Page_count is the index of the current page, starting at 1 */ - tmp1 = pdf_new_array (); - pdf_add_array (tmp1, pdf_ref_obj (glob_page_bop)); - if (this_page_bop) { - pdf_add_array (tmp1, pdf_ref_obj (this_page_bop)); - } - pdf_add_array (tmp1, pdf_link_obj (coord_xform_ref)); - pdf_add_array (tmp1, pdf_ref_obj (this_page_contents)); - pdf_add_array (tmp1, pdf_ref_obj (glob_page_eop)); - pdf_add_dict (pages[page_count].page_dict, - pdf_link_obj(contents_name), tmp1); - /* We keep .page_dict open because we don't know the parent yet */ - if (this_page_bop != NULL) { - pdf_add_stream (this_page_bop, "\n", 1); - pdf_release_obj (this_page_bop); - this_page_bop = NULL; - } - if (this_page_contents != NULL) { - pdf_add_stream (this_page_contents, "\n", 1); - pdf_release_obj (this_page_contents); - this_page_contents = NULL; - } - if (this_page_annots != NULL) { - pdf_add_dict (pages[page_count].page_dict, - pdf_link_obj(annots_name), - pdf_ref_obj (this_page_annots)); - pdf_release_obj (this_page_annots); - this_page_annots = NULL; - } - if (this_page_beads != NULL) { - pdf_add_dict (pages[page_count].page_dict, - pdf_link_obj (bead_name), - pdf_ref_obj (this_page_beads)); - pdf_release_obj (this_page_beads); - this_page_beads = NULL; - } - if (this_page_fonts != NULL) { - pdf_add_dict (current_page_resources, - pdf_new_name ("Font"), - pdf_ref_obj (this_page_fonts)); - pdf_release_obj (this_page_fonts); - this_page_fonts = NULL; - } - if (this_page_xobjects != NULL) { - pdf_add_dict (current_page_resources, - pdf_new_name ("XObject"), - pdf_ref_obj (this_page_xobjects)); - pdf_release_obj (this_page_xobjects); - this_page_xobjects = NULL; - } - if (current_page_resources != NULL) { - pdf_release_obj (current_page_resources); - current_page_resources = NULL; - } -#ifdef HAVE_LIBPNG - if (thumbnail_opt) { - char *thumb_filename; - pdf_obj *thumbnail; - thumb_filename = NEW (strlen(thumb_basename)+7, char); - sprintf (thumb_filename, "%s.%ld", thumb_basename, - page_count%99999+1L); - thumbnail = do_thumbnail (thumb_filename); - RELEASE (thumb_filename); - if (thumbnail) - pdf_add_dict (pages[page_count].page_dict, - pdf_link_obj (thumb_name), - thumbnail); - } -#endif - page_count += 1; -#ifdef MEM_DEBUG - MEM_END; -#endif -} - -pdf_obj *pdf_doc_current_page_resources (void) -{ - return current_page_resources; -} - - -static int highest_page_ref = 0; -pdf_obj *pdf_doc_ref_page (unsigned long page_no) -{ - if (debug) - fprintf (stderr, "(doc_ref_page:page_no=%ld)", page_no); - if (page_no >= max_pages) { - resize_pages (page_no+PAGES_ALLOC_SIZE); - } - /* Has this page been referenced yet? */ - if (pages[page_no-1].page_dict == NULL) { - /* If not, create it */ - pages[page_no-1].page_dict = pdf_new_dict (); - /* and reference it */ - pages[page_no-1].page_ref = pdf_ref_obj (pages[page_no-1].page_dict); - } - if (page_no > highest_page_ref) - highest_page_ref = page_no; - return pdf_link_obj (pages[page_no-1].page_ref); -} - -pdf_obj *pdf_doc_names (void) -{ - return names_dict; -} - -pdf_obj *pdf_doc_page_tree (void) -{ - return page_tree; -} - -pdf_obj *pdf_doc_catalog (void) -{ - return catalog; -} - -pdf_obj *pdf_doc_this_page (void) -{ - return pages[page_count].page_dict; -} - -pdf_obj *pdf_doc_this_page_ref (void) -{ - return pdf_doc_ref_page(page_count+1); -} - -pdf_obj *pdf_doc_prev_page_ref (void) -{ - if (page_count < 1) { - ERROR ("Reference to previous page, but no pages have been completed yet"); - } - return pdf_doc_ref_page(page_count>0?page_count:1); -} - -pdf_obj *pdf_doc_next_page_ref (void) -{ - return pdf_doc_ref_page(page_count+2); -} - -void pdf_doc_new_page (void) -{ -#ifdef MEM_DEBUG -MEM_START -#endif - if (debug) { - fprintf (stderr, "(pdf_doc_new_page)"); - fprintf (stderr, "page_count=%ld, max_pages=%ld\n", page_count, - max_pages); - } - /* See if we need more pages allocated yet */ - if (page_count >= max_pages) { - resize_pages(max_pages+PAGES_ALLOC_SIZE); - } - /* Was this page already instantiated by a forward reference to it? */ - if (pages[page_count].page_ref == NULL) { - /* If not, create it. */ - pages[page_count].page_dict = pdf_new_dict (); - /* and reference it */ - pages[page_count].page_ref = pdf_ref_obj(pages[page_count].page_dict); - } - pdf_add_dict (pages[page_count].page_dict, - pdf_link_obj(type_name), pdf_link_obj(page_name)); - /* start the contents stream for the new page */ - this_page_contents = pdf_new_stream(STREAM_COMPRESS); - start_current_page_resources(); - pdf_add_dict (pages[page_count].page_dict, - pdf_link_obj (resources_name), - pdf_ref_obj (current_page_resources)); - /* Contents are still available as this_page_contents until next - page is started */ - /* Even though the page is gone, a Reference to this page is kept - until program ends */ -#ifdef MEM_DEBUG -MEM_END -#endif -} - -void pdf_doc_add_to_page (char *buffer, unsigned length) -{ - pdf_add_stream (this_page_contents, buffer, length); -} - -void pdf_doc_init (char *filename) -{ -#ifdef MEM_DEBUG - MEM_START -#endif - if (debug) fprintf (stderr, "pdf_doc_init:\n"); - pdf_out_init (filename); -#ifdef HAVE_LIBPNG - /* Create a default name for thumbnail image files */ - if (thumbnail_opt) { - if (strlen(filename)>4 && !strncmp (".pdf", filename+strlen(filename)-4,4)) { - thumb_basename = NEW (strlen(filename)+1-4, char); - strncpy (thumb_basename, filename, strlen(filename)-4); - thumb_basename[strlen(filename)-4] = 0; - } else { - thumb_basename = NEW (strlen(filename)+1, char); - strcpy (thumb_basename, filename); - } - } -#endif /* HAVE_LIBPNG */ - make_short_cuts(); - create_docinfo (); - create_catalog (); -#ifdef MEM_DEBUG - MEM_END -#endif -} - -void pdf_doc_creator (char *s) -{ - pdf_add_dict (docinfo, pdf_new_name ("Creator"), - pdf_new_string (s, strlen(s))); -} - -void pdf_doc_close () -{ - if (debug) fprintf (stderr, "pdf_doc_finish:\n"); -#ifdef HAVE_LIBPNG - if (thumb_basename) - RELEASE (thumb_basename); -#endif /* HAVE_LIBPNG */ - /* Following things were kept around so user can add dictionary - items */ - finish_docinfo(); - finish_page_tree(); - /* Add names dict to catalog */ - finish_outline(); - finish_dests_tree(); - finish_articles(); - pdf_add_dict (catalog, - pdf_new_name ("Names"), - pdf_ref_obj (names_dict)); - pdf_release_obj (names_dict); - pdf_release_obj (catalog); - /* Do consistency check on forward references to pages */ - if (highest_page_ref > page_count) { - unsigned long i; - fprintf (stderr, "\nWarning: Nonexistent page(s) referenced\n"); - fprintf (stderr, " (PDF file may not work right)\n"); - for (i=page_count; i<highest_page_ref; i++) { - if (pages[i].page_dict) { - pdf_release_obj (pages[i].page_dict); - pdf_release_obj (pages[i].page_ref); - } - } - } - pdf_finish_specials(); - release_short_cuts(); - pdf_out_flush (); -} - -static pdf_obj *build_scale_array (double a, double b, double c, - double d, double e, double f) -{ - pdf_obj *result; - result = pdf_new_array(); - pdf_add_array (result, pdf_new_number (a)); - pdf_add_array (result, pdf_new_number (b)); - pdf_add_array (result, pdf_new_number (c)); - pdf_add_array (result, pdf_new_number (d)); - pdf_add_array (result, pdf_new_number (ROUND(e,0.01))); - pdf_add_array (result, pdf_new_number (ROUND(f,0.01))); - return result; -} - -/* All this routine does is give the form a name - and add a unity scaling matrix. It fills - in required fields. The caller must initialize - the stream */ - - -void doc_make_form_xobj (pdf_obj *this_form_contents, pdf_obj *bbox, - double refptx, double refpty, - double xscale, double yscale, - pdf_obj *resources, char *form_name) -{ - pdf_obj *xobj_dict, *tmp1; - xobj_dict = pdf_stream_dict (this_form_contents); - - pdf_add_dict (xobj_dict, pdf_new_name ("Name"), pdf_new_name(form_name)); - pdf_add_dict (xobj_dict, pdf_link_obj (type_name), - pdf_new_name ("XObject")); - pdf_add_dict (xobj_dict, pdf_new_name ("Subtype"), - pdf_new_name ("Form")); - pdf_add_dict (xobj_dict, pdf_new_name ("BBox"), bbox); - pdf_add_dict (xobj_dict, pdf_new_name ("FormType"), - pdf_new_number(1.0)); - /* The reference point of an Xobject is at the lower left corner - of the bounding box. Since we would like to have an arbitrary - reference point, we use a transformation matrix, translating - the reference point to (0,0) */ - tmp1 = build_scale_array (xscale, 0, 0, yscale, -xscale*refptx, -yscale*refpty); - pdf_add_dict (xobj_dict, pdf_new_name ("Matrix"), tmp1); - pdf_add_dict (xobj_dict, pdf_link_obj (resources_name), resources); - return; -} - -struct resource_stack -{ - pdf_obj *save_page_contents, *save_page_fonts; - pdf_obj *save_page_xobjects, *save_page_resources; - int xform_depth; -} res_stack[4]; - -static int xobjects_pending = 0; - -/* begin_form_xobj creates an xobject with its "origin" at - xpos and ypos that is clipped to the specified bbox. Note - that the origin is not the lower left corner of the bbox */ -pdf_obj *begin_form_xobj (double xpos, double ypos, - double bbllx, double bblly, - double bburx, double bbury, char *res_name) -{ - pdf_obj *bbox; - if (xobjects_pending >= sizeof(res_stack)/sizeof(res_stack[0])) { - fprintf (stderr, "\nForm XObjects nested too deeply. Limit is %d\n", - sizeof(res_stack)/sizeof(res_stack[0])); - return NULL; - } - /* This is a real hack. We basically treat each xobj as a separate mini - page unto itself. Save all the page structures and reinitialize - them when we finish this xobject. */ - res_stack[xobjects_pending].save_page_resources = current_page_resources; - current_page_resources = NULL; - res_stack[xobjects_pending].save_page_xobjects = this_page_xobjects; - this_page_xobjects = NULL; - res_stack[xobjects_pending].save_page_fonts = this_page_fonts; - this_page_fonts = NULL; - res_stack[xobjects_pending].save_page_contents = this_page_contents; - this_page_contents = NULL; - res_stack[xobjects_pending].xform_depth = dev_xform_depth(); - xobjects_pending += 1; - start_current_page_resources(); /* Starts current_page_resources */ - this_page_contents = pdf_new_stream (STREAM_COMPRESS); - /* Make a bounding box for this Xobject */ - /* Translate coordinate system so reference point of object - is at 0 */ - bbox = pdf_new_array (); - pdf_add_array (bbox, pdf_new_number (ROUND(bbllx,0.01))); - pdf_add_array (bbox, pdf_new_number (ROUND(bblly,0.01))); - pdf_add_array (bbox, pdf_new_number (ROUND(bburx,0.01))); - pdf_add_array (bbox, pdf_new_number (ROUND(bbury,0.01))); - /* Resource is already made, so call doc_make_form_xobj() */ - doc_make_form_xobj (this_page_contents, bbox, - xpos, ypos, 1.0, 1.0, - pdf_ref_obj(current_page_resources), res_name); - /* Make sure the object is self-contained by adding the - current font to the object stream */ - dev_reselect_font(); - /* Likewise for color */ - dev_do_color(); - return pdf_link_obj (this_page_contents); -} - -void end_form_xobj (void) -{ - if (xobjects_pending>0) { - xobjects_pending -= 1; - dev_close_all_xforms(res_stack[xobjects_pending].xform_depth); - if (this_page_xobjects) { - pdf_add_dict (current_page_resources, pdf_new_name ("XObject"), - pdf_ref_obj (this_page_xobjects)); - pdf_release_obj (this_page_xobjects); - } - if (this_page_fonts) { - pdf_add_dict (current_page_resources, pdf_new_name ("Font"), - pdf_ref_obj (this_page_fonts)); - pdf_release_obj (this_page_fonts); - } - if (current_page_resources) - pdf_release_obj (current_page_resources); - if (this_page_contents) - pdf_release_obj (this_page_contents); - current_page_resources = res_stack[xobjects_pending].save_page_resources; - this_page_xobjects = res_stack[xobjects_pending].save_page_xobjects; - this_page_fonts = res_stack[xobjects_pending].save_page_fonts; - this_page_contents = res_stack[xobjects_pending].save_page_contents; - /* Must reselect the font again in case there was a font change in - the object */ - dev_reselect_font(); - /* Must reselect color too */ - dev_do_color(); - } else{ - fprintf (stderr, "\nSpecial: exobj: Tried to close a nonexistent xobject\n"); - } - return; -} - -void finish_pending_xobjects (void) -{ - if (xobjects_pending) { - fprintf (stderr, "\nFinishing a pending form XObject at end of page\n"); - while (xobjects_pending--) { - end_form_xobj(); - } - } - return; -} - -static struct -{ - pdf_obj *annot_dict; - unsigned char dirty; - double llx, lly, urx, ury; -} breaking_state = {NULL, 0}; - -void pdf_doc_set_box (void) -{ - breaking_state.llx = dev_page_width(); - breaking_state.urx = 0; - breaking_state.lly = dev_page_height(); - breaking_state.ury = 0; - breaking_state.dirty = 0; - return; -} - -void pdf_doc_begin_annot (pdf_obj *dict) -{ - breaking_state.annot_dict = dict; - pdf_doc_set_box (); - dev_tag_depth (); - return; -} - -void pdf_doc_end_annot (void) -{ - pdf_doc_flush_annot(); - breaking_state.annot_dict = NULL; - dev_untag_depth (); - return; -} - -void pdf_doc_flush_annot (void) -{ - pdf_obj *rectangle, *new_dict; - double grow; - grow = pdf_special_tell_grow (); - if (breaking_state.dirty) { - rectangle = pdf_new_array (); - pdf_add_array (rectangle, pdf_new_number(ROUND(breaking_state.llx-grow, 0.01))); - pdf_add_array (rectangle, pdf_new_number(ROUND(breaking_state.lly-grow, 0.01))); - pdf_add_array (rectangle, pdf_new_number(ROUND(breaking_state.urx+grow, 0.01))); - pdf_add_array (rectangle, pdf_new_number(ROUND(breaking_state.ury+grow, 0.01))); - new_dict = pdf_new_dict (); - pdf_add_dict (new_dict, pdf_new_name ("Rect"), - rectangle); - pdf_merge_dict (new_dict, breaking_state.annot_dict); - pdf_doc_add_to_page_annots (pdf_ref_obj (new_dict)); - pdf_release_obj (new_dict); - } - pdf_doc_set_box(); - return; -} - -void pdf_doc_expand_box (double llx, double lly, double urx, double - ury) -{ - breaking_state.llx = MIN (breaking_state.llx, llx); - breaking_state.lly = MIN (breaking_state.lly, lly); - breaking_state.urx = MAX (breaking_state.urx, urx); - breaking_state.ury = MAX (breaking_state.ury, ury); - breaking_state.dirty = 1; - return; -} |