1.1 --- a/bitblt_g4.c Sat Mar 08 10:02:13 2003 +0000 1.2 +++ b/bitblt_g4.c Mon Mar 10 09:49:50 2003 +0000 1.3 @@ -3,8 +3,8 @@ 1.4 * bilevel image files. The images in the resulting PDF file 1.5 * will be compressed using ITU-T T.6 (G4) fax encoding. 1.6 * 1.7 - * PDF routines 1.8 - * $Id: bitblt_g4.c,v 1.8 2003/03/05 12:44:33 eric Exp $ 1.9 + * G4 compression 1.10 + * $Id: bitblt_g4.c,v 1.9 2003/03/10 01:49:50 eric Exp $ 1.11 * Copyright 2003 Eric Smith <eric@brouhaha.com> 1.12 * 1.13 * This program is free software; you can redistribute it and/or modify 1.14 @@ -32,108 +32,111 @@ 1.15 1.16 1.17 #include "bitblt.h" 1.18 -#include "pdf.h" 1.19 -#include "pdf_util.h" 1.20 -#include "pdf_prim.h" 1.21 -#include "pdf_private.h" 1.22 1.23 1.24 -#include "pdf_g4_tables.h" 1.25 - 1.26 - 1.27 -#define SWAP(type,a,b) do { type temp; temp = a; a = b; b = temp; } while (0) 1.28 +#include "g4_tables.h" 1.29 1.30 1.31 -struct pdf_g4_image 1.32 +#define BIT_BUF_SIZE 4096 1.33 + 1.34 +struct bit_buffer 1.35 { 1.36 - double width, height; 1.37 - double x, y; 1.38 - double r, g, b; /* fill color, only for ImageMask */ 1.39 - unsigned long Columns; 1.40 - unsigned long Rows; 1.41 - bool ImageMask; 1.42 - bool BlackIs1; 1.43 - Bitmap *bitmap; 1.44 - char XObject_name [4]; 1.45 + FILE *f; 1.46 + uint32_t byte_idx; /* index to next byte position in data buffer */ 1.47 + uint32_t bit_idx; /* index to next bit position in data buffer, 1.48 + 0 = MSB, 7 = LSB */ 1.49 + uint8_t data [BIT_BUF_SIZE]; 1.50 }; 1.51 1.52 1.53 -char pdf_new_XObject (pdf_page_handle pdf_page, struct pdf_obj *ind_ref) 1.54 +static void flush_bits (struct bit_buffer *buf) 1.55 { 1.56 - char XObject_name [4] = "Im "; 1.57 - 1.58 - XObject_name [2] = ++pdf_page->last_XObject_name; 1.59 - 1.60 - if (! pdf_page->XObject_dict) 1.61 + size_t s; 1.62 + if (buf->bit_idx) 1.63 { 1.64 - pdf_page->XObject_dict = pdf_new_obj (PT_DICTIONARY); 1.65 - pdf_set_dict_entry (pdf_page->resources, "XObject", pdf_page->XObject_dict); 1.66 + /* zero remaining bits in last byte */ 1.67 + buf->data [buf->byte_idx] &= ~ ((1 << (8 - buf->bit_idx)) - 1); 1.68 + buf->byte_idx++; 1.69 + buf->bit_idx = 0; 1.70 } 1.71 + s = fwrite (& buf->data [0], 1, buf->byte_idx, buf->f); 1.72 + /* $$$ should check result */ 1.73 + buf->byte_idx = 0; 1.74 +} 1.75 1.76 - pdf_set_dict_entry (pdf_page->XObject_dict, & XObject_name [0], ind_ref); 1.77 1.78 - return (pdf_page->last_XObject_name); 1.79 +static void advance_byte (struct bit_buffer *buf) 1.80 +{ 1.81 + buf->byte_idx++; 1.82 + buf->bit_idx = 0; 1.83 + if (buf->byte_idx == BIT_BUF_SIZE) 1.84 + flush_bits (buf); 1.85 } 1.86 1.87 1.88 -void pdf_write_g4_content_callback (pdf_file_handle pdf_file, 1.89 - struct pdf_obj *stream, 1.90 - void *app_data) 1.91 +static void write_bits (struct bit_buffer *buf, 1.92 + uint32_t count, 1.93 + uint32_t bits) 1.94 { 1.95 - struct pdf_g4_image *image = app_data; 1.96 + uint32_t b2; /* how many bits will fit in byte in data buffer */ 1.97 + uint32_t c2; /* how many bits to transfer on this iteration */ 1.98 + uint32_t d2; /* bits to transfer on this iteration */ 1.99 1.100 - /* transformation matrix is: width 0 0 height x y cm */ 1.101 - pdf_stream_printf (pdf_file, stream, "q %g 0 0 %g %g %g cm ", 1.102 - image->width, image->height, 1.103 - image->x, image->y); 1.104 - if (image->ImageMask) 1.105 - pdf_stream_printf (pdf_file, stream, "%g %g %g rg ", 1.106 - image->r, image->g, image->b); 1.107 - 1.108 - pdf_stream_printf (pdf_file, stream, "/%s Do Q\r\n", 1.109 - image->XObject_name); 1.110 + while (count) 1.111 + { 1.112 + b2 = 8 - buf->bit_idx; 1.113 + if (b2 >= count) 1.114 + c2 = count; 1.115 + else 1.116 + c2 = b2; 1.117 + d2 = bits >> (count - c2); 1.118 + buf->data [buf->byte_idx] |= (d2 << (b2 + c2)); 1.119 + buf->bit_idx += c2; 1.120 + if (buf->bit_idx > 7) 1.121 + advance_byte (buf); 1.122 + count -= c2; 1.123 + } 1.124 } 1.125 1.126 1.127 -static void pdf_g4_encode_horizontal_run (pdf_file_handle pdf_file, 1.128 - struct pdf_obj *stream, 1.129 - bool black, 1.130 - uint32_t run_length) 1.131 +static void g4_encode_horizontal_run (struct bit_buffer *buf, 1.132 + bool black, 1.133 + uint32_t run_length) 1.134 { 1.135 uint32_t i; 1.136 1.137 while (run_length >= 2560) 1.138 { 1.139 - pdf_stream_write_bits (pdf_file, stream, 12, 0x01f); 1.140 + write_bits (buf, 12, 0x01f); 1.141 run_length -= 2560; 1.142 } 1.143 1.144 if (run_length >= 1792) 1.145 { 1.146 i = (run_length - 1792) >> 6; 1.147 - pdf_stream_write_bits (pdf_file, stream, 1.148 - g4_long_makeup_code [i].count, 1.149 - g4_long_makeup_code [i].bits); 1.150 + write_bits (buf, 1.151 + g4_long_makeup_code [i].count, 1.152 + g4_long_makeup_code [i].bits); 1.153 run_length -= (1792 + (i << 6)); 1.154 } 1.155 else if (run_length >= 64) 1.156 { 1.157 i = (run_length >> 6) - 1; 1.158 - pdf_stream_write_bits (pdf_file, stream, 1.159 - g4_makeup_code [black] [i].count, 1.160 - g4_makeup_code [black] [i].bits); 1.161 + write_bits (buf, 1.162 + g4_makeup_code [black] [i].count, 1.163 + g4_makeup_code [black] [i].bits); 1.164 run_length -= (i + 1) << 6; 1.165 } 1.166 1.167 - pdf_stream_write_bits (pdf_file, stream, 1.168 - g4_h_code [black] [run_length].count, 1.169 - g4_h_code [black] [run_length].bits); 1.170 + write_bits (buf, 1.171 + g4_h_code [black] [run_length].count, 1.172 + g4_h_code [black] [run_length].bits); 1.173 } 1.174 1.175 1.176 -uint32_t find_transition (uint8_t *data, 1.177 - uint32_t pos, 1.178 - uint32_t width) 1.179 +static uint32_t find_transition (uint8_t *data, 1.180 + uint32_t pos, 1.181 + uint32_t width) 1.182 { 1.183 if (! data) 1.184 return (width); 1.185 @@ -141,11 +144,10 @@ 1.186 } 1.187 1.188 1.189 -static void pdf_g4_encode_row (pdf_file_handle pdf_file, 1.190 - struct pdf_obj *stream, 1.191 - uint32_t width, 1.192 - uint8_t *ref, 1.193 - uint8_t *row) 1.194 +static void g4_encode_row (struct bit_buffer *buf, 1.195 + uint32_t width, 1.196 + uint8_t *ref, 1.197 + uint8_t *row) 1.198 { 1.199 int a0, a1, a2; 1.200 int b1, b2; 1.201 @@ -167,152 +169,58 @@ 1.202 if (b2 < a1) 1.203 { 1.204 /* pass mode - 0001 */ 1.205 - pdf_stream_write_bits (pdf_file, stream, 4, 0x1); 1.206 + write_bits (buf, 4, 0x1); 1.207 a0 = b2; 1.208 } 1.209 else if (abs (a1 - b1) <= 3) 1.210 { 1.211 /* vertical mode */ 1.212 - pdf_stream_write_bits (pdf_file, stream, 1.213 - g4_vert_code [3 + a1 - b1].count, 1.214 - g4_vert_code [3 + a1 - b1].bits); 1.215 + write_bits (buf, 1.216 + g4_vert_code [3 + a1 - b1].count, 1.217 + g4_vert_code [3 + a1 - b1].bits); 1.218 a0 = a1; 1.219 } 1.220 else 1.221 { 1.222 /* horizontal mode - 001 */ 1.223 - pdf_stream_write_bits (pdf_file, stream, 3, 0x1); 1.224 - pdf_g4_encode_horizontal_run (pdf_file, stream, 1.225 - 0 /* $$$ color (a0) */, a1 - a0); 1.226 - pdf_g4_encode_horizontal_run (pdf_file, stream, 1.227 - 1 /* $$$ color (a1) */, a2 - a1); 1.228 + write_bits (buf, 3, 0x1); 1.229 + g4_encode_horizontal_run (buf, 0 /* $$$ color (a0) */, a1 - a0); 1.230 + g4_encode_horizontal_run (buf, 1 /* $$$ color (a1) */, a2 - a1); 1.231 a0 = a2; 1.232 } 1.233 } 1.234 } 1.235 1.236 1.237 -void pdf_write_g4_fax_image_callback (pdf_file_handle pdf_file, 1.238 - struct pdf_obj *stream, 1.239 - void *app_data) 1.240 +void bitblt_write_g4 (Bitmap *bitmap, FILE *f) 1.241 { 1.242 - struct pdf_g4_image *image = app_data; 1.243 - 1.244 uint32_t row; 1.245 + struct bit_buffer bb; 1.246 1.247 word_type *ref_line = NULL; /* reference (previous) row */ 1.248 - word_type *line = image->bitmap->bits; 1.249 + word_type *line = bitmap->bits; 1.250 + 1.251 + memset (& bb, 0, sizeof (bb)); 1.252 1.253 - for (row = image->bitmap->rect.min.y; 1.254 - row < image->bitmap->rect.max.y; 1.255 + bb.f = f; 1.256 + 1.257 + for (row = bitmap->rect.min.y; 1.258 + row < bitmap->rect.max.y; 1.259 row++) 1.260 { 1.261 - pdf_g4_encode_row (pdf_file, stream, image->Columns, 1.262 - (uint8_t *) ref_line, 1.263 - (uint8_t *) line); 1.264 + g4_encode_row (& bb, 1.265 + (bitmap->rect.max.x - bitmap->rect.min.x) + 1, 1.266 + (uint8_t *) ref_line, 1.267 + (uint8_t *) line); 1.268 ref_line = line; 1.269 - line += image->bitmap->row_words; 1.270 + line += bitmap->row_words; 1.271 } 1.272 1.273 1.274 /* write EOFB code */ 1.275 - pdf_stream_write_bits (pdf_file, stream, 24, 0x001001); 1.276 + write_bits (& bb, 24, 0x001001); 1.277 1.278 - pdf_stream_flush_bits (pdf_file, stream); 1.279 + flush_bits (& bb); 1.280 } 1.281 1.282 1.283 -void pdf_write_g4_fax_image (pdf_page_handle pdf_page, 1.284 - double x, 1.285 - double y, 1.286 - double width, 1.287 - double height, 1.288 - Bitmap *bitmap, 1.289 - bool ImageMask, 1.290 - double r, /* RGB fill color, only for ImageMask */ 1.291 - double g, 1.292 - double b, 1.293 - bool BlackIs1) /* boolean, typ. false */ 1.294 -{ 1.295 - struct pdf_g4_image *image; 1.296 - 1.297 - struct pdf_obj *stream; 1.298 - struct pdf_obj *stream_dict; 1.299 - struct pdf_obj *decode_parms; 1.300 - 1.301 - struct pdf_obj *content_stream; 1.302 - 1.303 - image = pdf_calloc (1, sizeof (struct pdf_g4_image)); 1.304 - 1.305 - image->width = width; 1.306 - image->height = height; 1.307 - image->x = x; 1.308 - image->y = y; 1.309 - image->r = r; 1.310 - image->g = g; 1.311 - image->b = b; 1.312 - 1.313 - image->bitmap = bitmap; 1.314 - image->Columns = bitmap->rect.max.x - bitmap->rect.min.x; 1.315 - image->Rows = bitmap->rect.max.y - bitmap->rect.min.y; 1.316 - image->ImageMask = ImageMask; 1.317 - image->BlackIs1 = BlackIs1; 1.318 - 1.319 - stream_dict = pdf_new_obj (PT_DICTIONARY); 1.320 - 1.321 - stream = pdf_new_ind_ref (pdf_page->pdf_file, 1.322 - pdf_new_stream (pdf_page->pdf_file, 1.323 - stream_dict, 1.324 - & pdf_write_g4_fax_image_callback, 1.325 - image)); 1.326 - 1.327 - strcpy (& image->XObject_name [0], "Im "); 1.328 - image->XObject_name [2] = pdf_new_XObject (pdf_page, stream); 1.329 - 1.330 - pdf_set_dict_entry (stream_dict, "Type", pdf_new_name ("XObject")); 1.331 - pdf_set_dict_entry (stream_dict, "Subtype", pdf_new_name ("Image")); 1.332 - pdf_set_dict_entry (stream_dict, "Name", pdf_new_name (& image->XObject_name [0])); 1.333 - pdf_set_dict_entry (stream_dict, "Width", pdf_new_integer (image->Columns)); 1.334 - pdf_set_dict_entry (stream_dict, "Height", pdf_new_integer (image->Rows)); 1.335 - pdf_set_dict_entry (stream_dict, "BitsPerComponent", pdf_new_integer (1)); 1.336 - if (ImageMask) 1.337 - pdf_set_dict_entry (stream_dict, "ImageMask", pdf_new_bool (ImageMask)); 1.338 - else 1.339 - pdf_set_dict_entry (stream_dict, "ColorSpace", pdf_new_name ("DeviceGray")); 1.340 - 1.341 - decode_parms = pdf_new_obj (PT_DICTIONARY); 1.342 - 1.343 - pdf_set_dict_entry (decode_parms, 1.344 - "K", 1.345 - pdf_new_integer (-1)); 1.346 - 1.347 - pdf_set_dict_entry (decode_parms, 1.348 - "Columns", 1.349 - pdf_new_integer (image->Columns)); 1.350 - 1.351 - pdf_set_dict_entry (decode_parms, 1.352 - "Rows", 1.353 - pdf_new_integer (image->Rows)); 1.354 - 1.355 - if (BlackIs1) 1.356 - pdf_set_dict_entry (decode_parms, 1.357 - "BlackIs1", 1.358 - pdf_new_bool (BlackIs1)); 1.359 - 1.360 - pdf_stream_add_filter (stream, "CCITTFaxDecode", decode_parms); 1.361 - 1.362 - /* the following will write the stream, using our callback function to 1.363 - get the actual data */ 1.364 - pdf_write_ind_obj (pdf_page->pdf_file, stream); 1.365 - 1.366 - content_stream = pdf_new_ind_ref (pdf_page->pdf_file, 1.367 - pdf_new_stream (pdf_page->pdf_file, 1.368 - pdf_new_obj (PT_DICTIONARY), 1.369 - & pdf_write_g4_content_callback, 1.370 - image)); 1.371 - 1.372 - pdf_set_dict_entry (pdf_page->page_dict, "Contents", content_stream); 1.373 - 1.374 - pdf_write_ind_obj (pdf_page->pdf_file, content_stream); 1.375 -} 1.376 -