Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
faxmodule.cpp
Go to the documentation of this file.
1// Copyright 2014 The PDFium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "core/fxcodec/fax/faxmodule.h"
8
9#include <stdint.h>
10
11#include <algorithm>
12#include <array>
13#include <iterator>
14#include <memory>
15#include <utility>
16
17#include "build/build_config.h"
18#include "core/fxcodec/scanlinedecoder.h"
19#include "core/fxcrt/binary_buffer.h"
20#include "core/fxcrt/check.h"
21#include "core/fxcrt/check_op.h"
22#include "core/fxcrt/compiler_specific.h"
23#include "core/fxcrt/data_vector.h"
24#include "core/fxcrt/fx_2d_size.h"
25#include "core/fxcrt/fx_memcpy_wrappers.h"
26#include "core/fxcrt/fx_memory.h"
27#include "core/fxcrt/numerics/safe_conversions.h"
28#include "core/fxcrt/raw_span.h"
29#include "core/fxcrt/span.h"
30#include "core/fxcrt/span_util.h"
31#include "core/fxcrt/stl_util.h"
32#include "core/fxge/calculate_pitch.h"
33
34#if BUILDFLAG(IS_WIN)
35#include "core/fxge/dib/cfx_dibbase.h"
36#endif
37
38namespace fxcodec {
39
40namespace {
41
42constexpr std::array<const uint8_t, 256> kOneLeadPos = {{
43 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3,
44 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
45 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
46 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
47 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
48 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
49 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
53 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
54}};
55
56// Limit of image dimension. Use the same limit as the JBIG2 codecs.
57constexpr int kFaxMaxImageDimension = 65535;
58
59constexpr int kFaxBpc = 1;
60constexpr int kFaxComps = 1;
61
62int FindBit(pdfium::span<const uint8_t> data_buf,
63 int max_pos,
64 int start_pos,
65 bool bit) {
66 DCHECK(start_pos >= 0);
67 if (start_pos >= max_pos)
68 return max_pos;
69
70 const uint8_t bit_xor = bit ? 0x00 : 0xff;
71 int bit_offset = start_pos % 8;
72 if (bit_offset) {
73 const int byte_pos = start_pos / 8;
74 uint8_t data = (data_buf[byte_pos] ^ bit_xor) & (0xff >> bit_offset);
75 if (data) {
76 return byte_pos * 8 + kOneLeadPos[data];
77 }
78 start_pos += 7;
79 }
80
81 const int max_byte = (max_pos + 7) / 8;
82 int byte_pos = start_pos / 8;
83
84 // Try reading in bigger chunks in case there are long runs to be skipped.
85 static constexpr int kBulkReadSize = 8;
86 if (max_byte >= kBulkReadSize && byte_pos < max_byte - kBulkReadSize) {
87 static constexpr uint8_t skip_block_0[kBulkReadSize] = {
88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
89 static constexpr uint8_t skip_block_1[kBulkReadSize] = {
90 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
91 const uint8_t* skip_block = bit ? skip_block_0 : skip_block_1;
92 while (byte_pos < max_byte - kBulkReadSize &&
93 memcmp(data_buf.subspan(byte_pos).data(), skip_block,
94 kBulkReadSize) == 0) {
95 byte_pos += kBulkReadSize;
96 }
97 }
98
99 while (byte_pos < max_byte) {
100 uint8_t data = data_buf[byte_pos] ^ bit_xor;
101 if (data) {
102 return std::min(byte_pos * 8 + kOneLeadPos[data], max_pos);
103 }
104 ++byte_pos;
105 }
106 return max_pos;
107}
108
109void FaxG4FindB1B2(pdfium::span<const uint8_t> ref_buf,
110 int columns,
111 int a0,
112 bool a0color,
113 int* b1,
114 int* b2) {
115 bool first_bit = a0 < 0 || (ref_buf[a0 / 8] & (1 << (7 - a0 % 8))) != 0;
116 *b1 = FindBit(ref_buf, columns, a0 + 1, !first_bit);
117 if (*b1 >= columns) {
118 *b1 = *b2 = columns;
119 return;
120 }
121 if (first_bit == !a0color) {
122 *b1 = FindBit(ref_buf, columns, *b1 + 1, first_bit);
123 first_bit = !first_bit;
124 }
125 if (*b1 >= columns) {
126 *b1 = *b2 = columns;
127 return;
128 }
129 *b2 = FindBit(ref_buf, columns, *b1 + 1, first_bit);
130}
131
132void FaxFillBits(uint8_t* dest_buf, int columns, int startpos, int endpos) {
133 startpos = std::max(startpos, 0);
134 endpos = std::clamp(endpos, 0, columns);
135 if (startpos >= endpos) {
136 return;
137 }
138 int first_byte = startpos / 8;
139 int last_byte = (endpos - 1) / 8;
140 if (first_byte == last_byte) {
141 for (int i = startpos % 8; i <= (endpos - 1) % 8; ++i) {
142 UNSAFE_TODO(dest_buf[first_byte] -= 1 << (7 - i));
143 }
144 return;
145 }
146 for (int i = startpos % 8; i < 8; ++i) {
147 UNSAFE_TODO(dest_buf[first_byte] -= 1 << (7 - i));
148 }
149 for (int i = 0; i <= (endpos - 1) % 8; ++i) {
150 UNSAFE_TODO(dest_buf[last_byte] -= 1 << (7 - i));
151 }
152 if (last_byte > first_byte + 1) {
154 FXSYS_memset(dest_buf + first_byte + 1, 0, last_byte - first_byte - 1));
155 }
156}
157
158inline bool NextBit(const uint8_t* src_buf, int* bitpos) {
159 int pos = (*bitpos)++;
160 return !!UNSAFE_TODO((src_buf[pos / 8] & (1 << (7 - pos % 8))));
161}
162
163const uint8_t kFaxBlackRunIns[] = {
164 0, 2, 0x02, 3, 0, 0x03,
165 2, 0, 2, 0x02, 1, 0,
166 0x03, 4, 0, 2, 0x02, 6,
167 0, 0x03, 5, 0, 1, 0x03,
168 7, 0, 2, 0x04, 9, 0,
169 0x05, 8, 0, 3, 0x04, 10,
170 0, 0x05, 11, 0, 0x07, 12,
171 0, 2, 0x04, 13, 0, 0x07,
172 14, 0, 1, 0x18, 15, 0,
173 5, 0x08, 18, 0, 0x0f, 64,
174 0, 0x17, 16, 0, 0x18, 17,
175 0, 0x37, 0, 0, 10, 0x08,
176 0x00, 0x07, 0x0c, 0x40, 0x07, 0x0d,
177 0x80, 0x07, 0x17, 24, 0, 0x18,
178 25, 0, 0x28, 23, 0, 0x37,
179 22, 0, 0x67, 19, 0, 0x68,
180 20, 0, 0x6c, 21, 0, 54,
181 0x12, 1984 % 256, 1984 / 256, 0x13, 2048 % 256, 2048 / 256,
182 0x14, 2112 % 256, 2112 / 256, 0x15, 2176 % 256, 2176 / 256,
183 0x16, 2240 % 256, 2240 / 256, 0x17, 2304 % 256, 2304 / 256,
184 0x1c, 2368 % 256, 2368 / 256, 0x1d, 2432 % 256, 2432 / 256,
185 0x1e, 2496 % 256, 2496 / 256, 0x1f, 2560 % 256, 2560 / 256,
186 0x24, 52, 0, 0x27, 55, 0,
187 0x28, 56, 0, 0x2b, 59, 0,
188 0x2c, 60, 0, 0x33, 320 % 256, 320 / 256,
189 0x34, 384 % 256, 384 / 256, 0x35, 448 % 256, 448 / 256,
190 0x37, 53, 0, 0x38, 54, 0,
191 0x52, 50, 0, 0x53, 51, 0,
192 0x54, 44, 0, 0x55, 45, 0,
193 0x56, 46, 0, 0x57, 47, 0,
194 0x58, 57, 0, 0x59, 58, 0,
195 0x5a, 61, 0, 0x5b, 256 % 256, 256 / 256,
196 0x64, 48, 0, 0x65, 49, 0,
197 0x66, 62, 0, 0x67, 63, 0,
198 0x68, 30, 0, 0x69, 31, 0,
199 0x6a, 32, 0, 0x6b, 33, 0,
200 0x6c, 40, 0, 0x6d, 41, 0,
201 0xc8, 128, 0, 0xc9, 192, 0,
202 0xca, 26, 0, 0xcb, 27, 0,
203 0xcc, 28, 0, 0xcd, 29, 0,
204 0xd2, 34, 0, 0xd3, 35, 0,
205 0xd4, 36, 0, 0xd5, 37, 0,
206 0xd6, 38, 0, 0xd7, 39, 0,
207 0xda, 42, 0, 0xdb, 43, 0,
208 20, 0x4a, 640 % 256, 640 / 256, 0x4b, 704 % 256,
209 704 / 256, 0x4c, 768 % 256, 768 / 256, 0x4d, 832 % 256,
210 832 / 256, 0x52, 1280 % 256, 1280 / 256, 0x53, 1344 % 256,
211 1344 / 256, 0x54, 1408 % 256, 1408 / 256, 0x55, 1472 % 256,
212 1472 / 256, 0x5a, 1536 % 256, 1536 / 256, 0x5b, 1600 % 256,
213 1600 / 256, 0x64, 1664 % 256, 1664 / 256, 0x65, 1728 % 256,
214 1728 / 256, 0x6c, 512 % 256, 512 / 256, 0x6d, 576 % 256,
215 576 / 256, 0x72, 896 % 256, 896 / 256, 0x73, 960 % 256,
216 960 / 256, 0x74, 1024 % 256, 1024 / 256, 0x75, 1088 % 256,
217 1088 / 256, 0x76, 1152 % 256, 1152 / 256, 0x77, 1216 % 256,
218 1216 / 256, 0xff};
219
220const uint8_t kFaxWhiteRunIns[] = {
221 0, 0, 0, 6, 0x07, 2,
222 0, 0x08, 3, 0, 0x0B, 4,
223 0, 0x0C, 5, 0, 0x0E, 6,
224 0, 0x0F, 7, 0, 6, 0x07,
225 10, 0, 0x08, 11, 0, 0x12,
226 128, 0, 0x13, 8, 0, 0x14,
227 9, 0, 0x1b, 64, 0, 9,
228 0x03, 13, 0, 0x07, 1, 0,
229 0x08, 12, 0, 0x17, 192, 0,
230 0x18, 1664 % 256, 1664 / 256, 0x2a, 16, 0,
231 0x2B, 17, 0, 0x34, 14, 0,
232 0x35, 15, 0, 12, 0x03, 22,
233 0, 0x04, 23, 0, 0x08, 20,
234 0, 0x0c, 19, 0, 0x13, 26,
235 0, 0x17, 21, 0, 0x18, 28,
236 0, 0x24, 27, 0, 0x27, 18,
237 0, 0x28, 24, 0, 0x2B, 25,
238 0, 0x37, 256 % 256, 256 / 256, 42, 0x02,
239 29, 0, 0x03, 30, 0, 0x04,
240 45, 0, 0x05, 46, 0, 0x0a,
241 47, 0, 0x0b, 48, 0, 0x12,
242 33, 0, 0x13, 34, 0, 0x14,
243 35, 0, 0x15, 36, 0, 0x16,
244 37, 0, 0x17, 38, 0, 0x1a,
245 31, 0, 0x1b, 32, 0, 0x24,
246 53, 0, 0x25, 54, 0, 0x28,
247 39, 0, 0x29, 40, 0, 0x2a,
248 41, 0, 0x2b, 42, 0, 0x2c,
249 43, 0, 0x2d, 44, 0, 0x32,
250 61, 0, 0x33, 62, 0, 0x34,
251 63, 0, 0x35, 0, 0, 0x36,
252 320 % 256, 320 / 256, 0x37, 384 % 256, 384 / 256, 0x4a,
253 59, 0, 0x4b, 60, 0, 0x52,
254 49, 0, 0x53, 50, 0, 0x54,
255 51, 0, 0x55, 52, 0, 0x58,
256 55, 0, 0x59, 56, 0, 0x5a,
257 57, 0, 0x5b, 58, 0, 0x64,
258 448 % 256, 448 / 256, 0x65, 512 % 256, 512 / 256, 0x67,
259 640 % 256, 640 / 256, 0x68, 576 % 256, 576 / 256, 16,
260 0x98, 1472 % 256, 1472 / 256, 0x99, 1536 % 256, 1536 / 256,
261 0x9a, 1600 % 256, 1600 / 256, 0x9b, 1728 % 256, 1728 / 256,
262 0xcc, 704 % 256, 704 / 256, 0xcd, 768 % 256, 768 / 256,
263 0xd2, 832 % 256, 832 / 256, 0xd3, 896 % 256, 896 / 256,
264 0xd4, 960 % 256, 960 / 256, 0xd5, 1024 % 256, 1024 / 256,
265 0xd6, 1088 % 256, 1088 / 256, 0xd7, 1152 % 256, 1152 / 256,
266 0xd8, 1216 % 256, 1216 / 256, 0xd9, 1280 % 256, 1280 / 256,
267 0xda, 1344 % 256, 1344 / 256, 0xdb, 1408 % 256, 1408 / 256,
268 0, 3, 0x08, 1792 % 256, 1792 / 256, 0x0c,
269 1856 % 256, 1856 / 256, 0x0d, 1920 % 256, 1920 / 256, 10,
270 0x12, 1984 % 256, 1984 / 256, 0x13, 2048 % 256, 2048 / 256,
271 0x14, 2112 % 256, 2112 / 256, 0x15, 2176 % 256, 2176 / 256,
272 0x16, 2240 % 256, 2240 / 256, 0x17, 2304 % 256, 2304 / 256,
273 0x1c, 2368 % 256, 2368 / 256, 0x1d, 2432 % 256, 2432 / 256,
274 0x1e, 2496 % 256, 2496 / 256, 0x1f, 2560 % 256, 2560 / 256,
275 0xff,
276};
277
278int FaxGetRun(pdfium::span<const uint8_t> ins_array,
279 const uint8_t* src_buf,
280 int* bitpos,
281 int bitsize) {
282 uint32_t code = 0;
283 int ins_off = 0;
284 while (true) {
285 uint8_t ins = ins_array[ins_off++];
286 if (ins == 0xff)
287 return -1;
288
289 if (*bitpos >= bitsize)
290 return -1;
291
292 code <<= 1;
294 if (src_buf[*bitpos / 8] & (1 << (7 - *bitpos % 8))) {
295 ++code;
296 }
297 });
298 ++(*bitpos);
299 int next_off = ins_off + ins * 3;
300 for (; ins_off < next_off; ins_off += 3) {
301 if (ins_array[ins_off] == code)
302 return ins_array[ins_off + 1] + ins_array[ins_off + 2] * 256;
303 }
304 }
305}
306
307void FaxG4GetRow(const uint8_t* src_buf,
308 int bitsize,
309 int* bitpos,
310 uint8_t* dest_buf,
311 pdfium::span<const uint8_t> ref_buf,
312 int columns) {
313 int a0 = -1;
314 bool a0color = true;
315 while (true) {
316 if (*bitpos >= bitsize)
317 return;
318
319 int a1;
320 int a2;
321 int b1;
322 int b2;
323 FaxG4FindB1B2(ref_buf, columns, a0, a0color, &b1, &b2);
324
325 int v_delta = 0;
326 if (!NextBit(src_buf, bitpos)) {
327 if (*bitpos >= bitsize)
328 return;
329
330 bool bit1 = NextBit(src_buf, bitpos);
331 if (*bitpos >= bitsize)
332 return;
333
334 bool bit2 = NextBit(src_buf, bitpos);
335 if (bit1) {
336 v_delta = bit2 ? 1 : -1;
337 } else if (bit2) {
338 int run_len1 = 0;
339 while (true) {
340 int run = FaxGetRun(a0color ? pdfium::make_span(kFaxWhiteRunIns)
341 : pdfium::make_span(kFaxBlackRunIns),
342 src_buf, bitpos, bitsize);
343 run_len1 += run;
344 if (run < 64)
345 break;
346 }
347 if (a0 < 0)
348 ++run_len1;
349 if (run_len1 < 0)
350 return;
351
352 a1 = a0 + run_len1;
353 if (!a0color)
354 FaxFillBits(dest_buf, columns, a0, a1);
355
356 int run_len2 = 0;
357 while (true) {
358 int run = FaxGetRun(a0color ? pdfium::make_span(kFaxBlackRunIns)
359 : pdfium::make_span(kFaxWhiteRunIns),
360 src_buf, bitpos, bitsize);
361 run_len2 += run;
362 if (run < 64)
363 break;
364 }
365 if (run_len2 < 0)
366 return;
367 a2 = a1 + run_len2;
368 if (a0color)
369 FaxFillBits(dest_buf, columns, a1, a2);
370
371 a0 = a2;
372 if (a0 < columns)
373 continue;
374
375 return;
376 } else {
377 if (*bitpos >= bitsize)
378 return;
379
380 if (NextBit(src_buf, bitpos)) {
381 if (!a0color)
382 FaxFillBits(dest_buf, columns, a0, b2);
383
384 if (b2 >= columns)
385 return;
386
387 a0 = b2;
388 continue;
389 }
390
391 if (*bitpos >= bitsize)
392 return;
393
394 bool next_bit1 = NextBit(src_buf, bitpos);
395 if (*bitpos >= bitsize)
396 return;
397
398 bool next_bit2 = NextBit(src_buf, bitpos);
399 if (next_bit1) {
400 v_delta = next_bit2 ? 2 : -2;
401 } else if (next_bit2) {
402 if (*bitpos >= bitsize)
403 return;
404
405 v_delta = NextBit(src_buf, bitpos) ? 3 : -3;
406 } else {
407 if (*bitpos >= bitsize)
408 return;
409
410 if (NextBit(src_buf, bitpos)) {
411 *bitpos += 3;
412 continue;
413 }
414 *bitpos += 5;
415 return;
416 }
417 }
418 }
419 a1 = b1 + v_delta;
420 if (!a0color)
421 FaxFillBits(dest_buf, columns, a0, a1);
422
423 if (a1 >= columns)
424 return;
425
426 // The position of picture element must be monotonic increasing.
427 if (a0 >= a1)
428 return;
429
430 a0 = a1;
431 a0color = !a0color;
432 }
433}
434
435void FaxSkipEOL(const uint8_t* src_buf, int bitsize, int* bitpos) {
436 int startbit = *bitpos;
437 while (*bitpos < bitsize) {
438 if (!NextBit(src_buf, bitpos))
439 continue;
440 if (*bitpos - startbit <= 11)
441 *bitpos = startbit;
442 return;
443 }
444}
445
446void FaxGet1DLine(const uint8_t* src_buf,
447 int bitsize,
448 int* bitpos,
449 uint8_t* dest_buf,
450 int columns) {
451 bool color = true;
452 int startpos = 0;
453 while (true) {
454 if (*bitpos >= bitsize)
455 return;
456
457 int run_len = 0;
458 while (true) {
459 int run = FaxGetRun(color ? pdfium::make_span(kFaxWhiteRunIns)
460 : pdfium::make_span(kFaxBlackRunIns),
461 src_buf, bitpos, bitsize);
462 if (run < 0) {
463 while (*bitpos < bitsize) {
464 if (NextBit(src_buf, bitpos))
465 return;
466 }
467 return;
468 }
469 run_len += run;
470 if (run < 64)
471 break;
472 }
473 if (!color)
474 FaxFillBits(dest_buf, columns, startpos, startpos + run_len);
475
476 startpos += run_len;
477 if (startpos >= columns)
478 break;
479
480 color = !color;
481 }
482}
483
484class FaxDecoder final : public ScanlineDecoder {
485 public:
486 FaxDecoder(pdfium::span<const uint8_t> src_span,
487 int width,
488 int height,
489 int K,
490 bool EndOfLine,
491 bool EncodedByteAlign,
492 bool BlackIs1);
493 ~FaxDecoder() override;
494
495 // ScanlineDecoder:
496 bool Rewind() override;
497 pdfium::span<uint8_t> GetNextLine() override;
498 uint32_t GetSrcOffset() override;
499
500 private:
501 void InvertBuffer();
502
503 const int m_Encoding;
504 int m_bitpos = 0;
505 bool m_bByteAlign = false;
506 const bool m_bEndOfLine;
507 const bool m_bBlack;
508 const pdfium::raw_span<const uint8_t> m_SrcSpan;
509 DataVector<uint8_t> m_ScanlineBuf;
510 DataVector<uint8_t> m_RefBuf;
511};
512
513FaxDecoder::FaxDecoder(pdfium::span<const uint8_t> src_span,
514 int width,
515 int height,
516 int K,
517 bool EndOfLine,
518 bool EncodedByteAlign,
519 bool BlackIs1)
520 : ScanlineDecoder(width,
521 height,
522 width,
523 height,
524 kFaxComps,
525 kFaxBpc,
527 m_Encoding(K),
528 m_bByteAlign(EncodedByteAlign),
529 m_bEndOfLine(EndOfLine),
530 m_bBlack(BlackIs1),
531 m_SrcSpan(src_span),
532 m_ScanlineBuf(m_Pitch),
533 m_RefBuf(m_Pitch) {}
534
535FaxDecoder::~FaxDecoder() {
536 // Span in superclass can't outlive our buffer.
537 m_pLastScanline = pdfium::span<uint8_t>();
538}
539
540bool FaxDecoder::Rewind() {
541 fxcrt::Fill(m_RefBuf, 0xff);
542 m_bitpos = 0;
543 return true;
544}
545
546pdfium::span<uint8_t> FaxDecoder::GetNextLine() {
547 int bitsize = pdfium::checked_cast<int>(m_SrcSpan.size() * 8);
548 FaxSkipEOL(m_SrcSpan.data(), bitsize, &m_bitpos);
549 if (m_bitpos >= bitsize)
550 return pdfium::span<uint8_t>();
551
552 fxcrt::Fill(m_ScanlineBuf, 0xff);
553 if (m_Encoding < 0) {
554 FaxG4GetRow(m_SrcSpan.data(), bitsize, &m_bitpos, m_ScanlineBuf.data(),
555 m_RefBuf, m_OrigWidth);
556 m_RefBuf = m_ScanlineBuf;
557 } else if (m_Encoding == 0) {
558 FaxGet1DLine(m_SrcSpan.data(), bitsize, &m_bitpos, m_ScanlineBuf.data(),
559 m_OrigWidth);
560 } else {
561 if (NextBit(m_SrcSpan.data(), &m_bitpos)) {
562 FaxGet1DLine(m_SrcSpan.data(), bitsize, &m_bitpos, m_ScanlineBuf.data(),
563 m_OrigWidth);
564 } else {
565 FaxG4GetRow(m_SrcSpan.data(), bitsize, &m_bitpos, m_ScanlineBuf.data(),
566 m_RefBuf, m_OrigWidth);
567 }
568 m_RefBuf = m_ScanlineBuf;
569 }
570 if (m_bEndOfLine)
571 FaxSkipEOL(m_SrcSpan.data(), bitsize, &m_bitpos);
572
573 if (m_bByteAlign && m_bitpos < bitsize) {
574 int bitpos0 = m_bitpos;
575 int bitpos1 = FxAlignToBoundary<8>(m_bitpos);
576 while (m_bByteAlign && bitpos0 < bitpos1) {
577 int bit = m_SrcSpan[bitpos0 / 8] & (1 << (7 - bitpos0 % 8));
578 if (bit != 0)
579 m_bByteAlign = false;
580 else
581 ++bitpos0;
582 }
583 if (m_bByteAlign)
584 m_bitpos = bitpos1;
585 }
586 if (m_bBlack)
587 InvertBuffer();
588 return m_ScanlineBuf;
589}
590
591uint32_t FaxDecoder::GetSrcOffset() {
592 return pdfium::checked_cast<uint32_t>(
593 std::min<size_t>((m_bitpos + 7) / 8, m_SrcSpan.size()));
594}
595
596void FaxDecoder::InvertBuffer() {
597 auto byte_span = pdfium::make_span(m_ScanlineBuf);
598 auto data = fxcrt::reinterpret_span<uint32_t>(byte_span);
599 for (auto& datum : data) {
600 datum = ~datum;
601 }
602}
603
604} // namespace
605
606// static
607std::unique_ptr<ScanlineDecoder> FaxModule::CreateDecoder(
608 pdfium::span<const uint8_t> src_span,
609 int width,
610 int height,
611 int K,
612 bool EndOfLine,
613 bool EncodedByteAlign,
614 bool BlackIs1,
615 int Columns,
616 int Rows) {
617 int actual_width = Columns ? Columns : width;
618 int actual_height = Rows ? Rows : height;
619
620 // Reject invalid values.
621 if (actual_width <= 0 || actual_height <= 0)
622 return nullptr;
623
624 // Reject unreasonable large input.
625 if (actual_width > kFaxMaxImageDimension ||
626 actual_height > kFaxMaxImageDimension) {
627 return nullptr;
628 }
629
630 return std::make_unique<FaxDecoder>(src_span, actual_width, actual_height, K,
631 EndOfLine, EncodedByteAlign, BlackIs1);
632}
633
634// static
635int FaxModule::FaxG4Decode(pdfium::span<const uint8_t> src_span,
636 int starting_bitpos,
637 int width,
638 int height,
639 int pitch,
640 uint8_t* dest_buf) {
641 DCHECK(pitch != 0);
642
643 const uint8_t* src_buf = src_span.data();
644 uint32_t src_size = pdfium::checked_cast<uint32_t>(src_span.size());
645
646 DataVector<uint8_t> ref_buf(pitch, 0xff);
647 int bitpos = starting_bitpos;
648 for (int iRow = 0; iRow < height; ++iRow) {
649 uint8_t* line_buf = UNSAFE_TODO(dest_buf + iRow * pitch);
650 UNSAFE_TODO(FXSYS_memset(line_buf, 0xff, pitch));
651 FaxG4GetRow(src_buf, src_size << 3, &bitpos, line_buf, ref_buf, width);
652 UNSAFE_TODO(FXSYS_memcpy(ref_buf.data(), line_buf, pitch));
653 }
654 return bitpos;
655}
656
657#if BUILDFLAG(IS_WIN)
658namespace {
659const uint8_t BlackRunTerminator[128] = {
660 0x37, 10, 0x02, 3, 0x03, 2, 0x02, 2, 0x03, 3, 0x03, 4, 0x02, 4,
661 0x03, 5, 0x05, 6, 0x04, 6, 0x04, 7, 0x05, 7, 0x07, 7, 0x04, 8,
662 0x07, 8, 0x18, 9, 0x17, 10, 0x18, 10, 0x08, 10, 0x67, 11, 0x68, 11,
663 0x6c, 11, 0x37, 11, 0x28, 11, 0x17, 11, 0x18, 11, 0xca, 12, 0xcb, 12,
664 0xcc, 12, 0xcd, 12, 0x68, 12, 0x69, 12, 0x6a, 12, 0x6b, 12, 0xd2, 12,
665 0xd3, 12, 0xd4, 12, 0xd5, 12, 0xd6, 12, 0xd7, 12, 0x6c, 12, 0x6d, 12,
666 0xda, 12, 0xdb, 12, 0x54, 12, 0x55, 12, 0x56, 12, 0x57, 12, 0x64, 12,
667 0x65, 12, 0x52, 12, 0x53, 12, 0x24, 12, 0x37, 12, 0x38, 12, 0x27, 12,
668 0x28, 12, 0x58, 12, 0x59, 12, 0x2b, 12, 0x2c, 12, 0x5a, 12, 0x66, 12,
669 0x67, 12,
670};
671
672const uint8_t BlackRunMarkup[80] = {
673 0x0f, 10, 0xc8, 12, 0xc9, 12, 0x5b, 12, 0x33, 12, 0x34, 12, 0x35, 12,
674 0x6c, 13, 0x6d, 13, 0x4a, 13, 0x4b, 13, 0x4c, 13, 0x4d, 13, 0x72, 13,
675 0x73, 13, 0x74, 13, 0x75, 13, 0x76, 13, 0x77, 13, 0x52, 13, 0x53, 13,
676 0x54, 13, 0x55, 13, 0x5a, 13, 0x5b, 13, 0x64, 13, 0x65, 13, 0x08, 11,
677 0x0c, 11, 0x0d, 11, 0x12, 12, 0x13, 12, 0x14, 12, 0x15, 12, 0x16, 12,
678 0x17, 12, 0x1c, 12, 0x1d, 12, 0x1e, 12, 0x1f, 12,
679};
680
681const uint8_t WhiteRunTerminator[128] = {
682 0x35, 8, 0x07, 6, 0x07, 4, 0x08, 4, 0x0B, 4, 0x0C, 4, 0x0E, 4, 0x0F, 4,
683 0x13, 5, 0x14, 5, 0x07, 5, 0x08, 5, 0x08, 6, 0x03, 6, 0x34, 6, 0x35, 6,
684 0x2a, 6, 0x2B, 6, 0x27, 7, 0x0c, 7, 0x08, 7, 0x17, 7, 0x03, 7, 0x04, 7,
685 0x28, 7, 0x2B, 7, 0x13, 7, 0x24, 7, 0x18, 7, 0x02, 8, 0x03, 8, 0x1a, 8,
686 0x1b, 8, 0x12, 8, 0x13, 8, 0x14, 8, 0x15, 8, 0x16, 8, 0x17, 8, 0x28, 8,
687 0x29, 8, 0x2a, 8, 0x2b, 8, 0x2c, 8, 0x2d, 8, 0x04, 8, 0x05, 8, 0x0a, 8,
688 0x0b, 8, 0x52, 8, 0x53, 8, 0x54, 8, 0x55, 8, 0x24, 8, 0x25, 8, 0x58, 8,
689 0x59, 8, 0x5a, 8, 0x5b, 8, 0x4a, 8, 0x4b, 8, 0x32, 8, 0x33, 8, 0x34, 8,
690};
691
692const uint8_t WhiteRunMarkup[80] = {
693 0x1b, 5, 0x12, 5, 0x17, 6, 0x37, 7, 0x36, 8, 0x37, 8, 0x64, 8,
694 0x65, 8, 0x68, 8, 0x67, 8, 0xcc, 9, 0xcd, 9, 0xd2, 9, 0xd3, 9,
695 0xd4, 9, 0xd5, 9, 0xd6, 9, 0xd7, 9, 0xd8, 9, 0xd9, 9, 0xda, 9,
696 0xdb, 9, 0x98, 9, 0x99, 9, 0x9a, 9, 0x18, 6, 0x9b, 9, 0x08, 11,
697 0x0c, 11, 0x0d, 11, 0x12, 12, 0x13, 12, 0x14, 12, 0x15, 12, 0x16, 12,
698 0x17, 12, 0x1c, 12, 0x1d, 12, 0x1e, 12, 0x1f, 12,
699};
700
701class FaxEncoder {
702 public:
703 explicit FaxEncoder(RetainPtr<const CFX_DIBBase> src);
704 ~FaxEncoder();
706
707 private:
709 void FaxEncodeRun(int run, bool bWhite);
710 void AddBitStream(int data, int bitlen);
711
712 // Must outlive `m_RefLineSpan`.
713 RetainPtr<const CFX_DIBBase> const m_Src;
714 int m_DestBitpos = 0;
715 const int m_Cols;
716 const int m_Rows;
717 const int m_Pitch;
719 // Must outlive `m_RefLineSpan`.
723};
724
726 : m_Src(std::move(src)),
733 DCHECK_EQ(1, m_Src->GetBPP());
734 m_DestBuf.SetAllocStep(10240);
735}
736
737FaxEncoder::~FaxEncoder() = default;
738
739void FaxEncoder::AddBitStream(int data, int bitlen) {
740 for (int i = bitlen - 1; i >= 0; --i, ++m_DestBitpos) {
741 if (data & (1 << i))
742 m_LineBuf[m_DestBitpos / 8] |= 1 << (7 - m_DestBitpos % 8);
743 }
744}
745
746void FaxEncoder::FaxEncodeRun(int run, bool bWhite) {
747 while (run >= 2560) {
748 AddBitStream(0x1f, 12);
749 run -= 2560;
750 }
752 if (run >= 64) {
753 int markup = run - run % 64;
755 p += (markup / 64 - 1) * 2;
756 AddBitStream(*p, p[1]);
757 }
758 run %= 64;
760 p += run * 2;
761 AddBitStream(*p, p[1]);
762 });
763}
764
766 int a0 = -1;
767 bool a0color = true;
768 while (1) {
769 int a1 = FindBit(src_span, m_Cols, a0 + 1, !a0color);
770 int b1;
771 int b2;
773 if (b2 < a1) {
774 m_DestBitpos += 3;
775 m_LineBuf[m_DestBitpos / 8] |= 1 << (7 - m_DestBitpos % 8);
776 ++m_DestBitpos;
777 a0 = b2;
778 } else if (a1 - b1 <= 3 && b1 - a1 <= 3) {
779 int delta = a1 - b1;
780 switch (delta) {
781 case 0:
782 m_LineBuf[m_DestBitpos / 8] |= 1 << (7 - m_DestBitpos % 8);
783 break;
784 case 1:
785 case 2:
786 case 3:
787 m_DestBitpos += delta == 1 ? 1 : delta + 2;
788 m_LineBuf[m_DestBitpos / 8] |= 1 << (7 - m_DestBitpos % 8);
789 ++m_DestBitpos;
790 m_LineBuf[m_DestBitpos / 8] |= 1 << (7 - m_DestBitpos % 8);
791 break;
792 case -1:
793 case -2:
794 case -3:
795 m_DestBitpos += delta == -1 ? 1 : -delta + 2;
796 m_LineBuf[m_DestBitpos / 8] |= 1 << (7 - m_DestBitpos % 8);
797 ++m_DestBitpos;
798 break;
799 }
800 ++m_DestBitpos;
801 a0 = a1;
802 a0color = !a0color;
803 } else {
804 int a2 = FindBit(src_span, m_Cols, a1 + 1, a0color);
805 ++m_DestBitpos;
806 ++m_DestBitpos;
807 m_LineBuf[m_DestBitpos / 8] |= 1 << (7 - m_DestBitpos % 8);
808 ++m_DestBitpos;
809 if (a0 < 0)
810 a0 = 0;
813 a0 = a2;
814 }
815 if (a0 >= m_Cols)
816 return;
817 }
818}
819
821 m_DestBitpos = 0;
822 uint8_t last_byte = 0;
823 for (int i = 0; i < m_Rows; ++i) {
824 fxcrt::Fill(m_LineBuf, 0);
825 m_LineBuf[0] = last_byte;
830 m_DestBitpos %= 8;
832 }
833 if (m_DestBitpos)
835 return m_DestBuf.DetachBuffer();
836}
837
838} // namespace
839
840// static
842 DCHECK_EQ(1, src->GetBPP());
844 return encoder.Encode();
845}
846
847#endif // BUILDFLAG(IS_WIN)
848
849} // namespace fxcodec
#define DCHECK
Definition check.h:33
ScanlineDecoder(int nOrigWidth, int nOrigHeight, int nOutputWidth, int nOutputHeight, int nComps, int nBpc, uint32_t nPitch)
#define UNSAFE_TODO(...)
UNSAFE_BUFFER_USAGE void * FXSYS_memset(void *ptr1, int val, size_t len)
uint32_t CalculatePitch32OrDie(int bits_per_pixel, int width_in_pixels)