1
0
mirror of synced 2026-04-08 22:31:06 +00:00

added bookmark support.

This commit is contained in:
Eric Smith
2003-03-05 01:58:36 +00:00
parent 6d1a3b3eed
commit a87794cf88
10 changed files with 380 additions and 39 deletions

View File

@@ -1,6 +1,6 @@
# t2p: build a PDF file out of one or more TIFF Class F Group 4 files
# Makefile
# $Id: Makefile,v 1.16 2003/02/22 02:02:06 eric Exp $
# $Id: Makefile,v 1.17 2003/03/04 17:58:36 eric Exp $
# Copyright 2001 Eric Smith <eric@brouhaha.com>
#
# This program is free software; you can redistribute it and/or modify
@@ -43,7 +43,7 @@ PACKAGE = t2p
TARGETS = t2p bitblt_test
CSRCS = t2p.c semantics.c bitblt.c bitblt_test.c bitblt_table_gen.c \
pdf.c pdf_util.c pdf_prim.c pdf_g4.c pdf_g4_table_gen.c
pdf.c pdf_util.c pdf_prim.c pdf_bookmark.c pdf_g4.c pdf_g4_table_gen.c
OSRCS = scanner.l parser.y
HDRS = t2p.h semantics.h bitblt.h \
pdf.h pdf_private.h pdf_util.h pdf_prim.h
@@ -62,7 +62,7 @@ all: $(TARGETS)
t2p: t2p.o scanner.o semantics.o parser.tab.o bitblt.o \
pdf.o pdf_util.o pdf_prim.o pdf_g4.o
pdf.o pdf_util.o pdf_prim.o pdf_bookmark.o pdf_g4.o
bitblt_tables.h: bitblt_table_gen
./bitblt_table_gen >bitblt_tables.h

3
TODO
View File

@@ -1,5 +1,5 @@
t2p TODO list
$Id: TODO,v 1.9 2003/02/21 01:25:47 eric Exp $
$Id: TODO,v 1.10 2003/03/04 17:58:36 eric Exp $
No particular order.
@@ -70,6 +70,7 @@ Adobe Systems Incorporated, Addison-Wesley, 1993.]
* proper output of real numbers - variable precision, no exponent
* bookmarks (outline)
* alternate destination specs (only is /Fit currently supported)
* name trees, number trees

11
pdf.h
View File

@@ -4,7 +4,7 @@
* will be compressed using ITU-T T.6 (G4) fax encoding.
*
* PDF routines
* $Id: pdf.h,v 1.4 2003/02/21 01:25:47 eric Exp $
* $Id: pdf.h,v 1.5 2003/03/04 17:58:36 eric Exp $
* Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -28,6 +28,8 @@ typedef struct pdf_file *pdf_file_handle;
typedef struct pdf_page *pdf_page_handle;
typedef struct pdf_bookmark *pdf_bookmark_handle;
void pdf_init (void);
@@ -68,6 +70,11 @@ void pdf_write_g4_fax_image (pdf_page_handle pdf_page,
void pdf_set_page_number (pdf_page_handle pdf_page, char *page_number);
void pdf_bookmark (pdf_page_handle pdf_page, int level, char *name);
/* Create a new bookmark, under the specified parent, or at the top
level if parent is NULL. */
pdf_bookmark_handle pdf_new_bookmark (pdf_bookmark_handle parent,
char *title,
bool open,
pdf_page_handle pdf_page);
void pdf_insert_tiff_image (pdf_page_handle pdf_page, char *filename);

132
pdf_bookmark.c Normal file
View File

@@ -0,0 +1,132 @@
/*
* t2p: Create a PDF file from the contents of one or more TIFF
* bilevel image files. The images in the resulting PDF file
* will be compressed using ITU-T T.6 (G4) fax encoding.
*
* PDF routines
* $Id: pdf_bookmark.c,v 1.1 2003/03/04 17:58:36 eric Exp $
* Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. Note that permission is
* not granted to redistribute this program under the terms of any
* other version of the General Public License.
*
* 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 USA
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bitblt.h"
#include "pdf.h"
#include "pdf_util.h"
#include "pdf_prim.h"
#include "pdf_private.h"
static void pdf_bookmark_update_count (pdf_bookmark_handle entry)
{
struct pdf_obj *count_obj;
while (entry)
{
count_obj = pdf_get_dict_entry (entry->dict, "Count");
if (! count_obj)
{
count_obj = pdf_new_integer (0);
pdf_set_dict_entry (entry->dict, "Count", count_obj);
}
pdf_set_integer (count_obj,
pdf_get_integer (count_obj) +
((entry->open) ? 1 : -1));
entry = entry->parent;
}
}
/* Create a new bookmark, under the specified parent, or at the top
level if parent is NULL. */
pdf_bookmark_handle pdf_new_bookmark (pdf_bookmark_handle parent,
char *title,
bool open,
pdf_page_handle pdf_page)
{
pdf_file_handle pdf_file = pdf_page->pdf_file;
struct pdf_bookmark *root;
struct pdf_bookmark *entry;
struct pdf_obj *dest_array;
root = pdf_file->outline_root;
if (! root)
{
root = pdf_calloc (1, sizeof (struct pdf_bookmark));
root->dict = pdf_new_ind_ref (pdf_file, pdf_new_obj (PT_DICTIONARY));
pdf_set_dict_entry (root->dict, "Count", pdf_new_integer (0));
pdf_file->outline_root = root;
pdf_set_dict_entry (pdf_file->catalog, "Outlines", root->dict);
}
entry = pdf_calloc (1, sizeof (struct pdf_bookmark));
entry->dict = pdf_new_ind_ref (pdf_file, pdf_new_obj (PT_DICTIONARY));
entry->open = open;
pdf_set_dict_entry (entry->dict, "Title", pdf_new_string (title));
dest_array = pdf_new_obj (PT_ARRAY);
pdf_add_array_elem (dest_array, pdf_page->page_dict);
pdf_add_array_elem (dest_array, pdf_new_name ("Fit"));
pdf_set_dict_entry (entry->dict, "Dest", dest_array);
if (parent)
{
entry->parent = parent;
entry->prev = parent->last;
}
else
{
parent = root;
entry->parent = root;
entry->prev = root->last;
}
pdf_set_dict_entry (entry->dict, "Parent", parent->dict);
if (entry->prev)
{
pdf_set_dict_entry (entry->dict, "Prev", entry->prev->dict);
entry->prev->next = entry;
pdf_set_dict_entry (entry->prev->dict, "Next", entry->dict);
parent->last = entry;
pdf_set_dict_entry (parent->dict, "Last", entry->dict);
}
else
{
parent->first = entry;
pdf_set_dict_entry (parent->dict, "First", entry->dict);
parent->last = entry;
pdf_set_dict_entry (parent->dict, "Last", entry->dict);
}
pdf_bookmark_update_count (parent);
return (entry);
}

View File

@@ -4,7 +4,7 @@
* will be compressed using ITU-T T.6 (G4) fax encoding.
*
* PDF routines
* $Id: pdf_prim.c,v 1.5 2003/02/21 02:49:11 eric Exp $
* $Id: pdf_prim.c,v 1.6 2003/03/04 17:58:36 eric Exp $
* Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -102,7 +102,7 @@ struct pdf_obj
bool boolean;
char *name;
char *string;
unsigned long integer;
long integer;
double real;
struct pdf_obj *ind_ref;
struct pdf_dict dict;
@@ -233,7 +233,7 @@ struct pdf_obj *pdf_new_string (char *str)
}
struct pdf_obj *pdf_new_integer (unsigned long val)
struct pdf_obj *pdf_new_integer (long val)
{
struct pdf_obj *obj = pdf_new_obj (PT_INTEGER);
obj->val.integer = val;
@@ -315,7 +315,7 @@ struct pdf_obj *pdf_new_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *obj)
}
unsigned long pdf_get_integer (struct pdf_obj *obj)
long pdf_get_integer (struct pdf_obj *obj)
{
if (obj->type == PT_IND_REF)
obj = pdf_deref_ind_obj (obj);
@@ -325,7 +325,7 @@ unsigned long pdf_get_integer (struct pdf_obj *obj)
return (obj->val.integer);
}
void pdf_set_integer (struct pdf_obj *obj, unsigned long val)
void pdf_set_integer (struct pdf_obj *obj, long val)
{
if (obj->type == PT_IND_REF)
obj = pdf_deref_ind_obj (obj);

View File

@@ -4,7 +4,7 @@
* will be compressed using ITU-T T.6 (G4) fax encoding.
*
* PDF routines
* $Id: pdf_prim.h,v 1.4 2003/02/21 02:49:11 eric Exp $
* $Id: pdf_prim.h,v 1.5 2003/03/04 17:58:36 eric Exp $
* Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -68,7 +68,7 @@ struct pdf_obj *pdf_new_name (char *name);
struct pdf_obj *pdf_new_string (char *str);
struct pdf_obj *pdf_new_integer (unsigned long val);
struct pdf_obj *pdf_new_integer (long val);
struct pdf_obj *pdf_new_real (double val);
@@ -80,8 +80,8 @@ struct pdf_obj *pdf_new_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *obj);
struct pdf_obj *pdf_deref_ind_obj (struct pdf_obj *ind_obj);
unsigned long pdf_get_integer (struct pdf_obj *obj);
void pdf_set_integer (struct pdf_obj *obj, unsigned long val);
long pdf_get_integer (struct pdf_obj *obj);
void pdf_set_integer (struct pdf_obj *obj, long val);
double pdf_get_real (struct pdf_obj *obj);

View File

@@ -4,7 +4,7 @@
* will be compressed using ITU-T T.6 (G4) fax encoding.
*
* PDF routines
* $Id: pdf_private.h,v 1.2 2003/02/20 04:44:17 eric Exp $
* $Id: pdf_private.h,v 1.3 2003/03/04 17:58:36 eric Exp $
* Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -45,14 +45,32 @@ struct pdf_pages
};
struct pdf_bookmark
{
struct pdf_obj *dict; /* indirect reference */
bool open;
struct pdf_bookmark *first;
struct pdf_bookmark *last;
/* the following fields don't appear in the root */
/* title and dest are in the dictionary but don't have
explicit fields in the C structure */
struct pdf_bookmark *parent;
struct pdf_bookmark *prev;
struct pdf_bookmark *next;
};
struct pdf_file
{
FILE *f;
struct pdf_obj *first_ind_obj;
struct pdf_obj *last_ind_obj;
long int xref_offset;
struct pdf_obj *catalog;
struct pdf_obj *info;
struct pdf_pages *root;
struct pdf_obj *trailer_dict;
FILE *f;
struct pdf_obj *first_ind_obj;
struct pdf_obj *last_ind_obj;
long int xref_offset;
struct pdf_obj *catalog;
struct pdf_obj *info;
struct pdf_pages *root;
struct pdf_bookmark *outline_root;
struct pdf_obj *trailer_dict;
};

View File

@@ -4,7 +4,7 @@
* will be compressed using ITU-T T.6 (G4) fax encoding.
*
* PDF routines
* $Id: pdf_util.h,v 1.3 2003/02/21 02:49:11 eric Exp $
* $Id: pdf_util.h,v 1.4 2003/03/04 17:58:36 eric Exp $
* Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -24,14 +24,21 @@
*/
#include <assert.h>
void pdf_fatal (char *fmt, ...);
void *pdf_calloc (size_t nmemb, size_t size);
char *pdf_strdup (char *s);
#if 1
#define pdf_assert(cond) assert(cond)
#else
#define pdf_assert(cond) do \
{ \
if (! (cond)) \
pdf_fatal ("assert at %s(%d)\n", __FILE__, __LINE__); \
} while (0)
#endif

102
t2p.c
View File

@@ -4,7 +4,7 @@
* will be compressed using ITU-T T.6 (G4) fax encoding.
*
* Main program
* $Id: t2p.c,v 1.24 2003/02/21 01:25:47 eric Exp $
* $Id: t2p.c,v 1.25 2003/03/04 17:58:36 eric Exp $
* Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -88,7 +88,7 @@ void usage (void)
fprintf (stderr, " -v verbose\n");
fprintf (stderr, " -b fmt create bookmarks\n");
fprintf (stderr, "bookmark format:\n");
fprintf (stderr, " %%F file name\n");
fprintf (stderr, " %%F file name (sans suffix)\n");
fprintf (stderr, " %%p page number\n");
}
@@ -311,7 +311,7 @@ bool process_page (int image, /* range 1 .. n */
points */
Rect rect;
Bitmap *bitmap;
Bitmap *bitmap = NULL;
int row;
@@ -464,6 +464,7 @@ bool process_page (int image, /* range 1 .. n */
page = pdf_new_page (out->pdf, width_points, height_points);
#if 0
pdf_write_g4_fax_image (page,
0, 0, /* x, y */
width_points, height_points,
@@ -471,21 +472,102 @@ bool process_page (int image, /* range 1 .. n */
0, /* ImageMask */
0, 0, 0, /* r, g, b */
0); /* BlackIs1 */
#endif
free_bitmap (bitmap);
while (bookmarks)
{
/* $$$ need to handle level here */
pdf_new_bookmark (NULL, bookmarks->name, 0, page);
bookmarks = bookmarks->next;
}
result = 1;
fail:
if (bitmap)
free_bitmap (bitmap);
return (result);
}
void main_args (char *out_fn, int inf_count, char **in_fn)
#define MAX_BOOKMARK_NAME_LEN 500
static int filename_length_without_suffix (char *in_fn)
{
char *p;
int len = strlen (in_fn);
p = strrchr (in_fn, '.');
if (p && ((strcasecmp (p, ".tif") == 0) ||
(strcasecmp (p, ".tiff") == 0)))
return (p - in_fn);
return (len);
}
/* $$$ this function should ensure that it doesn't overflow the name string! */
static void generate_bookmark_name (char *name,
char *bookmark_fmt,
char *in_fn,
int page)
{
bool meta = 0;
int len;
while (*bookmark_fmt)
{
if (meta)
{
meta = 0;
switch (*bookmark_fmt)
{
case '%':
*(name++) = '%';
break;
case 'F':
len = filename_length_without_suffix (in_fn);
strncpy (name, in_fn, len);
name += len;
break;
case 'p':
sprintf (name, "%d", page);
name += strlen (name);
break;
default:
break;
}
}
else
switch (*bookmark_fmt)
{
case '%':
meta = 1;
break;
default:
*(name++) = *bookmark_fmt;
}
bookmark_fmt++;
}
*bookmark_fmt = '\0';
}
void main_args (char *out_fn,
int inf_count,
char **in_fn,
char *bookmark_fmt)
{
int i, ip;
input_attributes_t input_attributes;
pdf_file_attributes_t output_attributes;
bookmark_t bookmark;
char bookmark_name [MAX_BOOKMARK_NAME_LEN];
bookmark.next = NULL;
bookmark.level = 1;
bookmark.name = & bookmark_name [0];
memset (& input_attributes, 0, sizeof (input_attributes));
memset (& output_attributes, 0, sizeof (output_attributes));
@@ -499,7 +581,13 @@ void main_args (char *out_fn, int inf_count, char **in_fn)
for (ip = 1;; ip++)
{
fprintf (stderr, "processing page %d of file \"%s\"\r", ip, in_fn [i]);
if (! process_page (ip, input_attributes, NULL))
if (bookmark_fmt)
generate_bookmark_name (& bookmark_name [0],
bookmark_fmt,
in_fn [i],
ip);
if (! process_page (ip, input_attributes,
bookmark_fmt ? & bookmark : NULL))
fatal (3, "error processing page %d of input file \"%s\"\n", ip, in_fn [i]);
if (last_tiff_page ())
break;
@@ -596,7 +684,7 @@ int main (int argc, char *argv[])
if (spec_fn)
main_spec (spec_fn);
else
main_args (out_fn, inf_count, in_fn);
main_args (out_fn, inf_count, in_fn, bookmark_fmt);
close_tiff_input_file ();
close_pdf_output_files ();

102
tumble.c
View File

@@ -4,7 +4,7 @@
* will be compressed using ITU-T T.6 (G4) fax encoding.
*
* Main program
* $Id: tumble.c,v 1.24 2003/02/21 01:25:47 eric Exp $
* $Id: tumble.c,v 1.25 2003/03/04 17:58:36 eric Exp $
* Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -88,7 +88,7 @@ void usage (void)
fprintf (stderr, " -v verbose\n");
fprintf (stderr, " -b fmt create bookmarks\n");
fprintf (stderr, "bookmark format:\n");
fprintf (stderr, " %%F file name\n");
fprintf (stderr, " %%F file name (sans suffix)\n");
fprintf (stderr, " %%p page number\n");
}
@@ -311,7 +311,7 @@ bool process_page (int image, /* range 1 .. n */
points */
Rect rect;
Bitmap *bitmap;
Bitmap *bitmap = NULL;
int row;
@@ -464,6 +464,7 @@ bool process_page (int image, /* range 1 .. n */
page = pdf_new_page (out->pdf, width_points, height_points);
#if 0
pdf_write_g4_fax_image (page,
0, 0, /* x, y */
width_points, height_points,
@@ -471,21 +472,102 @@ bool process_page (int image, /* range 1 .. n */
0, /* ImageMask */
0, 0, 0, /* r, g, b */
0); /* BlackIs1 */
#endif
free_bitmap (bitmap);
while (bookmarks)
{
/* $$$ need to handle level here */
pdf_new_bookmark (NULL, bookmarks->name, 0, page);
bookmarks = bookmarks->next;
}
result = 1;
fail:
if (bitmap)
free_bitmap (bitmap);
return (result);
}
void main_args (char *out_fn, int inf_count, char **in_fn)
#define MAX_BOOKMARK_NAME_LEN 500
static int filename_length_without_suffix (char *in_fn)
{
char *p;
int len = strlen (in_fn);
p = strrchr (in_fn, '.');
if (p && ((strcasecmp (p, ".tif") == 0) ||
(strcasecmp (p, ".tiff") == 0)))
return (p - in_fn);
return (len);
}
/* $$$ this function should ensure that it doesn't overflow the name string! */
static void generate_bookmark_name (char *name,
char *bookmark_fmt,
char *in_fn,
int page)
{
bool meta = 0;
int len;
while (*bookmark_fmt)
{
if (meta)
{
meta = 0;
switch (*bookmark_fmt)
{
case '%':
*(name++) = '%';
break;
case 'F':
len = filename_length_without_suffix (in_fn);
strncpy (name, in_fn, len);
name += len;
break;
case 'p':
sprintf (name, "%d", page);
name += strlen (name);
break;
default:
break;
}
}
else
switch (*bookmark_fmt)
{
case '%':
meta = 1;
break;
default:
*(name++) = *bookmark_fmt;
}
bookmark_fmt++;
}
*bookmark_fmt = '\0';
}
void main_args (char *out_fn,
int inf_count,
char **in_fn,
char *bookmark_fmt)
{
int i, ip;
input_attributes_t input_attributes;
pdf_file_attributes_t output_attributes;
bookmark_t bookmark;
char bookmark_name [MAX_BOOKMARK_NAME_LEN];
bookmark.next = NULL;
bookmark.level = 1;
bookmark.name = & bookmark_name [0];
memset (& input_attributes, 0, sizeof (input_attributes));
memset (& output_attributes, 0, sizeof (output_attributes));
@@ -499,7 +581,13 @@ void main_args (char *out_fn, int inf_count, char **in_fn)
for (ip = 1;; ip++)
{
fprintf (stderr, "processing page %d of file \"%s\"\r", ip, in_fn [i]);
if (! process_page (ip, input_attributes, NULL))
if (bookmark_fmt)
generate_bookmark_name (& bookmark_name [0],
bookmark_fmt,
in_fn [i],
ip);
if (! process_page (ip, input_attributes,
bookmark_fmt ? & bookmark : NULL))
fatal (3, "error processing page %d of input file \"%s\"\n", ip, in_fn [i]);
if (last_tiff_page ())
break;
@@ -596,7 +684,7 @@ int main (int argc, char *argv[])
if (spec_fn)
main_spec (spec_fn);
else
main_args (out_fn, inf_count, in_fn);
main_args (out_fn, inf_count, in_fn, bookmark_fmt);
close_tiff_input_file ();
close_pdf_output_files ();