comparison mupdf-source/source/fitz/encode-fax.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
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 }