diff --git a/pdf_jpeg.c b/pdf_jpeg.c index 1f74411..5686e88 100644 --- a/pdf_jpeg.c +++ b/pdf_jpeg.c @@ -2,7 +2,7 @@ * tumble: build a PDF file from image files * * PDF routines - * $Id: pdf_jpeg.c,v 1.2 2003/03/13 00:57:05 eric Exp $ + * $Id: pdf_jpeg.c,v 1.3 2003/03/19 07:39:55 eric Exp $ * Copyright 2003 Eric Smith * * This program is free software; you can redistribute it and/or modify @@ -40,9 +40,9 @@ struct pdf_jpeg_image { double width, height; double x, y; + bool color; /* false for grayscale */ + uint32_t width_samples, height_samples; FILE *f; - unsigned long Columns; - unsigned long Rows; char XObject_name [4]; }; @@ -69,14 +69,13 @@ static void pdf_write_jpeg_image_callback (pdf_file_handle pdf_file, void *app_data) { struct pdf_jpeg_image *image = app_data; - FILE *f; int rlen, wlen; uint8_t *wp; uint8_t buffer [8192]; while (! feof (image->f)) { - rlen = fread (& buffer [0], 1, JPEG_BUFFER_SIZE, f); + rlen = fread (& buffer [0], 1, JPEG_BUFFER_SIZE, image->f); wp = & buffer [0]; while (rlen) { @@ -88,9 +87,11 @@ static void pdf_write_jpeg_image_callback (pdf_file_handle pdf_file, rlen -= wlen; wp += wlen; } - if (ferror (f)) + if (ferror (image->f)) pdf_fatal ("error on input file\n"); } + + pdf_stream_printf (pdf_file, stream, "\r\n"); } @@ -105,7 +106,6 @@ void pdf_write_jpeg_image (pdf_page_handle pdf_page, struct pdf_obj *stream; struct pdf_obj *stream_dict; - struct pdf_obj *decode_parms; struct pdf_obj *content_stream; @@ -117,10 +117,14 @@ void pdf_write_jpeg_image (pdf_page_handle pdf_page, image->y = y; image->f = f; -#if 0 - image->Columns = bitmap->rect.max.x - bitmap->rect.min.x; - image->Rows = bitmap->rect.max.y - bitmap->rect.min.y; -#endif + + /* $$$ quick hack, should read these from file! */ + image->color = 1; + image->width_samples = 71; + image->height_samples = 88; + + pdf_add_array_elem_unique (pdf_page->procset, + pdf_new_name (image->color ? "ImageC" : "ImageB")); stream_dict = pdf_new_obj (PT_DICTIONARY); @@ -135,26 +139,14 @@ 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")); - 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->Columns)); - pdf_set_dict_entry (stream_dict, "Height", pdf_new_integer (image->Rows)); +// 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)); - decode_parms = pdf_new_obj (PT_DICTIONARY); - - pdf_set_dict_entry (decode_parms, - "K", - pdf_new_integer (-1)); - - pdf_set_dict_entry (decode_parms, - "Columns", - pdf_new_integer (image->Columns)); - - pdf_set_dict_entry (decode_parms, - "Rows", - pdf_new_integer (image->Rows)); - - pdf_stream_add_filter (stream, "DCTDecode", decode_parms); + pdf_stream_add_filter (stream, "DCTDecode", NULL); /* the following will write the stream, using our callback function to get the actual data */ @@ -170,4 +162,3 @@ void pdf_write_jpeg_image (pdf_page_handle pdf_page, pdf_write_ind_obj (pdf_page->pdf_file, content_stream); } - diff --git a/semantics.c b/semantics.c index cb26242..1b65adf 100644 --- a/semantics.c +++ b/semantics.c @@ -2,7 +2,7 @@ * tumble: build a PDF file from image files * * Semantic routines for spec file parser - * $Id: semantics.c,v 1.22 2003/03/16 05:58:25 eric Exp $ + * $Id: semantics.c,v 1.23 2003/03/19 07:39:55 eric Exp $ * Copyright 2001, 2002, 2003 Eric Smith * * This program is free software; you can redistribute it and/or modify @@ -667,10 +667,10 @@ bool process_controls (void) i = 0; input_fn = get_input_filename (image->input_context); if (verbose) - fprintf (stderr, "opening TIFF file '%s'\n", input_fn); - if (! open_tiff_input_file (input_fn)) + fprintf (stderr, "opening input file '%s'\n", input_fn); + if (! open_input_file (input_fn)) { - fprintf (stderr, "error opening TIFF file '%s'\n", input_fn); + fprintf (stderr, "error opening input file '%s'\n", input_fn); return (0); } } diff --git a/tumble.c b/tumble.c index 71d25de..a5f8d3f 100644 --- a/tumble.c +++ b/tumble.c @@ -2,7 +2,7 @@ * tumble: build a PDF file from image files * * Main program - * $Id: tumble.c,v 1.36 2003/03/16 05:58:26 eric Exp $ + * $Id: tumble.c,v 1.37 2003/03/19 07:39:55 eric Exp $ * Copyright 2001, 2002, 2003 Eric Smith * * This program is free software; you can redistribute it and/or modify @@ -60,8 +60,18 @@ typedef struct output_file_t int verbose; +typedef enum + { + INPUT_FILE_TYPE_NONE, + INPUT_FILE_TYPE_TIFF, + INPUT_FILE_TYPE_JPEG + } input_file_type_t; + + char *in_filename; -TIFF *in; +input_file_type_t in_type; +FILE *in; +TIFF *tiff_in; output_file_t *output_files; output_file_t *out; @@ -92,6 +102,8 @@ void usage (void) /* generate fatal error message to stderr, doesn't return */ +void fatal (int ret, char *format, ...) __attribute__ ((noreturn)); + void fatal (int ret, char *format, ...) { va_list ap; @@ -108,7 +120,7 @@ void fatal (int ret, char *format, ...) fprintf (stderr, "\n"); if (ret == 1) usage (); - close_tiff_input_file (); + close_input_file (); close_pdf_output_files (); exit (ret); } @@ -116,24 +128,49 @@ void fatal (int ret, char *format, ...) bool close_tiff_input_file (void) { - if (in) - { - free (in_filename); - TIFFClose (in); - } - in = NULL; - in_filename = NULL; + TIFFClose (tiff_in); return (1); } -bool open_tiff_input_file (char *name) +bool open_tiff_input_file (FILE *f, char *name) { + tiff_in = TIFFFdOpen (fileno (f), name, "r"); + if (! tiff_in) + { + fprintf (stderr, "can't open input file '%s'\n", name); + free (in_filename); + return (0); + } + in_type = INPUT_FILE_TYPE_TIFF; + return (1); +} + + +bool close_jpeg_input_file (void) +{ + return (1); +} + + +bool open_jpeg_input_file (FILE *f, char *name) +{ + in_type = INPUT_FILE_TYPE_JPEG; + return (1); +} + + +bool open_input_file (char *name) +{ + bool result; + uint8_t buf [2]; + size_t l; + if (in) { if (strcmp (name, in_filename) == 0) return (1); - close_tiff_input_file (); + close_input_file (); } in_filename = strdup (name); if (! in_filename) @@ -141,17 +178,90 @@ bool open_tiff_input_file (char *name) fprintf (stderr, "can't strdup input filename '%s'\n", name); return (0); } - in = TIFFOpen (name, "r"); + + in = fopen (name, "rb"); if (! in) + return (0); + + l = fread (& buf [0], 1, sizeof (buf), in); + if (l != sizeof (buf)) + return (0); + + rewind (in); + + if ((buf [0] == 0x49) && (buf [1] == 0x49)) + result = open_tiff_input_file (in, name); + else if ((buf [0] == 0xff) && (buf [1] == 0xd8)) + result = open_jpeg_input_file (in, name); + else { - fprintf (stderr, "can't open input file '%s'\n", name); - free (in_filename); - return (0); + fprintf (stderr, "unrecognized file header in file '%s'\n", name); + result = 0; } + if (! result) + { + if (in) + fclose (in); + in = NULL; + in_type = INPUT_FILE_TYPE_NONE; + } + return (result); +} + + +bool close_input_file (void) +{ + bool result; + + switch (in_type) + { + case INPUT_FILE_TYPE_NONE: + return (1); + case INPUT_FILE_TYPE_TIFF: + result = close_tiff_input_file (); + break; + case INPUT_FILE_TYPE_JPEG: + result = close_jpeg_input_file (); + break; + default: + fatal (3, "internal error: bad input file type\n"); + } + + if (in_filename) + free (in_filename); + fclose (in); + in = NULL; + + return (result); +} + + +bool last_tiff_input_page (void) +{ + return (TIFFLastDirectory (tiff_in)); +} + + +bool last_jpeg_input_page (void) +{ return (1); } +bool last_input_page (void) +{ + switch (in_type) + { + case INPUT_FILE_TYPE_TIFF: + return (last_tiff_input_page ()); + case INPUT_FILE_TYPE_JPEG: + return (last_jpeg_input_page ()); + default: + fatal (3, "internal error: bad input file type\n"); + } +} + + bool close_pdf_output_files (void) { output_file_t *o, *n; @@ -271,12 +381,6 @@ static void rotate_bitmap (Bitmap *src, #define SWAP(type,a,b) do { type temp; temp = a; a = b; b = temp; } while (0) -bool last_tiff_page (void) -{ - return (TIFFLastDirectory (in)); -} - - static pdf_page_handle process_tiff_page (int image, /* range 1 .. n */ input_attributes_t input_attributes) { @@ -304,50 +408,50 @@ static pdf_page_handle process_tiff_page (int image, /* range 1 .. n */ pdf_page_handle page = NULL; - if (! TIFFSetDirectory (in, image - 1)) + if (! TIFFSetDirectory (tiff_in, image - 1)) { fprintf (stderr, "can't find page %d of input file\n", image); goto fail; } - if (1 != TIFFGetField (in, TIFFTAG_IMAGELENGTH, & image_length)) + if (1 != TIFFGetField (tiff_in, TIFFTAG_IMAGELENGTH, & image_length)) { fprintf (stderr, "can't get image length\n"); goto fail; } - if (1 != TIFFGetField (in, TIFFTAG_IMAGEWIDTH, & image_width)) + if (1 != TIFFGetField (tiff_in, TIFFTAG_IMAGEWIDTH, & image_width)) { fprintf (stderr, "can't get image width\n"); goto fail; } - if (1 != TIFFGetField (in, TIFFTAG_SAMPLESPERPIXEL, & samples_per_pixel)) + if (1 != TIFFGetField (tiff_in, TIFFTAG_SAMPLESPERPIXEL, & samples_per_pixel)) { fprintf (stderr, "can't get samples per pixel\n"); goto fail; } #ifdef CHECK_DEPTH - if (1 != TIFFGetField (in, TIFFTAG_IMAGEDEPTH, & image_depth)) + if (1 != TIFFGetField (tiff_in, TIFFTAG_IMAGEDEPTH, & image_depth)) { fprintf (stderr, "can't get image depth\n"); goto fail; } #endif - if (1 != TIFFGetField (in, TIFFTAG_BITSPERSAMPLE, & bits_per_sample)) + if (1 != TIFFGetField (tiff_in, TIFFTAG_BITSPERSAMPLE, & bits_per_sample)) { fprintf (stderr, "can't get bits per sample\n"); goto fail; } - if (1 != TIFFGetField (in, TIFFTAG_PLANARCONFIG, & planar_config)) + if (1 != TIFFGetField (tiff_in, TIFFTAG_PLANARCONFIG, & planar_config)) planar_config = 1; - if (1 != TIFFGetField (in, TIFFTAG_RESOLUTIONUNIT, & resolution_unit)) + if (1 != TIFFGetField (tiff_in, TIFFTAG_RESOLUTIONUNIT, & resolution_unit)) resolution_unit = 2; - if (1 != TIFFGetField (in, TIFFTAG_XRESOLUTION, & x_resolution)) + if (1 != TIFFGetField (tiff_in, TIFFTAG_XRESOLUTION, & x_resolution)) x_resolution = 300; - if (1 != TIFFGetField (in, TIFFTAG_YRESOLUTION, & y_resolution)) + if (1 != TIFFGetField (tiff_in, TIFFTAG_YRESOLUTION, & y_resolution)) y_resolution = 300; if (samples_per_pixel != 1) @@ -412,7 +516,7 @@ static pdf_page_handle process_tiff_page (int image, /* range 1 .. n */ } for (row = 0; row < image_length; row++) - if (1 != TIFFReadScanline (in, + if (1 != TIFFReadScanline (tiff_in, bitmap->bits + row * bitmap->row_words, row, 0)) @@ -472,27 +576,26 @@ static pdf_page_handle process_tiff_page (int image, /* range 1 .. n */ } -#if 0 pdf_page_handle process_jpeg_page (int image, /* range 1 .. n */ input_attributes_t input_attributes) { - FILE *f; pdf_page_handle page; + double width_points, height_points; /* really 1/72 inch units rather than + points */ - f = fopen (filename, "rb"); - if (! f) - fatal ("error opening input file '%s'\n", filename); + /* $$$ need to get these from somewhere else, hardcoded for now */ + width_points = 4 * 72.0; + height_points = 4 * 72.0; page = pdf_new_page (out->pdf, width_points, height_points); pdf_write_jpeg_image (page, 0, 0, /* x, y */ width_points, height_points, - f); + in); return (page); } -#endif bool process_page (int image, /* range 1 .. n */ @@ -502,7 +605,17 @@ bool process_page (int image, /* range 1 .. n */ { pdf_page_handle page; - page = process_tiff_page (image, input_attributes); + switch (in_type) + { + case INPUT_FILE_TYPE_TIFF: + page = process_tiff_page (image, input_attributes); + break; + case INPUT_FILE_TYPE_JPEG: + page = process_jpeg_page (image, input_attributes); + break; + default: + fatal (3, "internal error: bad input file type\n"); + } while (bookmarks) { @@ -608,7 +721,7 @@ void main_args (char *out_fn, fatal (3, "error opening output file \"%s\"\n", out_fn); for (i = 0; i < inf_count; i++) { - if (! open_tiff_input_file (in_fn [i])) + if (! open_input_file (in_fn [i])) fatal (3, "error opening input file \"%s\"\n", in_fn [i]); for (ip = 1;; ip++) { @@ -622,12 +735,12 @@ void main_args (char *out_fn, bookmark_fmt ? & bookmark : NULL, NULL)) fatal (3, "error processing page %d of input file \"%s\"\n", ip, in_fn [i]); - if (last_tiff_page ()) + if (last_input_page ()) break; } if (verbose) fprintf (stderr, "processed %d pages of input file \"%s\"\n", ip, in_fn [i]); - if (! close_tiff_input_file ()) + if (! close_input_file ()) fatal (3, "error closing input file \"%s\"\n", in_fn [i]); } if (! close_pdf_output_files ()) @@ -719,7 +832,7 @@ int main (int argc, char *argv[]) else main_args (out_fn, inf_count, in_fn, bookmark_fmt); - close_tiff_input_file (); + close_input_file (); close_pdf_output_files (); exit (0); } diff --git a/tumble.h b/tumble.h index 92a2c1f..0c8537d 100644 --- a/tumble.h +++ b/tumble.h @@ -1,7 +1,7 @@ /* * tumble: build a PDF file from image files * - * $Id: tumble.h,v 1.15 2003/03/14 00:57:40 eric Exp $ + * $Id: tumble.h,v 1.16 2003/03/19 07:39:55 eric Exp $ * Copyright 2001, 2002, 2003 Eric Smith * * This program is free software; you can redistribute it and/or modify @@ -39,8 +39,9 @@ typedef struct crop_t crop; } input_attributes_t; -bool open_tiff_input_file (char *name); -bool close_tiff_input_file (void); + +bool open_input_file (char *name); +bool close_input_file (void); typedef struct