1
0
mirror of synced 2026-02-27 17:23:43 +00:00

Add very many enhancements by J. David Bryan.

This commit is contained in:
Eric Smith
2016-06-23 20:39:37 -06:00
parent 8f547d6a03
commit de75d376b7
24 changed files with 1326 additions and 120 deletions

View File

@@ -17,6 +17,11 @@
# 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
#
# 2010-09-02 [JDB] Allow building in a directory separate from the source and
# add PNG and blank-page support files. Also change the
# "include" of dependencies to suppress an error if the
# dependency files are not present.
# Conditionals: uncomment the following defines as nessary. Note that a
@@ -29,7 +34,7 @@
CTL_LANG=1
CFLAGS = -Wall
CFLAGS = -Wall -Wno-unused-function -Wno-unused-but-set-variable
LDFLAGS =
LDLIBS = -ltiff -ljpeg -lnetpbm -lz -lm
@@ -49,6 +54,7 @@ LDLIBS := -Wl,-static $(LDLIBS)
endif
LEX = flex
YACC = bison
YFLAGS = -d -v
@@ -58,18 +64,18 @@ YFLAGS = -d -v
# let me know why so I can improve this Makefile.
# -----------------------------------------------------------------------------
VERSION = 0.33
VERSION = 0.34
PACKAGE = tumble
TARGETS = tumble
CSRCS = tumble.c semantics.c \
tumble_input.c tumble_tiff.c tumble_jpeg.c tumble_pbm.c \
CSRCS = tumble.c semantics.c tumble_input.c \
tumble_tiff.c tumble_jpeg.c tumble_pbm.c tumble_png.c tumble_blank.c \
bitblt.c bitblt_table_gen.c bitblt_g4.c g4_table_gen.c \
pdf.c pdf_util.c pdf_prim.c pdf_name_tree.c \
pdf_bookmark.c pdf_page_label.c \
pdf_text.c pdf_g4.c pdf_jpeg.c
pdf_text.c pdf_g4.c pdf_jpeg.c pdf_png.c
OSRCS = scanner.l parser.y
HDRS = tumble.h tumble_input.h semantics.h bitblt.h bitblt_tables.h \
pdf.h pdf_private.h pdf_util.h pdf_prim.h pdf_name_tree.h
@@ -106,12 +112,12 @@ CFLAGS := $(CFLAGS) $(CDEFINES)
all: $(TARGETS) $(TEST_TARGETS)
TUMBLE_OBJS = tumble.o semantics.o \
tumble_input.o tumble_tiff.o tumble_jpeg.o tumble_pbm.o \
TUMBLE_OBJS = tumble.o semantics.o tumble_input.o \
tumble_tiff.o tumble_jpeg.o tumble_pbm.o tumble_png.o tumble_blank.o \
bitblt.o bitblt_g4.o bitblt_tables.o g4_tables.o \
pdf.o pdf_util.o pdf_prim.o pdf_name_tree.o \
pdf_bookmark.o pdf_page_label.o \
pdf_text.o pdf_g4.o pdf_jpeg.o
pdf_text.o pdf_g4.o pdf_jpeg.o pdf_png.o
ifdef CTL_LANG
TUMBLE_OBJS += scanner.o parser.tab.o
@@ -119,9 +125,6 @@ endif
tumble: $(TUMBLE_OBJS)
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
ifndef DEBUG
strip $@
endif
bitblt_tables.h: bitblt_table_gen
@@ -178,6 +181,6 @@ ALL_CSRCS = $(CSRCS) $(AUTO_CSRCS) $(TEST_CSRCS)
DEPENDS = $(ALL_CSRCS:.c=.d)
%.d: %.c
$(CC) -M -MG $(CFLAGS) $< | sed -e 's@ /[^ ]*@@g' -e 's@^\(.*\)\.o:@\1.d \1.o:@' > $@
$(CC) -M -MG $(CFLAGS) $< | sed -e 's@ \([A-Za-z]\):/@ /\1/@g' -e 's@^\(.*\)\.o:@\1.d \1.o:@' > $@
include $(DEPENDS)
-include $(DEPENDS)

View File

@@ -19,8 +19,15 @@
* 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
*
* 2009-03-13 [JDB] pm_config.h (part of NETPBM) defines BITS_PER_WORD but
* apparently doesn't use it externally. We undefine it here
* so that our version takes precedence and warnings are not
* generated.
*/
#undef BITS_PER_WORD
typedef struct Point
{

View File

@@ -19,6 +19,10 @@
* 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
*
* 2007-06-20 [JDB] Fixed a bug wherein "g4_get_pixel" is called with pixel
* index == width, causing an index off the end of the array
* if width % BITS_PER_WORD == 0.
*/
@@ -303,7 +307,7 @@ void bitblt_write_g4 (Bitmap *bitmap, FILE *f)
word_t *cur_line;
word_t *ref_line; /* reference (previous) row */
temp_buffer = pdf_calloc ((width + BITS_PER_WORD - 1) / BITS_PER_WORD,
temp_buffer = pdf_calloc (width / BITS_PER_WORD + 1,
sizeof (word_t));
cur_line = bitmap->bits;

View File

@@ -19,15 +19,23 @@
* 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
*/
*
* 2009-03-13 [JDB] Add support for blank pages, overlay images, color
* mapping, color-key masking, and push/pop of input
* contexts.
*/
%{
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "semantics.h"
extern int yylex (void);
%}
%error-verbose
%union {
int integer;
char character;
@@ -36,6 +44,9 @@
page_size_t size;
range_t range;
page_label_t page_label;
overlay_t overlay;
rgb_t rgb;
rgb_range_t rgb_range;
}
%token <integer> INTEGER
@@ -63,9 +74,13 @@
%token CROP
%token SIZE
%token RESOLUTION
%token BLANK
%token INPUT
%token TRANSPARENT
%token COLORMAP
%token LABEL
%token OVERLAY
%token PAGE
%token PAGES
%token BOOKMARK
@@ -89,6 +104,12 @@
%type <size> page_size
%type <rgb> rgb
%type <rgb_range> rgb_range
%type <rgb_range> gray_range
%type <rgb_range> color_range
%%
statements:
@@ -157,8 +178,21 @@ size_clause:
resolution_clause:
RESOLUTION FLOAT unit ;
rgb_range:
'(' range range range ')' { $$.red = $2; $$.green = $3; $$.blue = $4; }
gray_range:
'(' range ')' { $$.red = $2; $$.green = $2; $$.blue = $2; } ;
color_range:
rgb_range
| gray_range;
transparency_clause:
TRANSPARENT color_range ';' { input_set_transparency ($2); } ;
modifier_clause:
rotate_clause | crop_clause | size_clause | resolution_clause;
rotate_clause | crop_clause | size_clause | resolution_clause | transparency_clause;
modifier_clauses:
modifier_clause
@@ -175,12 +209,16 @@ part_clause:
modifier_clause_list ';'
{ input_set_modifier_context (INPUT_MODIFIER_ALL); } ;
blank_page_clause:
BLANK { input_set_file (NULL); } size_clause ;
input_clause:
input_file_clause
| image_clause
| images_clause
| part_clause
| modifier_clause
| blank_page_clause
| input_clause_list ;
input_clauses:
@@ -188,7 +226,8 @@ input_clauses:
| input_clauses input_clause ;
input_clause_list:
'{' input_clauses '}' ;
'{' { input_push_context (); }
input_clauses '}' { input_pop_context (); } ;
input_statement:
INPUT input_clauses ;
@@ -218,12 +257,23 @@ label_clause:
| LABEL CHARACTER ';' { page_label_t label = { NULL, $2 }; output_set_page_label (label); }
| LABEL STRING ',' CHARACTER ';' { page_label_t label = { $2, $4 }; output_set_page_label (label); } ;
overlay_clause_list:
/* empty */
| '{' overlay_clauses '}' ;
overlay_clauses:
overlay_clause
| overlay_clauses overlay_clause ;
overlay_clause:
OVERLAY length ',' length ';' { overlay_t overlay = { $2, $4 }; output_overlay (overlay); } ;
page_ranges:
range { output_pages ($1); }
| page_ranges ',' range { output_pages ($3); } ;
page_clause:
PAGE INTEGER ';' { range_t range = { $2, $2 }; output_pages (range); } ;
PAGE INTEGER { range_t range = { $2, $2 }; output_pages (range); } overlay_clause_list ';' ;
pages_clause:
PAGES page_ranges ';' ;
@@ -240,8 +290,15 @@ bookmark_clause:
bookmark_name_list
output_clause_list ';' { bookmark_level--; output_pop_context (); } ;
rgb:
'(' INTEGER INTEGER INTEGER ')' { $$.red = $2; $$.green = $3; $$.blue = $4; } ;
colormap_clause:
COLORMAP rgb ',' rgb ';' { output_set_colormap ($2, $4); } ;
output_clause:
output_file_clause
| colormap_clause
| label_clause
| page_clause | pages_clause
| bookmark_clause

27
pdf.c
View File

@@ -19,6 +19,9 @@
* 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
*
* 2005-05-03 [JDB] Add CreationDate and ModDate PDF headers.
* 2014-02-18 [JDB] Use PDF_PRODUCER definition.
*/
@@ -26,6 +29,7 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "bitblt.h"
@@ -70,6 +74,11 @@ struct pdf_pages *pdf_new_pages (pdf_file_handle pdf_file)
pdf_file_handle pdf_create (char *filename)
{
pdf_file_handle pdf_file;
time_t current_time, adjusted_time;
struct tm *time_and_date;
int gmt_diff;
char tm_string[18], gmt_string[24];
const char tm_format[] = "D:%Y%m%d%H%M%S";
pdf_file = pdf_calloc (1, sizeof (struct pdf_file));
@@ -88,7 +97,23 @@ pdf_file_handle pdf_create (char *filename)
pdf_set_dict_entry (pdf_file->catalog, "PageLayout", pdf_new_name ("SinglePage"));
pdf_file->info = pdf_new_ind_ref (pdf_file, pdf_new_obj (PT_DICTIONARY));
pdf_set_info (pdf_file, "Producer", "tumble by Eric Smith -- http://tumble.brouhaha.com/");
pdf_set_info (pdf_file, "Producer", PDF_PRODUCER);
/* Generate CreationDate and ModDate */
current_time = time (NULL);
time_and_date = gmtime (&current_time);
adjusted_time = mktime (time_and_date);
gmt_diff = (int) difftime (current_time, adjusted_time);
time_and_date = localtime (&current_time);
if (strftime (tm_string, sizeof (tm_string), tm_format, time_and_date))
{
sprintf (gmt_string, "%s%+03d'%02d'", tm_string, gmt_diff / 3600, gmt_diff % 60);
pdf_set_info (pdf_file, "CreationDate", gmt_string);
pdf_set_info (pdf_file, "ModDate", gmt_string);
}
pdf_file->trailer_dict = pdf_new_obj (PT_DICTIONARY);
/* Size key will be added later */

75
pdf.h
View File

@@ -19,14 +19,46 @@
* 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
*
* 2007-06-28 [JDB] Increase page limits from 45" to 200" square.
* 2010-09-02 [JDB] Added support for min-is-black TIFF images.
* 2014-02-18 [JDB] Added PDF_PRODUCER definition.
*/
#if !defined(SEMANTICS)
typedef struct
{
int first;
int last;
} range_t;
typedef struct
{
int red;
int green;
int blue;
} rgb_t;
typedef struct
{
range_t red;
range_t green;
range_t blue;
} rgb_range_t;
typedef struct
{
rgb_t black_map;
rgb_t white_map;
} colormap_t;
#endif
/* Acrobat default units aren't really points, but they're close. */
#define POINTS_PER_INCH 72.0
/* page size limited by Acrobat Reader to 45 inches on a side */
#define PAGE_MAX_INCHES 45
/* Page size for Acrobat Reader 4.0 and later is 200 x 200 inches.
Old limit of 45 inches applied to Acrobat Reader 3.x only. */
#define PAGE_MAX_INCHES 200
#define PAGE_MAX_POINTS (PAGE_MAX_INCHES * POINTS_PER_INCH)
@@ -48,11 +80,18 @@ pdf_file_handle pdf_create (char *filename);
void pdf_close (pdf_file_handle pdf_file, int page_mode);
#define AS_STR(S) #S
#define TO_STR(S) AS_STR(S)
#define PDF_PRODUCER "tumble " TO_STR(TUMBLE_VERSION) \
" by Eric Smith (modified by J. David Bryan)"
void pdf_set_author (pdf_file_handle pdf_file, char *author);
void pdf_set_creator (pdf_file_handle pdf_file, char *author);
void pdf_set_title (pdf_file_handle pdf_file, char *author);
void pdf_set_subject (pdf_file_handle pdf_file, char *author);
void pdf_set_keywords (pdf_file_handle pdf_file, char *author);
void pdf_set_creator (pdf_file_handle pdf_file, char *creator);
void pdf_set_producer (pdf_file_handle pdf_file, char *producer);
void pdf_set_title (pdf_file_handle pdf_file, char *title);
void pdf_set_subject (pdf_file_handle pdf_file, char *subject);
void pdf_set_keywords (pdf_file_handle pdf_file, char *keywords);
/* width and height in units of 1/72 inch */
@@ -74,12 +113,10 @@ void pdf_write_g4_fax_image (pdf_page_handle pdf_page,
double y,
double width,
double height,
bool negative,
Bitmap *bitmap,
bool ImageMask,
double r, /* RGB fill color, only for ImageMask */
double g,
double b,
bool BlackIs1); /* boolean, typ. false */
colormap_t *colormap,
rgb_range_t *transparency);
void pdf_write_jpeg_image (pdf_page_handle pdf_page,
@@ -90,9 +127,25 @@ void pdf_write_jpeg_image (pdf_page_handle pdf_page,
bool color,
uint32_t width_samples,
uint32_t height_samples,
rgb_range_t *transparency,
FILE *f);
void pdf_write_png_image (pdf_page_handle pdf_page,
double x,
double y,
double width,
double height,
int color,
char *pal,
int palent,
int bpp,
uint32_t width_samples,
uint32_t height_samples,
rgb_range_t *transparency,
FILE *f);
void pdf_set_page_number (pdf_page_handle pdf_page, char *page_number);
/* Create a new bookmark, under the specified parent, or at the top

View File

@@ -19,6 +19,12 @@
* 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
*
* 2008-12-30 [JDB] Fixed bug wherein "pdf_write_g4_content_callback" called
* "pdf_stream_printf" to write XObject name without escaping
* restricted characters. Now calls "pdf_write_name".
*
* 2010-09-02 [JDB] Added support for min-is-black TIFF images.
*/
@@ -40,11 +46,8 @@ struct pdf_g4_image
{
double width, height;
double x, y;
double r, g, b; /* fill color, only for ImageMask */
unsigned long Columns;
unsigned long Rows;
bool ImageMask;
bool BlackIs1;
Bitmap *bitmap;
char XObject_name [4];
};
@@ -60,12 +63,9 @@ static void pdf_write_g4_content_callback (pdf_file_handle pdf_file,
pdf_stream_printf (pdf_file, stream, "q %g 0 0 %g %g %g cm ",
image->width, image->height,
image->x, image->y);
if (image->ImageMask)
pdf_stream_printf (pdf_file, stream, "%g %g %g rg ",
image->r, image->g, image->b);
pdf_stream_printf (pdf_file, stream, "/%s Do Q\r\n",
image->XObject_name);
pdf_write_name (pdf_file, image->XObject_name);
pdf_stream_printf (pdf_file, stream, "Do Q\r\n");
}
@@ -84,12 +84,10 @@ void pdf_write_g4_fax_image (pdf_page_handle pdf_page,
double y,
double width,
double height,
bool negative,
Bitmap *bitmap,
bool ImageMask,
double r, /* RGB fill color, only for ImageMask */
double g,
double b,
bool BlackIs1) /* boolean, typ. false */
colormap_t *colormap,
rgb_range_t *transparency)
{
struct pdf_g4_image *image;
@@ -99,6 +97,16 @@ void pdf_write_g4_fax_image (pdf_page_handle pdf_page,
struct pdf_obj *content_stream;
struct pdf_obj *contents;
struct pdf_obj *mask;
typedef char MAP_STRING[6];
MAP_STRING color_index;
static MAP_STRING last_color_index;
static struct pdf_obj *color_space;
pdf_add_array_elem_unique (pdf_page->procset, pdf_new_name ("ImageB"));
image = pdf_calloc (1, sizeof (struct pdf_g4_image));
@@ -107,15 +115,10 @@ void pdf_write_g4_fax_image (pdf_page_handle pdf_page,
image->height = height;
image->x = x;
image->y = y;
image->r = r;
image->g = g;
image->b = b;
image->bitmap = bitmap;
image->Columns = bitmap->rect.max.x - bitmap->rect.min.x;
image->Rows = bitmap->rect.max.y - bitmap->rect.min.y;
image->ImageMask = ImageMask;
image->BlackIs1 = BlackIs1;
stream_dict = pdf_new_obj (PT_DICTIONARY);
@@ -134,8 +137,42 @@ void pdf_write_g4_fax_image (pdf_page_handle pdf_page,
pdf_set_dict_entry (stream_dict, "Width", pdf_new_integer (image->Columns));
pdf_set_dict_entry (stream_dict, "Height", pdf_new_integer (image->Rows));
pdf_set_dict_entry (stream_dict, "BitsPerComponent", pdf_new_integer (1));
if (ImageMask)
pdf_set_dict_entry (stream_dict, "ImageMask", pdf_new_bool (ImageMask));
if (transparency)
{
mask = pdf_new_obj (PT_ARRAY);
pdf_add_array_elem (mask, pdf_new_integer (transparency->red.first));
pdf_add_array_elem (mask, pdf_new_integer (transparency->red.last));
pdf_set_dict_entry (stream_dict, "Mask", mask);
}
if (colormap)
{
color_index [0] = (char) colormap->black_map.red;
color_index [1] = (char) colormap->black_map.green;
color_index [2] = (char) colormap->black_map.blue;
color_index [3] = (char) colormap->white_map.red;
color_index [4] = (char) colormap->white_map.green;
color_index [5] = (char) colormap->white_map.blue;
if ((color_space == NULL) ||
(memcmp (color_index, last_color_index, sizeof (MAP_STRING)) != 0))
{
memcpy (last_color_index, color_index, sizeof (MAP_STRING));
color_space = pdf_new_obj (PT_ARRAY);
pdf_add_array_elem (color_space, pdf_new_name ("Indexed"));
pdf_add_array_elem (color_space, pdf_new_name ("DeviceRGB"));
pdf_add_array_elem (color_space, pdf_new_integer (1));
pdf_add_array_elem (color_space, pdf_new_string_n (color_index, 6));
color_space = pdf_new_ind_ref (pdf_page->pdf_file, color_space);
}
pdf_set_dict_entry (stream_dict, "ColorSpace", color_space);
}
else
pdf_set_dict_entry (stream_dict, "ColorSpace", pdf_new_name ("DeviceGray"));
@@ -153,10 +190,10 @@ void pdf_write_g4_fax_image (pdf_page_handle pdf_page,
"Rows",
pdf_new_integer (image->Rows));
if (BlackIs1)
if (negative)
pdf_set_dict_entry (decode_parms,
"BlackIs1",
pdf_new_bool (BlackIs1));
pdf_new_bool (true));
pdf_stream_add_filter (stream, "CCITTFaxDecode", decode_parms);
@@ -170,7 +207,13 @@ void pdf_write_g4_fax_image (pdf_page_handle pdf_page,
& pdf_write_g4_content_callback,
image));
pdf_set_dict_entry (pdf_page->page_dict, "Contents", content_stream);
contents = pdf_get_dict_entry (pdf_page->page_dict, "Contents");
if (! contents)
contents = pdf_new_obj (PT_ARRAY);
pdf_add_array_elem (contents, content_stream);
pdf_set_dict_entry (pdf_page->page_dict, "Contents", contents);
pdf_write_ind_obj (pdf_page->pdf_file, content_stream);
}

View File

@@ -19,6 +19,10 @@
* 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
*
* 2008-12-30 [JDB] Fixed bug wherein "pdf_write_jpeg_content_callback" called
* "pdf_stream_printf" to write XObject name without escaping
* restricted characters. Now calls "pdf_write_name".
*/
@@ -57,8 +61,8 @@ static void pdf_write_jpeg_content_callback (pdf_file_handle pdf_file,
pdf_stream_printf (pdf_file, stream, "q %g 0 0 %g %g %g cm ",
image->width, image->height,
image->x, image->y);
pdf_stream_printf (pdf_file, stream, "/%s Do Q\r\n",
image->XObject_name);
pdf_write_name (pdf_file, image->XObject_name);
pdf_stream_printf (pdf_file, stream, "Do Q\r\n");
}
@@ -101,6 +105,7 @@ void pdf_write_jpeg_image (pdf_page_handle pdf_page,
bool color,
uint32_t width_samples,
uint32_t height_samples,
rgb_range_t *transparency,
FILE *f)
{
struct pdf_jpeg_image *image;
@@ -110,6 +115,9 @@ void pdf_write_jpeg_image (pdf_page_handle pdf_page,
struct pdf_obj *content_stream;
struct pdf_obj *contents;
struct pdf_obj *mask;
image = pdf_calloc (1, sizeof (struct pdf_jpeg_image));
image->width = width;
@@ -139,13 +147,28 @@ void pdf_write_jpeg_image (pdf_page_handle pdf_page,
pdf_set_dict_entry (stream_dict, "Type", pdf_new_name ("XObject"));
pdf_set_dict_entry (stream_dict, "Subtype", pdf_new_name ("Image"));
// Name is required in PDF 1.0 but obsoleted in later PDF versions
// pdf_set_dict_entry (stream_dict, "Name", pdf_new_name (& image->XObject_name [0]));
pdf_set_dict_entry (stream_dict, "Width", pdf_new_integer (image->width_samples));
pdf_set_dict_entry (stream_dict, "Height", pdf_new_integer (image->height_samples));
pdf_set_dict_entry (stream_dict, "ColorSpace", pdf_new_name (image->color ? "DeviceRGB" : "DeviceGray"));
pdf_set_dict_entry (stream_dict, "BitsPerComponent", pdf_new_integer (8));
if (transparency)
{
mask = pdf_new_obj (PT_ARRAY);
pdf_add_array_elem (mask, pdf_new_integer (transparency->red.first));
pdf_add_array_elem (mask, pdf_new_integer (transparency->red.last));
if (image->color) {
pdf_add_array_elem (mask, pdf_new_integer (transparency->green.first));
pdf_add_array_elem (mask, pdf_new_integer (transparency->green.last));
pdf_add_array_elem (mask, pdf_new_integer (transparency->blue.first));
pdf_add_array_elem (mask, pdf_new_integer (transparency->blue.last));
}
pdf_set_dict_entry (stream_dict, "Mask", mask);
}
pdf_stream_add_filter (stream, "DCTDecode", NULL);
/* the following will write the stream, using our callback function to
@@ -158,7 +181,13 @@ void pdf_write_jpeg_image (pdf_page_handle pdf_page,
& pdf_write_jpeg_content_callback,
image));
pdf_set_dict_entry (pdf_page->page_dict, "Contents", content_stream);
contents = pdf_get_dict_entry (pdf_page->page_dict, "Contents");
if (! contents)
contents = pdf_new_obj (PT_ARRAY);
pdf_add_array_elem (contents, content_stream);
pdf_set_dict_entry (pdf_page->page_dict, "Contents", contents);
pdf_write_ind_obj (pdf_page->pdf_file, content_stream);
}

View File

@@ -19,6 +19,11 @@
* 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
*
* 2007-05-07 [JDB] Fixed a bug wherein a page label specifying prefix without
* a style (e.g., LABEL <prefix>) produced bad PDF (no labels
* were displayed). Should have output "/P <prefix>" but
* instead output "/S /P <prefix>".
*/
@@ -53,10 +58,14 @@ void pdf_new_page_label (pdf_file_handle pdf_file,
}
label_dict = pdf_new_obj (PT_DICTIONARY);
pdf_set_dict_entry (label_dict, "S", pdf_new_name (style_str));
if (style)
pdf_set_dict_entry (label_dict, "S", pdf_new_name (style_str));
if (prefix)
pdf_set_dict_entry (label_dict, "P", pdf_new_string (prefix));
if (base != 1)
if (base > 1)
pdf_set_dict_entry (label_dict, "St", pdf_new_integer (base));
pdf_add_number_tree_element (pdf_file->page_label_tree,

233
pdf_png.c Normal file
View File

@@ -0,0 +1,233 @@
/*
* tumble: build a PDF file from image files
*
* PDF routines
* Copyright 2004 Daniel Gloeckner
*
* Derived from pdf_jpeg.c written 2003 by Eric Smith <eric at 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
*
* 2008-12-30 [JDB] Fixed bug wherein "pdf_write_png_content_callback" called
* "pdf_stream_printf" to write XObject name without escaping
* restricted characters. Now calls "pdf_write_name".
*/
#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"
struct pdf_png_image
{
double width, height;
double x, y;
bool color; /* false for grayscale */
uint32_t width_samples, height_samples;
FILE *f;
char XObject_name [4];
};
static void pdf_write_png_content_callback (pdf_file_handle pdf_file,
struct pdf_obj *stream,
void *app_data)
{
struct pdf_png_image *image = app_data;
/* transformation matrix is: width 0 0 height x y cm */
pdf_stream_printf (pdf_file, stream, "q %g 0 0 %g %g %g cm ",
image->width, image->height,
image->x, image->y);
pdf_write_name (pdf_file, image->XObject_name);
pdf_stream_printf (pdf_file, stream, "Do Q\r\n");
}
static void pdf_write_png_image_callback (pdf_file_handle pdf_file,
struct pdf_obj *stream,
void *app_data)
{
struct pdf_png_image *image = app_data;
int rlen, wlen;
uint8_t *wp;
uint8_t buffer [8192];
while (! feof (image->f))
{
uint32_t clen;
rlen = fread (buffer, 1, 8, image->f);
if (rlen != 8)
pdf_fatal ("unexpected EOF on input file\n");
clen=(buffer[0]<<24)+(buffer[1]<<16)+(buffer[2]<<8)+buffer[3];
if (!memcmp(buffer+4,"IEND",4))
break;
if (memcmp(buffer+4,"IDAT",4)) {
fseek(image->f, clen+4, SEEK_CUR);
continue;
}
while (clen)
{
rlen = fread (buffer, 1, (clen<sizeof(buffer))?clen:sizeof(buffer), image->f);
if(!rlen)
pdf_fatal ("unexpected EOF on input file\n");
clen -= rlen;
wp = buffer;
while (rlen)
{
wlen = fwrite (wp, 1, rlen, pdf_file->f);
if (feof (pdf_file->f))
pdf_fatal ("unexpected EOF on output file\n");
if (ferror (pdf_file->f))
pdf_fatal ("error on output file\n");
rlen -= wlen;
wp += wlen;
}
if (ferror (image->f))
pdf_fatal ("error on input file\n");
}
fseek(image->f, 4, SEEK_CUR);
}
}
void pdf_write_png_image (pdf_page_handle pdf_page,
double x,
double y,
double width,
double height,
int color,
char *indexed,
int palent,
int bpp,
uint32_t width_samples,
uint32_t height_samples,
rgb_range_t *transparency,
FILE *f)
{
struct pdf_png_image *image;
struct pdf_obj *stream;
struct pdf_obj *stream_dict;
struct pdf_obj *flateparams;
struct pdf_obj *content_stream;
struct pdf_obj *contents;
struct pdf_obj *mask;
image = pdf_calloc (1, sizeof (struct pdf_png_image));
image->width = width;
image->height = height;
image->x = x;
image->y = y;
image->f = f;
image->color = color;
image->width_samples = width_samples;
image->height_samples = height_samples;
pdf_add_array_elem_unique (pdf_page->procset,
pdf_new_name (palent ? "ImageI" : image->color ? "ImageC" : "ImageB"));
stream_dict = pdf_new_obj (PT_DICTIONARY);
stream = pdf_new_ind_ref (pdf_page->pdf_file,
pdf_new_stream (pdf_page->pdf_file,
stream_dict,
& pdf_write_png_image_callback,
image));
strcpy (& image->XObject_name [0], "Im ");
image->XObject_name [2] = pdf_new_XObject (pdf_page, stream);
flateparams = pdf_new_obj (PT_DICTIONARY);
pdf_set_dict_entry (stream_dict, "Type", pdf_new_name ("XObject"));
pdf_set_dict_entry (stream_dict, "Subtype", pdf_new_name ("Image"));
// Name is required in PDF 1.0 but obsoleted in later PDF versions
// pdf_set_dict_entry (stream_dict, "Name", pdf_new_name (& image->XObject_name [0]));
pdf_set_dict_entry (stream_dict, "Width", pdf_new_integer (image->width_samples));
pdf_set_dict_entry (flateparams, "Columns", pdf_new_integer (image->width_samples));
pdf_set_dict_entry (stream_dict, "Height", pdf_new_integer (image->height_samples));
if (transparency)
{
mask = pdf_new_obj (PT_ARRAY);
pdf_add_array_elem (mask, pdf_new_integer (transparency->red.first));
pdf_add_array_elem (mask, pdf_new_integer (transparency->red.last));
if (!palent && image->color) {
pdf_add_array_elem (mask, pdf_new_integer (transparency->green.first));
pdf_add_array_elem (mask, pdf_new_integer (transparency->green.last));
pdf_add_array_elem (mask, pdf_new_integer (transparency->blue.first));
pdf_add_array_elem (mask, pdf_new_integer (transparency->blue.last));
}
pdf_set_dict_entry (stream_dict, "Mask", mask);
}
if(palent) {
struct pdf_obj *space;
space = pdf_new_obj (PT_ARRAY);
pdf_add_array_elem (space, pdf_new_name ("Indexed"));
pdf_add_array_elem (space, pdf_new_name ("DeviceRGB"));
pdf_add_array_elem (space, pdf_new_integer (palent-1));
pdf_add_array_elem (space, pdf_new_string_n (indexed,3*palent));
pdf_set_dict_entry (stream_dict, "ColorSpace", space);
} else
pdf_set_dict_entry (stream_dict, "ColorSpace", pdf_new_name (image->color ? "DeviceRGB" : "DeviceGray"));
pdf_set_dict_entry (flateparams, "Colors", pdf_new_integer ((!indexed && image->color) ? 3 : 1));
pdf_set_dict_entry (stream_dict, "BitsPerComponent", pdf_new_integer (bpp));
pdf_set_dict_entry (flateparams, "BitsPerComponent", pdf_new_integer (bpp));
pdf_set_dict_entry (flateparams, "Predictor", pdf_new_integer (15));
pdf_stream_add_filter (stream, "FlateDecode", flateparams);
/* the following will write the stream, using our callback function to
get the actual data */
pdf_write_ind_obj (pdf_page->pdf_file, stream);
content_stream = pdf_new_ind_ref (pdf_page->pdf_file,
pdf_new_stream (pdf_page->pdf_file,
pdf_new_obj (PT_DICTIONARY),
& pdf_write_png_content_callback,
image));
contents = pdf_get_dict_entry (pdf_page->page_dict, "Contents");
if (! contents)
contents = pdf_new_obj (PT_ARRAY);
pdf_add_array_elem (contents, content_stream);
pdf_set_dict_entry (pdf_page->page_dict, "Contents", contents);
pdf_write_ind_obj (pdf_page->pdf_file, content_stream);
}

View File

@@ -19,6 +19,9 @@
* 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
*
* 2007-05-07 [JDB] Allow embedded nulls in strings by storing as character
* arrays plus length words.
*/
@@ -90,7 +93,10 @@ struct pdf_obj
union {
bool boolean;
char *name;
char *string;
struct {
char *content;
int length;
} string;
long integer;
double real;
struct pdf_obj *ind_ref;
@@ -243,7 +249,18 @@ struct pdf_obj *pdf_new_name (char *name)
struct pdf_obj *pdf_new_string (char *str)
{
struct pdf_obj *obj = pdf_new_obj (PT_STRING);
obj->val.string = pdf_strdup (str);
obj->val.string.content = pdf_strdup (str);
obj->val.string.length = strlen(str);
return (obj);
}
struct pdf_obj *pdf_new_string_n (char *str, int n)
{
struct pdf_obj *obj = pdf_new_obj (PT_STRING);
obj->val.string.length = n;
obj->val.string.content = pdf_calloc (1,n);
memcpy(obj->val.string.content, str, n);
return (obj);
}
@@ -397,7 +414,16 @@ int pdf_compare_obj (struct pdf_obj *o1, struct pdf_obj *o2)
return (1);
return (0);
case PT_STRING:
return (strcmp (o1->val.string, o2->val.string));
{
int l;
l = o1->val.string.length;
if(l > o2->val.string.length)
l = o2->val.string.length;
l = memcmp (o1->val.string.content, o2->val.string.content, l);
if (l)
return l;
return o1->val.string.length - o2->val.string.length;
}
case PT_NAME:
return (strcmp (o1->val.name, o2->val.name));
default:
@@ -427,22 +453,70 @@ void pdf_write_name (pdf_file_handle pdf_file, char *s)
}
static int string_char_needs_quoting (char c)
static int pdf_write_literal_string (pdf_file_handle pdf_file, char *s, int n)
{
return ((c < ' ') || (c > '~') || (c == '\\') ||
(c == '(') || (c == ')'));
int i, p;
if (pdf_file)
fprintf (pdf_file->f, "(");
for (i = p = 0; n; n--)
{
int j, k;
k = 0;
switch (*s)
{
case '\\':
k = 1;
break;
case '(':
for (j = k =1; k && j < n; j++)
k += (s[j] == '(') ? 1 : (s[j] == ')') ? -1 : 0;
p += !k;
break;
case ')':
if (p)
p--;
else
k = 1;
break;
}
if (k)
{
i++;
if (pdf_file)
fprintf (pdf_file->f, "\\");
}
i++;
if (pdf_file)
fprintf (pdf_file->f, "%c", *(s++));
}
if (pdf_file)
fprintf (pdf_file->f, ") ");
return i;
}
void pdf_write_string (pdf_file_handle pdf_file, char *s)
void pdf_write_string (pdf_file_handle pdf_file, char *s, int n)
{
fprintf (pdf_file->f, "(");
while (*s)
if (string_char_needs_quoting (*s))
fprintf (pdf_file->f, "\\%03o", 0xff & *(s++));
else
fprintf (pdf_file->f, "%c", *(s++));
fprintf (pdf_file->f, ") ");
if (pdf_write_literal_string (NULL, s, n) < 2 * n)
pdf_write_literal_string (pdf_file, s, n);
else
{
fprintf (pdf_file->f, "<");
for( ; n--; )
fprintf (pdf_file->f, "%.2X",*(s++));
fprintf (pdf_file->f, "> ");
}
}
@@ -560,7 +634,7 @@ void pdf_write_obj (pdf_file_handle pdf_file, struct pdf_obj *obj)
pdf_write_name (pdf_file, obj->val.name);
break;
case PT_STRING:
pdf_write_string (pdf_file, obj->val.string);
pdf_write_string (pdf_file, obj->val.string.content, obj->val.string.length);
break;
case PT_INTEGER:
fprintf (pdf_file->f, "%ld ", obj->val.integer);

View File

@@ -19,6 +19,9 @@
* 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
*
* 2007-05-07 [JDB] Add declarations for pdf_new_string_n() and
* pdf_write_name().
*/
@@ -79,6 +82,8 @@ struct pdf_obj *pdf_new_name (char *name);
struct pdf_obj *pdf_new_string (char *str);
struct pdf_obj *pdf_new_string_n (char *str, int n);
struct pdf_obj *pdf_new_integer (long val);
struct pdf_obj *pdf_new_real (double val);
@@ -146,5 +151,9 @@ void pdf_write_all_ind_obj (pdf_file_handle pdf_file);
unsigned long pdf_write_xref (pdf_file_handle pdf_file);
/* Write a name, escaping reserved characters */
void pdf_write_name (pdf_file_handle pdf_file, char *s);
/* this isn't really a PDF primitive data type */
char pdf_new_XObject (pdf_page_handle pdf_page, struct pdf_obj *ind_ref);

View File

@@ -19,10 +19,16 @@
* 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
*/
*
* 2009-03-13 [JDB] Add support for blank pages, overlay images, color
* mapping, color-key masking, and push/pop of input
* contexts.
*/
%option case-insensitive
%option noyywrap
%option nounput
%option noinput
%{
#include <stdbool.h>
@@ -46,7 +52,7 @@ dot [\.]
%%
[\,;{}] { return (yytext [0]); }
[\,;{}()] { return (yytext [0]); }
{dot}{dot} { LDBG(("elipsis\n")); return (ELIPSIS); }
/* decimal integer */
@@ -75,8 +81,10 @@ e { yylval.size.width = 34.0;
all { return (ALL); }
author { return (AUTHOR); }
blank { return (BLANK); }
bookmark { return (BOOKMARK); }
cm { return (CM); }
colormap { return (COLORMAP); }
creator { return (CREATOR); }
crop { return (CROP); }
even { return (EVEN); }
@@ -90,6 +98,7 @@ label { return (LABEL); }
landscape { return (LANDSCAPE); }
odd { return (ODD); }
output { return (OUTPUT); }
overlay { return (OVERLAY); }
page { return (PAGE); }
pages { return (PAGES); }
portrait { return (PORTRAIT) ; }
@@ -98,6 +107,7 @@ rotate { return (ROTATE); }
size { return (SIZE); }
subject { return (SUBJECT); }
title { return (TITLE); }
transparent { return (TRANSPARENT); }
'[^\n']' {
yylval.character = yytext [1];

View File

@@ -19,6 +19,10 @@
* 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
*
* 2009-03-13 [JDB] Add support for blank pages, overlay images, color
* mapping, color-key masking, and push/pop of input
* contexts.
*/
@@ -47,6 +51,9 @@ typedef struct
bool has_crop;
crop_t crop;
bool has_transparency;
rgb_range_t transparency;
} input_modifiers_t;
@@ -59,6 +66,7 @@ typedef struct input_context_t
including those from subcontexts */
char *input_file;
bool is_blank;
input_modifiers_t modifiers [INPUT_MODIFIER_TYPE_COUNT];
} input_context_t;
@@ -88,6 +96,9 @@ typedef struct output_context_t
bool has_page_label;
page_label_t page_label;
bool has_colormap;
colormap_t colormap;
} output_context_t;
@@ -97,11 +108,11 @@ typedef struct output_page_t
output_context_t *output_context;
range_t range;
bookmark_t *bookmark_list;
bool has_overlay;
overlay_t overlay;
} output_page_t;
#undef SEMANTIC_DEBUG
#ifdef SEMANTIC_DEBUG
#define SDBG(x) printf x
#else
@@ -117,7 +128,7 @@ int bookmark_level;
input_context_t *first_input_context;
input_context_t *last_input_context;
input_modifier_type_t current_modifier_context;
input_modifier_type_t current_modifier_context = INPUT_MODIFIER_ALL;
input_image_t *first_input_image;
input_image_t *last_input_image;
@@ -206,6 +217,7 @@ void input_set_file (char *name)
{
input_clone ();
last_input_context->input_file = name;
last_input_context->is_blank = (name == NULL);
};
void input_set_rotation (int rotation)
@@ -222,6 +234,12 @@ void input_set_page_size (page_size_t size)
SDBG(("page size %f, %f\n", size.width, size.height));
}
void input_set_transparency (rgb_range_t rgb_range)
{
last_input_context->modifiers [current_modifier_context].has_transparency = 1;
last_input_context->modifiers [current_modifier_context].transparency = rgb_range;
}
static void increment_input_image_count (int count)
{
input_context_t *context;
@@ -446,16 +464,31 @@ void output_pages (range_t range)
}
void output_overlay (overlay_t overlay)
{
output_pages (last_output_page->range);
last_output_page->has_overlay = 1;
last_output_page->overlay.left = overlay.left;
last_output_page->overlay.top = overlay.top;
}
void output_set_colormap (rgb_t black_color, rgb_t white_color)
{
output_clone ();
last_output_context->has_colormap = 1;
last_output_context->colormap.black_map = black_color;
last_output_context->colormap.white_map = white_color;
}
void yyerror (char *s)
{
fprintf (stderr, "%d: %s\n", line, s);
}
static char *get_input_filename (input_context_t *context)
{
for (; context; context = context->parent)
if (context->input_file)
if ((context->input_file) || (context->is_blank))
return (context->input_file);
fprintf (stderr, "no input file name found\n");
exit (2);
@@ -481,6 +514,23 @@ static bool get_input_rotation (input_context_t *context,
return (0); /* default */
}
static rgb_range_t *get_input_transparency (input_context_t *context,
input_modifier_type_t type)
{
for (; context; context = context->parent)
{
if (context->modifiers [type].has_transparency)
{
return & (context->modifiers [type].transparency);
}
if (context->modifiers [INPUT_MODIFIER_ALL].has_transparency)
{
return & (context->modifiers [INPUT_MODIFIER_ALL].transparency);
}
}
return NULL; /* default */
}
static bool get_input_page_size (input_context_t *context,
input_modifier_type_t type,
page_size_t *page_size)
@@ -527,12 +577,21 @@ static page_label_t *get_output_page_label (output_context_t *context)
return (NULL); /* default */
}
static colormap_t *get_output_colormap (output_context_t *context)
{
for (; context; context = context->parent)
if (context->has_colormap)
return (& context->colormap);
return (NULL); /* default */
}
#ifdef SEMANTIC_DEBUG
void dump_input_tree (void)
{
input_image_t *image;
int i;
char *fn;
printf ("input images:\n");
for (image = first_input_image; image; image = image->next)
@@ -542,6 +601,7 @@ void dump_input_tree (void)
bool has_rotation, has_page_size;
int rotation;
page_size_t page_size;
rgb_range_t *transparency;
has_rotation = get_input_rotation (image->input_context,
parity,
@@ -549,11 +609,19 @@ void dump_input_tree (void)
has_page_size = get_input_page_size (image->input_context,
parity,
& page_size);
printf ("file '%s' image %d",
get_input_filename (image->input_context),
i);
transparency = get_input_transparency (image->input_context, parity);
fn = get_input_filename (image->input_context);
if (fn)
printf ("file '%s' image %d", fn, i);
else
printf ("blank image %d", i);
if (has_rotation)
printf (" rotation %d", rotation);
if (transparency)
printf (" transparency %d..%d, %d..%d, %d..%d",
transparency->red.first, transparency->red.last,
transparency->green.first, transparency->green.last,
transparency->blue.first, transparency->blue.last);
if (has_page_size)
printf (" size %f, %f", page_size.width, page_size.height);
printf ("\n");
@@ -578,6 +646,7 @@ void dump_output_tree (void)
for (i = page->range.first; i <= page->range.last; i++)
{
page_label_t *label = get_output_page_label (page->output_context);
colormap_t *colormap = get_output_colormap (page->output_context);
printf ("file \"%s\" ", get_output_filename (page->output_context));
if (label)
{
@@ -587,6 +656,10 @@ void dump_output_tree (void)
if (label->style)
printf ("'%c' ", label->style);
}
if (colormap)
printf ("colormap (%d %d %d) (%d %d %d) ",
colormap->black_map.red, colormap->black_map.green, colormap->black_map.blue,
colormap->white_map.red, colormap->white_map.green, colormap->white_map.blue);
printf ("page %d\n", i);
}
}
@@ -630,7 +703,7 @@ bool parse_control_file (char *fn)
goto fail;
}
fprintf (stderr, "%d pages specified\n", first_input_context->image_count);
fprintf (stderr, "%d images specified\n", first_input_context->image_count);
result = 1;
@@ -646,6 +719,22 @@ bool parse_control_file (char *fn)
return (result);
}
bool omit_label (page_label_t *page_label)
{
static page_label_t *last_page_label;
bool unneeded;
unneeded = ( (last_page_label != NULL) &&
page_label->prefix &&
last_page_label->prefix &&
(strcmp (page_label->prefix, last_page_label->prefix) == 0) &&
(page_label->style == last_page_label->style) &&
(page_label->base == last_page_label->base + 1) );
last_page_label = page_label;
return unneeded;
}
bool process_controls (void)
{
@@ -672,7 +761,12 @@ bool process_controls (void)
i = 0;
input_fn = get_input_filename (image->input_context);
if (verbose)
fprintf (stderr, "opening input file '%s'\n", input_fn);
{
if (input_fn)
fprintf (stderr, "opening input file '%s'\n", input_fn);
else
fprintf (stderr, "generating blank image\n");
}
if (! open_input_file (input_fn))
{
fprintf (stderr, "error opening input file '%s'\n", input_fn);
@@ -712,6 +806,12 @@ bool process_controls (void)
parity,
& input_attributes.page_size);
input_attributes.transparency = get_input_transparency (image->input_context, parity);
// really an output attribute, but we don't have such an thing
input_attributes.colormap = get_output_colormap (page->output_context);
if (verbose)
fprintf (stderr, "processing image %d\n", image->range.first + i);
@@ -725,20 +825,27 @@ bool process_controls (void)
page_label->page_index = page_index;
page_label->base = page->range.first;
page_label->count = range_count (page->range);
if (omit_label (page_label))
page_label = NULL;
}
}
if (! process_page (image->range.first + i,
input_attributes,
p ? NULL : page->bookmark_list,
page_label))
page_label,
page->has_overlay ? & page->overlay : NULL,
input_attributes.transparency))
{
fprintf (stderr, "error processing image %d\n", image->range.first + i);
return (0);
}
i++;
p++;
page_index++;
if (! page->has_overlay)
page_index++;
}
}
#endif /* CTL_LANG */

View File

@@ -19,14 +19,14 @@
* 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
*
* 2009-03-13 [JDB] Add support for blank pages, overlay images, color
* mapping, color-key masking, and push/pop of input
* contexts.
*/
typedef struct
{
double width;
double height;
} page_size_t;
// HACK! rgb_t and colormap_t have to appear here and in pdf_g4! See pdf.h
#define SEMANTICS
typedef struct
{
@@ -34,6 +34,46 @@ typedef struct
int last;
} range_t;
typedef struct
{
int red;
int green;
int blue;
} rgb_t;
typedef struct
{
range_t red;
range_t green;
range_t blue;
} rgb_range_t;
typedef struct
{
rgb_t black_map;
rgb_t white_map;
} colormap_t;
// end of HACK
typedef struct
{
double x;
double y;
} position_t;
typedef struct
{
double left;
double top;
} overlay_t;
typedef struct
{
double width;
double height;
} page_size_t;
typedef struct
{
double left;
@@ -74,12 +114,17 @@ extern int line; /* line number in spec file */
extern int bookmark_level;
/* Bison interface */
extern int yyparse (void);
void yyerror (char *s);
/* semantic routines for input statements */
void input_push_context (void);
void input_pop_context (void);
void input_set_modifier_context (input_modifier_type_t type);
void input_set_file (char *name);
void input_set_rotation (int rotation);
void input_set_transparency (rgb_range_t rgb_range);
void input_set_page_size (page_size_t size);
void input_images (range_t range);
@@ -97,6 +142,9 @@ void output_set_keywords (char *keywords);
void output_set_bookmark (char *name);
void output_set_page_label (page_label_t label);
void output_pages (range_t range);
void output_overlay (overlay_t overlay);
void output_transparency (rgb_range_t rgb_range);
void output_set_colormap (rgb_t black_color, rgb_t white_color);
/* functions to be called from main program: */

View File

@@ -19,6 +19,9 @@
* 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
*
* 2009-03-02 [JDB] Add support for overlay images and color key masking.
* 2014-02-18 [JDB] Add -V option to print the program version.
*/
@@ -53,7 +56,7 @@ typedef struct output_file_t
} output_file_t;
int verbose;
int verbose, version;
output_file_t *output_files;
@@ -81,9 +84,11 @@ void usage (void)
fprintf (stderr, " %s [options] -c <control.tum>\n", progname);
#endif
fprintf (stderr, " %s [options] <input.tif>... -o <output.pdf>\n", progname);
fprintf (stderr, " %s -V\n", progname);
fprintf (stderr, "options:\n");
fprintf (stderr, " -v verbose\n");
fprintf (stderr, " -b <fmt> create bookmarks\n");
fprintf (stderr, " -V print program version\n");
fprintf (stderr, "bookmark format:\n");
fprintf (stderr, " %%F file name (sans suffix)\n");
fprintf (stderr, " %%p page number\n");
@@ -191,25 +196,54 @@ bool open_pdf_output_file (char *name,
#define MAX_BOOKMARK_LEVEL 20
static pdf_bookmark_handle bookmark_vector [MAX_BOOKMARK_LEVEL + 1] = { NULL };
static pdf_page_handle last_page = NULL;
static page_size_t last_size;
bool process_page (int image, /* range 1 .. n */
input_attributes_t input_attributes,
bookmark_t *bookmarks,
page_label_t *page_label)
page_label_t *page_label,
overlay_t *overlay,
rgb_range_t *transparency)
{
pdf_page_handle page;
image_info_t image_info;
position_t position;
if (! get_image_info (image, input_attributes, & image_info))
return (0);
page = pdf_new_page (out->pdf,
image_info.width_points,
image_info.height_points);
if (overlay)
{
page = last_page;
position.x = overlay->left * POINTS_PER_INCH;
position.y = last_size.height - image_info.height_points - overlay->top * POINTS_PER_INCH;
if (! process_image (image, input_attributes, & image_info, page))
if (verbose)
fprintf (stderr, "overlaying image at %.3f, %.3f\n", position.x, position.y);
if (transparency)
{
input_attributes.transparency = transparency;
}
}
else
{
last_page = page = pdf_new_page (out->pdf,
image_info.width_points,
image_info.height_points);
last_size.width = image_info.width_points;
last_size.height = image_info.height_points;
position.x = 0.0;
position.y = 0.0;
}
if (! process_image (image, input_attributes, & image_info, page, position))
return (0);
if (overlay)
return (page != NULL);
while (bookmarks)
{
if (bookmarks->level <= MAX_BOOKMARK_LEVEL)
@@ -338,6 +372,8 @@ void main_args (char *out_fn,
ip);
if (! process_page (ip, input_attributes,
bookmark_fmt ? & bookmark : NULL,
NULL,
NULL,
NULL))
fatal (3, "error processing page %d of input file \"%s\"\n", ip, in_fn [i]);
if (last_input_page ())
@@ -381,12 +417,18 @@ int main (int argc, char *argv[])
init_tiff_handler ();
init_jpeg_handler ();
init_pbm_handler ();
init_png_handler ();
while (--argc)
{
if (argv [1][0] == '-')
{
if (strcmp (argv [1], "-v") == 0)
if (strcmp (argv [1], "-V") == 0)
{
version++;
break;
}
else if (strcmp (argv [1], "-v") == 0)
verbose++;
else if (strcmp (argv [1], "-o") == 0)
{
@@ -433,6 +475,12 @@ int main (int argc, char *argv[])
argv++;
}
if (version)
{
puts (PDF_PRODUCER);
exit (0);
}
#ifdef CTL_LANG
if (! ((! out_fn) ^ (! control_fn)))
fatal (1, "either a control file or an output file (but not both) must be specified\n");

View File

@@ -18,6 +18,8 @@
* 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
*
* 2009-03-02 [JDB] Add support for overlay images and color key masking.
*/
@@ -38,6 +40,11 @@ typedef struct
bool has_crop;
crop_t crop;
rgb_range_t *transparency;
colormap_t *colormap; // really an output attribute, but we don't have such a thing
} input_attributes_t;
@@ -61,4 +68,6 @@ bool open_pdf_output_file (char *name,
bool process_page (int image, /* range 1 .. n */
input_attributes_t input_attributes,
bookmark_t *bookmarks,
page_label_t *page_label);
page_label_t *page_label,
overlay_t *overlay,
rgb_range_t *transparency);

149
tumble_blank.c Normal file
View File

@@ -0,0 +1,149 @@
/*
* tumble: build a PDF file from image files
*
* $Id: tumble_blank.c ... Exp $
* Copyright ...
*
* 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
*
* 2007-05-07 [JDB] New file to add support for blank pages.
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "semantics.h"
#include "tumble.h"
#include "bitblt.h"
#include "pdf.h"
#include "pdf_util.h"
#include "pdf_prim.h"
#include "pdf_private.h"
#include "tumble_input.h"
struct pdf_blank_page
{
double width;
double height;
double x;
double y;
double red;
double green;
double blue;
};
static bool match_blank_suffix (char *suffix)
{
return (0);
}
static bool close_blank_input_file (void)
{
return (1);
}
static bool open_blank_input_file (FILE *f, char *name)
{
return (1);
}
static bool last_blank_input_page (void)
{
return (1);
}
static bool get_blank_image_info (int image,
input_attributes_t input_attributes,
image_info_t *image_info)
{
if (input_attributes.has_page_size)
{
image_info->width_points = input_attributes.page_size.width * POINTS_PER_INCH;
image_info->height_points = input_attributes.page_size.height * POINTS_PER_INCH;
return (1);
}
else
return (0);
}
static void pdf_write_blank_content_callback (pdf_file_handle pdf_file,
struct pdf_obj *stream,
void *app_data)
{
struct pdf_blank_page *page = app_data;
pdf_stream_printf (pdf_file, stream,
"%g %g %g rg\r\n%g %g %g %g re\r\nf\r\n",
page->red, page->green, page->blue,
page->x, page->y,
page->width, page->height);
}
static bool process_blank_image (int image, /* range 1 .. n */
input_attributes_t input_attributes,
image_info_t *image_info,
pdf_page_handle pdf_page,
position_t position)
{
struct pdf_blank_page *page;
struct pdf_obj *content_stream;
/* If colormap set, use "white" color and draw rectangle to cover page. */
if (input_attributes.colormap)
{
page = pdf_calloc (1, sizeof (struct pdf_blank_page));
page->width = image_info->width_points;
page->height = image_info->height_points;
page->x = 0;
page->y = 0;
page->red = (double) input_attributes.colormap->white_map.red / 255.0;
page->green = (double) input_attributes.colormap->white_map.green / 255.0;
page->blue = (double) input_attributes.colormap->white_map.blue / 255.0;
content_stream = pdf_new_ind_ref (pdf_page->pdf_file,
pdf_new_stream (pdf_page->pdf_file,
pdf_new_obj (PT_DICTIONARY),
& pdf_write_blank_content_callback,
page));
pdf_set_dict_entry (pdf_page->page_dict, "Contents", content_stream);
pdf_write_ind_obj (pdf_page->pdf_file, content_stream);
}
return (1);
}
input_handler_t blank_handler =
{
match_blank_suffix,
open_blank_input_file,
close_blank_input_file,
last_blank_input_page,
get_blank_image_info,
process_blank_image
};

View File

@@ -19,6 +19,9 @@
* 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
*
* 2007-05-07 [JDB] Add support for blank pages and fix a bug that caused a
* double free.
*/
@@ -66,10 +69,19 @@ bool match_input_suffix (char *suffix)
return (0);
}
bool open_input_file (char *name)
{
int i;
if (name == NULL)
{
if (in)
close_input_file ();
current_input_handler = & blank_handler;
return (1);
}
if (in)
{
if (strcmp (name, in_filename) == 0)
@@ -117,8 +129,10 @@ bool close_input_file (void)
result = current_input_handler->close_input_file ();
current_input_handler = NULL;
}
if (in_filename)
if (in_filename) {
free (in_filename);
in_filename = NULL;
}
if (in)
{
fclose (in);
@@ -151,12 +165,14 @@ bool get_image_info (int image,
bool process_image (int image,
input_attributes_t input_attributes,
image_info_t *image_info,
pdf_page_handle page)
pdf_page_handle page,
position_t position)
{
if (! current_input_handler)
return (0);
return (current_input_handler->process_image (image,
input_attributes,
image_info,
page));
page,
position));
}

View File

@@ -18,12 +18,15 @@
* 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
*
* 2010-09-02 [JDB] Added support for min-is-black TIFF images.
*/
typedef struct
{
bool color;
bool negative;
uint32_t width_samples, height_samples;
double width_points, height_points;
double x_resolution, y_resolution;
@@ -42,7 +45,8 @@ typedef struct
bool (*process_image) (int image,
input_attributes_t input_attributes,
image_info_t *image_info,
pdf_page_handle page);
pdf_page_handle page,
position_t position);
} input_handler_t;
@@ -59,9 +63,13 @@ bool get_image_info (int image,
bool process_image (int image,
input_attributes_t input_attributes,
image_info_t *image_info,
pdf_page_handle page);
pdf_page_handle page,
position_t position);
void init_tiff_handler (void);
void init_jpeg_handler (void);
void init_pbm_handler (void);
void init_png_handler (void);
input_handler_t blank_handler;

View File

@@ -18,6 +18,8 @@
* 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
*
* 2009-03-02 [JDB] Add support for overlay images.
*/
@@ -165,15 +167,17 @@ static bool get_jpeg_image_info (int image,
static bool process_jpeg_image (int image, /* range 1 .. n */
input_attributes_t input_attributes,
image_info_t *image_info,
pdf_page_handle page)
pdf_page_handle page,
position_t position)
{
pdf_write_jpeg_image (page,
0, 0, /* x, y */
position.x, position.y,
image_info->width_points,
image_info->height_points,
image_info->color,
image_info->width_samples,
image_info->height_samples,
input_attributes.transparency,
jpeg_f);
return (1);

View File

@@ -18,6 +18,8 @@
* 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
*
* 2009-03-02 [JDB] Add support for overlay images.
*/
@@ -125,6 +127,8 @@ static bool get_pbm_image_info (int image,
return (0);
}
image_info->negative = false;
return (1);
}
@@ -132,7 +136,8 @@ static bool get_pbm_image_info (int image,
static bool process_pbm_image (int image, /* range 1 .. n */
input_attributes_t input_attributes,
image_info_t *image_info,
pdf_page_handle page)
pdf_page_handle page,
position_t position)
{
bool result = 0;
Rect rect;
@@ -192,12 +197,12 @@ static bool process_pbm_image (int image, /* range 1 .. n */
#endif
pdf_write_g4_fax_image (page,
0, 0, /* x, y */
position.x, position.y,
image_info->width_points, image_info->height_points,
image_info->negative,
bitmap,
0, /* ImageMask */
0, 0, 0, /* r, g, b */
0); /* BlackIs1 */
NULL,
NULL);
result = 1;

237
tumble_png.c Normal file
View File

@@ -0,0 +1,237 @@
/*
* tumble: build a PDF file from image files
*
* Copyright 2004 Daniel Gloeckner
*
* Derived from tumble_jpeg.c written 2003 by Eric Smith <eric at 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
*
* 2009-03-13 [JDB] New module to add PNG image support.
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <strings.h> /* strcasecmp() is a BSDism */
#include "semantics.h"
#include "tumble.h"
#include "bitblt.h"
#include "pdf.h"
#include "tumble_input.h"
static FILE *png_f;
static struct {
uint32_t palent;
uint8_t bpp;
uint8_t color;
char pal[256*3];
} cinfo;
static bool match_png_suffix (char *suffix)
{
return (strcasecmp (suffix, ".png") == 0);
}
static bool close_png_input_file (void)
{
return (1);
}
#define BENUM(p) (((p)[0]<<24)+((p)[1]<<16)+((p)[2]<<8)+(p)[3])
static bool open_png_input_file (FILE *f, char *name)
{
const char sig [8]="\211PNG\r\n\032\n";
uint8_t buf [8];
int l;
l = fread (buf, 1, sizeof (sig), f);
if (l != sizeof (sig) || memcmp(buf,sig,sizeof(sig))) {
rewind(f);
return 0;
}
png_f = f;
return 1;
}
static bool last_png_input_page (void)
{
return 1;
}
static bool get_png_image_info (int image,
input_attributes_t input_attributes,
image_info_t *image_info)
{
uint8_t buf [20], unit;
uint32_t width,height,xppu,yppu;
size_t l;
bool seen_IHDR,seen_PLTE,seen_pHYs;
seen_IHDR=seen_PLTE=seen_pHYs=false;
memset(&cinfo,0,sizeof(cinfo));
unit=0;
xppu=yppu=1;
for(;;)
{
l = fread (buf, 1, 8, png_f);
if(l != 8)
return 0;
l=BENUM(buf);
if(!memcmp(buf+4,"IHDR",4)) {
if(seen_IHDR || l!=13)
return 0;
seen_IHDR=true;
l = fread (buf, 1, 17, png_f);
if(l!=17)
return 0;
width=BENUM(buf);
height=BENUM(buf+4);
cinfo.bpp=buf[8];
cinfo.color=buf[9];
if(buf[8]>8 || buf[10] || buf[11] || buf[12])
return 0;
continue;
}
if(!seen_IHDR)
return 0;
if(!memcmp(buf+4,"PLTE",4)) {
size_t i;
if(seen_PLTE || l>256*3 || l%3 || !cinfo.color)
return 0;
seen_PLTE=true;
i = fread (cinfo.pal, 1, l, png_f);
if(i != l)
return 0;
cinfo.palent=l/3;
fseek(png_f,4,SEEK_CUR);
} else if(!memcmp(buf+4,"pHYs",4)) {
if(seen_pHYs || l!=9)
return 0;
seen_pHYs=true;
l = fread (buf, 1, 13, png_f);
if(l != 13)
return 0;
xppu=BENUM(buf);
yppu=BENUM(buf+4);
unit=buf[8];
} else if(!memcmp(buf+4,"IDAT",4)) {
fseek(png_f,-8,SEEK_CUR);
break;
} else {
fseek(png_f,l+4,SEEK_CUR);
}
}
if(cinfo.color==3 && !seen_PLTE)
return 0;
#ifdef DEBUG_JPEG
printf ("color type: %d\n", cinfo.color);
printf ("bit depth: %d\n", cinfo.bpp);
printf ("density unit: %d\n", unit);
printf ("x density: %d\n", xppu);
printf ("y density: %d\n", yppu);
printf ("width: %d\n", width);
printf ("height: %d\n", height);
#endif
switch (cinfo.color)
{
case 0:
image_info->color = 0;
break;
case 2:
case 3:
image_info->color = 1;
break;
default:
fprintf (stderr, "PNG color type %d not supported\n", cinfo.color);
return (0);
}
image_info->width_samples = width;
image_info->height_samples = height;
switch (unit==1)
{
case 1:
image_info->width_points = ((image_info->width_samples * POINTS_PER_INCH) /
(xppu * 0.0254));
image_info->height_points = ((image_info->height_samples * POINTS_PER_INCH) /
(yppu * 0.0254));
break;
case 0:
/* assume 300 DPI - not great, but what else can we do? */
image_info->width_points = (image_info->width_samples * POINTS_PER_INCH) / 300.0;
image_info->height_points = ((double) yppu * image_info->height_samples * POINTS_PER_INCH) / ( 300.0 * xppu);
break;
default:
fprintf (stderr, "PNG pHYs unit %d not supported\n", unit);
}
return 1;
}
static bool process_png_image (int image, /* range 1 .. n */
input_attributes_t input_attributes,
image_info_t *image_info,
pdf_page_handle page,
position_t position)
{
pdf_write_png_image (page,
position.x, position.y,
image_info->width_points,
image_info->height_points,
cinfo.color,
cinfo.color==3?cinfo.pal:NULL,
cinfo.palent,
cinfo.bpp,
image_info->width_samples,
image_info->height_samples,
input_attributes.transparency,
png_f);
return (1);
}
input_handler_t png_handler =
{
match_png_suffix,
open_png_input_file,
close_png_input_file,
last_png_input_page,
get_png_image_info,
process_png_image
};
void init_png_handler (void)
{
install_input_handler (& png_handler);
}

View File

@@ -18,6 +18,8 @@
* 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
*
* 2010-09-02 [JDB] Added support for min-is-black TIFF images.
*/
@@ -102,6 +104,7 @@ static bool get_tiff_image_info (int image,
uint32_t image_height, image_width;
uint16_t samples_per_pixel;
uint16_t bits_per_sample;
uint16_t photometric_interpretation;
uint16_t planar_config;
uint16_t resolution_unit;
@@ -149,6 +152,19 @@ static bool get_tiff_image_info (int image,
return (0);
}
if (1 != TIFFGetField (tiff_in, TIFFTAG_PHOTOMETRIC, & photometric_interpretation))
{
fprintf(stderr, "warning: photometric interpretation not specified, assuming min-is-white\n");
photometric_interpretation = PHOTOMETRIC_MINISWHITE;
}
else if ((photometric_interpretation != PHOTOMETRIC_MINISWHITE) &&
(photometric_interpretation != PHOTOMETRIC_MINISBLACK))
{
fprintf(stderr, "photometric interpretation value %u is invalid\n", photometric_interpretation);
return (0);
}
if (1 != TIFFGetField (tiff_in, TIFFTAG_PLANARCONFIG, & planar_config))
planar_config = 1;
@@ -217,6 +233,8 @@ static bool get_tiff_image_info (int image,
return (0);
}
image_info->negative = (photometric_interpretation == PHOTOMETRIC_MINISBLACK);
return (1);
}
@@ -267,7 +285,8 @@ static void rotate_bitmap (Bitmap *src,
static bool process_tiff_image (int image, /* range 1 .. n */
input_attributes_t input_attributes,
image_info_t *image_info,
pdf_page_handle page)
pdf_page_handle page,
position_t position)
{
bool result = 0;
Rect rect;
@@ -328,12 +347,12 @@ static bool process_tiff_image (int image, /* range 1 .. n */
pdf_write_text (page);
#else
pdf_write_g4_fax_image (page,
0, 0, /* x, y */
position.x, position.y,
image_info->width_points, image_info->height_points,
image_info->negative,
bitmap,
0, /* ImageMask */
0, 0, 0, /* r, g, b */
0); /* BlackIs1 */
input_attributes.colormap,
input_attributes.transparency);
#endif
result = 1;