Mon, 10 Mar 2003 13:08:25 +0000
Working on G4 encoding.
1 /*
2 * t2p: Create a PDF file from the contents of one or more TIFF
3 * bilevel image files. The images in the resulting PDF file
4 * will be compressed using ITU-T T.6 (G4) fax encoding.
5 *
6 * G4 compression
7 * $Id: bitblt_g4.c,v 1.10 2003/03/10 05:08:25 eric Exp $
8 * Copyright 2003 Eric Smith <eric@brouhaha.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation. Note that permission is
13 * not granted to redistribute this program under the terms of any
14 * other version of the General Public License.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
24 */
27 #include <stdbool.h>
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
34 #include "bitblt.h"
35 #include "pdf_util.h"
38 #include "g4_tables.h"
41 #define BIT_BUF_SIZE 4096
43 struct bit_buffer
44 {
45 FILE *f;
46 uint32_t byte_idx; /* index to next byte position in data buffer */
47 uint32_t bit_idx; /* index to next bit position in data buffer,
48 0 = MSB, 7 = LSB */
49 uint8_t data [BIT_BUF_SIZE];
50 };
53 static void flush_bits (struct bit_buffer *buf)
54 {
55 size_t s;
56 if (buf->bit_idx)
57 {
58 /* zero remaining bits in last byte */
59 buf->data [buf->byte_idx] &= ~ ((1 << (8 - buf->bit_idx)) - 1);
60 buf->byte_idx++;
61 buf->bit_idx = 0;
62 }
63 s = fwrite (& buf->data [0], 1, buf->byte_idx, buf->f);
64 /* $$$ should check result */
65 buf->byte_idx = 0;
66 }
69 static void advance_byte (struct bit_buffer *buf)
70 {
71 buf->byte_idx++;
72 buf->bit_idx = 0;
73 if (buf->byte_idx == BIT_BUF_SIZE)
74 flush_bits (buf);
75 }
78 static void write_bits (struct bit_buffer *buf,
79 uint32_t count,
80 uint32_t bits)
81 {
82 uint32_t b2; /* how many bits will fit in byte in data buffer */
83 uint32_t c2; /* how many bits to transfer on this iteration */
84 uint32_t d2; /* bits to transfer on this iteration */
86 while (count)
87 {
88 b2 = 8 - buf->bit_idx;
89 if (b2 >= count)
90 c2 = count;
91 else
92 c2 = b2;
93 d2 = bits >> (count - c2);
94 buf->data [buf->byte_idx] |= (d2 << (b2 + c2));
95 buf->bit_idx += c2;
96 if (buf->bit_idx > 7)
97 advance_byte (buf);
98 count -= c2;
99 }
100 }
103 static void g4_encode_horizontal_run (struct bit_buffer *buf,
104 bool black,
105 uint32_t run_length)
106 {
107 uint32_t i;
109 while (run_length >= 2560)
110 {
111 write_bits (buf, 12, 0x01f);
112 run_length -= 2560;
113 }
115 if (run_length >= 1792)
116 {
117 i = (run_length - 1792) >> 6;
118 write_bits (buf,
119 g4_long_makeup_code [i].count,
120 g4_long_makeup_code [i].bits);
121 run_length -= (1792 + (i << 6));
122 }
123 else if (run_length >= 64)
124 {
125 i = (run_length >> 6) - 1;
126 write_bits (buf,
127 g4_makeup_code [black] [i].count,
128 g4_makeup_code [black] [i].bits);
129 run_length -= (i + 1) << 6;
130 }
132 write_bits (buf,
133 g4_h_code [black] [run_length].count,
134 g4_h_code [black] [run_length].bits);
135 }
138 static inline int g4_get_pixel (uint8_t *buf, uint32_t x)
139 {
140 return ((buf [x >> 3] >> (x & 7)) & 1);
141 }
144 static uint32_t g4_find_pixel (uint8_t *buf,
145 uint32_t pos,
146 uint32_t width,
147 bool color)
148 {
149 while (pos < width)
150 {
151 if (g4_get_pixel (buf, pos) == color)
152 return (pos);
153 pos++;
154 }
155 return (width);
156 }
159 static void g4_encode_row (struct bit_buffer *buf,
160 uint32_t width,
161 uint8_t *ref,
162 uint8_t *row)
163 {
164 uint32_t a0, a1, a2;
165 uint32_t b1, b2;
166 bool a0_c;
168 a0 = 0;
169 a0_c = 0;
171 a1 = g4_find_pixel (row, 0, width, 1);
172 b1 = g4_find_pixel (ref, 0, width, 1);
174 while (a0 < width)
175 {
176 b2 = g4_find_pixel (ref, b1 + 1, width, g4_get_pixel (ref, b1));
178 if (b2 < a1)
179 {
180 /* pass mode - 0001 */
181 write_bits (buf, 4, 0x1);
182 a0 = b2;
183 }
184 else if (abs (a1 - b1) <= 3)
185 {
186 /* vertical mode */
187 write_bits (buf,
188 g4_vert_code [3 + a1 - b1].count,
189 g4_vert_code [3 + a1 - b1].bits);
190 a0 = a1;
191 }
192 else
193 {
194 /* horizontal mode - 001 */
195 a2 = g4_find_pixel (row, a1, width, a0_c);
196 write_bits (buf, 3, 0x1);
197 g4_encode_horizontal_run (buf, a0_c, a1 - a0);
198 g4_encode_horizontal_run (buf, ! a0_c, a2 - a1);
199 a0 = a2;
200 }
202 if (a0 >= width)
203 break;;
205 a0_c = g4_get_pixel (row, a0);
207 a1 = g4_find_pixel (row, a0 + 1, width, ! a0_c);
208 b1 = g4_find_pixel (ref, a0 + 1, width, a0_c);
209 b1 = g4_find_pixel (ref, b1 + 1, width, ! a0_c);
210 }
211 }
214 void bitblt_write_g4 (Bitmap *bitmap, FILE *f)
215 {
216 uint32_t width = (bitmap->rect.max.x - bitmap->rect.min.x) + 1;
217 uint32_t row;
218 struct bit_buffer bb;
220 word_type *temp_buffer;
222 word_type *cur_line;
223 word_type *ref_line; /* reference (previous) row */
225 temp_buffer = pdf_calloc ((width + BITS_PER_WORD - 1) / BITS_PER_WORD,
226 sizeof (word_type));
228 cur_line = bitmap->bits;
229 ref_line = temp_buffer;
231 memset (& bb, 0, sizeof (bb));
233 bb.f = f;
235 for (row = bitmap->rect.min.y;
236 row < bitmap->rect.max.y;
237 row++)
238 {
239 g4_encode_row (& bb,
240 width,
241 (uint8_t *) ref_line,
242 (uint8_t *) cur_line);
243 ref_line = cur_line;
244 cur_line += bitmap->row_words;
245 }
248 /* write EOFB code */
249 write_bits (& bb, 24, 0x001001);
251 flush_bits (& bb);
253 free (temp_buffer);
254 }