//C- -*- C++ -*- //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 &inp); void init(const bool striped); public: // Initializes a bit source on a bytestream static GP create(GP &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 ginp; ByteStream &inp; unsigned char buffer[ VLSBUFSIZE ]; unsigned int codeword; int lowbits; int bufpos; int bufmax; int readmax; }; MMRDecoder::VLSource::VLSource(GP &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::create(GP &inp, const bool striped) { VLSource *src=new VLSource(inp); GP 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 && readmax0) 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 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 gindex; }; GP MMRDecoder::VLTable::create(VLCode const * const codes, const int nbits) { VLTable *table=new VLTable(codes); GP 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) { 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 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::create( GP gbs, const int width, const int height, const bool striped ) { MMRDecoder *mmr=new MMRDecoder(width,height); GP 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; } /* 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; } /* 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 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 lenghts 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 (a0b ? a : b; } static inline int MIN(int a, int b) { return a MMRDecoder::decode(GP gbs) { ByteStream &inp=*gbs; // Read header int width, height, invert; const bool striped=decode_header(inp, width, height, invert); // Prepare image GP 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 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 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 (bcompress(); 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