979df381970ef2428783884b67337df00cff6286
[pdfium.git] / core / src / fxcodec / codec / fx_codec_fax.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
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 "../../../include/fxcodec/fx_codec.h"
8 #include "codec_int.h"
9 extern const FX_BYTE OneLeadPos[256];
10 extern const FX_BYTE ZeroLeadPos[256];
11 int _FindBit(const FX_BYTE* data_buf, int max_pos, int start_pos, int bit)
12 {
13     if (start_pos >= max_pos) {
14         return max_pos;
15     }
16     FX_LPCBYTE leading_pos = bit ? OneLeadPos : ZeroLeadPos;
17     if (start_pos % 8) {
18         FX_BYTE data = data_buf[start_pos / 8];
19         if (bit) {
20             data &= 0xff >> (start_pos % 8);
21         } else {
22             data |= 0xff << (8 - start_pos % 8);
23         }
24         if (leading_pos[data] < 8) {
25             return start_pos / 8 * 8 + leading_pos[data];
26         }
27         start_pos += 7;
28     }
29     FX_BYTE skip = bit ? 0x00 : 0xff;
30     int byte_pos = start_pos / 8;
31     int max_byte = (max_pos + 7) / 8;
32     while (byte_pos < max_byte) {
33         if (data_buf[byte_pos] != skip) {
34             break;
35         }
36         byte_pos ++;
37     }
38     if (byte_pos == max_byte) {
39         return max_pos;
40     }
41     int pos = leading_pos[data_buf[byte_pos]] + byte_pos * 8;
42     if (pos > max_pos) {
43         pos = max_pos;
44     }
45     return pos;
46 }
47 void _FaxG4FindB1B2(const FX_BYTE* ref_buf, int columns, int a0, FX_BOOL a0color, int& b1, int& b2)
48 {
49     if (a0color) {
50         a0color = 1;
51     }
52     FX_BYTE first_bit = (a0 < 0) ? 1 : ((ref_buf[a0 / 8] & (1 << (7 - a0 % 8))) != 0);
53     b1 = _FindBit(ref_buf, columns, a0 + 1, !first_bit);
54     if (b1 >= columns) {
55         b1 = b2 = columns;
56         return;
57     }
58     if (first_bit == !a0color) {
59         b1 = _FindBit(ref_buf, columns, b1 + 1, first_bit);
60         first_bit = !first_bit;
61     }
62     if (b1 >= columns) {
63         b1 = b2 = columns;
64         return;
65     }
66     b2 = _FindBit(ref_buf, columns, b1 + 1, first_bit);
67 }
68 void _FaxFillBits(FX_LPBYTE dest_buf, int columns, int startpos, int endpos)
69 {
70     if (startpos < 0) {
71         startpos = 0;
72     }
73     if (endpos < 0) {
74         endpos = 0;
75     }
76     if (endpos >= columns) {
77         endpos = columns;
78     }
79     if (startpos >= endpos) {
80         return;
81     }
82     int first_byte = startpos / 8;
83     int last_byte = (endpos - 1) / 8;
84     if (first_byte == last_byte) {
85         for (int i = startpos % 8; i <= (endpos - 1) % 8; i ++) {
86             dest_buf[first_byte] -= 1 << (7 - i);
87         }
88         return;
89     }
90     int i;
91     for (i = startpos % 8; i < 8; i ++) {
92         dest_buf[first_byte] -= 1 << (7 - i);
93     }
94     for (i = 0; i <= (endpos - 1) % 8; i ++) {
95         dest_buf[last_byte] -= 1 << (7 - i);
96     }
97     if (last_byte > first_byte + 1) {
98         FXSYS_memset32(dest_buf + first_byte + 1, 0, last_byte - first_byte - 1);
99     }
100 }
101 #define NEXTBIT src_buf[bitpos/8] & (1 << (7-bitpos%8)); bitpos ++;
102 #define ADDBIT(code, bit) code = code << 1; if (bit) code ++;
103 #define GETBIT(bitpos) src_buf[bitpos/8] & (1 << (7-bitpos%8))
104 static const FX_BYTE FaxBlackRunIns[] = {
105     0,
106     2,
107     0x02, 3, 0,
108     0x03, 2, 0,
109     2,
110     0x02, 1, 0,
111     0x03, 4, 0,
112     2,
113     0x02, 6, 0,
114     0x03, 5, 0,
115     1,
116     0x03, 7, 0,
117     2,
118     0x04, 9, 0,
119     0x05, 8, 0,
120     3,
121     0x04, 10, 0,
122     0x05, 11, 0,
123     0x07, 12, 0,
124     2,
125     0x04, 13, 0,
126     0x07, 14, 0,
127     1,
128     0x18, 15, 0,
129     5,
130     0x08, 18, 0,
131     0x0f, 64, 0,
132     0x17, 16, 0,
133     0x18, 17, 0,
134     0x37, 0, 0,
135     10,
136     0x08, 0x00, 0x07,
137     0x0c, 0x40, 0x07,
138     0x0d, 0x80, 0x07,
139     0x17, 24, 0,
140     0x18, 25, 0,
141     0x28, 23, 0,
142     0x37, 22, 0,
143     0x67, 19, 0,
144     0x68, 20, 0,
145     0x6c, 21, 0,
146     54,
147     0x12, 1984 % 256, 1984 / 256,
148     0x13, 2048 % 256, 2048 / 256,
149     0x14, 2112 % 256, 2112 / 256,
150     0x15, 2176 % 256, 2176 / 256,
151     0x16, 2240 % 256, 2240 / 256,
152     0x17, 2304 % 256, 2304 / 256,
153     0x1c, 2368 % 256, 2368 / 256,
154     0x1d, 2432 % 256, 2432 / 256,
155     0x1e, 2496 % 256, 2496 / 256,
156     0x1f, 2560 % 256, 2560 / 256,
157     0x24, 52, 0,
158     0x27, 55, 0,
159     0x28, 56, 0,
160     0x2b, 59, 0,
161     0x2c, 60, 0,
162     0x33, 320 % 256, 320 / 256,
163     0x34, 384 % 256, 384 / 256,
164     0x35, 448 % 256, 448 / 256,
165     0x37, 53, 0,
166     0x38, 54, 0,
167     0x52, 50, 0,
168     0x53, 51, 0,
169     0x54, 44, 0,
170     0x55, 45, 0,
171     0x56, 46, 0,
172     0x57, 47, 0,
173     0x58, 57, 0,
174     0x59, 58, 0,
175     0x5a, 61, 0,
176     0x5b, 256 % 256, 256 / 256,
177     0x64, 48, 0,
178     0x65, 49, 0,
179     0x66, 62, 0,
180     0x67, 63, 0,
181     0x68, 30, 0,
182     0x69, 31, 0,
183     0x6a, 32, 0,
184     0x6b, 33, 0,
185     0x6c, 40, 0,
186     0x6d, 41, 0,
187     0xc8, 128, 0,
188     0xc9, 192, 0,
189     0xca, 26, 0,
190     0xcb, 27, 0,
191     0xcc, 28, 0,
192     0xcd, 29, 0,
193     0xd2, 34, 0,
194     0xd3, 35, 0,
195     0xd4, 36, 0,
196     0xd5, 37, 0,
197     0xd6, 38, 0,
198     0xd7, 39, 0,
199     0xda, 42, 0,
200     0xdb, 43, 0,
201     20,
202     0x4a, 640 % 256, 640 / 256,
203     0x4b, 704 % 256, 704 / 256,
204     0x4c, 768 % 256, 768 / 256,
205     0x4d, 832 % 256, 832 / 256,
206     0x52, 1280 % 256, 1280 / 256,
207     0x53, 1344 % 256, 1344 / 256,
208     0x54, 1408 % 256, 1408 / 256,
209     0x55, 1472 % 256, 1472 / 256,
210     0x5a, 1536 % 256, 1536 / 256,
211     0x5b, 1600 % 256, 1600 / 256,
212     0x64, 1664 % 256, 1664 / 256,
213     0x65, 1728 % 256, 1728 / 256,
214     0x6c, 512 % 256, 512 / 256,
215     0x6d, 576 % 256, 576 / 256,
216     0x72, 896 % 256, 896 / 256,
217     0x73, 960 % 256, 960 / 256,
218     0x74, 1024 % 256, 1024 / 256,
219     0x75, 1088 % 256, 1088 / 256,
220     0x76, 1152 % 256, 1152 / 256,
221     0x77, 1216 % 256, 1216 / 256,
222     0xff
223 };
224 static const FX_BYTE FaxWhiteRunIns[] = {
225     0,
226     0,
227     0,
228     6,
229     0x07, 2, 0,
230     0x08, 3, 0,
231     0x0B, 4, 0,
232     0x0C, 5, 0,
233     0x0E, 6, 0,
234     0x0F, 7, 0,
235     6,
236     0x07, 10, 0,
237     0x08, 11, 0,
238     0x12, 128, 0,
239     0x13, 8, 0,
240     0x14, 9, 0,
241     0x1b, 64, 0,
242     9,
243     0x03, 13, 0,
244     0x07, 1, 0,
245     0x08, 12, 0,
246     0x17, 192, 0,
247     0x18, 1664 % 256, 1664 / 256,
248     0x2a, 16, 0,
249     0x2B, 17, 0,
250     0x34, 14, 0,
251     0x35, 15, 0,
252     12,
253     0x03, 22, 0,
254     0x04, 23, 0,
255     0x08, 20, 0,
256     0x0c, 19, 0,
257     0x13, 26, 0,
258     0x17, 21, 0,
259     0x18, 28, 0,
260     0x24, 27, 0,
261     0x27, 18, 0,
262     0x28, 24, 0,
263     0x2B, 25, 0,
264     0x37, 256 % 256, 256 / 256,
265     42,
266     0x02, 29, 0,
267     0x03, 30, 0,
268     0x04, 45, 0,
269     0x05, 46, 0,
270     0x0a, 47, 0,
271     0x0b, 48, 0,
272     0x12, 33, 0,
273     0x13, 34, 0,
274     0x14, 35, 0,
275     0x15, 36, 0,
276     0x16, 37, 0,
277     0x17, 38, 0,
278     0x1a, 31, 0,
279     0x1b, 32, 0,
280     0x24, 53, 0,
281     0x25, 54, 0,
282     0x28, 39, 0,
283     0x29, 40, 0,
284     0x2a, 41, 0,
285     0x2b, 42, 0,
286     0x2c, 43, 0,
287     0x2d, 44, 0,
288     0x32, 61, 0,
289     0x33, 62, 0,
290     0x34, 63, 0,
291     0x35, 0, 0,
292     0x36, 320 % 256, 320 / 256,
293     0x37, 384 % 256, 384 / 256,
294     0x4a, 59, 0,
295     0x4b, 60, 0,
296     0x52, 49, 0,
297     0x53, 50, 0,
298     0x54, 51, 0,
299     0x55, 52, 0,
300     0x58, 55, 0,
301     0x59, 56, 0,
302     0x5a, 57, 0,
303     0x5b, 58, 0,
304     0x64, 448 % 256, 448 / 256,
305     0x65, 512 % 256, 512 / 256,
306     0x67, 640 % 256, 640 / 256,
307     0x68, 576 % 256, 576 / 256,
308     16,
309     0x98, 1472 % 256, 1472 / 256,
310     0x99, 1536 % 256, 1536 / 256,
311     0x9a, 1600 % 256, 1600 / 256,
312     0x9b, 1728 % 256, 1728 / 256,
313     0xcc, 704 % 256, 704 / 256,
314     0xcd, 768 % 256, 768 / 256,
315     0xd2, 832 % 256, 832 / 256,
316     0xd3, 896 % 256, 896 / 256,
317     0xd4, 960 % 256, 960 / 256,
318     0xd5, 1024 % 256, 1024 / 256,
319     0xd6, 1088 % 256, 1088 / 256,
320     0xd7, 1152 % 256, 1152 / 256,
321     0xd8, 1216 % 256, 1216 / 256,
322     0xd9, 1280 % 256, 1280 / 256,
323     0xda, 1344 % 256, 1344 / 256,
324     0xdb, 1408 % 256, 1408 / 256,
325     0,
326     3,
327     0x08, 1792 % 256, 1792 / 256,
328     0x0c, 1856 % 256, 1856 / 256,
329     0x0d, 1920 % 256, 1920 / 256,
330     10,
331     0x12, 1984 % 256, 1984 / 256,
332     0x13, 2048 % 256, 2048 / 256,
333     0x14, 2112 % 256, 2112 / 256,
334     0x15, 2176 % 256, 2176 / 256,
335     0x16, 2240 % 256, 2240 / 256,
336     0x17, 2304 % 256, 2304 / 256,
337     0x1c, 2368 % 256, 2368 / 256,
338     0x1d, 2432 % 256, 2432 / 256,
339     0x1e, 2496 % 256, 2496 / 256,
340     0x1f, 2560 % 256, 2560 / 256,
341     0xff,
342 };
343 int _FaxGetRun(FX_LPCBYTE ins_array, const FX_BYTE* src_buf, int& bitpos, int bitsize)
344 {
345     FX_DWORD code = 0;
346     int ins_off = 0;
347     while (1) {
348         FX_BYTE ins = ins_array[ins_off++];
349         if (ins == 0xff) {
350             return -1;
351         }
352         if (bitpos >= bitsize) {
353             return -1;
354         }
355         code <<= 1;
356         if (src_buf[bitpos / 8] & (1 << (7 - bitpos % 8))) {
357             code ++;
358         }
359         bitpos ++;
360         int next_off = ins_off + ins * 3;
361         for (; ins_off < next_off; ins_off += 3) {
362             if (ins_array[ins_off] == code) {
363                 return ins_array[ins_off + 1] + ins_array[ins_off + 2] * 256;
364             }
365         }
366     }
367 }
368 FX_BOOL _FaxG4GetRow(const FX_BYTE* src_buf, int bitsize, int& bitpos, FX_LPBYTE dest_buf, const FX_BYTE* ref_buf, int columns)
369 {
370     int a0 = -1, a0color = 1;
371     while (1) {
372         if (bitpos >= bitsize) {
373             return FALSE;
374         }
375         int a1, a2, b1, b2;
376         _FaxG4FindB1B2(ref_buf, columns, a0, a0color, b1, b2);
377         FX_BOOL bit = NEXTBIT;
378         int v_delta = 0;
379         if (bit) {
380         } else {
381             if (bitpos >= bitsize) {
382                 return FALSE;
383             }
384             FX_BOOL bit1 = NEXTBIT;
385             if (bitpos >= bitsize) {
386                 return FALSE;
387             }
388             FX_BOOL bit2 = NEXTBIT;
389             if (bit1 && bit2) {
390                 v_delta = 1;
391             } else if (bit1) {
392                 v_delta = -1;
393             } else if (bit2) {
394                 int run_len1 = 0;
395                 while (1) {
396                     int run = _FaxGetRun(a0color ? FaxWhiteRunIns : FaxBlackRunIns, src_buf, bitpos, bitsize);
397                     run_len1 += run;
398                     if (run < 64) {
399                         break;
400                     }
401                 }
402                 if (a0 < 0) {
403                     run_len1 ++;
404                 }
405                 a1 = a0 + run_len1;
406                 if (!a0color) {
407                     _FaxFillBits(dest_buf, columns, a0, a1);
408                 }
409                 int run_len2 = 0;
410                 while (1) {
411                     int run = _FaxGetRun(a0color ? FaxBlackRunIns : FaxWhiteRunIns, src_buf, bitpos, bitsize);
412                     run_len2 += run;
413                     if (run < 64) {
414                         break;
415                     }
416                 }
417                 a2 = a1 + run_len2;
418                 if (a0color) {
419                     _FaxFillBits(dest_buf, columns, a1, a2);
420                 }
421                 a0 = a2;
422                 if (a0 < columns) {
423                     continue;
424                 }
425                 return TRUE;
426             } else {
427                 if (bitpos >= bitsize) {
428                     return FALSE;
429                 }
430                 bit = NEXTBIT;
431                 if (bit) {
432                     if (!a0color) {
433                         _FaxFillBits(dest_buf, columns, a0, b2);
434                     }
435                     if (b2 >= columns) {
436                         return TRUE;
437                     }
438                     a0 = b2;
439                     continue;
440                 } else {
441                     if (bitpos >= bitsize) {
442                         return FALSE;
443                     }
444                     FX_BOOL bit1 = NEXTBIT;
445                     if (bitpos >= bitsize) {
446                         return FALSE;
447                     }
448                     FX_BOOL bit2 = NEXTBIT;
449                     if (bit1 && bit2) {
450                         v_delta = 2;
451                     } else if (bit1) {
452                         v_delta = -2;
453                     } else if (bit2) {
454                         if (bitpos >= bitsize) {
455                             return FALSE;
456                         }
457                         bit = NEXTBIT;
458                         if (bit) {
459                             v_delta = 3;
460                         } else {
461                             v_delta = -3;
462                         }
463                     } else {
464                         if (bitpos >= bitsize) {
465                             return FALSE;
466                         }
467                         bit = NEXTBIT;
468                         if (bit) {
469                             bitpos += 3;
470                             continue;
471                         } else {
472                             bitpos += 5;
473                             return TRUE;
474                         }
475                     }
476                 }
477             }
478         }
479         a1 = b1 + v_delta;
480         if (!a0color) {
481             _FaxFillBits(dest_buf, columns, a0, a1);
482         }
483         if (a1 >= columns) {
484             return TRUE;
485         }
486         a0 = a1;
487         a0color = !a0color;
488     }
489 }
490 FX_BOOL _FaxSkipEOL(const FX_BYTE* src_buf, int bitsize, int& bitpos)
491 {
492     int startbit = bitpos;
493     while (bitpos < bitsize) {
494         int bit = NEXTBIT;
495         if (bit) {
496             if (bitpos - startbit <= 11) {
497                 bitpos = startbit;
498             }
499             return TRUE;
500         }
501     }
502     return FALSE;
503 }
504 FX_BOOL _FaxGet1DLine(const FX_BYTE* src_buf, int bitsize, int& bitpos, FX_LPBYTE dest_buf, int columns)
505 {
506     int color = TRUE;
507     int startpos = 0;
508     while (1) {
509         if (bitpos >= bitsize) {
510             return FALSE;
511         }
512         int run_len = 0;
513         while (1) {
514             int run = _FaxGetRun(color ? FaxWhiteRunIns : FaxBlackRunIns, src_buf, bitpos, bitsize);
515             if (run < 0) {
516                 while (bitpos < bitsize) {
517                     int bit = NEXTBIT;
518                     if (bit) {
519                         return TRUE;
520                     }
521                 }
522                 return FALSE;
523             }
524             run_len += run;
525             if (run < 64) {
526                 break;
527             }
528         }
529         if (!color) {
530             _FaxFillBits(dest_buf, columns, startpos, startpos + run_len);
531         }
532         startpos += run_len;
533         if (startpos >= columns) {
534             break;
535         }
536         color = !color;
537     }
538     return TRUE;
539 }
540 class CCodec_FaxDecoder : public CCodec_ScanlineDecoder
541 {
542 public:
543     CCodec_FaxDecoder();
544     virtual ~CCodec_FaxDecoder();
545     FX_BOOL                             Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height,
546                                int K, FX_BOOL EndOfLine, FX_BOOL EncodedByteAlign, FX_BOOL BlackIs1, int Columns, int Rows);
547     virtual void                v_DownScale(int dest_width, int dest_height) {}
548     virtual FX_BOOL             v_Rewind();
549     virtual FX_LPBYTE   v_GetNextLine();
550     virtual FX_DWORD    GetSrcOffset();
551     int                 m_Encoding, m_bEndOfLine, m_bByteAlign, m_bBlack;
552     int                 bitpos;
553     FX_LPCBYTE  m_pSrcBuf;
554     FX_DWORD    m_SrcSize;
555     FX_LPBYTE   m_pScanlineBuf, m_pRefBuf;
556 };
557 CCodec_FaxDecoder::CCodec_FaxDecoder()
558 {
559     m_pScanlineBuf = NULL;
560     m_pRefBuf = NULL;
561 }
562 CCodec_FaxDecoder::~CCodec_FaxDecoder()
563 {
564     if (m_pScanlineBuf) {
565         FX_Free(m_pScanlineBuf);
566     }
567     if (m_pRefBuf) {
568         FX_Free(m_pRefBuf);
569     }
570 }
571 FX_BOOL CCodec_FaxDecoder::Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height,
572                                   int K, FX_BOOL EndOfLine, FX_BOOL EncodedByteAlign, FX_BOOL BlackIs1, int Columns, int Rows)
573 {
574     m_Encoding = K;
575     m_bEndOfLine = EndOfLine;
576     m_bByteAlign = EncodedByteAlign;
577     m_bBlack = BlackIs1;
578     m_OrigWidth = Columns;
579     m_OrigHeight = Rows;
580     if (m_OrigWidth == 0) {
581         m_OrigWidth = width;
582     }
583     if (m_OrigHeight == 0) {
584         m_OrigHeight = height;
585     }
586     m_Pitch = (m_OrigWidth + 31) / 32 * 4;
587     m_OutputWidth = m_OrigWidth;
588     m_OutputHeight = m_OrigHeight;
589     m_pScanlineBuf = FX_Alloc(FX_BYTE, m_Pitch);
590     if (m_pScanlineBuf == NULL) {
591         return FALSE;
592     }
593     m_pRefBuf = FX_Alloc(FX_BYTE, m_Pitch);
594     if (m_pRefBuf == NULL) {
595         return FALSE;
596     }
597     m_pSrcBuf = src_buf;
598     m_SrcSize = src_size;
599     m_nComps = 1;
600     m_bpc = 1;
601     m_bColorTransformed = FALSE;
602     return TRUE;
603 }
604 FX_BOOL CCodec_FaxDecoder::v_Rewind()
605 {
606     FXSYS_memset8(m_pRefBuf, 0xff, m_Pitch);
607     bitpos = 0;
608     return TRUE;
609 }
610 FX_LPBYTE CCodec_FaxDecoder::v_GetNextLine()
611 {
612     int bitsize = m_SrcSize * 8;
613     _FaxSkipEOL(m_pSrcBuf, bitsize, bitpos);
614     if (bitpos >= bitsize) {
615         return NULL;
616     }
617     FXSYS_memset8(m_pScanlineBuf, 0xff, m_Pitch);
618     if (m_Encoding < 0) {
619         _FaxG4GetRow(m_pSrcBuf, bitsize, bitpos, m_pScanlineBuf, m_pRefBuf, m_OrigWidth);
620         FXSYS_memcpy32(m_pRefBuf, m_pScanlineBuf, m_Pitch);
621     } else if (m_Encoding == 0) {
622         _FaxGet1DLine(m_pSrcBuf, bitsize, bitpos, m_pScanlineBuf, m_OrigWidth);
623     } else {
624         FX_BOOL bNext1D = m_pSrcBuf[bitpos / 8] & (1 << (7 - bitpos % 8));
625         bitpos ++;
626         if (bNext1D) {
627             _FaxGet1DLine(m_pSrcBuf, bitsize, bitpos, m_pScanlineBuf, m_OrigWidth);
628         } else {
629             _FaxG4GetRow(m_pSrcBuf, bitsize, bitpos, m_pScanlineBuf, m_pRefBuf, m_OrigWidth);
630         }
631         FXSYS_memcpy32(m_pRefBuf, m_pScanlineBuf, m_Pitch);
632     }
633     if (m_bEndOfLine) {
634         _FaxSkipEOL(m_pSrcBuf, bitsize, bitpos);
635     }
636     if (m_bByteAlign && bitpos < bitsize) {
637         int bitpos0 = bitpos;
638         int bitpos1 = (bitpos + 7) / 8 * 8;
639         while (m_bByteAlign && bitpos0 < bitpos1) {
640             int bit = m_pSrcBuf[bitpos0 / 8] & (1 << (7 - bitpos0 % 8));
641             if (bit != 0) {
642                 m_bByteAlign = FALSE;
643             } else {
644                 bitpos0 ++;
645             }
646         }
647         if (m_bByteAlign) {
648             bitpos = bitpos1;
649         }
650     }
651     if (m_bBlack) {
652         for (int i = 0; i < m_Pitch; i ++) {
653             m_pScanlineBuf[i] = ~m_pScanlineBuf[i];
654         }
655     }
656     return m_pScanlineBuf;
657 }
658 FX_DWORD CCodec_FaxDecoder::GetSrcOffset()
659 {
660     FX_DWORD ret = (bitpos + 7) / 8;
661     if (ret > m_SrcSize) {
662         ret = m_SrcSize;
663     }
664     return ret;
665 }
666 extern "C" {
667     void _FaxG4Decode(void*, FX_LPCBYTE src_buf, FX_DWORD src_size, int* pbitpos, FX_LPBYTE dest_buf, int width, int height, int pitch)
668     {
669         if (pitch == 0) {
670             pitch = (width + 7) / 8;
671         }
672         FX_LPBYTE ref_buf = FX_Alloc(FX_BYTE, pitch);
673         if (ref_buf == NULL) {
674             return;
675         }
676         FXSYS_memset8(ref_buf, 0xff, pitch);
677         int bitpos = *pbitpos;
678         for (int iRow = 0; iRow < height; iRow ++) {
679             FX_LPBYTE line_buf = dest_buf + iRow * pitch;
680             FXSYS_memset8(line_buf, 0xff, pitch);
681             _FaxG4GetRow(src_buf, src_size << 3, bitpos, line_buf, ref_buf, width);
682             FXSYS_memcpy32(ref_buf, line_buf, pitch);
683         }
684         FX_Free(ref_buf);
685         *pbitpos = bitpos;
686     }
687 };
688 static const FX_BYTE BlackRunTerminator[128] = {
689     0x37, 10, 0x02, 3, 0x03, 2, 0x02, 2, 0x03, 3, 0x03, 4, 0x02, 4, 0x03, 5,
690     0x05, 6, 0x04, 6, 0x04, 7, 0x05, 7, 0x07, 7, 0x04, 8, 0x07, 8, 0x18, 9,
691     0x17, 10, 0x18, 10, 0x08, 10, 0x67, 11, 0x68, 11, 0x6c, 11, 0x37, 11, 0x28, 11,
692     0x17, 11, 0x18, 11, 0xca, 12, 0xcb, 12, 0xcc, 12, 0xcd, 12, 0x68, 12, 0x69, 12,
693     0x6a, 12, 0x6b, 12, 0xd2, 12, 0xd3, 12, 0xd4, 12, 0xd5, 12, 0xd6, 12, 0xd7, 12,
694     0x6c, 12, 0x6d, 12, 0xda, 12, 0xdb, 12, 0x54, 12, 0x55, 12, 0x56, 12, 0x57, 12,
695     0x64, 12, 0x65, 12, 0x52, 12, 0x53, 12, 0x24, 12, 0x37, 12, 0x38, 12, 0x27, 12,
696     0x28, 12, 0x58, 12, 0x59, 12, 0x2b, 12, 0x2c, 12, 0x5a, 12, 0x66, 12, 0x67, 12,
697 };
698 static const FX_BYTE BlackRunMarkup[80] = {
699     0x0f, 10, 0xc8, 12, 0xc9, 12, 0x5b, 12, 0x33, 12, 0x34, 12, 0x35, 12, 0x6c, 13,
700     0x6d, 13, 0x4a, 13, 0x4b, 13, 0x4c, 13, 0x4d, 13, 0x72, 13, 0x73, 13, 0x74, 13,
701     0x75, 13, 0x76, 13, 0x77, 13, 0x52, 13, 0x53, 13, 0x54, 13, 0x55, 13, 0x5a, 13,
702     0x5b, 13, 0x64, 13, 0x65, 13, 0x08, 11, 0x0c, 11, 0x0d, 11, 0x12, 12, 0x13, 12,
703     0x14, 12, 0x15, 12, 0x16, 12, 0x17, 12, 0x1c, 12, 0x1d, 12, 0x1e, 12, 0x1f, 12,
704 };
705 static const FX_BYTE WhiteRunTerminator[128] = {
706     0x35, 8,
707     0x07, 6,
708     0x07, 4,
709     0x08, 4,
710     0x0B, 4,
711     0x0C, 4,
712     0x0E, 4,
713     0x0F, 4,
714     0x13, 5,
715     0x14, 5,
716     0x07, 5,
717     0x08, 5,
718     0x08, 6,
719     0x03, 6,
720     0x34, 6,
721     0x35, 6,
722     0x2a, 6,
723     0x2B, 6,
724     0x27, 7,
725     0x0c, 7,
726     0x08, 7,
727     0x17, 7,
728     0x03, 7,
729     0x04, 7,
730     0x28, 7,
731     0x2B, 7,
732     0x13, 7,
733     0x24, 7,
734     0x18, 7,
735     0x02, 8,
736     0x03, 8,
737     0x1a, 8,
738     0x1b, 8,
739     0x12, 8,
740     0x13, 8,
741     0x14, 8,
742     0x15, 8,
743     0x16, 8,
744     0x17, 8,
745     0x28, 8,
746     0x29, 8,
747     0x2a, 8,
748     0x2b, 8,
749     0x2c, 8,
750     0x2d, 8,
751     0x04, 8,
752     0x05, 8,
753     0x0a, 8,
754     0x0b, 8,
755     0x52, 8,
756     0x53, 8,
757     0x54, 8,
758     0x55, 8,
759     0x24, 8,
760     0x25, 8,
761     0x58, 8,
762     0x59, 8,
763     0x5a, 8,
764     0x5b, 8,
765     0x4a, 8,
766     0x4b, 8,
767     0x32, 8,
768     0x33, 8,
769     0x34, 8,
770 };
771 static const FX_BYTE WhiteRunMarkup[80] = {
772     0x1b, 5,
773     0x12, 5,
774     0x17, 6,
775     0x37, 7,
776     0x36, 8,
777     0x37, 8,
778     0x64, 8,
779     0x65, 8,
780     0x68, 8,
781     0x67, 8,
782     0xcc, 9,
783     0xcd, 9,
784     0xd2, 9,
785     0xd3, 9,
786     0xd4, 9,
787     0xd5, 9,
788     0xd6, 9,
789     0xd7, 9,
790     0xd8, 9,
791     0xd9, 9,
792     0xda, 9,
793     0xdb, 9,
794     0x98, 9,
795     0x99, 9,
796     0x9a, 9,
797     0x18, 6,
798     0x9b, 9,
799     0x08, 11,
800     0x0c, 11,
801     0x0d, 11,
802     0x12, 12,
803     0x13, 12,
804     0x14, 12,
805     0x15, 12,
806     0x16, 12,
807     0x17, 12,
808     0x1c, 12,
809     0x1d, 12,
810     0x1e, 12,
811     0x1f, 12,
812 };
813 static void _AddBitStream(FX_LPBYTE dest_buf, int& dest_bitpos, int data, int bitlen)
814 {
815     for (int i = bitlen - 1; i >= 0; i --) {
816         if (data & (1 << i)) {
817             dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
818         }
819         dest_bitpos ++;
820     }
821 }
822 static void _FaxEncodeRun(FX_LPBYTE dest_buf, int& dest_bitpos, int run, FX_BOOL bWhite)
823 {
824     while (run >= 2560) {
825         _AddBitStream(dest_buf, dest_bitpos, 0x1f, 12);
826         run -= 2560;
827     }
828     if (run >= 64) {
829         int markup = run - run % 64;
830         FX_LPCBYTE p = bWhite ? WhiteRunMarkup : BlackRunMarkup;
831         p += (markup / 64 - 1) * 2;
832         _AddBitStream(dest_buf, dest_bitpos, *p, p[1]);
833     }
834     run %= 64;
835     FX_LPCBYTE p = bWhite ? WhiteRunTerminator : BlackRunTerminator;
836     p += run * 2;
837     _AddBitStream(dest_buf, dest_bitpos, *p, p[1]);
838 }
839 static void _FaxEncode2DLine(FX_LPBYTE dest_buf, int& dest_bitpos, FX_LPCBYTE src_buf, FX_LPCBYTE ref_buf, int cols)
840 {
841     int a0 = -1, a0color = 1;
842     while (1) {
843         int a1 = _FindBit(src_buf, cols, a0 + 1, 1 - a0color);
844         int b1, b2;
845         _FaxG4FindB1B2(ref_buf, cols, a0, a0color, b1, b2);
846         if (b2 < a1) {
847             dest_bitpos += 3;
848             dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
849             dest_bitpos ++;
850             a0 = b2;
851         } else if (a1 - b1 <= 3 && b1 - a1 <= 3) {
852             int delta = a1 - b1;
853             switch (delta) {
854                 case 0:
855                     dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
856                     break;
857                 case 1:
858                 case 2:
859                 case 3:
860                     dest_bitpos += delta == 1 ? 1 : delta + 2;
861                     dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
862                     dest_bitpos ++;
863                     dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
864                     break;
865                 case -1:
866                 case -2:
867                 case -3:
868                     dest_bitpos += delta == -1 ? 1 : -delta + 2;
869                     dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
870                     dest_bitpos ++;
871                     break;
872             }
873             dest_bitpos ++;
874             a0 = a1;
875             a0color = 1 - a0color;
876         } else {
877             int a2 = _FindBit(src_buf, cols, a1 + 1, a0color);
878             dest_bitpos ++;
879             dest_bitpos ++;
880             dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
881             dest_bitpos ++;
882             if (a0 < 0) {
883                 a0 = 0;
884             }
885             _FaxEncodeRun(dest_buf, dest_bitpos, a1 - a0, a0color);
886             _FaxEncodeRun(dest_buf, dest_bitpos, a2 - a1, 1 - a0color);
887             a0 = a2;
888         }
889         if (a0 >= cols) {
890             return;
891         }
892     }
893 }
894 class CCodec_FaxEncoder : public CFX_Object
895 {
896 public:
897     CCodec_FaxEncoder(FX_LPCBYTE src_buf, int width, int height, int pitch);
898     ~CCodec_FaxEncoder();
899     void                        Encode(FX_LPBYTE& dest_buf, FX_DWORD& dest_size);
900     void                        Encode2DLine(FX_LPCBYTE scan_line);
901     CFX_BinaryBuf       m_DestBuf;
902     FX_LPBYTE           m_pRefLine, m_pLineBuf;
903     int                         m_Cols, m_Rows, m_Pitch;
904     FX_LPCBYTE          m_pSrcBuf;
905 };
906 CCodec_FaxEncoder::CCodec_FaxEncoder(FX_LPCBYTE src_buf, int width, int height, int pitch)
907 {
908     m_pSrcBuf = src_buf;
909     m_Cols = width;
910     m_Rows = height;
911     m_Pitch = pitch;
912     m_pRefLine = FX_Alloc(FX_BYTE, m_Pitch);
913     if (m_pRefLine == NULL) {
914         return;
915     }
916     FXSYS_memset8(m_pRefLine, 0xff, m_Pitch);
917     m_pLineBuf = FX_Alloc(FX_BYTE, m_Pitch * 8);
918     if (m_pLineBuf == NULL) {
919         return;
920     }
921     m_DestBuf.EstimateSize(0, 10240);
922 }
923 CCodec_FaxEncoder::~CCodec_FaxEncoder()
924 {
925     if (m_pRefLine) {
926         FX_Free(m_pRefLine);
927     }
928     if (m_pLineBuf) {
929         FX_Free(m_pLineBuf);
930     }
931 }
932 void CCodec_FaxEncoder::Encode(FX_LPBYTE& dest_buf, FX_DWORD& dest_size)
933 {
934     int dest_bitpos = 0;
935     FX_BYTE last_byte = 0;
936     for (int i = 0; i < m_Rows; i ++) {
937         FX_LPCBYTE scan_line = m_pSrcBuf + i * m_Pitch;
938         FXSYS_memset32(m_pLineBuf, 0, m_Pitch * 8);
939         m_pLineBuf[0] = last_byte;
940         _FaxEncode2DLine(m_pLineBuf, dest_bitpos, scan_line, m_pRefLine, m_Cols);
941         m_DestBuf.AppendBlock(m_pLineBuf, dest_bitpos / 8);
942         last_byte = m_pLineBuf[dest_bitpos / 8];
943         dest_bitpos %= 8;
944         FXSYS_memcpy32(m_pRefLine, scan_line, m_Pitch);
945     }
946     if (dest_bitpos) {
947         m_DestBuf.AppendByte(last_byte);
948     }
949     dest_buf = m_DestBuf.GetBuffer();
950     dest_size = m_DestBuf.GetSize();
951     m_DestBuf.DetachBuffer();
952 }
953 FX_BOOL CCodec_FaxModule::Encode(FX_LPCBYTE src_buf, int width, int height, int pitch, FX_LPBYTE& dest_buf, FX_DWORD& dest_size)
954 {
955     CCodec_FaxEncoder encoder(src_buf, width, height, pitch);
956     encoder.Encode(dest_buf, dest_size);
957     return TRUE;
958 }
959 ICodec_ScanlineDecoder* CCodec_FaxModule::CreateDecoder(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height,
960         int K, FX_BOOL EndOfLine, FX_BOOL EncodedByteAlign, FX_BOOL BlackIs1, int Columns, int Rows)
961 {
962     CCodec_FaxDecoder* pDecoder = FX_NEW CCodec_FaxDecoder;
963     if (pDecoder == NULL) {
964         return NULL;
965     }
966     pDecoder->Create(src_buf, src_size, width, height, K, EndOfLine, EncodedByteAlign, BlackIs1, Columns, Rows);
967     return pDecoder;
968 }