diff --git a/bitblt_g4.c b/bitblt_g4.c index 5a82122..b4ad2ab 100644 --- a/bitblt_g4.c +++ b/bitblt_g4.c @@ -4,7 +4,7 @@ * will be compressed using ITU-T T.6 (G4) fax encoding. * * PDF routines - * $Id: bitblt_g4.c,v 1.5 2003/02/21 01:25:47 eric Exp $ + * $Id: bitblt_g4.c,v 1.6 2003/02/21 02:49:11 eric Exp $ * Copyright 2001, 2002, 2003 Eric Smith * * This program is free software; you can redistribute it and/or modify @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -37,6 +38,9 @@ #include "pdf_private.h" +#define SWAP(type,a,b) do { type temp; temp = a; a = b; b = temp; } while (0) + + struct pdf_g4_image { double width, height; @@ -94,28 +98,48 @@ void pdf_write_g4_fax_image_callback (pdf_file_handle pdf_file, { struct pdf_g4_image *image = app_data; -#if 0 - pdf_stream_write_data (pdf_file, stream, image->data, image->len); -#else - unsigned long row = 0; - word_type *ref; - word_type *raw; + uint32_t row; - ref = NULL; - raw = image->bitmap->bits; + /* reference (previous) row */ + uint32_t *ref_runs = pdf_calloc (image->Columns, sizeof (uint32_t)); + uint32_t ref_run_count; - while (row < image->Rows) + /* row being converted */ + uint32_t *row_runs = pdf_calloc (image->Columns, sizeof (uint32_t)); + uint32_t row_run_count; + + /* initialize reference row - all white */ + ref_runs [0] = image->Columns; + ref_run_count = 0; + + for (row = image->bitmap->rect.min.y; + row < image->bitmap->rect.max.y; + row++) { - pdf_stream_write_data (pdf_file, stream, (uint8_t *) raw, - image->bitmap->row_words * sizeof (word_type)); + row_run_count = get_row_run_lengths (image->bitmap, + row, + image->bitmap->rect.min.x, + image->bitmap->rect.max.x - 1, + image->Columns, /* max_runs */ + row_runs); + pdf_assert (row_run_count > 0); - row++; - ref = raw; - raw += image->bitmap->row_words; + /* $$$ G4 encode the runs here */ + + /* pdf_stream_write_data (pdf_file, stream, image->data, image->len); */ + + SWAP (uint32_t *, row_runs, ref_runs); + ref_run_count = row_run_count; } + + /* $$$ generate and write EOFB code */ - /* $$$ flush any remaining buffered bits */ -#endif + pdf_stream_write_bits (pdf_file, stream, 24, 0x001001); + + pdf_stream_flush_bits (pdf_file, stream); + + free (ref_runs); + free (row_runs); } @@ -139,7 +163,7 @@ void pdf_write_g4_fax_image (pdf_page_handle pdf_page, struct pdf_obj *content_stream; - image = pdf_calloc (sizeof (struct pdf_g4_image)); + image = pdf_calloc (1, sizeof (struct pdf_g4_image)); image->width = width; image->height = height; diff --git a/pdf.c b/pdf.c index 4033c82..6dd5f55 100644 --- a/pdf.c +++ b/pdf.c @@ -4,7 +4,7 @@ * will be compressed using ITU-T T.6 (G4) fax encoding. * * PDF routines - * $Id: pdf.c,v 1.3 2003/02/20 04:44:17 eric Exp $ + * $Id: pdf.c,v 1.4 2003/02/21 02:49:11 eric Exp $ * Copyright 2001, 2002, 2003 Eric Smith * * This program is free software; you can redistribute it and/or modify @@ -53,7 +53,7 @@ void pdf_init (void) struct pdf_pages *pdf_new_pages (pdf_file_handle pdf_file) { - struct pdf_pages *pages = pdf_calloc (sizeof (struct pdf_pages)); + struct pdf_pages *pages = pdf_calloc (1, sizeof (struct pdf_pages)); pages->kids = pdf_new_ind_ref (pdf_file, pdf_new_obj (PT_ARRAY)); pages->count = pdf_new_integer (0); pages->pages_dict = pdf_new_ind_ref (pdf_file, pdf_new_obj (PT_DICTIONARY)); @@ -68,7 +68,7 @@ pdf_file_handle pdf_create (char *filename) { pdf_file_handle pdf_file; - pdf_file = pdf_calloc (sizeof (struct pdf_file)); + pdf_file = pdf_calloc (1, sizeof (struct pdf_file)); pdf_file->f = fopen (filename, "wb"); if (! pdf_file->f) @@ -154,7 +154,7 @@ pdf_page_handle pdf_new_page (pdf_file_handle pdf_file, double width, double height) { - pdf_page_handle page = pdf_calloc (sizeof (struct pdf_page)); + pdf_page_handle page = pdf_calloc (1, sizeof (struct pdf_page)); page->pdf_file = pdf_file; diff --git a/pdf_g4.c b/pdf_g4.c index eef5e68..cdbd8ec 100644 --- a/pdf_g4.c +++ b/pdf_g4.c @@ -4,7 +4,7 @@ * will be compressed using ITU-T T.6 (G4) fax encoding. * * PDF routines - * $Id: pdf_g4.c,v 1.5 2003/02/21 01:25:47 eric Exp $ + * $Id: pdf_g4.c,v 1.6 2003/02/21 02:49:11 eric Exp $ * Copyright 2001, 2002, 2003 Eric Smith * * This program is free software; you can redistribute it and/or modify @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -37,6 +38,9 @@ #include "pdf_private.h" +#define SWAP(type,a,b) do { type temp; temp = a; a = b; b = temp; } while (0) + + struct pdf_g4_image { double width, height; @@ -94,28 +98,48 @@ void pdf_write_g4_fax_image_callback (pdf_file_handle pdf_file, { struct pdf_g4_image *image = app_data; -#if 0 - pdf_stream_write_data (pdf_file, stream, image->data, image->len); -#else - unsigned long row = 0; - word_type *ref; - word_type *raw; + uint32_t row; - ref = NULL; - raw = image->bitmap->bits; + /* reference (previous) row */ + uint32_t *ref_runs = pdf_calloc (image->Columns, sizeof (uint32_t)); + uint32_t ref_run_count; - while (row < image->Rows) + /* row being converted */ + uint32_t *row_runs = pdf_calloc (image->Columns, sizeof (uint32_t)); + uint32_t row_run_count; + + /* initialize reference row - all white */ + ref_runs [0] = image->Columns; + ref_run_count = 0; + + for (row = image->bitmap->rect.min.y; + row < image->bitmap->rect.max.y; + row++) { - pdf_stream_write_data (pdf_file, stream, (uint8_t *) raw, - image->bitmap->row_words * sizeof (word_type)); + row_run_count = get_row_run_lengths (image->bitmap, + row, + image->bitmap->rect.min.x, + image->bitmap->rect.max.x - 1, + image->Columns, /* max_runs */ + row_runs); + pdf_assert (row_run_count > 0); - row++; - ref = raw; - raw += image->bitmap->row_words; + /* $$$ G4 encode the runs here */ + + /* pdf_stream_write_data (pdf_file, stream, image->data, image->len); */ + + SWAP (uint32_t *, row_runs, ref_runs); + ref_run_count = row_run_count; } + + /* $$$ generate and write EOFB code */ - /* $$$ flush any remaining buffered bits */ -#endif + pdf_stream_write_bits (pdf_file, stream, 24, 0x001001); + + pdf_stream_flush_bits (pdf_file, stream); + + free (ref_runs); + free (row_runs); } @@ -139,7 +163,7 @@ void pdf_write_g4_fax_image (pdf_page_handle pdf_page, struct pdf_obj *content_stream; - image = pdf_calloc (sizeof (struct pdf_g4_image)); + image = pdf_calloc (1, sizeof (struct pdf_g4_image)); image->width = width; image->height = height; diff --git a/pdf_prim.c b/pdf_prim.c index bbf6ddf..e0f2c3c 100644 --- a/pdf_prim.c +++ b/pdf_prim.c @@ -4,7 +4,7 @@ * will be compressed using ITU-T T.6 (G4) fax encoding. * * PDF routines - * $Id: pdf_prim.c,v 1.4 2003/02/21 01:25:47 eric Exp $ + * $Id: pdf_prim.c,v 1.5 2003/02/21 02:49:11 eric Exp $ * Copyright 2001, 2002, 2003 Eric Smith * * This program is free software; you can redistribute it and/or modify @@ -66,6 +66,8 @@ struct pdf_dict }; +#define STREAM_BUF_SIZE 4096 + struct pdf_stream { struct pdf_obj *stream_dict; @@ -74,6 +76,13 @@ struct pdf_stream void *app_data; /* arg to pass to callback */ struct pdf_obj *filters; /* name or array of names */ struct pdf_obj *decode_parms; + + /* The following fields are used by pdf_stream_write_bits() and + pdf_stream_flush_bits(). */ + uint32_t byte_idx; /* index to next byte position in data buffer */ + uint32_t bit_idx; /* index to next bit position in data buffer, + 0 = MSB, 7 = LSB */ + uint8_t data [STREAM_BUF_SIZE]; }; @@ -145,7 +154,7 @@ void pdf_set_dict_entry (struct pdf_obj *dict_obj, char *key, struct pdf_obj *va } /* new entry */ - entry = pdf_calloc (sizeof (struct pdf_dict_entry)); + entry = pdf_calloc (1, sizeof (struct pdf_dict_entry)); entry->next = dict_obj->val.dict.first; dict_obj->val.dict.first = entry; @@ -174,7 +183,7 @@ struct pdf_obj *pdf_get_dict_entry (struct pdf_obj *dict_obj, char *key) void pdf_add_array_elem (struct pdf_obj *array_obj, struct pdf_obj *val) { - struct pdf_array_elem *elem = pdf_calloc (sizeof (struct pdf_array_elem)); + struct pdf_array_elem *elem = pdf_calloc (1, sizeof (struct pdf_array_elem)); if (array_obj->type == PT_IND_REF) array_obj = pdf_deref_ind_obj (array_obj); @@ -194,7 +203,7 @@ void pdf_add_array_elem (struct pdf_obj *array_obj, struct pdf_obj *val) struct pdf_obj *pdf_new_obj (pdf_obj_type type) { - struct pdf_obj *obj = pdf_calloc (sizeof (struct pdf_obj)); + struct pdf_obj *obj = pdf_calloc (1, sizeof (struct pdf_obj)); obj->type = type; return (obj); } @@ -453,6 +462,65 @@ void pdf_stream_write_data (pdf_file_handle pdf_file, } +void pdf_stream_flush_bits (pdf_file_handle pdf_file, + struct pdf_obj *stream) +{ + struct pdf_stream *s = & stream->val.stream; + + if (s->bit_idx) + { + /* zero remaining bits in last byte */ + s->data [s->byte_idx] &= ~ ((1 << (8 - s->bit_idx)) - 1); + s->byte_idx++; + s->bit_idx = 0; + } + pdf_stream_write_data (pdf_file, stream, + (char *) & s->data [0], + s->byte_idx); + s->byte_idx = 0; +} + + +static void pdf_stream_advance_byte (pdf_file_handle pdf_file, + struct pdf_obj *stream) +{ + struct pdf_stream *s = & stream->val.stream; + + s->byte_idx++; + s->bit_idx = 0; + if (s->byte_idx == STREAM_BUF_SIZE) + pdf_stream_flush_bits (pdf_file, stream); +} + + +void pdf_stream_write_bits (pdf_file_handle pdf_file, + struct pdf_obj *stream, + uint32_t count, + uint32_t bits) +{ + struct pdf_stream *s = & stream->val.stream; + + uint32_t b2; /* how many bits will fit in byte in data buffer */ + uint32_t c2; /* how many bits to transfer on this iteration */ + uint32_t d2; /* bits to transfer on this iteration */ + + while (count) + { + b2 = 8 - s->bit_idx; + if (b2 >= count) + c2 = count; + else + c2 = b2; + d2 = bits >> (count - c2); + s->data [s->byte_idx] |= (d2 << (b2 + c2)); + s->bit_idx += c2; + if (s->bit_idx > 7) + pdf_stream_advance_byte (pdf_file, stream); + count -= c2; + } +} + + void pdf_stream_printf (pdf_file_handle pdf_file, struct pdf_obj *stream, char *fmt, ...) diff --git a/pdf_prim.h b/pdf_prim.h index 22bbbbd..e3fc073 100644 --- a/pdf_prim.h +++ b/pdf_prim.h @@ -4,7 +4,7 @@ * will be compressed using ITU-T T.6 (G4) fax encoding. * * PDF routines - * $Id: pdf_prim.h,v 1.3 2003/02/21 01:25:47 eric Exp $ + * $Id: pdf_prim.h,v 1.4 2003/02/21 02:49:11 eric Exp $ * Copyright 2001, 2002, 2003 Eric Smith * * This program is free software; you can redistribute it and/or modify @@ -95,8 +95,19 @@ struct pdf_obj *pdf_new_stream (pdf_file_handle pdf_file, pdf_stream_write_callback callback, void *app_data); -/* The callback should call pdf_stream_write_data or pdf_stream_printf - to write the actual stream data. */ +/* The callback should call pdf_stream_write_bits(), pdf_stream_write_data(), + or pdf_stream_printf() to write the actual stream data. If + pdf_stream_write_bits() is used, pdf_stream_flush_bits() should be + called after all the bits are written. */ + +void pdf_stream_write_bits (pdf_file_handle pdf_file, + struct pdf_obj *stream, + uint32_t count, + uint32_t bits); + +void pdf_stream_flush_bits (pdf_file_handle pdf_file, + struct pdf_obj *stream); + void pdf_stream_write_data (pdf_file_handle pdf_file, struct pdf_obj *stream, char *data, diff --git a/pdf_util.c b/pdf_util.c index 47e683c..e0c30c0 100644 --- a/pdf_util.c +++ b/pdf_util.c @@ -4,7 +4,7 @@ * will be compressed using ITU-T T.6 (G4) fax encoding. * * PDF routines - * $Id: pdf_util.c,v 1.3 2003/02/20 04:44:17 eric Exp $ + * $Id: pdf_util.c,v 1.4 2003/02/21 02:49:11 eric Exp $ * Copyright 2001, 2002, 2003 Eric Smith * * This program is free software; you can redistribute it and/or modify @@ -48,9 +48,9 @@ void pdf_fatal (char *fmt, ...) } -void *pdf_calloc (long int size) +void *pdf_calloc (size_t nmemb, size_t size) { - void *m = calloc (1, size); + void *m = calloc (nmemb, size); if (! m) pdf_fatal ("failed to allocate memory\n"); return (m); @@ -60,7 +60,7 @@ void *pdf_calloc (long int size) char *pdf_strdup (char *s) { unsigned long len = strlen (s); - char *s2 = pdf_calloc (len + 1); + char *s2 = pdf_calloc (1, len + 1); strcpy (s2, s); return (s2); } diff --git a/pdf_util.h b/pdf_util.h index 2dcbc5e..971ae70 100644 --- a/pdf_util.h +++ b/pdf_util.h @@ -4,7 +4,7 @@ * will be compressed using ITU-T T.6 (G4) fax encoding. * * PDF routines - * $Id: pdf_util.h,v 1.2 2003/02/20 04:44:17 eric Exp $ + * $Id: pdf_util.h,v 1.3 2003/02/21 02:49:11 eric Exp $ * Copyright 2001, 2002, 2003 Eric Smith * * This program is free software; you can redistribute it and/or modify @@ -26,7 +26,7 @@ void pdf_fatal (char *fmt, ...); -void *pdf_calloc (long int size); +void *pdf_calloc (size_t nmemb, size_t size); char *pdf_strdup (char *s);