bitblt_g4.c

Fri, 14 Mar 2003 08:56:38 +0000

author
eric
date
Fri, 14 Mar 2003 08:56:38 +0000
changeset 132
ccf1c28a2940
parent 125
e2ef1c2f9eca
permissions
-rw-r--r--

remove debug output.

eric@62 1 /*
eric@125 2 * tumble: build a PDF file from image files
eric@62 3 *
eric@91 4 * G4 compression
eric@125 5 * $Id: bitblt_g4.c,v 1.14 2003/03/13 00:57:05 eric Exp $
eric@78 6 * Copyright 2003 Eric Smith <eric@brouhaha.com>
eric@62 7 *
eric@62 8 * This program is free software; you can redistribute it and/or modify
eric@62 9 * it under the terms of the GNU General Public License version 2 as
eric@62 10 * published by the Free Software Foundation. Note that permission is
eric@62 11 * not granted to redistribute this program under the terms of any
eric@62 12 * other version of the General Public License.
eric@62 13 *
eric@62 14 * This program is distributed in the hope that it will be useful,
eric@62 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
eric@62 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
eric@62 17 * GNU General Public License for more details.
eric@62 18 *
eric@62 19 * You should have received a copy of the GNU General Public License
eric@62 20 * along with this program; if not, write to the Free Software
eric@62 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
eric@62 22 */
eric@62 23
eric@62 24
eric@95 25 #define G4_DEBUG 0
eric@95 26
eric@95 27
eric@62 28 #include <stdbool.h>
eric@62 29 #include <stdint.h>
eric@59 30 #include <stdio.h>
eric@67 31 #include <stdlib.h>
eric@59 32 #include <string.h>
eric@59 33
eric@59 34
eric@62 35 #include "bitblt.h"
eric@110 36 #include "bitblt_tables.h"
eric@94 37 #include "pdf_util.h"
eric@59 38
eric@59 39
eric@91 40 #include "g4_tables.h"
eric@67 41
eric@67 42
eric@115 43 #define BIT_BUF_SIZE 4096
eric@91 44
eric@91 45 struct bit_buffer
eric@59 46 {
eric@91 47 FILE *f;
eric@91 48 uint32_t byte_idx; /* index to next byte position in data buffer */
eric@95 49 uint32_t bit_idx; /* one greater than the next bit position in data buffer,
eric@95 50 8 = MSB, 1 = LSB */
eric@91 51 uint8_t data [BIT_BUF_SIZE];
eric@59 52 };
eric@59 53
eric@59 54
eric@95 55 static void init_bit_buffer (struct bit_buffer *buf)
eric@95 56 {
eric@95 57 buf->byte_idx = 0;
eric@95 58 buf->bit_idx = 8;
eric@95 59 memset (& buf->data [0], 0, BIT_BUF_SIZE);
eric@95 60 }
eric@95 61
eric@95 62
eric@91 63 static void flush_bits (struct bit_buffer *buf)
eric@59 64 {
eric@91 65 size_t s;
eric@95 66 if (buf->bit_idx != 8)
eric@59 67 {
eric@91 68 buf->byte_idx++;
eric@95 69 buf->bit_idx = 8;
eric@59 70 }
eric@91 71 s = fwrite (& buf->data [0], 1, buf->byte_idx, buf->f);
eric@91 72 /* $$$ should check result */
eric@95 73 init_bit_buffer (buf);
eric@91 74 }
eric@59 75
eric@59 76
eric@91 77 static void advance_byte (struct bit_buffer *buf)
eric@91 78 {
eric@91 79 buf->byte_idx++;
eric@95 80 buf->bit_idx = 8;
eric@91 81 if (buf->byte_idx == BIT_BUF_SIZE)
eric@91 82 flush_bits (buf);
eric@59 83 }
eric@59 84
eric@59 85
eric@91 86 static void write_bits (struct bit_buffer *buf,
eric@91 87 uint32_t count,
eric@91 88 uint32_t bits)
eric@59 89 {
eric@95 90 while (count > buf->bit_idx)
eric@91 91 {
eric@95 92 buf->data [buf->byte_idx] |= bits >> (count - buf->bit_idx);
eric@95 93 count -= buf->bit_idx;
eric@95 94 advance_byte (buf);
eric@91 95 }
eric@95 96
eric@95 97 bits &= ((1 << count) - 1);
eric@95 98 buf->data [buf->byte_idx] |= bits << (buf->bit_idx - count);
eric@95 99 buf->bit_idx -= count;
eric@95 100 if (buf->bit_idx == 0)
eric@95 101 advance_byte (buf);
eric@59 102 }
eric@59 103
eric@59 104
eric@91 105 static void g4_encode_horizontal_run (struct bit_buffer *buf,
eric@91 106 bool black,
eric@91 107 uint32_t run_length)
eric@73 108 {
eric@73 109 uint32_t i;
eric@73 110
eric@73 111 while (run_length >= 2560)
eric@73 112 {
eric@91 113 write_bits (buf, 12, 0x01f);
eric@73 114 run_length -= 2560;
eric@73 115 }
eric@73 116
eric@73 117 if (run_length >= 1792)
eric@73 118 {
eric@73 119 i = (run_length - 1792) >> 6;
eric@91 120 write_bits (buf,
eric@91 121 g4_long_makeup_code [i].count,
eric@91 122 g4_long_makeup_code [i].bits);
eric@73 123 run_length -= (1792 + (i << 6));
eric@73 124 }
eric@73 125 else if (run_length >= 64)
eric@73 126 {
eric@73 127 i = (run_length >> 6) - 1;
eric@91 128 write_bits (buf,
eric@91 129 g4_makeup_code [black] [i].count,
eric@91 130 g4_makeup_code [black] [i].bits);
eric@73 131 run_length -= (i + 1) << 6;
eric@73 132 }
eric@73 133
eric@91 134 write_bits (buf,
eric@91 135 g4_h_code [black] [run_length].count,
eric@91 136 g4_h_code [black] [run_length].bits);
eric@73 137 }
eric@73 138
eric@73 139
eric@94 140 static inline int g4_get_pixel (uint8_t *buf, uint32_t x)
eric@73 141 {
eric@94 142 return ((buf [x >> 3] >> (x & 7)) & 1);
eric@94 143 }
eric@94 144
eric@94 145
eric@110 146 #define not_aligned(p) (((word_t) p) & (sizeof (word_t) - 1))
eric@110 147
eric@110 148
eric@94 149 static uint32_t g4_find_pixel (uint8_t *buf,
eric@94 150 uint32_t pos,
eric@94 151 uint32_t width,
eric@94 152 bool color)
eric@94 153 {
eric@110 154 uint8_t *p = buf + pos / 8;
eric@110 155 int bit = pos & 7;
eric@110 156 uint8_t *max_p = buf + (width - 1) / 8;
eric@110 157 uint8_t d;
eric@110 158
eric@110 159 /* check first byte (may be partial) */
eric@110 160 d = *p;
eric@110 161 if (! color)
eric@110 162 d = ~d;
eric@110 163 bit += rle_tab [bit][d];
eric@110 164 if (bit < 8)
eric@110 165 goto done;
eric@110 166 p++;
eric@110 167
eric@110 168 /* check individual bytes until we hit word alignment */
eric@110 169 while ((p <= max_p) && not_aligned (p))
eric@110 170 {
eric@110 171 d = *p;
eric@110 172 if (! color)
eric@110 173 d = ~d;
eric@110 174 if (d != 0)
eric@110 175 goto found;
eric@110 176 p++;
eric@110 177 }
eric@110 178
eric@110 179 /* check aligned words in middle */
eric@110 180 while ((p <= (max_p - sizeof (word_t))))
eric@94 181 {
eric@110 182 word_t w = *((word_t *) p);
eric@110 183 if (! color)
eric@110 184 w = ~w;
eric@110 185 if (w != 0)
eric@110 186 break;
eric@110 187 p += sizeof (word_t);
eric@94 188 }
eric@110 189
eric@110 190 /* check trailing bytes */
eric@110 191 while (p <= max_p)
eric@110 192 {
eric@110 193 d = *p;
eric@110 194 if (! color)
eric@110 195 d = ~d;
eric@110 196 if (d)
eric@110 197 goto found;
eric@110 198 p++;
eric@110 199 }
eric@110 200
eric@110 201 goto not_found;
eric@110 202
eric@110 203 found:
eric@110 204 bit = rle_tab [0][d];
eric@110 205
eric@110 206 done:
eric@110 207 pos = ((p - buf) << 3) + bit;
eric@110 208 if (pos < width)
eric@110 209 return (pos);
eric@110 210
eric@110 211 not_found:
eric@94 212 return (width);
eric@73 213 }
eric@73 214
eric@73 215
eric@91 216 static void g4_encode_row (struct bit_buffer *buf,
eric@91 217 uint32_t width,
eric@91 218 uint8_t *ref,
eric@91 219 uint8_t *row)
eric@73 220 {
eric@94 221 uint32_t a0, a1, a2;
eric@94 222 uint32_t b1, b2;
eric@94 223 bool a0_c;
eric@73 224
eric@94 225 a0 = 0;
eric@94 226 a0_c = 0;
eric@94 227
eric@94 228 a1 = g4_find_pixel (row, 0, width, 1);
eric@95 229
eric@94 230 b1 = g4_find_pixel (ref, 0, width, 1);
eric@95 231
eric@110 232 #if (G4_DEBUG & 1)
eric@95 233 fprintf (stderr, "start of row\n");
eric@95 234 if ((a1 != width) || (b1 != width))
eric@95 235 {
eric@95 236 fprintf (stderr, "a1 = %u, b1 = %u\n", a1, b1);
eric@95 237 }
eric@95 238 #endif
eric@73 239
eric@73 240 while (a0 < width)
eric@73 241 {
eric@95 242 b2 = g4_find_pixel (ref, b1 + 1, width, ! g4_get_pixel (ref, b1));
eric@73 243
eric@73 244 if (b2 < a1)
eric@73 245 {
eric@73 246 /* pass mode - 0001 */
eric@91 247 write_bits (buf, 4, 0x1);
eric@73 248 a0 = b2;
eric@110 249 #if (G4_DEBUG & 1)
eric@95 250 fprintf (stderr, "pass\n");
eric@95 251 #endif
eric@73 252 }
eric@73 253 else if (abs (a1 - b1) <= 3)
eric@73 254 {
eric@73 255 /* vertical mode */
eric@91 256 write_bits (buf,
eric@91 257 g4_vert_code [3 + a1 - b1].count,
eric@91 258 g4_vert_code [3 + a1 - b1].bits);
eric@73 259 a0 = a1;
eric@110 260 #if (G4_DEBUG & 1)
eric@95 261 fprintf (stderr, "vertical %d\n", a1 - b1);
eric@95 262 #endif
eric@73 263 }
eric@73 264 else
eric@73 265 {
eric@73 266 /* horizontal mode - 001 */
eric@95 267 a2 = g4_find_pixel (row, a1 + 1, width, a0_c);
eric@91 268 write_bits (buf, 3, 0x1);
eric@94 269 g4_encode_horizontal_run (buf, a0_c, a1 - a0);
eric@94 270 g4_encode_horizontal_run (buf, ! a0_c, a2 - a1);
eric@110 271 #if (G4_DEBUG & 1)
eric@95 272 fprintf (stderr, "horizontal %d %s, %d %s\n",
eric@95 273 a1 - a0, a0_c ? "black" : "white",
eric@95 274 a2 - a1, a0_c ? "white" : "black");
eric@95 275 #endif
eric@73 276 a0 = a2;
eric@73 277 }
eric@94 278
eric@94 279 if (a0 >= width)
eric@94 280 break;;
eric@94 281
eric@94 282 a0_c = g4_get_pixel (row, a0);
eric@94 283
eric@94 284 a1 = g4_find_pixel (row, a0 + 1, width, ! a0_c);
eric@95 285 b1 = g4_find_pixel (ref, a0 + 1, width, ! g4_get_pixel (ref, a0));
eric@95 286 if (g4_get_pixel (ref, b1) == a0_c)
eric@95 287 b1 = g4_find_pixel (ref, b1 + 1, width, ! a0_c);
eric@110 288 #if (G4_DEBUG & 1)
eric@95 289 fprintf (stderr, "a1 = %u, b1 = %u\n", a1, b1);
eric@95 290 #endif
eric@73 291 }
eric@73 292 }
eric@73 293
eric@73 294
eric@91 295 void bitblt_write_g4 (Bitmap *bitmap, FILE *f)
eric@59 296 {
eric@95 297 uint32_t width = bitmap->rect.max.x - bitmap->rect.min.x;
eric@67 298 uint32_t row;
eric@91 299 struct bit_buffer bb;
eric@67 300
eric@110 301 word_t *temp_buffer;
eric@94 302
eric@110 303 word_t *cur_line;
eric@110 304 word_t *ref_line; /* reference (previous) row */
eric@95 305
eric@94 306 temp_buffer = pdf_calloc ((width + BITS_PER_WORD - 1) / BITS_PER_WORD,
eric@110 307 sizeof (word_t));
eric@94 308
eric@94 309 cur_line = bitmap->bits;
eric@94 310 ref_line = temp_buffer;
eric@91 311
eric@95 312 init_bit_buffer (& bb);
eric@59 313
eric@91 314 bb.f = f;
eric@91 315
eric@91 316 for (row = bitmap->rect.min.y;
eric@91 317 row < bitmap->rect.max.y;
eric@67 318 row++)
eric@59 319 {
eric@91 320 g4_encode_row (& bb,
eric@94 321 width,
eric@91 322 (uint8_t *) ref_line,
eric@94 323 (uint8_t *) cur_line);
eric@94 324 ref_line = cur_line;
eric@94 325 cur_line += bitmap->row_words;
eric@59 326 }
eric@67 327
eric@67 328
eric@73 329 /* write EOFB code */
eric@91 330 write_bits (& bb, 24, 0x001001);
eric@67 331
eric@91 332 flush_bits (& bb);
eric@94 333
eric@94 334 free (temp_buffer);
eric@59 335 }
eric@59 336
eric@59 337