|
| 1 | +#include "mupdf/fitz.h" |
| 2 | + |
| 3 | +/* Fax G3/G4 tables */ |
| 4 | + |
| 5 | +typedef struct |
| 6 | +{ |
| 7 | + unsigned short code; |
| 8 | + unsigned short nbits; |
| 9 | +} cfe_code; |
| 10 | + |
| 11 | +typedef struct { |
| 12 | + cfe_code termination[64]; |
| 13 | + cfe_code makeup[41]; |
| 14 | +} cf_runs; |
| 15 | + |
| 16 | +/* Define the end-of-line code. */ |
| 17 | +static const cfe_code cf_run_eol = {1, 12}; |
| 18 | + |
| 19 | +/* Define the 2-D run codes. */ |
| 20 | +static const cfe_code cf2_run_pass = {0x1, 4}; |
| 21 | +static const cfe_code cf2_run_vertical[7] = |
| 22 | +{ |
| 23 | + {0x3, 7}, |
| 24 | + {0x3, 6}, |
| 25 | + {0x3, 3}, |
| 26 | + {0x1, 1}, |
| 27 | + {0x2, 3}, |
| 28 | + {0x2, 6}, |
| 29 | + {0x2, 7} |
| 30 | +}; |
| 31 | +static const cfe_code cf2_run_horizontal = {1, 3}; |
| 32 | + |
| 33 | +/* White run codes. */ |
| 34 | +static const cf_runs cf_white_runs = |
| 35 | +{ |
| 36 | + /* Termination codes */ |
| 37 | + { |
| 38 | + {0x35, 8}, {0x7, 6}, {0x7, 4}, {0x8, 4}, |
| 39 | + {0xb, 4}, {0xc, 4}, {0xe, 4}, {0xf, 4}, |
| 40 | + {0x13, 5}, {0x14, 5}, {0x7, 5}, {0x8, 5}, |
| 41 | + {0x8, 6}, {0x3, 6}, {0x34, 6}, {0x35, 6}, |
| 42 | + {0x2a, 6}, {0x2b, 6}, {0x27, 7}, {0xc, 7}, |
| 43 | + {0x8, 7}, {0x17, 7}, {0x3, 7}, {0x4, 7}, |
| 44 | + {0x28, 7}, {0x2b, 7}, {0x13, 7}, {0x24, 7}, |
| 45 | + {0x18, 7}, {0x2, 8}, {0x3, 8}, {0x1a, 8}, |
| 46 | + {0x1b, 8}, {0x12, 8}, {0x13, 8}, {0x14, 8}, |
| 47 | + {0x15, 8}, {0x16, 8}, {0x17, 8}, {0x28, 8}, |
| 48 | + {0x29, 8}, {0x2a, 8}, {0x2b, 8}, {0x2c, 8}, |
| 49 | + {0x2d, 8}, {0x4, 8}, {0x5, 8}, {0xa, 8}, |
| 50 | + {0xb, 8}, {0x52, 8}, {0x53, 8}, {0x54, 8}, |
| 51 | + {0x55, 8}, {0x24, 8}, {0x25, 8}, {0x58, 8}, |
| 52 | + {0x59, 8}, {0x5a, 8}, {0x5b, 8}, {0x4a, 8}, |
| 53 | + {0x4b, 8}, {0x32, 8}, {0x33, 8}, {0x34, 8} |
| 54 | + }, |
| 55 | + |
| 56 | + /* Make-up codes */ |
| 57 | + { |
| 58 | + {0, 0} /* dummy */ , {0x1b, 5}, {0x12, 5}, {0x17, 6}, |
| 59 | + {0x37, 7}, {0x36, 8}, {0x37, 8}, {0x64, 8}, |
| 60 | + {0x65, 8}, {0x68, 8}, {0x67, 8}, {0xcc, 9}, |
| 61 | + {0xcd, 9}, {0xd2, 9}, {0xd3, 9}, {0xd4, 9}, |
| 62 | + {0xd5, 9}, {0xd6, 9}, {0xd7, 9}, {0xd8, 9}, |
| 63 | + {0xd9, 9}, {0xda, 9}, {0xdb, 9}, {0x98, 9}, |
| 64 | + {0x99, 9}, {0x9a, 9}, {0x18, 6}, {0x9b, 9}, |
| 65 | + {0x8, 11}, {0xc, 11}, {0xd, 11}, {0x12, 12}, |
| 66 | + {0x13, 12}, {0x14, 12}, {0x15, 12}, {0x16, 12}, |
| 67 | + {0x17, 12}, {0x1c, 12}, {0x1d, 12}, {0x1e, 12}, |
| 68 | + {0x1f, 12} |
| 69 | + } |
| 70 | +}; |
| 71 | + |
| 72 | +/* Black run codes. */ |
| 73 | +static const cf_runs cf_black_runs = |
| 74 | +{ |
| 75 | + /* Termination codes */ |
| 76 | + { |
| 77 | + {0x37, 10}, {0x2, 3}, {0x3, 2}, {0x2, 2}, |
| 78 | + {0x3, 3}, {0x3, 4}, {0x2, 4}, {0x3, 5}, |
| 79 | + {0x5, 6}, {0x4, 6}, {0x4, 7}, {0x5, 7}, |
| 80 | + {0x7, 7}, {0x4, 8}, {0x7, 8}, {0x18, 9}, |
| 81 | + {0x17, 10}, {0x18, 10}, {0x8, 10}, {0x67, 11}, |
| 82 | + {0x68, 11}, {0x6c, 11}, {0x37, 11}, {0x28, 11}, |
| 83 | + {0x17, 11}, {0x18, 11}, {0xca, 12}, {0xcb, 12}, |
| 84 | + {0xcc, 12}, {0xcd, 12}, {0x68, 12}, {0x69, 12}, |
| 85 | + {0x6a, 12}, {0x6b, 12}, {0xd2, 12}, {0xd3, 12}, |
| 86 | + {0xd4, 12}, {0xd5, 12}, {0xd6, 12}, {0xd7, 12}, |
| 87 | + {0x6c, 12}, {0x6d, 12}, {0xda, 12}, {0xdb, 12}, |
| 88 | + {0x54, 12}, {0x55, 12}, {0x56, 12}, {0x57, 12}, |
| 89 | + {0x64, 12}, {0x65, 12}, {0x52, 12}, {0x53, 12}, |
| 90 | + {0x24, 12}, {0x37, 12}, {0x38, 12}, {0x27, 12}, |
| 91 | + {0x28, 12}, {0x58, 12}, {0x59, 12}, {0x2b, 12}, |
| 92 | + {0x2c, 12}, {0x5a, 12}, {0x66, 12}, {0x67, 12} |
| 93 | + }, |
| 94 | + |
| 95 | + /* Make-up codes. */ |
| 96 | + { |
| 97 | + {0, 0} /* dummy */ , {0xf, 10}, {0xc8, 12}, {0xc9, 12}, |
| 98 | + {0x5b, 12}, {0x33, 12}, {0x34, 12}, {0x35, 12}, |
| 99 | + {0x6c, 13}, {0x6d, 13}, {0x4a, 13}, {0x4b, 13}, |
| 100 | + {0x4c, 13}, {0x4d, 13}, {0x72, 13}, {0x73, 13}, |
| 101 | + {0x74, 13}, {0x75, 13}, {0x76, 13}, {0x77, 13}, |
| 102 | + {0x52, 13}, {0x53, 13}, {0x54, 13}, {0x55, 13}, |
| 103 | + {0x5a, 13}, {0x5b, 13}, {0x64, 13}, {0x65, 13}, |
| 104 | + {0x8, 11}, {0xc, 11}, {0xd, 11}, {0x12, 12}, |
| 105 | + {0x13, 12}, {0x14, 12}, {0x15, 12}, {0x16, 12}, |
| 106 | + {0x17, 12}, {0x1c, 12}, {0x1d, 12}, {0x1e, 12}, |
| 107 | + {0x1f, 12} |
| 108 | + } |
| 109 | +}; |
| 110 | + |
| 111 | +static inline int |
| 112 | +getbit(const unsigned char *buf, int x) |
| 113 | +{ |
| 114 | + /* Invert bit to handle BlackIs1=false */ |
| 115 | + return ( ( buf[x >> 3] >> ( 7 - (x & 7) ) ) & 1 ) ^ 1; |
| 116 | +} |
| 117 | + |
| 118 | +static inline int |
| 119 | +find_changing(const unsigned char *line, int x, int w) |
| 120 | +{ |
| 121 | + int a, b; |
| 122 | + |
| 123 | + if (!line || x >= w) |
| 124 | + return w; |
| 125 | + |
| 126 | + if (x == -1) |
| 127 | + { |
| 128 | + a = 0; |
| 129 | + x = 0; |
| 130 | + } |
| 131 | + else |
| 132 | + { |
| 133 | + a = getbit(line, x); |
| 134 | + x++; |
| 135 | + } |
| 136 | + while (x < w) |
| 137 | + { |
| 138 | + b = getbit(line, x); |
| 139 | + if (a != b) |
| 140 | + break; |
| 141 | + x++; |
| 142 | + } |
| 143 | + |
| 144 | + return x; |
| 145 | +} |
| 146 | + |
| 147 | +static inline int |
| 148 | +find_changing_color(const unsigned char *line, int x, int w, int color) |
| 149 | +{ |
| 150 | + if (!line || x >= w) |
| 151 | + return w; |
| 152 | + x = find_changing(line, x, w); |
| 153 | + if (x < w && getbit(line, x) != color) |
| 154 | + x = find_changing(line, x, w); |
| 155 | + return x; |
| 156 | +} |
| 157 | + |
| 158 | +static inline int |
| 159 | +getrun(const unsigned char *line, int x, int w, int c) |
| 160 | +{ |
| 161 | + int z = x; |
| 162 | + while (z < w) |
| 163 | + { |
| 164 | + int b = getbit(line, z); |
| 165 | + if (c != b) |
| 166 | + break; |
| 167 | + ++z; |
| 168 | + } |
| 169 | + return z - x; |
| 170 | +} |
| 171 | + |
| 172 | +static inline void |
| 173 | +putcode(fz_context *ctx, fz_buffer *out, const cfe_code *run) |
| 174 | +{ |
| 175 | + fz_append_bits(ctx, out, run->code, run->nbits); |
| 176 | +} |
| 177 | + |
| 178 | +static void |
| 179 | +putrun(fz_context *ctx, fz_buffer *out, int run, int c) |
| 180 | +{ |
| 181 | + const cf_runs *codetable = c ? &cf_black_runs : &cf_white_runs; |
| 182 | + if (run > 63) |
| 183 | + { |
| 184 | + int m = run >> 6; |
| 185 | + while (m > 40) |
| 186 | + { |
| 187 | + putcode(ctx, out, &codetable->makeup[40]); |
| 188 | + m -= 40; |
| 189 | + } |
| 190 | + if (m > 0) |
| 191 | + putcode(ctx, out, &codetable->makeup[m]); |
| 192 | + putcode(ctx, out, &codetable->termination[run & 63]); |
| 193 | + } |
| 194 | + else |
| 195 | + { |
| 196 | + putcode(ctx, out, &codetable->termination[run]); |
| 197 | + } |
| 198 | +} |
| 199 | + |
| 200 | +fz_buffer * |
| 201 | +fz_compress_ccitt_fax_g4(fz_context *ctx, const unsigned char *src, int columns, int rows) |
| 202 | +{ |
| 203 | + int stride = (columns + 7) >> 3; |
| 204 | + fz_buffer *out = fz_new_buffer(ctx, (stride * rows) >> 3); |
| 205 | + const unsigned char *ref = NULL; |
| 206 | + |
| 207 | + fz_try(ctx) |
| 208 | + { |
| 209 | + while (rows-- > 0) |
| 210 | + { |
| 211 | + int a0 = -1; |
| 212 | + int c = 0; |
| 213 | + |
| 214 | + while (a0 < columns) |
| 215 | + { |
| 216 | + int a1 = find_changing(src, a0, columns); |
| 217 | + int b1 = find_changing_color(ref, a0, columns, c^1); |
| 218 | + int b2 = find_changing(ref, b1, columns); |
| 219 | + int diff = b1 - a1; |
| 220 | + if (a0 < 0) |
| 221 | + a0 = 0; |
| 222 | + |
| 223 | + /* pass mode */ |
| 224 | + if (b2 < a1) |
| 225 | + { |
| 226 | + putcode(ctx, out, &cf2_run_pass); |
| 227 | + a0 = b2; |
| 228 | + } |
| 229 | + |
| 230 | + /* vertical mode */ |
| 231 | + else if (diff >= -3 && diff <= 3) |
| 232 | + { |
| 233 | + putcode(ctx, out, &cf2_run_vertical[diff + 3]); |
| 234 | + a0 = a1; |
| 235 | + c = c^1; |
| 236 | + } |
| 237 | + |
| 238 | + /* horizontal mode */ |
| 239 | + else |
| 240 | + { |
| 241 | + int a2 = find_changing(src, a1, columns); |
| 242 | + putcode(ctx, out, &cf2_run_horizontal); |
| 243 | + putrun(ctx, out, a1 - a0, c); |
| 244 | + putrun(ctx, out, a2 - a1, c^1); |
| 245 | + a0 = a2; |
| 246 | + } |
| 247 | + } |
| 248 | + |
| 249 | + ref = src; |
| 250 | + src += stride; |
| 251 | + } |
| 252 | + |
| 253 | + putcode(ctx, out, &cf_run_eol); |
| 254 | + putcode(ctx, out, &cf_run_eol); |
| 255 | + } |
| 256 | + fz_catch(ctx) |
| 257 | + { |
| 258 | + fz_drop_buffer(ctx, out); |
| 259 | + fz_rethrow(ctx); |
| 260 | + } |
| 261 | + |
| 262 | + return out; |
| 263 | +} |
| 264 | + |
| 265 | +fz_buffer * |
| 266 | +fz_compress_ccitt_fax_g3(fz_context *ctx, const unsigned char *src, int columns, int rows) |
| 267 | +{ |
| 268 | + int stride = (columns + 7) >> 3; |
| 269 | + fz_buffer *out = fz_new_buffer(ctx, (stride * rows) >> 3); |
| 270 | + int i; |
| 271 | + |
| 272 | + fz_try(ctx) |
| 273 | + { |
| 274 | + while (rows-- > 0) |
| 275 | + { |
| 276 | + int a0 = 0; |
| 277 | + int c = 0; |
| 278 | + while (a0 < columns) |
| 279 | + { |
| 280 | + int run = getrun(src, a0, columns, c); |
| 281 | + putrun(ctx, out, run, c); |
| 282 | + a0 += run; |
| 283 | + c = c^1; |
| 284 | + } |
| 285 | + src += stride; |
| 286 | + } |
| 287 | + |
| 288 | + for (i = 0; i < 6; ++i) |
| 289 | + putcode(ctx, out, &cf_run_eol); |
| 290 | + } |
| 291 | + fz_catch(ctx) |
| 292 | + { |
| 293 | + fz_drop_buffer(ctx, out); |
| 294 | + fz_rethrow(ctx); |
| 295 | + } |
| 296 | + |
| 297 | + return out; |
| 298 | +} |
0 commit comments