Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/source/fitz/encode-fax.c @ 3:2c135c81b16c
MERGE: upstream PyMuPDF 1.26.4 with MuPDF 1.26.7
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:44:09 +0200 |
| parents | b50eed0cc0ef |
| children |
comparison
equal
deleted
inserted
replaced
| 0:6015a75abc2d | 3:2c135c81b16c |
|---|---|
| 1 // Copyright (C) 2004-2021 Artifex Software, Inc. | |
| 2 // | |
| 3 // This file is part of MuPDF. | |
| 4 // | |
| 5 // MuPDF is free software: you can redistribute it and/or modify it under the | |
| 6 // terms of the GNU Affero General Public License as published by the Free | |
| 7 // Software Foundation, either version 3 of the License, or (at your option) | |
| 8 // any later version. | |
| 9 // | |
| 10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY | |
| 11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
| 12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more | |
| 13 // details. | |
| 14 // | |
| 15 // You should have received a copy of the GNU Affero General Public License | |
| 16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> | |
| 17 // | |
| 18 // Alternative licensing terms are available from the licensor. | |
| 19 // For commercial licensing, see <https://www.artifex.com/> or contact | |
| 20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, | |
| 21 // CA 94129, USA, for further information. | |
| 22 | |
| 23 #include "mupdf/fitz.h" | |
| 24 | |
| 25 /* Fax G3/G4 tables */ | |
| 26 | |
| 27 typedef struct | |
| 28 { | |
| 29 unsigned short code; | |
| 30 unsigned short nbits; | |
| 31 } cfe_code; | |
| 32 | |
| 33 typedef struct { | |
| 34 cfe_code termination[64]; | |
| 35 cfe_code makeup[41]; | |
| 36 } cf_runs; | |
| 37 | |
| 38 /* Define the end-of-line code. */ | |
| 39 static const cfe_code cf_run_eol = {1, 12}; | |
| 40 | |
| 41 /* Define the 2-D run codes. */ | |
| 42 static const cfe_code cf2_run_pass = {0x1, 4}; | |
| 43 static const cfe_code cf2_run_vertical[7] = | |
| 44 { | |
| 45 {0x3, 7}, | |
| 46 {0x3, 6}, | |
| 47 {0x3, 3}, | |
| 48 {0x1, 1}, | |
| 49 {0x2, 3}, | |
| 50 {0x2, 6}, | |
| 51 {0x2, 7} | |
| 52 }; | |
| 53 static const cfe_code cf2_run_horizontal = {1, 3}; | |
| 54 | |
| 55 /* White run codes. */ | |
| 56 static const cf_runs cf_white_runs = | |
| 57 { | |
| 58 /* Termination codes */ | |
| 59 { | |
| 60 {0x35, 8}, {0x7, 6}, {0x7, 4}, {0x8, 4}, | |
| 61 {0xb, 4}, {0xc, 4}, {0xe, 4}, {0xf, 4}, | |
| 62 {0x13, 5}, {0x14, 5}, {0x7, 5}, {0x8, 5}, | |
| 63 {0x8, 6}, {0x3, 6}, {0x34, 6}, {0x35, 6}, | |
| 64 {0x2a, 6}, {0x2b, 6}, {0x27, 7}, {0xc, 7}, | |
| 65 {0x8, 7}, {0x17, 7}, {0x3, 7}, {0x4, 7}, | |
| 66 {0x28, 7}, {0x2b, 7}, {0x13, 7}, {0x24, 7}, | |
| 67 {0x18, 7}, {0x2, 8}, {0x3, 8}, {0x1a, 8}, | |
| 68 {0x1b, 8}, {0x12, 8}, {0x13, 8}, {0x14, 8}, | |
| 69 {0x15, 8}, {0x16, 8}, {0x17, 8}, {0x28, 8}, | |
| 70 {0x29, 8}, {0x2a, 8}, {0x2b, 8}, {0x2c, 8}, | |
| 71 {0x2d, 8}, {0x4, 8}, {0x5, 8}, {0xa, 8}, | |
| 72 {0xb, 8}, {0x52, 8}, {0x53, 8}, {0x54, 8}, | |
| 73 {0x55, 8}, {0x24, 8}, {0x25, 8}, {0x58, 8}, | |
| 74 {0x59, 8}, {0x5a, 8}, {0x5b, 8}, {0x4a, 8}, | |
| 75 {0x4b, 8}, {0x32, 8}, {0x33, 8}, {0x34, 8} | |
| 76 }, | |
| 77 | |
| 78 /* Make-up codes */ | |
| 79 { | |
| 80 {0, 0} /* dummy */ , {0x1b, 5}, {0x12, 5}, {0x17, 6}, | |
| 81 {0x37, 7}, {0x36, 8}, {0x37, 8}, {0x64, 8}, | |
| 82 {0x65, 8}, {0x68, 8}, {0x67, 8}, {0xcc, 9}, | |
| 83 {0xcd, 9}, {0xd2, 9}, {0xd3, 9}, {0xd4, 9}, | |
| 84 {0xd5, 9}, {0xd6, 9}, {0xd7, 9}, {0xd8, 9}, | |
| 85 {0xd9, 9}, {0xda, 9}, {0xdb, 9}, {0x98, 9}, | |
| 86 {0x99, 9}, {0x9a, 9}, {0x18, 6}, {0x9b, 9}, | |
| 87 {0x8, 11}, {0xc, 11}, {0xd, 11}, {0x12, 12}, | |
| 88 {0x13, 12}, {0x14, 12}, {0x15, 12}, {0x16, 12}, | |
| 89 {0x17, 12}, {0x1c, 12}, {0x1d, 12}, {0x1e, 12}, | |
| 90 {0x1f, 12} | |
| 91 } | |
| 92 }; | |
| 93 | |
| 94 /* Black run codes. */ | |
| 95 static const cf_runs cf_black_runs = | |
| 96 { | |
| 97 /* Termination codes */ | |
| 98 { | |
| 99 {0x37, 10}, {0x2, 3}, {0x3, 2}, {0x2, 2}, | |
| 100 {0x3, 3}, {0x3, 4}, {0x2, 4}, {0x3, 5}, | |
| 101 {0x5, 6}, {0x4, 6}, {0x4, 7}, {0x5, 7}, | |
| 102 {0x7, 7}, {0x4, 8}, {0x7, 8}, {0x18, 9}, | |
| 103 {0x17, 10}, {0x18, 10}, {0x8, 10}, {0x67, 11}, | |
| 104 {0x68, 11}, {0x6c, 11}, {0x37, 11}, {0x28, 11}, | |
| 105 {0x17, 11}, {0x18, 11}, {0xca, 12}, {0xcb, 12}, | |
| 106 {0xcc, 12}, {0xcd, 12}, {0x68, 12}, {0x69, 12}, | |
| 107 {0x6a, 12}, {0x6b, 12}, {0xd2, 12}, {0xd3, 12}, | |
| 108 {0xd4, 12}, {0xd5, 12}, {0xd6, 12}, {0xd7, 12}, | |
| 109 {0x6c, 12}, {0x6d, 12}, {0xda, 12}, {0xdb, 12}, | |
| 110 {0x54, 12}, {0x55, 12}, {0x56, 12}, {0x57, 12}, | |
| 111 {0x64, 12}, {0x65, 12}, {0x52, 12}, {0x53, 12}, | |
| 112 {0x24, 12}, {0x37, 12}, {0x38, 12}, {0x27, 12}, | |
| 113 {0x28, 12}, {0x58, 12}, {0x59, 12}, {0x2b, 12}, | |
| 114 {0x2c, 12}, {0x5a, 12}, {0x66, 12}, {0x67, 12} | |
| 115 }, | |
| 116 | |
| 117 /* Make-up codes. */ | |
| 118 { | |
| 119 {0, 0} /* dummy */ , {0xf, 10}, {0xc8, 12}, {0xc9, 12}, | |
| 120 {0x5b, 12}, {0x33, 12}, {0x34, 12}, {0x35, 12}, | |
| 121 {0x6c, 13}, {0x6d, 13}, {0x4a, 13}, {0x4b, 13}, | |
| 122 {0x4c, 13}, {0x4d, 13}, {0x72, 13}, {0x73, 13}, | |
| 123 {0x74, 13}, {0x75, 13}, {0x76, 13}, {0x77, 13}, | |
| 124 {0x52, 13}, {0x53, 13}, {0x54, 13}, {0x55, 13}, | |
| 125 {0x5a, 13}, {0x5b, 13}, {0x64, 13}, {0x65, 13}, | |
| 126 {0x8, 11}, {0xc, 11}, {0xd, 11}, {0x12, 12}, | |
| 127 {0x13, 12}, {0x14, 12}, {0x15, 12}, {0x16, 12}, | |
| 128 {0x17, 12}, {0x1c, 12}, {0x1d, 12}, {0x1e, 12}, | |
| 129 {0x1f, 12} | |
| 130 } | |
| 131 }; | |
| 132 | |
| 133 static inline int | |
| 134 getbit(const unsigned char *buf, int x) | |
| 135 { | |
| 136 /* Invert bit to handle BlackIs1=false */ | |
| 137 return ( ( buf[x >> 3] >> ( 7 - (x & 7) ) ) & 1 ) ^ 1; | |
| 138 } | |
| 139 | |
| 140 static inline int | |
| 141 find_changing(const unsigned char *line, int x, int w) | |
| 142 { | |
| 143 int a, b; | |
| 144 | |
| 145 if (!line || x >= w) | |
| 146 return w; | |
| 147 | |
| 148 if (x == -1) | |
| 149 { | |
| 150 a = 0; | |
| 151 x = 0; | |
| 152 } | |
| 153 else | |
| 154 { | |
| 155 a = getbit(line, x); | |
| 156 x++; | |
| 157 } | |
| 158 while (x < w) | |
| 159 { | |
| 160 b = getbit(line, x); | |
| 161 if (a != b) | |
| 162 break; | |
| 163 x++; | |
| 164 } | |
| 165 | |
| 166 return x; | |
| 167 } | |
| 168 | |
| 169 static inline int | |
| 170 find_changing_color(const unsigned char *line, int x, int w, int color) | |
| 171 { | |
| 172 if (!line || x >= w) | |
| 173 return w; | |
| 174 x = find_changing(line, x, w); | |
| 175 if (x < w && getbit(line, x) != color) | |
| 176 x = find_changing(line, x, w); | |
| 177 return x; | |
| 178 } | |
| 179 | |
| 180 static inline int | |
| 181 getrun(const unsigned char *line, int x, int w, int c) | |
| 182 { | |
| 183 int z = x; | |
| 184 while (z < w) | |
| 185 { | |
| 186 int b = getbit(line, z); | |
| 187 if (c != b) | |
| 188 break; | |
| 189 ++z; | |
| 190 } | |
| 191 return z - x; | |
| 192 } | |
| 193 | |
| 194 static inline void | |
| 195 putcode(fz_context *ctx, fz_buffer *out, const cfe_code *run) | |
| 196 { | |
| 197 fz_append_bits(ctx, out, run->code, run->nbits); | |
| 198 } | |
| 199 | |
| 200 static void | |
| 201 putrun(fz_context *ctx, fz_buffer *out, int run, int c) | |
| 202 { | |
| 203 const cf_runs *codetable = c ? &cf_black_runs : &cf_white_runs; | |
| 204 if (run > 63) | |
| 205 { | |
| 206 int m = run >> 6; | |
| 207 while (m > 40) | |
| 208 { | |
| 209 putcode(ctx, out, &codetable->makeup[40]); | |
| 210 m -= 40; | |
| 211 } | |
| 212 if (m > 0) | |
| 213 putcode(ctx, out, &codetable->makeup[m]); | |
| 214 putcode(ctx, out, &codetable->termination[run & 63]); | |
| 215 } | |
| 216 else | |
| 217 { | |
| 218 putcode(ctx, out, &codetable->termination[run]); | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 fz_buffer * | |
| 223 fz_compress_ccitt_fax_g4(fz_context *ctx, const unsigned char *src, int columns, int rows, ptrdiff_t stride) | |
| 224 { | |
| 225 fz_buffer *out = fz_new_buffer(ctx, (stride * rows) >> 3); | |
| 226 const unsigned char *ref = NULL; | |
| 227 | |
| 228 fz_try(ctx) | |
| 229 { | |
| 230 while (rows-- > 0) | |
| 231 { | |
| 232 int a0 = -1; | |
| 233 int c = 0; | |
| 234 | |
| 235 while (a0 < columns) | |
| 236 { | |
| 237 int a1 = find_changing(src, a0, columns); | |
| 238 int b1 = find_changing_color(ref, a0, columns, c^1); | |
| 239 int b2 = find_changing(ref, b1, columns); | |
| 240 int diff = b1 - a1; | |
| 241 if (a0 < 0) | |
| 242 a0 = 0; | |
| 243 | |
| 244 /* pass mode */ | |
| 245 if (b2 < a1) | |
| 246 { | |
| 247 putcode(ctx, out, &cf2_run_pass); | |
| 248 a0 = b2; | |
| 249 } | |
| 250 | |
| 251 /* vertical mode */ | |
| 252 else if (diff >= -3 && diff <= 3) | |
| 253 { | |
| 254 putcode(ctx, out, &cf2_run_vertical[diff + 3]); | |
| 255 a0 = a1; | |
| 256 c = c^1; | |
| 257 } | |
| 258 | |
| 259 /* horizontal mode */ | |
| 260 else | |
| 261 { | |
| 262 int a2 = find_changing(src, a1, columns); | |
| 263 putcode(ctx, out, &cf2_run_horizontal); | |
| 264 putrun(ctx, out, a1 - a0, c); | |
| 265 putrun(ctx, out, a2 - a1, c^1); | |
| 266 a0 = a2; | |
| 267 } | |
| 268 } | |
| 269 | |
| 270 ref = src; | |
| 271 src += stride; | |
| 272 } | |
| 273 | |
| 274 putcode(ctx, out, &cf_run_eol); | |
| 275 putcode(ctx, out, &cf_run_eol); | |
| 276 } | |
| 277 fz_catch(ctx) | |
| 278 { | |
| 279 fz_drop_buffer(ctx, out); | |
| 280 fz_rethrow(ctx); | |
| 281 } | |
| 282 | |
| 283 return out; | |
| 284 } | |
| 285 | |
| 286 fz_buffer * | |
| 287 fz_compress_ccitt_fax_g3(fz_context *ctx, const unsigned char *src, int columns, int rows, ptrdiff_t stride) | |
| 288 { | |
| 289 fz_buffer *out = fz_new_buffer(ctx, (stride * rows) >> 3); | |
| 290 int i; | |
| 291 | |
| 292 fz_try(ctx) | |
| 293 { | |
| 294 while (rows-- > 0) | |
| 295 { | |
| 296 int a0 = 0; | |
| 297 int c = 0; | |
| 298 while (a0 < columns) | |
| 299 { | |
| 300 int run = getrun(src, a0, columns, c); | |
| 301 putrun(ctx, out, run, c); | |
| 302 a0 += run; | |
| 303 c = c^1; | |
| 304 } | |
| 305 src += stride; | |
| 306 } | |
| 307 | |
| 308 for (i = 0; i < 6; ++i) | |
| 309 putcode(ctx, out, &cf_run_eol); | |
| 310 } | |
| 311 fz_catch(ctx) | |
| 312 { | |
| 313 fz_drop_buffer(ctx, out); | |
| 314 fz_rethrow(ctx); | |
| 315 } | |
| 316 | |
| 317 return out; | |
| 318 } |
