[PATCH] PNG & JPEG 2000 support
Daniel Glöckner
daniel-gl at gmx.net
Sun Oct 17 14:22:32 PDT 2004
Once again without PGP signature and compression to make the list
server happy.
Daniel
-----------------------------------------------------------------------
The attached patch adds PNG and JP2 support to tumble.
PNG:
As the deflated data is directly copied into the PDF, there are some
limitations to the list of supported images:
- bit depth <= 8
- no alpha channel
- no interlace
JP2:
The PDF Reference says JP2 is just a subset of the allowed JPX
format. I don't have a copy of the official standard, so I don't know
what to change to cover JPXes as well.
You'll need the Adobe Acrobat Reader 6 to display those images.
Xpdf and Ghostscript are missing the ColorSpace key in the image
dictionary, which is optional for JPXDecode and IMHO not just a matter
of a few lines of code.
One thing left to do is to change the PDF version to 1.5 if a JP2 file
has been given to tumble - maybe using the Version key in the Catalog
if seeking is not possible.
Using the resolution info in a JP2 (resc/resd boxes) is implemented but
untested. Jasper doesn't write those boxes.
I had to change the string handling to allow black in PNG palettes.
And there was a double free in tumble_input.c which happens when not
using control files.
Daniel
-------------- next part --------------
diff -rwudN tumble-0.33/Makefile tumble-0.33-my/Makefile
--- tumble-0.33/Makefile Tue Dec 9 18:54:48 2003
+++ tumble-0.33-my/Makefile Sun Oct 17 03:05:10 2004
@@ -65,11 +65,12 @@
TARGETS = tumble
CSRCS = tumble.c semantics.c \
- tumble_input.c tumble_tiff.c tumble_jpeg.c tumble_pbm.c \
+ tumble_input.c tumble_tiff.c tumble_jpeg.c \
+ tumble_pbm.c tumble_png.c tumble_jp2.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 pdf_jp2.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
@@ -107,11 +108,12 @@
TUMBLE_OBJS = tumble.o semantics.o \
- tumble_input.o tumble_tiff.o tumble_jpeg.o tumble_pbm.o \
+ tumble_input.o tumble_tiff.o tumble_jpeg.o \
+ tumble_pbm.o tumble_png.o tumble_jp2.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 pdf_jp2.o
ifdef CTL_LANG
TUMBLE_OBJS += scanner.o parser.tab.o
diff -rwudN tumble-0.33/pdf.h tumble-0.33-my/pdf.h
--- tumble-0.33/pdf.h Tue Dec 9 17:45:41 2003
+++ tumble-0.33-my/pdf.h Sun Oct 17 03:05:10 2004
@@ -92,6 +92,27 @@
uint32_t height_samples,
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,
+ FILE *f);
+
+void pdf_write_jp2_image (pdf_page_handle pdf_page,
+ double x,
+ double y,
+ double width,
+ double height,
+ uint32_t width_samples,
+ uint32_t height_samples,
+ FILE *f);
void pdf_set_page_number (pdf_page_handle pdf_page, char *page_number);
diff -rwudN tumble-0.33/pdf_jp2.c tumble-0.33-my/pdf_jp2.c
--- tumble-0.33/pdf_jp2.c Thu Jan 1 01:00:00 1970
+++ tumble-0.33-my/pdf_jp2.c Sun Oct 17 03:05:44 2004
@@ -0,0 +1,161 @@
+/*
+ * 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
+ */
+
+
+#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_jp2_image
+{
+ double width, height;
+ double x, y;
+ uint32_t width_samples, height_samples;
+ FILE *f;
+ char XObject_name [4];
+};
+
+
+static void pdf_write_jp2_content_callback (pdf_file_handle pdf_file,
+ struct pdf_obj *stream,
+ void *app_data)
+{
+ struct pdf_jp2_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_stream_printf (pdf_file, stream, "/%s Do Q\r\n",
+ image->XObject_name);
+}
+
+
+#define JPEG_BUFFER_SIZE 8192
+
+static void pdf_write_jp2_image_callback (pdf_file_handle pdf_file,
+ struct pdf_obj *stream,
+ void *app_data)
+{
+ struct pdf_jp2_image *image = app_data;
+ int rlen, wlen;
+ uint8_t *wp;
+ uint8_t buffer [8192];
+
+ while (! feof (image->f))
+ {
+ rlen = fread (& buffer [0], 1, JPEG_BUFFER_SIZE, image->f);
+ wp = & buffer [0];
+ 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");
+ }
+}
+
+
+void pdf_write_jp2_image (pdf_page_handle pdf_page,
+ double x,
+ double y,
+ double width,
+ double height,
+ uint32_t width_samples,
+ uint32_t height_samples,
+ FILE *f)
+{
+ struct pdf_jp2_image *image;
+
+ struct pdf_obj *stream;
+ struct pdf_obj *stream_dict;
+
+ struct pdf_obj *content_stream;
+
+ image = pdf_calloc (1, sizeof (struct pdf_jp2_image));
+
+ image->width = width;
+ image->height = height;
+ image->x = x;
+ image->y = y;
+
+ image->f = f;
+
+ image->width_samples = width_samples;
+ image->height_samples = height_samples;
+
+ 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_jp2_image_callback,
+ image));
+
+ strcpy (& image->XObject_name [0], "Im ");
+ image->XObject_name [2] = pdf_new_XObject (pdf_page, stream);
+
+ 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));
+
+ // not required for JPXDecode, but
+ pdf_set_dict_entry (stream_dict, "BitsPerComponent", pdf_new_integer (8));
+
+ pdf_stream_add_filter (stream, "JPXDecode", NULL);
+
+ /* 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_jp2_content_callback,
+ image));
+
+ pdf_set_dict_entry (pdf_page->page_dict, "Contents", content_stream);
+
+ pdf_write_ind_obj (pdf_page->pdf_file, content_stream);
+
+}
diff -rwudN tumble-0.33/pdf_png.c tumble-0.33-my/pdf_png.c
--- tumble-0.33/pdf_png.c Thu Jan 1 01:00:00 1970
+++ tumble-0.33-my/pdf_png.c Sun Oct 17 03:05:41 2004
@@ -0,0 +1,200 @@
+/*
+ * 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
+ */
+
+
+#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_stream_printf (pdf_file, stream, "/%s Do Q\r\n",
+ image->XObject_name);
+}
+
+
+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,
+ 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;
+
+ 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(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));
+
+ pdf_set_dict_entry (pdf_page->page_dict, "Contents", content_stream);
+
+ pdf_write_ind_obj (pdf_page->pdf_file, content_stream);
+}
diff -rwudN tumble-0.33/pdf_prim.c tumble-0.33-my/pdf_prim.c
--- tumble-0.33/pdf_prim.c Tue Dec 9 17:45:39 2003
+++ tumble-0.33-my/pdf_prim.c Sun Oct 17 03:05:10 2004
@@ -90,7 +90,10 @@
union {
bool boolean;
char *name;
- char *string;
+ struct {
+ char *content;
+ int length;
+ } string;
long integer;
double real;
struct pdf_obj *ind_ref;
@@ -243,7 +246,18 @@
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 +411,16 @@
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 +450,51 @@
}
-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 +612,7 @@
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);
diff -rwudN tumble-0.33/pdf_prim.h tumble-0.33-my/pdf_prim.h
--- tumble-0.33/pdf_prim.h Tue Dec 9 17:45:39 2003
+++ tumble-0.33-my/pdf_prim.h Sun Oct 17 03:05:10 2004
@@ -79,6 +79,8 @@
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);
diff -rwudN tumble-0.33/tumble.c tumble-0.33-my/tumble.c
--- tumble-0.33/tumble.c Tue Dec 9 18:17:19 2003
+++ tumble-0.33-my/tumble.c Sun Oct 17 03:05:10 2004
@@ -381,6 +381,8 @@
init_tiff_handler ();
init_jpeg_handler ();
init_pbm_handler ();
+ init_png_handler ();
+ init_jp2_handler ();
while (--argc)
{
diff -rwudN tumble-0.33/tumble_input.c tumble-0.33-my/tumble_input.c
--- tumble-0.33/tumble_input.c Tue Dec 9 17:45:40 2003
+++ tumble-0.33-my/tumble_input.c Sun Oct 17 03:06:41 2004
@@ -117,8 +117,10 @@
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);
diff -rwudN tumble-0.33/tumble_input.h tumble-0.33-my/tumble_input.h
--- tumble-0.33/tumble_input.h Tue Dec 9 17:45:40 2003
+++ tumble-0.33-my/tumble_input.h Sun Oct 17 03:05:10 2004
@@ -65,3 +65,5 @@
void init_tiff_handler (void);
void init_jpeg_handler (void);
void init_pbm_handler (void);
+void init_png_handler (void);
+void init_jp2_handler (void);
diff -rwudN tumble-0.33/tumble_jp2.c tumble-0.33-my/tumble_jp2.c
--- tumble-0.33/tumble_jp2.c Thu Jan 1 01:00:00 1970
+++ tumble-0.33-my/tumble_jp2.c Sun Oct 17 03:11:45 2004
@@ -0,0 +1,275 @@
+/*
+ * 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
+ */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <math.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 bool match_jp2_suffix (char *suffix)
+{
+ return (strcasecmp (suffix, ".jp2") == 0);
+}
+
+static bool close_jp2_input_file (void)
+{
+ return (1);
+}
+
+static struct {
+ FILE *f;
+ uint32_t width,height;
+ struct {
+ double VR,HR;
+ } res[2];
+} jp2info;
+
+struct box {
+ char TBox[4];
+ bool (*func)(uint64_t size, void *cparam);
+ void *cparam;
+};
+
+#define BE32(p) (((p)[0]<<24)+((p)[1]<<16)+((p)[2]<<8)+(p)[3])
+#define BE16(p) (((p)[2]<<8)+(p)[3])
+
+static bool skipbox(uint64_t size, void *cparam)
+{
+ if(size==~0)
+ fseek(jp2info.f,0,SEEK_END);
+ else {
+ if(cparam)
+ size-=*(int *)cparam;
+ fseek(jp2info.f,size,SEEK_CUR); /*FIXME: size is 64bit*/
+ }
+ return 1;
+}
+
+static bool read_res(uint64_t size, void *cparam)
+{
+ int read=0;
+ bool ret=1;
+ if(size>=10) {
+ int i;
+ unsigned char buf[10];
+
+ ret=0;
+ i=(int)cparam;
+ read=fread(buf,1,10,jp2info.f);
+ if(read==10) {
+ uint16_t vrn,vrd,hrn,hrd;
+ int8_t vre,hre;
+ vrn=BE16(buf);
+ vrd=BE16(buf+2);
+ hrn=BE16(buf+4);
+ hrd=BE16(buf+6);
+ vre=((signed char *)buf)[8];
+ hre=((signed char *)buf)[9];
+ if(vrn && vrd && hrn && hrd) {
+ jp2info.res[i].VR=vrn*pow(10.0,vre)/vrd;
+ jp2info.res[i].HR=hrn*pow(10.0,hre)/hrd;
+ ret=1;
+ }
+ }
+ }
+ skipbox(size,&read);
+ return ret;
+}
+
+static bool read_ihdr(uint64_t size, void *cparam)
+{
+ int read=0;
+ bool ret=1;
+ if(size>=8) {
+ unsigned char buf[8];
+ read=fread(buf,1,8,jp2info.f);
+ if(read==8) {
+ jp2info.height=BE32(buf);
+ jp2info.width=BE32(buf+4);
+ } else
+ ret=0;
+ }
+ skipbox(size,&read);
+ return ret;
+}
+
+static bool superbox(uint64_t size, void *cparam)
+{
+ while(size>=8) {
+ static unsigned char buf[12];
+ int r;
+ uint64_t s;
+ struct box *l;
+
+ r=fread(buf+4,1,8,jp2info.f);
+ if(r<8)
+ return (size==~0 && r==0);
+
+ s=BE32(buf+4);
+ if(s==1 && size>=16) {
+ r=fread(buf,1,8,jp2info.f);
+ if(r<8)
+ return 0;
+ s=((uint64_t)BE32(buf)<<32)+BE32(buf+4);
+ }
+ if(s && s<8)
+ return 0;
+ if(size!=~0) {
+ if(!s)
+ return 0;
+ size-=s;
+ } else if(!s)
+ size=0;
+ s=s?s-8:~0;
+
+ for(l=(struct box *)cparam;l->func;l++)
+ if(!memcmp(l->TBox,buf+8,4))
+ break;
+ if(l->func) {
+ if(!l->func(s,l->cparam))
+ return 0;
+ }else
+ if(!skipbox(s,NULL))
+ return 0;
+ }
+
+ return size==0;
+}
+
+static const struct box res_boxes[]={
+ {"resc",read_res,(void *)0},
+ {"resd",read_res,(void *)1},
+ {"",NULL,NULL}
+};
+
+static const struct box jp2h_boxes[]={
+ {"ihdr",read_ihdr,NULL},
+ {"res ",superbox,(void *)res_boxes},
+ {"",NULL,NULL}
+};
+
+static const struct box root[]={
+ {"jp2h",superbox,(void *)jp2h_boxes},
+ {"",NULL,NULL}
+};
+
+static bool open_jp2_input_file (FILE *f, char *name)
+{
+ int s;
+ const char sig[12]="\0\0\0\xCjP \r\n\x87\n";
+ char buf[12];
+
+ memset(&jp2info,0,sizeof(jp2info));
+ jp2info.f=f;
+
+ s=fread(buf,1,12,f);
+ rewind(f);
+ return (s==12 && !memcmp(buf,sig,12));
+}
+
+
+static bool last_jp2_input_page (void)
+{
+ return 1;
+}
+
+
+static bool get_jp2_image_info (int image,
+ input_attributes_t input_attributes,
+ image_info_t *image_info)
+{
+ int i;
+
+ if(!superbox(~0,(void *)root))
+ return 0;
+ rewind(jp2info.f);
+
+#ifdef DEBUG_JPEG
+ printf ("capture x density: %d pixel/m\n", jp2info.res[0].HR);
+ printf ("capture y density: %d pixel/m\n", jp2info.res[0].VR);
+ printf ("display x density: %d pixel/m\n", jp2info.res[1].HR);
+ printf ("display y density: %d pixel/m\n", jp2info.res[1].VR);
+ printf ("width: %d\n", jp2info.width);
+ printf ("height: %d\n", jp2info.height);
+#endif
+
+ image_info->color = 1;
+ image_info->width_samples = jp2info.width;
+ image_info->height_samples = jp2info.height;
+
+ image_info->width_points = (image_info->width_samples * POINTS_PER_INCH) / 300.0;
+ image_info->height_points = (image_info->height_samples * POINTS_PER_INCH) / 300.0;
+
+ for(i=2;i--;)
+ if(jp2info.res[i].VR > 0.0 && jp2info.res[i].HR > 0.0) {
+ image_info->width_points = (image_info->width_samples * POINTS_PER_INCH * 10000)/(jp2info.res[i].HR * 254);
+ image_info->height_points = (image_info->height_samples * POINTS_PER_INCH * 10000)/(jp2info.res[i].VR * 254);
+ break;
+ }
+
+ return 1;
+}
+
+
+static bool process_jp2_image (int image, /* range 1 .. n */
+ input_attributes_t input_attributes,
+ image_info_t *image_info,
+ pdf_page_handle page)
+{
+ pdf_write_jp2_image (page,
+ 0, 0, /* x, y */
+ image_info->width_points,
+ image_info->height_points,
+ image_info->width_samples,
+ image_info->height_samples,
+ jp2info.f);
+
+ return (1);
+}
+
+
+input_handler_t jp2_handler =
+ {
+ match_jp2_suffix,
+ open_jp2_input_file,
+ close_jp2_input_file,
+ last_jp2_input_page,
+ get_jp2_image_info,
+ process_jp2_image
+ };
+
+
+void init_jp2_handler (void)
+{
+ install_input_handler (& jp2_handler);
+}
diff -rwudN tumble-0.33/tumble_png.c tumble-0.33-my/tumble_png.c
--- tumble-0.33/tumble_png.c Thu Jan 1 01:00:00 1970
+++ tumble-0.33-my/tumble_png.c Sun Oct 17 03:05:38 2004
@@ -0,0 +1,233 @@
+/*
+ * 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
+ */
+
+
+#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)
+{
+ pdf_write_png_image (page,
+ 0, 0, /* x, 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,
+ 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);
+}
More information about the Tumble-devel
mailing list