source: trunk/libdjvu/MMRDecoder.cpp @ 81

Last change on this file since 81 was 17, checked in by Eugene Romanenko, 16 years ago

update makefiles, remove absolute paths, update djvulibre to version 3.5.17

File size: 27.4 KB
Line 
1//C-  -*- C++ -*-
2//C- -------------------------------------------------------------------
3//C- DjVuLibre-3.5
4//C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
5//C- Copyright (c) 2001  AT&T
6//C-
7//C- This software is subject to, and may be distributed under, the
8//C- GNU General Public License, Version 2. The license should have
9//C- accompanied the software or you may obtain a copy of the license
10//C- from the Free Software Foundation at http://www.fsf.org .
11//C-
12//C- This program is distributed in the hope that it will be useful,
13//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
14//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15//C- GNU General Public License for more details.
16//C-
17//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library
18//C- distributed by Lizardtech Software.  On July 19th 2002, Lizardtech
19//C- Software authorized us to replace the original DjVu(r) Reference
20//C- Library notice by the following text (see doc/lizard2002.djvu):
21//C-
22//C-  ------------------------------------------------------------------
23//C- | DjVu (r) Reference Library (v. 3.5)
24//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
25//C- | The DjVu Reference Library is protected by U.S. Pat. No.
26//C- | 6,058,214 and patents pending.
27//C- |
28//C- | This software is subject to, and may be distributed under, the
29//C- | GNU General Public License, Version 2. The license should have
30//C- | accompanied the software or you may obtain a copy of the license
31//C- | from the Free Software Foundation at http://www.fsf.org .
32//C- |
33//C- | The computer code originally released by LizardTech under this
34//C- | license and unmodified by other parties is deemed "the LIZARDTECH
35//C- | ORIGINAL CODE."  Subject to any third party intellectual property
36//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
37//C- | non-exclusive license to make, use, sell, or otherwise dispose of
38//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
39//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
40//C- | General Public License.   This grant only confers the right to
41//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
42//C- | the extent such infringement is reasonably necessary to enable
43//C- | recipient to make, have made, practice, sell, or otherwise dispose
44//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
45//C- | any greater extent that may be necessary to utilize further
46//C- | modifications or combinations.
47//C- |
48//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
49//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
50//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
51//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
52//C- +------------------------------------------------------------------
53//
54// $Id: MMRDecoder.cpp,v 1.8 2003/11/07 22:08:22 leonb Exp $
55// $Name:  $
56
57#ifdef HAVE_CONFIG_H
58# include "config.h"
59#endif
60#if NEED_GNUG_PRAGMAS
61# pragma implementation
62#endif
63
64#include "MMRDecoder.h"
65#include "JB2Image.h"
66#include "ByteStream.h"
67#include "GBitmap.h"
68
69
70#ifdef HAVE_NAMESPACES
71namespace DJVU {
72# ifdef NOT_DEFINED // Just to fool emacs c++ mode
73}
74#endif
75#endif
76
77
78// ----------------------------------------
79// MMR CODEBOOKS
80
81static const char invalid_mmr_data[]= ERR_MSG("MMRDecoder.bad_data");
82
83struct VLCode
84{
85  unsigned short code;
86  short codelen;
87  short value;
88};
89
90enum MMRMode
91{ 
92  P=0, H=1, V0=2, VR1=3, VR2=4, VR3=5, VL1=6, VL2=7, VL3=8 
93};
94
95static const VLCode mrcodes[] =
96{   // Codes on 7 bits
97  // 7 bit codes
98  { 0x08,   4,    P }, // 0001
99  { 0x10,   3,    H }, // 001
100  { 0x40,   1,   V0 }, // 1
101  { 0x30,   3,  VR1 }, // 011
102  { 0x06,   6,  VR2 }, // 000011
103  { 0x03,   7,  VR3 }, // 0000011
104  { 0x20,   3,  VL1 }, // 010
105  { 0x04,   6,  VL2 }, // 000010
106  { 0x02,   7,  VL3 }, // 0000010
107  { 0x00,   0,   -1 }  // Illegal entry
108};
109
110
111static const VLCode wcodes[] = {   
112  // 13 bit codes
113  { 0x06a0,  8,    0 }, // 00110101
114  { 0x0380,  6,    1 }, // 000111
115  { 0x0e00,  4,    2 }, // 0111
116  { 0x1000,  4,    3 }, // 1000
117  { 0x1600,  4,    4 }, // 1011
118  { 0x1800,  4,    5 }, // 1100
119  { 0x1c00,  4,    6 }, // 1110
120  { 0x1e00,  4,    7 }, // 1111
121  { 0x1300,  5,    8 }, // 10011
122  { 0x1400,  5,    9 }, // 10100
123  { 0x0700,  5,   10 }, // 00111
124  { 0x0800,  5,   11 }, // 01000
125  { 0x0400,  6,   12 }, // 001000
126  { 0x0180,  6,   13 }, // 000011
127  { 0x1a00,  6,   14 }, // 110100
128  { 0x1a80,  6,   15 }, // 110101
129  { 0x1500,  6,   16 }, // 101010
130  { 0x1580,  6,   17 }, // 101011
131  { 0x09c0,  7,   18 }, // 0100111
132  { 0x0300,  7,   19 }, // 0001100
133  { 0x0200,  7,   20 }, // 0001000
134  { 0x05c0,  7,   21 }, // 0010111
135  { 0x00c0,  7,   22 }, // 0000011
136  { 0x0100,  7,   23 }, // 0000100
137  { 0x0a00,  7,   24 }, // 0101000
138  { 0x0ac0,  7,   25 }, // 0101011
139  { 0x04c0,  7,   26 }, // 0010011
140  { 0x0900,  7,   27 }, // 0100100
141  { 0x0600,  7,   28 }, // 0011000
142  { 0x0040,  8,   29 }, // 00000010
143  { 0x0060,  8,   30 }, // 00000011
144  { 0x0340,  8,   31 }, // 00011010
145  { 0x0360,  8,   32 }, // 00011011
146  { 0x0240,  8,   33 }, // 00010010
147  { 0x0260,  8,   34 }, // 00010011
148  { 0x0280,  8,   35 }, // 00010100
149  { 0x02a0,  8,   36 }, // 00010101
150  { 0x02c0,  8,   37 }, // 00010110
151  { 0x02e0,  8,   38 }, // 00010111
152  { 0x0500,  8,   39 }, // 00101000
153  { 0x0520,  8,   40 }, // 00101001
154  { 0x0540,  8,   41 }, // 00101010
155  { 0x0560,  8,   42 }, // 00101011
156  { 0x0580,  8,   43 }, // 00101100
157  { 0x05a0,  8,   44 }, // 00101101
158  { 0x0080,  8,   45 }, // 00000100
159  { 0x00a0,  8,   46 }, // 00000101
160  { 0x0140,  8,   47 }, // 00001010
161  { 0x0160,  8,   48 }, // 00001011
162  { 0x0a40,  8,   49 }, // 01010010
163  { 0x0a60,  8,   50 }, // 01010011
164  { 0x0a80,  8,   51 }, // 01010100
165  { 0x0aa0,  8,   52 }, // 01010101
166  { 0x0480,  8,   53 }, // 00100100
167  { 0x04a0,  8,   54 }, // 00100101
168  { 0x0b00,  8,   55 }, // 01011000
169  { 0x0b20,  8,   56 }, // 01011001
170  { 0x0b40,  8,   57 }, // 01011010
171  { 0x0b60,  8,   58 }, // 01011011
172  { 0x0940,  8,   59 }, // 01001010
173  { 0x0960,  8,   60 }, // 01001011
174  { 0x0640,  8,   61 }, // 00110010
175  { 0x0660,  8,   62 }, // 00110011
176  { 0x0680,  8,   63 }, // 00110100
177  { 0x1b00,  5,   64 }, // 11011
178  { 0x1200,  5,  128 }, // 10010
179  { 0x0b80,  6,  192 }, // 010111
180  { 0x0dc0,  7,  256 }, // 0110111
181  { 0x06c0,  8,  320 }, // 00110110
182  { 0x06e0,  8,  384 }, // 00110111
183  { 0x0c80,  8,  448 }, // 01100100
184  { 0x0ca0,  8,  512 }, // 01100101
185  { 0x0d00,  8,  576 }, // 01101000
186  { 0x0ce0,  8,  640 }, // 01100111
187  { 0x0cc0,  9,  704 }, // 011001100
188  { 0x0cd0,  9,  768 }, // 011001101
189  { 0x0d20,  9,  832 }, // 011010010
190  { 0x0d30,  9,  896 }, // 011010011
191  { 0x0d40,  9,  960 }, // 011010100
192  { 0x0d50,  9, 1024 }, // 011010101
193  { 0x0d60,  9, 1088 }, // 011010110
194  { 0x0d70,  9, 1152 }, // 011010111
195  { 0x0d80,  9, 1216 }, // 011011000
196  { 0x0d90,  9, 1280 }, // 011011001
197  { 0x0da0,  9, 1344 }, // 011011010
198  { 0x0db0,  9, 1408 }, // 011011011
199  { 0x0980,  9, 1472 }, // 010011000
200  { 0x0990,  9, 1536 }, // 010011001
201  { 0x09a0,  9, 1600 }, // 010011010
202  { 0x0c00,  6, 1664 }, // 011000  (what did they think?)
203  { 0x09b0,  9, 1728 }, // 010011011
204  { 0x0020, 11, 1792 }, // 00000001000
205  { 0x0030, 11, 1856 }, // 00000001100
206  { 0x0034, 11, 1920 }, // 00000001101
207  { 0x0024, 12, 1984 }, // 000000010010
208  { 0x0026, 12, 2048 }, // 000000010011
209  { 0x0028, 12, 2112 }, // 000000010100
210  { 0x002a, 12, 2176 }, // 000000010101
211  { 0x002c, 12, 2240 }, // 000000010110
212  { 0x002e, 12, 2304 }, // 000000010111
213  { 0x0038, 12, 2368 }, // 000000011100
214  { 0x003a, 12, 2432 }, // 000000011101
215  { 0x003c, 12, 2496 }, // 000000011110
216  { 0x003e, 12, 2560 }, // 000000011111
217  { 0x0000,  0,   -1 }  // Illegal entry
218};
219
220
221static const VLCode bcodes[] = {
222  // 13 bit codes
223  { 0x01b8, 10,    0 }, // 0000110111
224  { 0x0800,  3,    1 }, // 010
225  { 0x1800,  2,    2 }, // 11
226  { 0x1000,  2,    3 }, // 10
227  { 0x0c00,  3,    4 }, // 011
228  { 0x0600,  4,    5 }, // 0011
229  { 0x0400,  4,    6 }, // 0010
230  { 0x0300,  5,    7 }, // 00011
231  { 0x0280,  6,    8 }, // 000101
232  { 0x0200,  6,    9 }, // 000100
233  { 0x0100,  7,   10 }, // 0000100
234  { 0x0140,  7,   11 }, // 0000101
235  { 0x01c0,  7,   12 }, // 0000111
236  { 0x0080,  8,   13 }, // 00000100
237  { 0x00e0,  8,   14 }, // 00000111
238  { 0x0180,  9,   15 }, // 000011000
239  { 0x00b8, 10,   16 }, // 0000010111
240  { 0x00c0, 10,   17 }, // 0000011000
241  { 0x0040, 10,   18 }, // 0000001000
242  { 0x019c, 11,   19 }, // 00001100111
243  { 0x01a0, 11,   20 }, // 00001101000
244  { 0x01b0, 11,   21 }, // 00001101100
245  { 0x00dc, 11,   22 }, // 00000110111
246  { 0x00a0, 11,   23 }, // 00000101000
247  { 0x005c, 11,   24 }, // 00000010111
248  { 0x0060, 11,   25 }, // 00000011000
249  { 0x0194, 12,   26 }, // 000011001010
250  { 0x0196, 12,   27 }, // 000011001011
251  { 0x0198, 12,   28 }, // 000011001100
252  { 0x019a, 12,   29 }, // 000011001101
253  { 0x00d0, 12,   30 }, // 000001101000
254  { 0x00d2, 12,   31 }, // 000001101001
255  { 0x00d4, 12,   32 }, // 000001101010
256  { 0x00d6, 12,   33 }, // 000001101011
257  { 0x01a4, 12,   34 }, // 000011010010
258  { 0x01a6, 12,   35 }, // 000011010011
259  { 0x01a8, 12,   36 }, // 000011010100
260  { 0x01aa, 12,   37 }, // 000011010101
261  { 0x01ac, 12,   38 }, // 000011010110
262  { 0x01ae, 12,   39 }, // 000011010111
263  { 0x00d8, 12,   40 }, // 000001101100
264  { 0x00da, 12,   41 }, // 000001101101
265  { 0x01b4, 12,   42 }, // 000011011010
266  { 0x01b6, 12,   43 }, // 000011011011
267  { 0x00a8, 12,   44 }, // 000001010100
268  { 0x00aa, 12,   45 }, // 000001010101
269  { 0x00ac, 12,   46 }, // 000001010110
270  { 0x00ae, 12,   47 }, // 000001010111
271  { 0x00c8, 12,   48 }, // 000001100100
272  { 0x00ca, 12,   49 }, // 000001100101
273  { 0x00a4, 12,   50 }, // 000001010010
274  { 0x00a6, 12,   51 }, // 000001010011
275  { 0x0048, 12,   52 }, // 000000100100
276  { 0x006e, 12,   53 }, // 000000110111
277  { 0x0070, 12,   54 }, // 000000111000
278  { 0x004e, 12,   55 }, // 000000100111
279  { 0x0050, 12,   56 }, // 000000101000
280  { 0x00b0, 12,   57 }, // 000001011000
281  { 0x00b2, 12,   58 }, // 000001011001
282  { 0x0056, 12,   59 }, // 000000101011
283  { 0x0058, 12,   60 }, // 000000101100
284  { 0x00b4, 12,   61 }, // 000001011010
285  { 0x00cc, 12,   62 }, // 000001100110
286  { 0x00ce, 12,   63 }, // 000001100111
287  { 0x0078, 10,   64 }, // 0000001111
288  { 0x0190, 12,  128 }, // 000011001000
289  { 0x0192, 12,  192 }, // 000011001001
290  { 0x00b6, 12,  256 }, // 000001011011
291  { 0x0066, 12,  320 }, // 000000110011
292  { 0x0068, 12,  384 }, // 000000110100
293  { 0x006a, 12,  448 }, // 000000110101
294  { 0x006c, 13,  512 }, // 0000001101100
295  { 0x006d, 13,  576 }, // 0000001101101
296  { 0x004a, 13,  640 }, // 0000001001010
297  { 0x004b, 13,  704 }, // 0000001001011
298  { 0x004c, 13,  768 }, // 0000001001100
299  { 0x004d, 13,  832 }, // 0000001001101
300  { 0x0072, 13,  896 }, // 0000001110010
301  { 0x0073, 13,  960 }, // 0000001110011
302  { 0x0074, 13, 1024 }, // 0000001110100
303  { 0x0075, 13, 1088 }, // 0000001110101
304  { 0x0076, 13, 1152 }, // 0000001110110
305  { 0x0077, 13, 1216 }, // 0000001110111
306  { 0x0052, 13, 1280 }, // 0000001010010
307  { 0x0053, 13, 1344 }, // 0000001010011
308  { 0x0054, 13, 1408 }, // 0000001010100
309  { 0x0055, 13, 1472 }, // 0000001010101
310  { 0x005a, 13, 1536 }, // 0000001011010
311  { 0x005b, 13, 1600 }, // 0000001011011
312  { 0x0064, 13, 1664 }, // 0000001100100
313  { 0x0065, 13, 1728 }, // 0000001100101
314  { 0x0020, 11, 1792 }, // 00000001000
315  { 0x0030, 11, 1856 }, // 00000001100
316  { 0x0034, 11, 1920 }, // 00000001101
317  { 0x0024, 12, 1984 }, // 000000010010
318  { 0x0026, 12, 2048 }, // 000000010011
319  { 0x0028, 12, 2112 }, // 000000010100
320  { 0x002a, 12, 2176 }, // 000000010101
321  { 0x002c, 12, 2240 }, // 000000010110
322  { 0x002e, 12, 2304 }, // 000000010111
323  { 0x0038, 12, 2368 }, // 000000011100
324  { 0x003a, 12, 2432 }, // 000000011101
325  { 0x003c, 12, 2496 }, // 000000011110
326  { 0x003e, 12, 2560 }, // 000000011111
327  { 0x0000,  0,   -1 }  // Illegal entry
328};
329
330
331
332
333// ----------------------------------------
334// SOURCE OF BITS
335
336#define VLSBUFSIZE    64
337
338class MMRDecoder::VLSource : public GPEnabled
339{
340protected:
341  VLSource(GP<ByteStream> &inp);
342  void init(const bool striped);
343public:
344  // Initializes a bit source on a bytestream
345  static GP<VLSource> create(GP<ByteStream> &inp, const bool striped);
346
347  // Synchronize on the next stripe
348  void nextstripe(void);
349  // Returns a 32 bits integer with at least the
350  // next sixteen code bits in the high order bits.
351  inline unsigned int peek(void);
352  // Ensures that next #peek()# contains at least
353  // the next 24 code bits.
354  void preload(void);
355  // Consumes #n# bits.
356  void shift(const int n);
357private:
358  GP<ByteStream> ginp;
359  ByteStream &inp;
360  unsigned char buffer[ VLSBUFSIZE ];
361  unsigned int codeword;
362  int lowbits;
363  int bufpos;
364  int bufmax;
365  int readmax;
366};
367
368MMRDecoder::VLSource::VLSource(GP<ByteStream> &xinp)
369: ginp(xinp), inp(*ginp), codeword(0), 
370  lowbits(0), bufpos(0), bufmax(0),
371  readmax(-1)
372{}
373
374void
375MMRDecoder::VLSource::init(const bool striped)
376{
377  if (striped)
378    readmax = inp.read32();
379  lowbits = 32;
380  preload();
381}
382
383GP<MMRDecoder::VLSource>
384MMRDecoder::VLSource::create(GP<ByteStream> &inp, const bool striped)
385{
386  VLSource *src=new VLSource(inp);
387  GP<VLSource> retval=src;
388  src->init(striped);
389  return retval;
390}
391
392void 
393MMRDecoder::VLSource::shift(const int n)
394{ 
395  codeword<<=n;
396  lowbits+=n;
397  if (lowbits>=16)
398    preload();
399}
400
401inline unsigned int
402MMRDecoder::VLSource::peek(void)
403{
404  return codeword;
405}
406
407
408void
409MMRDecoder::VLSource::nextstripe(void)
410{
411  while (readmax>0)
412    {
413      int size = sizeof(buffer);
414      if (readmax < size) 
415        size = readmax;
416      inp.readall(buffer, size);
417      readmax -= size;
418    }
419  bufpos = bufmax = 0;
420  memset(buffer,0,sizeof(buffer));
421  readmax = inp.read32();
422  codeword = 0; 
423  lowbits = 32;
424  preload();
425}
426
427void
428MMRDecoder::VLSource::preload(void)
429{
430  while (lowbits>=8) 
431    {
432      if (bufpos >= bufmax) 
433        {
434          // Refill buffer
435          bufpos = bufmax = 0;
436          int size = sizeof(buffer);
437          if (readmax>=0 && readmax<size) 
438            size = readmax;
439          if (size>0)
440            bufmax = inp.read((void*)buffer, size);
441          readmax -= bufmax;
442          if (bufmax <= 0)
443            return;
444        }
445      lowbits -= 8;
446      codeword |= buffer[bufpos++] << lowbits;
447    }
448}
449
450
451
452// ----------------------------------------
453// VARIABLE LENGTH CODES
454
455
456
457class MMRDecoder::VLTable : public GPEnabled
458{
459protected:
460  VLTable(const VLCode *codes);
461  void init(const int nbits);
462public:
463  // Construct a VLTable given a codebook with #nbits# long codes.
464  static GP<VLTable> create(VLCode const * const codes, const int nbits);
465
466  // Reads one symbol from a VLSource
467  int decode(MMRDecoder::VLSource *src);
468
469  const VLCode *code;
470  int codewordshift;
471  unsigned char *index;
472  GPBuffer<unsigned char> gindex;
473};
474
475GP<MMRDecoder::VLTable>
476MMRDecoder::VLTable::create(VLCode const * const codes, const int nbits)
477{
478  VLTable *table=new VLTable(codes);
479  GP<VLTable> retval=table;
480  table->init(nbits);
481  return retval;
482}
483
484inline int
485MMRDecoder::VLTable::decode(MMRDecoder::VLSource *src)   
486{ 
487  const VLCode &c = code[ index[ src->peek() >> codewordshift ] ];
488  src->shift(c.codelen); 
489  return c.value; 
490}
491
492MMRDecoder::VLTable::VLTable(const VLCode *codes)
493: code(codes), codewordshift(0), gindex(index,0)
494{}
495
496void
497MMRDecoder::VLTable::init(const int nbits)
498{
499  // count entries
500  int ncodes = 0;
501  while (code[ncodes].codelen)
502    ncodes++;
503  // check arguments
504  if (nbits<=1 || nbits>16)
505    G_THROW(invalid_mmr_data);
506  if (ncodes>=256)
507    G_THROW(invalid_mmr_data);
508  codewordshift = 32 - nbits;
509  // allocate table
510  int size = (1<<nbits);
511  gindex.resize(size);
512  gindex.set(ncodes);
513  // process codes
514  for (int i=0; i<ncodes; i++) {
515    const int c = code[i].code;
516    const int b = code[i].codelen;
517    if(b<=0 || b>nbits)
518    {
519      G_THROW(invalid_mmr_data);
520    }
521    // fill table entries whose index high bits are code.
522    int n = c + (1<<(nbits-b));
523    while ( --n >= c ) {
524      if(index[n] != ncodes)
525       G_THROW( ERR_MSG("MMRDecoder.bad_codebook") );
526      index[n] = i;
527    }
528  }
529}
530
531// ----------------------------------------
532// MMR DECODER
533
534
535
536MMRDecoder::~MMRDecoder() {}
537
538MMRDecoder::MMRDecoder( const int xwidth, const int xheight )
539: width(xwidth), height(xheight), lineno(0), 
540  striplineno(0), rowsperstrip(0), gline(line,width+8),
541  glineruns(lineruns,width+4), gprevruns(prevruns,width+4)
542{
543  gline.clear();
544  glineruns.clear();
545  gprevruns.clear();
546  lineruns[0] = width;
547  prevruns[0] = width;
548}
549
550void
551MMRDecoder::init(GP<ByteStream> gbs, const bool striped)
552{
553  rowsperstrip = (striped ? gbs->read16() : height);
554  src = VLSource::create(gbs, striped);
555  mrtable = VLTable::create(mrcodes, 7);
556  btable = VLTable::create(bcodes, 13);
557  wtable = VLTable::create(wcodes, 13);
558}
559
560GP<MMRDecoder> 
561MMRDecoder::create( GP<ByteStream> gbs, const int width,
562  const int height, const bool striped )
563{
564  MMRDecoder *mmr=new MMRDecoder(width,height);
565  GP<MMRDecoder> retval=mmr;
566  mmr->init(gbs,striped);
567  return retval;
568}
569
570const unsigned short *
571MMRDecoder::scanruns(const unsigned short **endptr)
572{
573  // Check if all lines have been returned
574  if (lineno >= height)
575    return 0;
576  // Check end of stripe
577  if ( striplineno == rowsperstrip )
578    {
579      striplineno=0;
580      lineruns[0] = prevruns[0] = width;
581      src->nextstripe();
582    }
583  // Swap run buffers
584  unsigned short *pr = lineruns;
585  unsigned short *xr = prevruns;
586  prevruns = pr;
587  lineruns = xr;
588  // Loop until scanline is complete
589  bool a0color = false;
590  int a0,rle,b1;
591  for(a0=0,rle=0,b1=*pr++;a0 < width;)
592    {
593      // Process MMR codes
594      const int c=mrtable->decode(src);
595      switch ( c )
596      {
597          /* Pass Mode */
598        case P: 
599          { 
600            b1 += *pr++;
601            rle += b1 - a0;
602            a0 = b1;
603            b1 += *pr++;
604            break;
605          }
606          /* Horizontal Mode */
607        case H: 
608          { 
609            // First run
610            VLTable &table1 = *(a0color ? btable : wtable);
611            int inc;
612            do { inc=table1.decode(src); a0+=inc; rle+=inc; } while (inc>=64);
613            *xr = rle; xr++; rle = 0;
614            // Second run
615            VLTable &table2 = *(!a0color ? btable : wtable);
616            do { inc=table2.decode(src); a0+=inc; rle+=inc; } while (inc>=64);
617            *xr = rle; xr++; rle = 0;
618            break;
619          }
620          /* Vertical Modes */
621        case V0:
622        case VR3:
623        case VR2:
624        case VR1:
625        case VL3:
626        case VL2:
627        case VL1:
628        {
629          int inc=b1;
630          switch ( c )
631          {
632          case V0:
633            inc = b1;
634            b1 += *pr++;
635            break;
636          case VR3:
637            inc = b1+3;
638            b1 += *pr++;
639            break;
640          case VR2:
641            inc = b1+2;
642            b1 += *pr++;
643            break;
644          case VR1:
645            inc = b1+1;
646            b1 += *pr++;
647            break;
648          case VL3:
649            inc = b1-3;
650            b1 -= *--pr;
651            break;
652          case VL2:
653            inc = b1-2;
654            b1 -= *--pr;
655            break;
656          case VL1:
657            inc = b1-1;
658            b1 -= *--pr;
659            break;
660          }
661          *xr = inc+rle-a0;
662          xr++;
663          a0 = inc;
664          rle = 0;
665          a0color = !a0color;
666          break;
667        }
668          /* Uncommon modes */
669        default: 
670          {
671            src->preload();
672            unsigned int m = src->peek();
673            // -- Could be EOFB ``000000000001000000000001''
674            //    TIFF6 says that all remaining lines are white
675            if ((m & 0xffffff00) == 0x00100100)
676              {
677                lineno = height;
678                return 0;
679              }
680            // -- Could be UNCOMPRESSED ``0000001111''
681            //    TIFF6 says people should not do this.
682            //    RFC1314 says people should do this.
683            else if ((m & 0xffc00000) == 0x03c00000)
684              {
685#ifdef MMRDECODER_REFUSES_UNCOMPRESSED
686                G_THROW( ERR_MSG("MMRDecoder.cant_process") );
687#else
688                // ---THE-FOLLOWING-CODE-IS-POORLY-TESTED---
689                src->shift(10);
690                while ((m = (src->peek() & 0xfc000000)))
691                  {
692                    if (m == 0x04000000)       // 000001
693                      {
694                        src->shift(6);
695                        if (a0color)
696                        {
697                          *xr = rle;
698                          xr++;
699                          rle = 0;
700                          a0color = !a0color;
701                        }
702                        rle += 5;
703                        a0 += 5;
704                      }
705                    else                       // 000010 to 111111
706                      { 
707                        src->shift(1);
708                        if (a0color == !(m & 0x80000000))
709                        {
710                          *xr = rle;
711                          xr++;
712                          rle = 0;
713                          a0color = !a0color;
714                        }
715                        rle++;
716                        a0++;
717                      }
718                    if (a0 > width)
719                      G_THROW(invalid_mmr_data);
720                  }
721                // Analyze uncompressed termination code.
722                m = src->peek() & 0xff000000; 
723                src->shift(8);
724                if ( (m & 0xfe000000) != 0x02000000 )
725                  G_THROW(invalid_mmr_data);
726                if (rle)
727                {
728                  *xr = rle;
729                  xr++;
730                  rle = 0;
731                  a0color = !a0color;
732                }                 
733                if (a0color == !(m & 0x01000000))
734                {
735                  *xr = rle;
736                  xr++;
737                  rle = 0;
738                  a0color = !a0color;
739                }
740                // Cross fingers and proceed ...
741                break;
742#endif
743              }
744            // -- Unknown MMR code.
745            G_THROW(invalid_mmr_data);
746          }
747      }
748      // Next reference run
749      for(;b1<=a0 && b1<width;pr+=2)
750      {
751        b1 += pr[0]+pr[1];
752      }
753    }
754  // Final P must be followed by V0 (they say!)
755  if (rle > 0)
756  {
757    if (mrtable->decode(src) != V0)
758    {
759      G_THROW(invalid_mmr_data);
760    }
761  }
762  if (rle > 0)
763  {
764    *xr = rle;
765    xr++;
766  }
767  // At this point we should have A0 equal to WIDTH
768  // But there are buggy files around (Kofax!)
769  // and we are not the CCITT police.
770  if (a0 > width) 
771    {
772      while (a0 > width && xr > lineruns)
773        a0 -= *--xr;
774      if (a0 < width)
775      {
776        *xr = width-a0;
777        xr++;
778      }
779    }
780  /* Increment and return */
781  if (endptr) 
782    *endptr = xr;
783  xr[0] = 0;
784  xr[1] = 0;
785  lineno ++;
786  striplineno ++;
787  return lineruns;
788}
789
790
791
792const unsigned char *
793MMRDecoder::scanrle(const bool invert, const unsigned char **endptr)
794{
795  // Obtain run lengths
796  const unsigned short *xr = scanruns();
797  if (!xr) return 0;
798  unsigned char *p=line;
799  // Process inversion
800  if (invert)
801    {
802      if (! *xr) 
803      {
804        xr++;
805      }else
806      {
807        *p = 0; p++;
808      }
809    }
810  // Encode lenghts using the RLE format
811  for(int a0=0;a0 < width;)
812  {
813    int count = *xr++;
814    a0 += count;
815    GBitmap::append_run(p, count);
816  }
817  if (endptr)
818    *endptr = p;
819  p[0] = 0;
820  p[1] = 0;
821  return line;
822}
823
824
825#if 0
826const unsigned char *
827MMRDecoder::scanline(void)
828{
829  // Obtain run lengths
830  const unsigned short *xr = scanruns();
831  if (!xr) return 0;
832  // Allocate data buffer if needed
833  unsigned char *p = line;
834  // Decode run lengths
835  int a0 = 0;
836  int a0color = 0;
837  while (a0 < width)
838    {
839      int a1 = a0 + *xr++;
840      while (a0<a1 && a0<width)
841        line[a0++] = a0color;
842      a0color = !a0color;
843    }
844  return line;
845}
846#endif
847
848
849
850
851// ----------------------------------------
852// MAIN DECODING ROUTINE
853
854bool
855MMRDecoder::decode_header(
856  ByteStream &inp, int &width, int &height, int &invert)
857{
858  unsigned long int magic = inp.read32();
859  if((magic&0xfffffffc) != 0x4d4d5200)
860    G_THROW( ERR_MSG("MMRDecoder.unrecog_header") ); 
861  invert = ((magic & 0x1) ? 1 : 0);
862  const bool strip =  ((magic & 0x2) ? 1 : 0);
863  width = inp.read16();
864  height = inp.read16();
865  if (width<=0 || height<=0)
866    G_THROW( ERR_MSG("MMRDecoder.bad_header") );
867  return strip;
868}
869
870static inline int MAX(int a, int b) { return a>b ? a : b; }
871static inline int MIN(int a, int b) { return a<b ? a : b; }
872
873GP<JB2Image>
874MMRDecoder::decode(GP<ByteStream> gbs)
875{
876  ByteStream &inp=*gbs;
877  // Read header
878  int width, height, invert;
879  const bool striped=decode_header(inp, width, height, invert);
880  // Prepare image
881  GP<JB2Image> jimg = JB2Image::create();
882  jimg->set_dimension(width, height);
883  // Choose pertinent blocksize
884  int blocksize = MIN(500,MAX(64,MAX(width/17,height/22)));
885  int blocksperline = (width+blocksize-1)/blocksize;
886  // Prepare decoder
887  GP<MMRDecoder> gdcd=MMRDecoder::create(gbs, width, height, striped);
888  MMRDecoder &dcd=*gdcd;
889  // Loop on JB2 bands
890  int line = height-1;
891  while (line >= 0)
892    {
893      int bandline = MIN(blocksize-1,line);
894      GPArray<GBitmap> blocks(0,blocksperline-1);
895      // Loop on scanlines
896      for(; bandline >= 0; bandline--,line--)
897      {
898        // Decode one scanline
899        const unsigned short *s = dcd.scanruns();
900        if (s)
901        {
902          // Loop on blocks
903          int x = 0;
904          int b = 0;
905          int firstx = 0;
906          bool c = !!invert;
907          while (x < width)
908            {
909              int xend = x + *s++;
910              while (b<blocksperline)
911                {
912                  int lastx = MIN(firstx+blocksize,width);
913                  if (c)
914                    {
915                      if (!blocks[b])
916                        blocks[b] = GBitmap::create(bandline+1, lastx-firstx);
917                      unsigned char *bptr = (*blocks[b])[bandline] - firstx;
918                      int x1 = MAX(x,firstx);
919                      int x2 = MIN(xend,lastx);
920                      while (x1 < x2)
921                        bptr[x1++] = 1;
922                    }
923                  if (xend < lastx)
924                    break;
925                  firstx = lastx;
926                  b ++;
927                }
928              x = xend;
929              c = !c; 
930            }
931        }
932      }
933      // Insert blocks into JB2Image
934      for (int b=0; b<blocksperline; b++)
935        {
936          JB2Shape shape;
937          shape.bits = blocks[b];
938          if (shape.bits) 
939            {
940              shape.parent = -1;
941              shape.bits->compress();
942              JB2Blit blit;
943              blit.left = b*blocksize;
944              blit.bottom = line+1;
945              blit.shapeno = jimg->add_shape(shape);
946              jimg->add_blit(blit);
947            }
948        }
949    }
950  // Return
951  return jimg;
952}
953
954
955
956#ifdef HAVE_NAMESPACES
957}
958# ifndef NOT_USING_DJVU_NAMESPACE
959using namespace DJVU;
960# endif
961#endif
Note: See TracBrowser for help on using the repository browser.