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