You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
961 lines
26 KiB
961 lines
26 KiB
//C- -------------------------------------------------------------------
|
|
//C- DjVuLibre-3.5
|
|
//C- Copyright (c) 2002 Leon Bottou and Yann Le Cun.
|
|
//C- Copyright (c) 2001 AT&T
|
|
//C-
|
|
//C- This software is subject to, and may be distributed under, the
|
|
//C- GNU General Public License, Version 2. The license should have
|
|
//C- accompanied the software or you may obtain a copy of the license
|
|
//C- from the Free Software Foundation at http://www.fsf.org .
|
|
//C-
|
|
//C- This program is distributed in the hope that it will be useful,
|
|
//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
//C- GNU General Public License for more details.
|
|
//C-
|
|
//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library
|
|
//C- distributed by Lizardtech Software. On July 19th 2002, Lizardtech
|
|
//C- Software authorized us to replace the original DjVu(r) Reference
|
|
//C- Library notice by the following text (see doc/lizard2002.djvu):
|
|
//C-
|
|
//C- ------------------------------------------------------------------
|
|
//C- | DjVu (r) Reference Library (v. 3.5)
|
|
//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
|
|
//C- | The DjVu Reference Library is protected by U.S. Pat. No.
|
|
//C- | 6,058,214 and patents pending.
|
|
//C- |
|
|
//C- | This software is subject to, and may be distributed under, the
|
|
//C- | GNU General Public License, Version 2. The license should have
|
|
//C- | accompanied the software or you may obtain a copy of the license
|
|
//C- | from the Free Software Foundation at http://www.fsf.org .
|
|
//C- |
|
|
//C- | The computer code originally released by LizardTech under this
|
|
//C- | license and unmodified by other parties is deemed "the LIZARDTECH
|
|
//C- | ORIGINAL CODE." Subject to any third party intellectual property
|
|
//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
|
|
//C- | non-exclusive license to make, use, sell, or otherwise dispose of
|
|
//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
|
|
//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
|
|
//C- | General Public License. This grant only confers the right to
|
|
//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
|
|
//C- | the extent such infringement is reasonably necessary to enable
|
|
//C- | recipient to make, have made, practice, sell, or otherwise dispose
|
|
//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
|
|
//C- | any greater extent that may be necessary to utilize further
|
|
//C- | modifications or combinations.
|
|
//C- |
|
|
//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
|
|
//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
|
|
//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
//C- +------------------------------------------------------------------
|
|
//
|
|
// $Id: MMRDecoder.cpp,v 1.8 2003/11/07 22:08:22 leonb Exp $
|
|
// $Name: release_3_5_15 $
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
#if NEED_GNUG_PRAGMAS
|
|
# pragma implementation
|
|
#endif
|
|
|
|
#include "MMRDecoder.h"
|
|
#include "JB2Image.h"
|
|
#include "ByteStream.h"
|
|
#include "GBitmap.h"
|
|
|
|
|
|
#ifdef HAVE_NAMESPACES
|
|
namespace DJVU {
|
|
# ifdef NOT_DEFINED // Just to fool emacs c++ mode
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
// ----------------------------------------
|
|
// MMR CODEBOOKS
|
|
|
|
static const char invalid_mmr_data[]= ERR_MSG("MMRDecoder.bad_data");
|
|
|
|
struct VLCode
|
|
{
|
|
unsigned short code;
|
|
short codelen;
|
|
short value;
|
|
};
|
|
|
|
enum MMRMode
|
|
{
|
|
P=0, H=1, V0=2, VR1=3, VR2=4, VR3=5, VL1=6, VL2=7, VL3=8
|
|
};
|
|
|
|
static const VLCode mrcodes[] =
|
|
{ // Codes on 7 bits
|
|
// 7 bit codes
|
|
{ 0x08, 4, P }, // 0001
|
|
{ 0x10, 3, H }, // 001
|
|
{ 0x40, 1, V0 }, // 1
|
|
{ 0x30, 3, VR1 }, // 011
|
|
{ 0x06, 6, VR2 }, // 000011
|
|
{ 0x03, 7, VR3 }, // 0000011
|
|
{ 0x20, 3, VL1 }, // 010
|
|
{ 0x04, 6, VL2 }, // 000010
|
|
{ 0x02, 7, VL3 }, // 0000010
|
|
{ 0x00, 0, -1 } // Illegal entry
|
|
};
|
|
|
|
|
|
static const VLCode wcodes[] = {
|
|
// 13 bit codes
|
|
{ 0x06a0, 8, 0 }, // 00110101
|
|
{ 0x0380, 6, 1 }, // 000111
|
|
{ 0x0e00, 4, 2 }, // 0111
|
|
{ 0x1000, 4, 3 }, // 1000
|
|
{ 0x1600, 4, 4 }, // 1011
|
|
{ 0x1800, 4, 5 }, // 1100
|
|
{ 0x1c00, 4, 6 }, // 1110
|
|
{ 0x1e00, 4, 7 }, // 1111
|
|
{ 0x1300, 5, 8 }, // 10011
|
|
{ 0x1400, 5, 9 }, // 10100
|
|
{ 0x0700, 5, 10 }, // 00111
|
|
{ 0x0800, 5, 11 }, // 01000
|
|
{ 0x0400, 6, 12 }, // 001000
|
|
{ 0x0180, 6, 13 }, // 000011
|
|
{ 0x1a00, 6, 14 }, // 110100
|
|
{ 0x1a80, 6, 15 }, // 110101
|
|
{ 0x1500, 6, 16 }, // 101010
|
|
{ 0x1580, 6, 17 }, // 101011
|
|
{ 0x09c0, 7, 18 }, // 0100111
|
|
{ 0x0300, 7, 19 }, // 0001100
|
|
{ 0x0200, 7, 20 }, // 0001000
|
|
{ 0x05c0, 7, 21 }, // 0010111
|
|
{ 0x00c0, 7, 22 }, // 0000011
|
|
{ 0x0100, 7, 23 }, // 0000100
|
|
{ 0x0a00, 7, 24 }, // 0101000
|
|
{ 0x0ac0, 7, 25 }, // 0101011
|
|
{ 0x04c0, 7, 26 }, // 0010011
|
|
{ 0x0900, 7, 27 }, // 0100100
|
|
{ 0x0600, 7, 28 }, // 0011000
|
|
{ 0x0040, 8, 29 }, // 00000010
|
|
{ 0x0060, 8, 30 }, // 00000011
|
|
{ 0x0340, 8, 31 }, // 00011010
|
|
{ 0x0360, 8, 32 }, // 00011011
|
|
{ 0x0240, 8, 33 }, // 00010010
|
|
{ 0x0260, 8, 34 }, // 00010011
|
|
{ 0x0280, 8, 35 }, // 00010100
|
|
{ 0x02a0, 8, 36 }, // 00010101
|
|
{ 0x02c0, 8, 37 }, // 00010110
|
|
{ 0x02e0, 8, 38 }, // 00010111
|
|
{ 0x0500, 8, 39 }, // 00101000
|
|
{ 0x0520, 8, 40 }, // 00101001
|
|
{ 0x0540, 8, 41 }, // 00101010
|
|
{ 0x0560, 8, 42 }, // 00101011
|
|
{ 0x0580, 8, 43 }, // 00101100
|
|
{ 0x05a0, 8, 44 }, // 00101101
|
|
{ 0x0080, 8, 45 }, // 00000100
|
|
{ 0x00a0, 8, 46 }, // 00000101
|
|
{ 0x0140, 8, 47 }, // 00001010
|
|
{ 0x0160, 8, 48 }, // 00001011
|
|
{ 0x0a40, 8, 49 }, // 01010010
|
|
{ 0x0a60, 8, 50 }, // 01010011
|
|
{ 0x0a80, 8, 51 }, // 01010100
|
|
{ 0x0aa0, 8, 52 }, // 01010101
|
|
{ 0x0480, 8, 53 }, // 00100100
|
|
{ 0x04a0, 8, 54 }, // 00100101
|
|
{ 0x0b00, 8, 55 }, // 01011000
|
|
{ 0x0b20, 8, 56 }, // 01011001
|
|
{ 0x0b40, 8, 57 }, // 01011010
|
|
{ 0x0b60, 8, 58 }, // 01011011
|
|
{ 0x0940, 8, 59 }, // 01001010
|
|
{ 0x0960, 8, 60 }, // 01001011
|
|
{ 0x0640, 8, 61 }, // 00110010
|
|
{ 0x0660, 8, 62 }, // 00110011
|
|
{ 0x0680, 8, 63 }, // 00110100
|
|
{ 0x1b00, 5, 64 }, // 11011
|
|
{ 0x1200, 5, 128 }, // 10010
|
|
{ 0x0b80, 6, 192 }, // 010111
|
|
{ 0x0dc0, 7, 256 }, // 0110111
|
|
{ 0x06c0, 8, 320 }, // 00110110
|
|
{ 0x06e0, 8, 384 }, // 00110111
|
|
{ 0x0c80, 8, 448 }, // 01100100
|
|
{ 0x0ca0, 8, 512 }, // 01100101
|
|
{ 0x0d00, 8, 576 }, // 01101000
|
|
{ 0x0ce0, 8, 640 }, // 01100111
|
|
{ 0x0cc0, 9, 704 }, // 011001100
|
|
{ 0x0cd0, 9, 768 }, // 011001101
|
|
{ 0x0d20, 9, 832 }, // 011010010
|
|
{ 0x0d30, 9, 896 }, // 011010011
|
|
{ 0x0d40, 9, 960 }, // 011010100
|
|
{ 0x0d50, 9, 1024 }, // 011010101
|
|
{ 0x0d60, 9, 1088 }, // 011010110
|
|
{ 0x0d70, 9, 1152 }, // 011010111
|
|
{ 0x0d80, 9, 1216 }, // 011011000
|
|
{ 0x0d90, 9, 1280 }, // 011011001
|
|
{ 0x0da0, 9, 1344 }, // 011011010
|
|
{ 0x0db0, 9, 1408 }, // 011011011
|
|
{ 0x0980, 9, 1472 }, // 010011000
|
|
{ 0x0990, 9, 1536 }, // 010011001
|
|
{ 0x09a0, 9, 1600 }, // 010011010
|
|
{ 0x0c00, 6, 1664 }, // 011000 (what did they think?)
|
|
{ 0x09b0, 9, 1728 }, // 010011011
|
|
{ 0x0020, 11, 1792 }, // 00000001000
|
|
{ 0x0030, 11, 1856 }, // 00000001100
|
|
{ 0x0034, 11, 1920 }, // 00000001101
|
|
{ 0x0024, 12, 1984 }, // 000000010010
|
|
{ 0x0026, 12, 2048 }, // 000000010011
|
|
{ 0x0028, 12, 2112 }, // 000000010100
|
|
{ 0x002a, 12, 2176 }, // 000000010101
|
|
{ 0x002c, 12, 2240 }, // 000000010110
|
|
{ 0x002e, 12, 2304 }, // 000000010111
|
|
{ 0x0038, 12, 2368 }, // 000000011100
|
|
{ 0x003a, 12, 2432 }, // 000000011101
|
|
{ 0x003c, 12, 2496 }, // 000000011110
|
|
{ 0x003e, 12, 2560 }, // 000000011111
|
|
{ 0x0000, 0, -1 } // Illegal entry
|
|
};
|
|
|
|
|
|
static const VLCode bcodes[] = {
|
|
// 13 bit codes
|
|
{ 0x01b8, 10, 0 }, // 0000110111
|
|
{ 0x0800, 3, 1 }, // 010
|
|
{ 0x1800, 2, 2 }, // 11
|
|
{ 0x1000, 2, 3 }, // 10
|
|
{ 0x0c00, 3, 4 }, // 011
|
|
{ 0x0600, 4, 5 }, // 0011
|
|
{ 0x0400, 4, 6 }, // 0010
|
|
{ 0x0300, 5, 7 }, // 00011
|
|
{ 0x0280, 6, 8 }, // 000101
|
|
{ 0x0200, 6, 9 }, // 000100
|
|
{ 0x0100, 7, 10 }, // 0000100
|
|
{ 0x0140, 7, 11 }, // 0000101
|
|
{ 0x01c0, 7, 12 }, // 0000111
|
|
{ 0x0080, 8, 13 }, // 00000100
|
|
{ 0x00e0, 8, 14 }, // 00000111
|
|
{ 0x0180, 9, 15 }, // 000011000
|
|
{ 0x00b8, 10, 16 }, // 0000010111
|
|
{ 0x00c0, 10, 17 }, // 0000011000
|
|
{ 0x0040, 10, 18 }, // 0000001000
|
|
{ 0x019c, 11, 19 }, // 00001100111
|
|
{ 0x01a0, 11, 20 }, // 00001101000
|
|
{ 0x01b0, 11, 21 }, // 00001101100
|
|
{ 0x00dc, 11, 22 }, // 00000110111
|
|
{ 0x00a0, 11, 23 }, // 00000101000
|
|
{ 0x005c, 11, 24 }, // 00000010111
|
|
{ 0x0060, 11, 25 }, // 00000011000
|
|
{ 0x0194, 12, 26 }, // 000011001010
|
|
{ 0x0196, 12, 27 }, // 000011001011
|
|
{ 0x0198, 12, 28 }, // 000011001100
|
|
{ 0x019a, 12, 29 }, // 000011001101
|
|
{ 0x00d0, 12, 30 }, // 000001101000
|
|
{ 0x00d2, 12, 31 }, // 000001101001
|
|
{ 0x00d4, 12, 32 }, // 000001101010
|
|
{ 0x00d6, 12, 33 }, // 000001101011
|
|
{ 0x01a4, 12, 34 }, // 000011010010
|
|
{ 0x01a6, 12, 35 }, // 000011010011
|
|
{ 0x01a8, 12, 36 }, // 000011010100
|
|
{ 0x01aa, 12, 37 }, // 000011010101
|
|
{ 0x01ac, 12, 38 }, // 000011010110
|
|
{ 0x01ae, 12, 39 }, // 000011010111
|
|
{ 0x00d8, 12, 40 }, // 000001101100
|
|
{ 0x00da, 12, 41 }, // 000001101101
|
|
{ 0x01b4, 12, 42 }, // 000011011010
|
|
{ 0x01b6, 12, 43 }, // 000011011011
|
|
{ 0x00a8, 12, 44 }, // 000001010100
|
|
{ 0x00aa, 12, 45 }, // 000001010101
|
|
{ 0x00ac, 12, 46 }, // 000001010110
|
|
{ 0x00ae, 12, 47 }, // 000001010111
|
|
{ 0x00c8, 12, 48 }, // 000001100100
|
|
{ 0x00ca, 12, 49 }, // 000001100101
|
|
{ 0x00a4, 12, 50 }, // 000001010010
|
|
{ 0x00a6, 12, 51 }, // 000001010011
|
|
{ 0x0048, 12, 52 }, // 000000100100
|
|
{ 0x006e, 12, 53 }, // 000000110111
|
|
{ 0x0070, 12, 54 }, // 000000111000
|
|
{ 0x004e, 12, 55 }, // 000000100111
|
|
{ 0x0050, 12, 56 }, // 000000101000
|
|
{ 0x00b0, 12, 57 }, // 000001011000
|
|
{ 0x00b2, 12, 58 }, // 000001011001
|
|
{ 0x0056, 12, 59 }, // 000000101011
|
|
{ 0x0058, 12, 60 }, // 000000101100
|
|
{ 0x00b4, 12, 61 }, // 000001011010
|
|
{ 0x00cc, 12, 62 }, // 000001100110
|
|
{ 0x00ce, 12, 63 }, // 000001100111
|
|
{ 0x0078, 10, 64 }, // 0000001111
|
|
{ 0x0190, 12, 128 }, // 000011001000
|
|
{ 0x0192, 12, 192 }, // 000011001001
|
|
{ 0x00b6, 12, 256 }, // 000001011011
|
|
{ 0x0066, 12, 320 }, // 000000110011
|
|
{ 0x0068, 12, 384 }, // 000000110100
|
|
{ 0x006a, 12, 448 }, // 000000110101
|
|
{ 0x006c, 13, 512 }, // 0000001101100
|
|
{ 0x006d, 13, 576 }, // 0000001101101
|
|
{ 0x004a, 13, 640 }, // 0000001001010
|
|
{ 0x004b, 13, 704 }, // 0000001001011
|
|
{ 0x004c, 13, 768 }, // 0000001001100
|
|
{ 0x004d, 13, 832 }, // 0000001001101
|
|
{ 0x0072, 13, 896 }, // 0000001110010
|
|
{ 0x0073, 13, 960 }, // 0000001110011
|
|
{ 0x0074, 13, 1024 }, // 0000001110100
|
|
{ 0x0075, 13, 1088 }, // 0000001110101
|
|
{ 0x0076, 13, 1152 }, // 0000001110110
|
|
{ 0x0077, 13, 1216 }, // 0000001110111
|
|
{ 0x0052, 13, 1280 }, // 0000001010010
|
|
{ 0x0053, 13, 1344 }, // 0000001010011
|
|
{ 0x0054, 13, 1408 }, // 0000001010100
|
|
{ 0x0055, 13, 1472 }, // 0000001010101
|
|
{ 0x005a, 13, 1536 }, // 0000001011010
|
|
{ 0x005b, 13, 1600 }, // 0000001011011
|
|
{ 0x0064, 13, 1664 }, // 0000001100100
|
|
{ 0x0065, 13, 1728 }, // 0000001100101
|
|
{ 0x0020, 11, 1792 }, // 00000001000
|
|
{ 0x0030, 11, 1856 }, // 00000001100
|
|
{ 0x0034, 11, 1920 }, // 00000001101
|
|
{ 0x0024, 12, 1984 }, // 000000010010
|
|
{ 0x0026, 12, 2048 }, // 000000010011
|
|
{ 0x0028, 12, 2112 }, // 000000010100
|
|
{ 0x002a, 12, 2176 }, // 000000010101
|
|
{ 0x002c, 12, 2240 }, // 000000010110
|
|
{ 0x002e, 12, 2304 }, // 000000010111
|
|
{ 0x0038, 12, 2368 }, // 000000011100
|
|
{ 0x003a, 12, 2432 }, // 000000011101
|
|
{ 0x003c, 12, 2496 }, // 000000011110
|
|
{ 0x003e, 12, 2560 }, // 000000011111
|
|
{ 0x0000, 0, -1 } // Illegal entry
|
|
};
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------
|
|
// SOURCE OF BITS
|
|
|
|
#define VLSBUFSIZE 64
|
|
|
|
class MMRDecoder::VLSource : public GPEnabled
|
|
{
|
|
protected:
|
|
VLSource(GP<ByteStream> &inp);
|
|
void init(const bool striped);
|
|
public:
|
|
// Initializes a bit source on a bytestream
|
|
static GP<VLSource> create(GP<ByteStream> &inp, const bool striped);
|
|
|
|
// Synchronize on the next stripe
|
|
void nextstripe(void);
|
|
// Returns a 32 bits integer with at least the
|
|
// next sixteen code bits in the high order bits.
|
|
inline unsigned int peek(void);
|
|
// Ensures that next #peek()# contains at least
|
|
// the next 24 code bits.
|
|
void preload(void);
|
|
// Consumes #n# bits.
|
|
void shift(const int n);
|
|
private:
|
|
GP<ByteStream> ginp;
|
|
ByteStream &inp;
|
|
unsigned char buffer[ VLSBUFSIZE ];
|
|
unsigned int codeword;
|
|
int lowbits;
|
|
int bufpos;
|
|
int bufmax;
|
|
int readmax;
|
|
};
|
|
|
|
MMRDecoder::VLSource::VLSource(GP<ByteStream> &xinp)
|
|
: ginp(xinp), inp(*ginp), codeword(0),
|
|
lowbits(0), bufpos(0), bufmax(0),
|
|
readmax(-1)
|
|
{}
|
|
|
|
void
|
|
MMRDecoder::VLSource::init(const bool striped)
|
|
{
|
|
if (striped)
|
|
readmax = inp.read32();
|
|
lowbits = 32;
|
|
preload();
|
|
}
|
|
|
|
GP<MMRDecoder::VLSource>
|
|
MMRDecoder::VLSource::create(GP<ByteStream> &inp, const bool striped)
|
|
{
|
|
VLSource *src=new VLSource(inp);
|
|
GP<VLSource> retval=src;
|
|
src->init(striped);
|
|
return retval;
|
|
}
|
|
|
|
void
|
|
MMRDecoder::VLSource::shift(const int n)
|
|
{
|
|
codeword<<=n;
|
|
lowbits+=n;
|
|
if (lowbits>=16)
|
|
preload();
|
|
}
|
|
|
|
inline unsigned int
|
|
MMRDecoder::VLSource::peek(void)
|
|
{
|
|
return codeword;
|
|
}
|
|
|
|
|
|
void
|
|
MMRDecoder::VLSource::nextstripe(void)
|
|
{
|
|
while (readmax>0)
|
|
{
|
|
int size = sizeof(buffer);
|
|
if (readmax < size)
|
|
size = readmax;
|
|
inp.readall(buffer, size);
|
|
readmax -= size;
|
|
}
|
|
bufpos = bufmax = 0;
|
|
memset(buffer,0,sizeof(buffer));
|
|
readmax = inp.read32();
|
|
codeword = 0;
|
|
lowbits = 32;
|
|
preload();
|
|
}
|
|
|
|
void
|
|
MMRDecoder::VLSource::preload(void)
|
|
{
|
|
while (lowbits>=8)
|
|
{
|
|
if (bufpos >= bufmax)
|
|
{
|
|
// Refill buffer
|
|
bufpos = bufmax = 0;
|
|
int size = sizeof(buffer);
|
|
if (readmax>=0 && readmax<size)
|
|
size = readmax;
|
|
if (size>0)
|
|
bufmax = inp.read((void*)buffer, size);
|
|
readmax -= bufmax;
|
|
if (bufmax <= 0)
|
|
return;
|
|
}
|
|
lowbits -= 8;
|
|
codeword |= buffer[bufpos++] << lowbits;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------
|
|
// VARIABLE LENGTH CODES
|
|
|
|
|
|
|
|
class MMRDecoder::VLTable : public GPEnabled
|
|
{
|
|
protected:
|
|
VLTable(const VLCode *codes);
|
|
void init(const int nbits);
|
|
public:
|
|
// Construct a VLTable given a codebook with #nbits# long codes.
|
|
static GP<VLTable> create(VLCode const * const codes, const int nbits);
|
|
|
|
// Reads one symbol from a VLSource
|
|
int decode(MMRDecoder::VLSource *src);
|
|
|
|
const VLCode *code;
|
|
int codewordshift;
|
|
unsigned char *index;
|
|
GPBuffer<unsigned char> gindex;
|
|
};
|
|
|
|
GP<MMRDecoder::VLTable>
|
|
MMRDecoder::VLTable::create(VLCode const * const codes, const int nbits)
|
|
{
|
|
VLTable *table=new VLTable(codes);
|
|
GP<VLTable> retval=table;
|
|
table->init(nbits);
|
|
return retval;
|
|
}
|
|
|
|
inline int
|
|
MMRDecoder::VLTable::decode(MMRDecoder::VLSource *src)
|
|
{
|
|
const VLCode &c = code[ index[ src->peek() >> codewordshift ] ];
|
|
src->shift(c.codelen);
|
|
return c.value;
|
|
}
|
|
|
|
MMRDecoder::VLTable::VLTable(const VLCode *codes)
|
|
: code(codes), codewordshift(0), gindex(index,0)
|
|
{}
|
|
|
|
void
|
|
MMRDecoder::VLTable::init(const int nbits)
|
|
{
|
|
// count entries
|
|
int ncodes = 0;
|
|
while (code[ncodes].codelen)
|
|
ncodes++;
|
|
// check arguments
|
|
if (nbits<=1 || nbits>16)
|
|
G_THROW(invalid_mmr_data);
|
|
if (ncodes>=256)
|
|
G_THROW(invalid_mmr_data);
|
|
codewordshift = 32 - nbits;
|
|
// allocate table
|
|
int size = (1<<nbits);
|
|
gindex.resize(size);
|
|
gindex.set(ncodes);
|
|
// process codes
|
|
for (int i=0; i<ncodes; i++) {
|
|
const int c = code[i].code;
|
|
const int b = code[i].codelen;
|
|
if(b<=0 || b>nbits)
|
|
{
|
|
G_THROW(invalid_mmr_data);
|
|
}
|
|
// fill table entries whose index high bits are code.
|
|
int n = c + (1<<(nbits-b));
|
|
while ( --n >= c ) {
|
|
if(index[n] != ncodes)
|
|
G_THROW( ERR_MSG("MMRDecoder.bad_codebook") );
|
|
index[n] = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------
|
|
// MMR DECODER
|
|
|
|
|
|
|
|
MMRDecoder::~MMRDecoder() {}
|
|
|
|
MMRDecoder::MMRDecoder( const int xwidth, const int xheight )
|
|
: width(xwidth), height(xheight), lineno(0),
|
|
striplineno(0), rowsperstrip(0), gline(line,width+8),
|
|
glineruns(lineruns,width+4), gprevruns(prevruns,width+4)
|
|
{
|
|
gline.clear();
|
|
glineruns.clear();
|
|
gprevruns.clear();
|
|
lineruns[0] = width;
|
|
prevruns[0] = width;
|
|
}
|
|
|
|
void
|
|
MMRDecoder::init(GP<ByteStream> gbs, const bool striped)
|
|
{
|
|
rowsperstrip = (striped ? gbs->read16() : height);
|
|
src = VLSource::create(gbs, striped);
|
|
mrtable = VLTable::create(mrcodes, 7);
|
|
btable = VLTable::create(bcodes, 13);
|
|
wtable = VLTable::create(wcodes, 13);
|
|
}
|
|
|
|
GP<MMRDecoder>
|
|
MMRDecoder::create( GP<ByteStream> gbs, const int width,
|
|
const int height, const bool striped )
|
|
{
|
|
MMRDecoder *mmr=new MMRDecoder(width,height);
|
|
GP<MMRDecoder> retval=mmr;
|
|
mmr->init(gbs,striped);
|
|
return retval;
|
|
}
|
|
|
|
const unsigned short *
|
|
MMRDecoder::scanruns(const unsigned short **endptr)
|
|
{
|
|
// Check if all lines have been returned
|
|
if (lineno >= height)
|
|
return 0;
|
|
// Check end of stripe
|
|
if ( striplineno == rowsperstrip )
|
|
{
|
|
striplineno=0;
|
|
lineruns[0] = prevruns[0] = width;
|
|
src->nextstripe();
|
|
}
|
|
// Swap run buffers
|
|
unsigned short *pr = lineruns;
|
|
unsigned short *xr = prevruns;
|
|
prevruns = pr;
|
|
lineruns = xr;
|
|
// Loop until scanline is complete
|
|
bool a0color = false;
|
|
int a0,rle,b1;
|
|
for(a0=0,rle=0,b1=*pr++;a0 < width;)
|
|
{
|
|
// Process MMR codes
|
|
const int c=mrtable->decode(src);
|
|
switch ( c )
|
|
{
|
|
/* Pass Mode */
|
|
case P:
|
|
{
|
|
b1 += *pr++;
|
|
rle += b1 - a0;
|
|
a0 = b1;
|
|
b1 += *pr++;
|
|
break;
|
|
}
|
|
/*Qt::Horizontal Mode */
|
|
case H:
|
|
{
|
|
// First run
|
|
VLTable &table1 = *(a0color ? btable : wtable);
|
|
int inc;
|
|
do { inc=table1.decode(src); a0+=inc; rle+=inc; } while (inc>=64);
|
|
*xr = rle; xr++; rle = 0;
|
|
// Second run
|
|
VLTable &table2 = *(!a0color ? btable : wtable);
|
|
do { inc=table2.decode(src); a0+=inc; rle+=inc; } while (inc>=64);
|
|
*xr = rle; xr++; rle = 0;
|
|
break;
|
|
}
|
|
/*Qt::Vertical Modes */
|
|
case V0:
|
|
case VR3:
|
|
case VR2:
|
|
case VR1:
|
|
case VL3:
|
|
case VL2:
|
|
case VL1:
|
|
{
|
|
int inc=b1;
|
|
switch ( c )
|
|
{
|
|
case V0:
|
|
inc = b1;
|
|
b1 += *pr++;
|
|
break;
|
|
case VR3:
|
|
inc = b1+3;
|
|
b1 += *pr++;
|
|
break;
|
|
case VR2:
|
|
inc = b1+2;
|
|
b1 += *pr++;
|
|
break;
|
|
case VR1:
|
|
inc = b1+1;
|
|
b1 += *pr++;
|
|
break;
|
|
case VL3:
|
|
inc = b1-3;
|
|
b1 -= *--pr;
|
|
break;
|
|
case VL2:
|
|
inc = b1-2;
|
|
b1 -= *--pr;
|
|
break;
|
|
case VL1:
|
|
inc = b1-1;
|
|
b1 -= *--pr;
|
|
break;
|
|
}
|
|
*xr = inc+rle-a0;
|
|
xr++;
|
|
a0 = inc;
|
|
rle = 0;
|
|
a0color = !a0color;
|
|
break;
|
|
}
|
|
/* Uncommon modes */
|
|
default:
|
|
{
|
|
src->preload();
|
|
unsigned int m = src->peek();
|
|
// -- Could be EOFB ``000000000001000000000001''
|
|
// TIFF6 says that all remaining lines are white
|
|
if ((m & 0xffffff00) == 0x00100100)
|
|
{
|
|
lineno = height;
|
|
return 0;
|
|
}
|
|
// -- Could be UNCOMPRESSED ``0000001111''
|
|
// TIFF6 says people should not do this.
|
|
// RFC1314 says people should do this.
|
|
else if ((m & 0xffc00000) == 0x03c00000)
|
|
{
|
|
#ifdef MMRDECODER_REFUSES_UNCOMPRESSED
|
|
G_THROW( ERR_MSG("MMRDecoder.cant_process") );
|
|
#else
|
|
// ---THE-FOLLOWING-CODE-IS-POORLY-TESTED---
|
|
src->shift(10);
|
|
while ((m = (src->peek() & 0xfc000000)))
|
|
{
|
|
if (m == 0x04000000) // 000001
|
|
{
|
|
src->shift(6);
|
|
if (a0color)
|
|
{
|
|
*xr = rle;
|
|
xr++;
|
|
rle = 0;
|
|
a0color = !a0color;
|
|
}
|
|
rle += 5;
|
|
a0 += 5;
|
|
}
|
|
else // 000010 to 111111
|
|
{
|
|
src->shift(1);
|
|
if (a0color == !(m & 0x80000000))
|
|
{
|
|
*xr = rle;
|
|
xr++;
|
|
rle = 0;
|
|
a0color = !a0color;
|
|
}
|
|
rle++;
|
|
a0++;
|
|
}
|
|
if (a0 > width)
|
|
G_THROW(invalid_mmr_data);
|
|
}
|
|
// Analyze uncompressed termination code.
|
|
m = src->peek() & 0xff000000;
|
|
src->shift(8);
|
|
if ( (m & 0xfe000000) != 0x02000000 )
|
|
G_THROW(invalid_mmr_data);
|
|
if (rle)
|
|
{
|
|
*xr = rle;
|
|
xr++;
|
|
rle = 0;
|
|
a0color = !a0color;
|
|
}
|
|
if (a0color == !(m & 0x01000000))
|
|
{
|
|
*xr = rle;
|
|
xr++;
|
|
rle = 0;
|
|
a0color = !a0color;
|
|
}
|
|
// Cross fingers and proceed ...
|
|
break;
|
|
#endif
|
|
}
|
|
// -- Unknown MMR code.
|
|
G_THROW(invalid_mmr_data);
|
|
}
|
|
}
|
|
// Next reference run
|
|
for(;b1<=a0 && b1<width;pr+=2)
|
|
{
|
|
b1 += pr[0]+pr[1];
|
|
}
|
|
}
|
|
// Final P must be followed by V0 (they say!)
|
|
if (rle > 0)
|
|
{
|
|
if (mrtable->decode(src) != V0)
|
|
{
|
|
G_THROW(invalid_mmr_data);
|
|
}
|
|
}
|
|
if (rle > 0)
|
|
{
|
|
*xr = rle;
|
|
xr++;
|
|
}
|
|
// At this point we should have A0 equal to WIDTH
|
|
// But there are buggy files around (Kofax!)
|
|
// and we are not the CCITT police.
|
|
if (a0 > width)
|
|
{
|
|
while (a0 > width && xr > lineruns)
|
|
a0 -= *--xr;
|
|
if (a0 < width)
|
|
{
|
|
*xr = width-a0;
|
|
xr++;
|
|
}
|
|
}
|
|
/* Increment and return */
|
|
if (endptr)
|
|
*endptr = xr;
|
|
xr[0] = 0;
|
|
xr[1] = 0;
|
|
lineno ++;
|
|
striplineno ++;
|
|
return lineruns;
|
|
}
|
|
|
|
|
|
|
|
const unsigned char *
|
|
MMRDecoder::scanrle(const bool invert, const unsigned char **endptr)
|
|
{
|
|
// Obtain run lengths
|
|
const unsigned short *xr = scanruns();
|
|
if (!xr) return 0;
|
|
unsigned char *p=line;
|
|
// Process inversion
|
|
if (invert)
|
|
{
|
|
if (! *xr)
|
|
{
|
|
xr++;
|
|
}else
|
|
{
|
|
*p = 0; p++;
|
|
}
|
|
}
|
|
// Encode lengths using the RLE format
|
|
for(int a0=0;a0 < width;)
|
|
{
|
|
int count = *xr++;
|
|
a0 += count;
|
|
GBitmap::append_run(p, count);
|
|
}
|
|
if (endptr)
|
|
*endptr = p;
|
|
p[0] = 0;
|
|
p[1] = 0;
|
|
return line;
|
|
}
|
|
|
|
|
|
#if 0
|
|
const unsigned char *
|
|
MMRDecoder::scanline(void)
|
|
{
|
|
// Obtain run lengths
|
|
const unsigned short *xr = scanruns();
|
|
if (!xr) return 0;
|
|
// Allocate data buffer if needed
|
|
unsigned char *p = line;
|
|
// Decode run lengths
|
|
int a0 = 0;
|
|
int a0color = 0;
|
|
while (a0 < width)
|
|
{
|
|
int a1 = a0 + *xr++;
|
|
while (a0<a1 && a0<width)
|
|
line[a0++] = a0color;
|
|
a0color = !a0color;
|
|
}
|
|
return line;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------
|
|
// MAIN DECODING ROUTINE
|
|
|
|
bool
|
|
MMRDecoder::decode_header(
|
|
ByteStream &inp, int &width, int &height, int &invert)
|
|
{
|
|
unsigned long int magic = inp.read32();
|
|
if((magic&0xfffffffc) != 0x4d4d5200)
|
|
G_THROW( ERR_MSG("MMRDecoder.unrecog_header") );
|
|
invert = ((magic & 0x1) ? 1 : 0);
|
|
const bool strip = ((magic & 0x2) ? 1 : 0);
|
|
width = inp.read16();
|
|
height = inp.read16();
|
|
if (width<=0 || height<=0)
|
|
G_THROW( ERR_MSG("MMRDecoder.bad_header") );
|
|
return strip;
|
|
}
|
|
|
|
static inline int MAX(int a, int b) { return a>b ? a : b; }
|
|
static inline int MIN(int a, int b) { return a<b ? a : b; }
|
|
|
|
GP<JB2Image>
|
|
MMRDecoder::decode(GP<ByteStream> gbs)
|
|
{
|
|
ByteStream &inp=*gbs;
|
|
// Read header
|
|
int width, height, invert;
|
|
const bool striped=decode_header(inp, width, height, invert);
|
|
// Prepare image
|
|
GP<JB2Image> jimg = JB2Image::create();
|
|
jimg->set_dimension(width, height);
|
|
// Choose pertinent blocksize
|
|
int blocksize = MIN(500,MAX(64,MAX(width/17,height/22)));
|
|
int blocksperline = (width+blocksize-1)/blocksize;
|
|
// Prepare decoder
|
|
GP<MMRDecoder> gdcd=MMRDecoder::create(gbs, width, height, striped);
|
|
MMRDecoder &dcd=*gdcd;
|
|
// Loop on JB2 bands
|
|
int line = height-1;
|
|
while (line >= 0)
|
|
{
|
|
int bandline = MIN(blocksize-1,line);
|
|
GPArray<GBitmap> blocks(0,blocksperline-1);
|
|
// Loop on scanlines
|
|
for(; bandline >= 0; bandline--,line--)
|
|
{
|
|
// Decode one scanline
|
|
const unsigned short *s = dcd.scanruns();
|
|
if (s)
|
|
{
|
|
// Loop on blocks
|
|
int x = 0;
|
|
int b = 0;
|
|
int firstx = 0;
|
|
bool c = !!invert;
|
|
while (x < width)
|
|
{
|
|
int xend = x + *s++;
|
|
while (b<blocksperline)
|
|
{
|
|
int lastx = MIN(firstx+blocksize,width);
|
|
if (c)
|
|
{
|
|
if (!blocks[b])
|
|
blocks[b] = GBitmap::create(bandline+1, lastx-firstx);
|
|
unsigned char *bptr = (*blocks[b])[bandline] - firstx;
|
|
int x1 = MAX(x,firstx);
|
|
int x2 = MIN(xend,lastx);
|
|
while (x1 < x2)
|
|
bptr[x1++] = 1;
|
|
}
|
|
if (xend < lastx)
|
|
break;
|
|
firstx = lastx;
|
|
b ++;
|
|
}
|
|
x = xend;
|
|
c = !c;
|
|
}
|
|
}
|
|
}
|
|
// Insert blocks into JB2Image
|
|
for (int b=0; b<blocksperline; b++)
|
|
{
|
|
JB2Shape shape;
|
|
shape.bits = blocks[b];
|
|
if (shape.bits)
|
|
{
|
|
shape.parent = -1;
|
|
shape.bits->compress();
|
|
JB2Blit blit;
|
|
blit.left = b*blocksize;
|
|
blit.bottom = line+1;
|
|
blit.shapeno = jimg->add_shape(shape);
|
|
jimg->add_blit(blit);
|
|
}
|
|
}
|
|
}
|
|
// Return
|
|
return jimg;
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_NAMESPACES
|
|
}
|
|
# ifndef NOT_USING_DJVU_NAMESPACE
|
|
using namespace DJVU;
|
|
# endif
|
|
#endif
|