|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* libopenraw - ljpegdecompressor.cpp
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Copyright (C) 2007-2016 Hubert Figuiere
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* This library is free software: you can redistribute it and/or
|
|
rpm-build |
d2b433 |
* modify it under the terms of the GNU Lesser General Public License
|
|
rpm-build |
d2b433 |
* as published by the Free Software Foundation, either version 3 of
|
|
rpm-build |
d2b433 |
* the License, or (at your option) any later version.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* This library is distributed in the hope that it will be useful,
|
|
rpm-build |
d2b433 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
rpm-build |
d2b433 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
rpm-build |
d2b433 |
* Lesser General Public License for more details.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* You should have received a copy of the GNU Lesser General Public
|
|
rpm-build |
d2b433 |
* License along with this library. If not, see
|
|
rpm-build |
d2b433 |
* <http://www.gnu.org/licenses/>.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Code for JPEG lossless decoding. Large parts are grabbed from the IJG
|
|
rpm-build |
d2b433 |
* software, so:
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Copyright (C) 1991, 1992, Thomas G. Lane.
|
|
rpm-build |
d2b433 |
* Part of the Independent JPEG Group's software.
|
|
rpm-build |
d2b433 |
* See the file Copyright for more details.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Copyright (c) 1993 Brian C. Smith, The Regents of the University
|
|
rpm-build |
d2b433 |
* of California
|
|
rpm-build |
d2b433 |
* All rights reserved.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Copyright (c) 1994 Kongji Huang and Brian C. Smith.
|
|
rpm-build |
d2b433 |
* Cornell University
|
|
rpm-build |
d2b433 |
* All rights reserved.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Permission to use, copy, modify, and distribute this software and its
|
|
rpm-build |
d2b433 |
* documentation for any purpose, without fee, and without written agreement is
|
|
rpm-build |
d2b433 |
* hereby granted, provided that the above copyright notice and the following
|
|
rpm-build |
d2b433 |
* two paragraphs appear in all copies of this software.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* IN NO EVENT SHALL CORNELL UNIVERSITY BE LIABLE TO ANY PARTY FOR
|
|
rpm-build |
d2b433 |
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
|
|
rpm-build |
d2b433 |
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF CORNELL
|
|
rpm-build |
d2b433 |
* UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* CORNELL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
|
|
rpm-build |
d2b433 |
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
rpm-build |
d2b433 |
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
|
rpm-build |
d2b433 |
* ON AN "AS IS" BASIS, AND CORNELL UNIVERSITY HAS NO OBLIGATION TO
|
|
rpm-build |
d2b433 |
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
#include <stdlib.h>
|
|
rpm-build |
d2b433 |
#include <string.h>
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
#include <fcntl.h>
|
|
rpm-build |
d2b433 |
#include <algorithm>
|
|
rpm-build |
d2b433 |
#include <cstdint>
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
#include <boost/format.hpp>
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
#include <libopenraw/consts.h>
|
|
rpm-build |
d2b433 |
#include <libopenraw/debug.h>
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
#include "rawdata.hpp"
|
|
rpm-build |
d2b433 |
#include "exception.hpp"
|
|
rpm-build |
d2b433 |
#include "io/stream.hpp"
|
|
rpm-build |
d2b433 |
#include "trace.hpp"
|
|
rpm-build |
d2b433 |
#include "ljpegdecompressor.hpp"
|
|
rpm-build |
d2b433 |
#include "ljpegdecompressor_priv.hpp"
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
namespace OpenRaw {
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
using namespace Debug;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
namespace Internals {
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
static void SkipVariable(IO::Stream *s);
|
|
rpm-build |
d2b433 |
static uint16_t Get2bytes (IO::Stream * s);
|
|
rpm-build |
d2b433 |
static int32_t NextMarker(IO::Stream * );
|
|
rpm-build |
d2b433 |
static void GetSoi(DecompressInfo *dcPtr);
|
|
rpm-build |
d2b433 |
static void GetApp0(IO::Stream *);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
LJpegDecompressor::LJpegDecompressor(IO::Stream *stream,
|
|
rpm-build |
d2b433 |
RawContainer *container)
|
|
rpm-build |
d2b433 |
: Decompressor(stream, container),
|
|
rpm-build |
d2b433 |
m_slices(),
|
|
rpm-build |
d2b433 |
m_mcuROW1(NULL), m_mcuROW2(NULL),
|
|
rpm-build |
d2b433 |
m_buf1(NULL), m_buf2(NULL),
|
|
rpm-build |
d2b433 |
m_bitsLeft(0),
|
|
rpm-build |
d2b433 |
m_getBuffer(0)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
LJpegDecompressor::~LJpegDecompressor()
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
if(m_mcuROW1) {
|
|
rpm-build |
d2b433 |
free(m_mcuROW1);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
if(m_mcuROW2) {
|
|
rpm-build |
d2b433 |
free(m_mcuROW2);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
if(m_buf1) {
|
|
rpm-build |
d2b433 |
free(m_buf1);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
if(m_buf2) {
|
|
rpm-build |
d2b433 |
free(m_buf2);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
void LJpegDecompressor::setSlices(const std::vector<uint16_t> & slices)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
uint16_t n = slices[0];
|
|
rpm-build |
d2b433 |
m_slices.resize(n + 1);
|
|
rpm-build |
d2b433 |
for(uint16_t i = 0; i < n; i++) {
|
|
rpm-build |
d2b433 |
m_slices[i] = slices[1];
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
m_slices[n] = slices[2];
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
static uint32_t bitMask[] = { 0xffffffff, 0x7fffffff,
|
|
rpm-build |
d2b433 |
0x3fffffff, 0x1fffffff,
|
|
rpm-build |
d2b433 |
0x0fffffff, 0x07ffffff,
|
|
rpm-build |
d2b433 |
0x03ffffff, 0x01ffffff,
|
|
rpm-build |
d2b433 |
0x00ffffff, 0x007fffff,
|
|
rpm-build |
d2b433 |
0x003fffff, 0x001fffff,
|
|
rpm-build |
d2b433 |
0x000fffff, 0x0007ffff,
|
|
rpm-build |
d2b433 |
0x0003ffff, 0x0001ffff,
|
|
rpm-build |
d2b433 |
0x0000ffff, 0x00007fff,
|
|
rpm-build |
d2b433 |
0x00003fff, 0x00001fff,
|
|
rpm-build |
d2b433 |
0x00000fff, 0x000007ff,
|
|
rpm-build |
d2b433 |
0x000003ff, 0x000001ff,
|
|
rpm-build |
d2b433 |
0x000000ff, 0x0000007f,
|
|
rpm-build |
d2b433 |
0x0000003f, 0x0000001f,
|
|
rpm-build |
d2b433 |
0x0000000f, 0x00000007,
|
|
rpm-build |
d2b433 |
0x00000003, 0x00000001};
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
void FixHuffTbl (HuffmanTable *htbl);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* FixHuffTbl --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Compute derived values for a Huffman table one the DHT marker
|
|
rpm-build |
d2b433 |
* has been processed. This generates both the encoding and
|
|
rpm-build |
d2b433 |
* decoding tables.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* None.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
void
|
|
rpm-build |
d2b433 |
FixHuffTbl (HuffmanTable *htbl)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int32_t p, i, l, lastp, si;
|
|
rpm-build |
d2b433 |
char huffsize[257];
|
|
rpm-build |
d2b433 |
uint16_t huffcode[257];
|
|
rpm-build |
d2b433 |
uint16_t code;
|
|
rpm-build |
d2b433 |
int32_t size;
|
|
rpm-build |
d2b433 |
int32_t value, ll, ul;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Figure C.1: make table of Huffman code length for each symbol
|
|
rpm-build |
d2b433 |
* Note that this is in code-length order.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
p = 0;
|
|
rpm-build |
d2b433 |
for (l = 1; l <= 16; l++) {
|
|
rpm-build |
d2b433 |
for (i = 1; i <= (int)htbl->bits[l]; i++)
|
|
rpm-build |
d2b433 |
huffsize[p++] = (char)l;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
huffsize[p] = 0;
|
|
rpm-build |
d2b433 |
lastp = p;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Figure C.2: generate the codes themselves
|
|
rpm-build |
d2b433 |
* Note that this is in code-length order.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
code = 0;
|
|
rpm-build |
d2b433 |
si = huffsize[0];
|
|
rpm-build |
d2b433 |
p = 0;
|
|
rpm-build |
d2b433 |
while (huffsize[p]) {
|
|
rpm-build |
d2b433 |
while (((int)huffsize[p]) == si) {
|
|
rpm-build |
d2b433 |
huffcode[p++] = code;
|
|
rpm-build |
d2b433 |
code++;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
code <<= 1;
|
|
rpm-build |
d2b433 |
si++;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Figure C.3: generate encoding tables
|
|
rpm-build |
d2b433 |
* These are code and size indexed by symbol value
|
|
rpm-build |
d2b433 |
* Set any codeless symbols to have code length 0; this allows
|
|
rpm-build |
d2b433 |
* EmitBits to detect any attempt to emit such symbols.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
memset(htbl->ehufsi, 0, sizeof(htbl->ehufsi));
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
for (p = 0; p < lastp; p++) {
|
|
rpm-build |
d2b433 |
htbl->ehufco[htbl->huffval[p]] = huffcode[p];
|
|
rpm-build |
d2b433 |
htbl->ehufsi[htbl->huffval[p]] = huffsize[p];
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Figure F.15: generate decoding tables
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
p = 0;
|
|
rpm-build |
d2b433 |
for (l = 1; l <= 16; l++) {
|
|
rpm-build |
d2b433 |
if (htbl->bits[l]) {
|
|
rpm-build |
d2b433 |
htbl->valptr[l] = p;
|
|
rpm-build |
d2b433 |
htbl->mincode[l] = huffcode[p];
|
|
rpm-build |
d2b433 |
p += htbl->bits[l];
|
|
rpm-build |
d2b433 |
htbl->maxcode[l] = huffcode[p - 1];
|
|
rpm-build |
d2b433 |
} else {
|
|
rpm-build |
d2b433 |
htbl->maxcode[l] = -1;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* We put in this value to ensure HuffDecode terminates.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
htbl->maxcode[17] = 0xFFFFFL;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Build the numbits, value lookup tables.
|
|
rpm-build |
d2b433 |
* These table allow us to gather 8 bits from the bits stream,
|
|
rpm-build |
d2b433 |
* and immediately lookup the size and value of the huffman codes.
|
|
rpm-build |
d2b433 |
* If size is zero, it means that more than 8 bits are in the huffman
|
|
rpm-build |
d2b433 |
* code (this happens about 3-4% of the time).
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
bzero (htbl->numbits, sizeof(htbl->numbits));
|
|
rpm-build |
d2b433 |
for (p=0; p
|
|
rpm-build |
d2b433 |
size = huffsize[p];
|
|
rpm-build |
d2b433 |
if (size <= 8) {
|
|
rpm-build |
d2b433 |
value = htbl->huffval[p];
|
|
rpm-build |
d2b433 |
code = huffcode[p];
|
|
rpm-build |
d2b433 |
ll = code << (8-size);
|
|
rpm-build |
d2b433 |
if (size < 8) {
|
|
rpm-build |
d2b433 |
ul = ll | bitMask[24+size];
|
|
rpm-build |
d2b433 |
} else {
|
|
rpm-build |
d2b433 |
ul = ll;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
for (i=ll; i<=ul; i++) {
|
|
rpm-build |
d2b433 |
htbl->numbits[i] = size;
|
|
rpm-build |
d2b433 |
htbl->value[i] = value;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
#define RST0 0xD0 /* RST0 marker code */
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
#if 0
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* The following variables keep track of the input buffer
|
|
rpm-build |
d2b433 |
* for the JPEG data, which is read by ReadJpegData.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
uint8_t inputBuffer[JPEG_BUF_SIZE]; /* Input buffer for JPEG data */
|
|
rpm-build |
d2b433 |
int numInputBytes; /* The total number of bytes in inputBuffer */
|
|
rpm-build |
d2b433 |
int maxInputBytes; /* Size of inputBuffer */
|
|
rpm-build |
d2b433 |
int inputBufferOffset; /* Offset of current byte */
|
|
rpm-build |
d2b433 |
#endif
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Code for extracting the next N bits from the input stream.
|
|
rpm-build |
d2b433 |
* (N never exceeds 15 for JPEG data.)
|
|
rpm-build |
d2b433 |
* This needs to go as fast as possible!
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* We read source bytes into getBuffer and dole out bits as needed.
|
|
rpm-build |
d2b433 |
* If getBuffer already contains enough bits, they are fetched in-line
|
|
rpm-build |
d2b433 |
* by the macros get_bits() and get_bit(). When there aren't enough bits,
|
|
rpm-build |
d2b433 |
* fillBitBuffer is called; it will attempt to fill getBuffer to the
|
|
rpm-build |
d2b433 |
* "high water mark", then extract the desired number of bits. The idea,
|
|
rpm-build |
d2b433 |
* of course, is to minimize the function-call overhead cost of entering
|
|
rpm-build |
d2b433 |
* fillBitBuffer.
|
|
rpm-build |
d2b433 |
* On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width
|
|
rpm-build |
d2b433 |
* of getBuffer to be used. (On machines with wider words, an even larger
|
|
rpm-build |
d2b433 |
* buffer could be used.)
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
#define BITS_PER_LONG (8*sizeof(int32_t))
|
|
rpm-build |
d2b433 |
#define MIN_GET_BITS (BITS_PER_LONG-7) /* max value for long getBuffer */
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* bmask[n] is mask for n rightmost bits
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
static int32_t bmask[] = {0x0000,
|
|
rpm-build |
d2b433 |
0x0001, 0x0003, 0x0007, 0x000F,
|
|
rpm-build |
d2b433 |
0x001F, 0x003F, 0x007F, 0x00FF,
|
|
rpm-build |
d2b433 |
0x01FF, 0x03FF, 0x07FF, 0x0FFF,
|
|
rpm-build |
d2b433 |
0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF};
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Lossless JPEG specifies data precision to be from 2 to 16 bits/sample.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
#define MinPrecisionBits 2
|
|
rpm-build |
d2b433 |
#define MaxPrecisionBits 16
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* DecoderStructInit --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Initalize the rest of the fields in the decompression
|
|
rpm-build |
d2b433 |
* structure.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* None.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
void
|
|
rpm-build |
d2b433 |
LJpegDecompressor::DecoderStructInit (DecompressInfo *dcPtr)
|
|
rpm-build |
d2b433 |
noexcept(false)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int16_t ci,i;
|
|
rpm-build |
d2b433 |
JpegComponentInfo *compPtr;
|
|
rpm-build |
d2b433 |
int32_t mcuSize;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Check sampling factor validity.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
for (ci = 0; ci < dcPtr->numComponents; ci++) {
|
|
rpm-build |
d2b433 |
compPtr = &dcPtr->compInfo[ci];
|
|
rpm-build |
d2b433 |
if ((compPtr->hSampFactor != 1) || (compPtr->vSampFactor != 1)) {
|
|
rpm-build |
d2b433 |
throw DecodingException("Error: Downsampling is not supported.\n");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Prepare array describing MCU composition
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
if (dcPtr->compsInScan == 1) {
|
|
rpm-build |
d2b433 |
dcPtr->MCUmembership[0] = 0;
|
|
rpm-build |
d2b433 |
} else {
|
|
rpm-build |
d2b433 |
if (dcPtr->compsInScan > 4) {
|
|
rpm-build |
d2b433 |
throw DecodingException("Too many components for interleaved scan");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
for (ci = 0; ci < dcPtr->compsInScan; ci++) {
|
|
rpm-build |
d2b433 |
dcPtr->MCUmembership[ci] = ci;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Initialize mucROW1 and mcuROW2 which buffer two rows of
|
|
rpm-build |
d2b433 |
* pixels for predictor calculation.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
if ((m_mcuROW1 = (MCU *)malloc(dcPtr->imageWidth*sizeof(MCU)))==NULL) {
|
|
rpm-build |
d2b433 |
throw DecodingException("Not enough memory for mcuROW1\n");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
if ((m_mcuROW2 = (MCU *)malloc(dcPtr->imageWidth*sizeof(MCU)))==NULL) {
|
|
rpm-build |
d2b433 |
throw DecodingException("Not enough memory for mcuROW2\n");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
mcuSize=dcPtr->compsInScan * sizeof(ComponentType);
|
|
rpm-build |
d2b433 |
if ((m_buf1 = (char *)malloc(dcPtr->imageWidth*mcuSize))==NULL) {
|
|
rpm-build |
d2b433 |
throw DecodingException("Not enough memory for buf1\n");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
if ((m_buf2 = (char *)malloc(dcPtr->imageWidth*mcuSize))==NULL) {
|
|
rpm-build |
d2b433 |
throw DecodingException("Not enough memory for buf2\n");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
for (i=0;i<dcPtr->imageWidth;i++) {
|
|
rpm-build |
d2b433 |
m_mcuROW1[i]=(MCU)(m_buf1+i*mcuSize);
|
|
rpm-build |
d2b433 |
m_mcuROW2[i]=(MCU)(m_buf2+i*mcuSize);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* fillBitBuffer --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Load up the bit buffer with at least nbits
|
|
rpm-build |
d2b433 |
* Process any stuffed bytes at this time.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* The bitwise global variables are updated.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
void
|
|
rpm-build |
d2b433 |
LJpegDecompressor::fillBitBuffer (IO::Stream * s,uint16_t nbits)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
uint8_t c, c2;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
while (m_bitsLeft < MIN_GET_BITS) {
|
|
rpm-build |
d2b433 |
c = s->readByte();
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* If it's 0xFF, check and discard stuffed zero byte
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
if (c == 0xFF) {
|
|
rpm-build |
d2b433 |
c2 = s->readByte();
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
if (c2 != 0) {
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Oops, it's actually a marker indicating end of
|
|
rpm-build |
d2b433 |
* compressed data. Better put it back for use later.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
s->seek(-2, SEEK_CUR);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* There should be enough bits still left in the data
|
|
rpm-build |
d2b433 |
* segment; if so, just break out of the while loop.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
if (m_bitsLeft >= nbits)
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Uh-oh. Corrupted data: stuff zeroes into the data
|
|
rpm-build |
d2b433 |
* stream, since this sometimes occurs when we are on the
|
|
rpm-build |
d2b433 |
* last show_bits(8) during decoding of the Huffman
|
|
rpm-build |
d2b433 |
* segment.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
c = 0;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* OK, load c into getBuffer
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
m_getBuffer = (m_getBuffer << 8) | c;
|
|
rpm-build |
d2b433 |
m_bitsLeft += 8;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
inline int32_t LJpegDecompressor::QuickPredict(int32_t col, int16_t curComp,
|
|
rpm-build |
d2b433 |
MCU *curRowBuf,
|
|
rpm-build |
d2b433 |
MCU *prevRowBuf,
|
|
rpm-build |
d2b433 |
int32_t psv)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int32_t left,upper,diag,leftcol;
|
|
rpm-build |
d2b433 |
int32_t predictor;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
leftcol=col-1;
|
|
rpm-build |
d2b433 |
upper=prevRowBuf[col][curComp];
|
|
rpm-build |
d2b433 |
left=curRowBuf[leftcol][curComp];
|
|
rpm-build |
d2b433 |
diag=prevRowBuf[leftcol][curComp];
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* All predictor are calculated according to psv.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
switch (psv) {
|
|
rpm-build |
d2b433 |
case 0:
|
|
rpm-build |
d2b433 |
predictor = 0;
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
case 1:
|
|
rpm-build |
d2b433 |
predictor = left;
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
case 2:
|
|
rpm-build |
d2b433 |
predictor = upper;
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
case 3:
|
|
rpm-build |
d2b433 |
predictor = diag;
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
case 4:
|
|
rpm-build |
d2b433 |
predictor = left+upper-diag;
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
case 5:
|
|
rpm-build |
d2b433 |
predictor = left+((upper-diag)>>1);
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
case 6:
|
|
rpm-build |
d2b433 |
predictor = upper+((left-diag)>>1);
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
case 7:
|
|
rpm-build |
d2b433 |
predictor = (left+upper)>>1;
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
default:
|
|
rpm-build |
d2b433 |
LOGWARN("Warning: Undefined PSV\n");
|
|
rpm-build |
d2b433 |
predictor = 0;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
return predictor;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
inline
|
|
rpm-build |
d2b433 |
int32_t LJpegDecompressor::show_bits8(IO::Stream * s)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
if (m_bitsLeft < 8) {
|
|
rpm-build |
d2b433 |
fillBitBuffer(s, 8);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
return (m_getBuffer >> (m_bitsLeft-8)) & 0xff;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
inline
|
|
rpm-build |
d2b433 |
void LJpegDecompressor::flush_bits(uint16_t nbits)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
m_bitsLeft -= (nbits);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
inline
|
|
rpm-build |
d2b433 |
int32_t LJpegDecompressor::get_bits(uint16_t nbits)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
if (m_bitsLeft < nbits)
|
|
rpm-build |
d2b433 |
fillBitBuffer(m_stream, nbits);
|
|
rpm-build |
d2b433 |
return ((m_getBuffer >> (m_bitsLeft -= (nbits)))) & bmask[nbits];
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
inline
|
|
rpm-build |
d2b433 |
int32_t LJpegDecompressor::get_bit()
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
if (!m_bitsLeft)
|
|
rpm-build |
d2b433 |
fillBitBuffer(m_stream, 1);
|
|
rpm-build |
d2b433 |
return (m_getBuffer >> (--m_bitsLeft)) & 1;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
inline
|
|
rpm-build |
d2b433 |
int32_t LJpegDecompressor::readBits(IO::Stream * s, uint16_t nbits)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
if (m_bitsLeft < nbits) {
|
|
rpm-build |
d2b433 |
fillBitBuffer(s, nbits);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
return ((m_getBuffer >> (m_bitsLeft -= (nbits)))) & bmask[nbits];
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* PmPutRow --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Output one row of pixels stored in RowBuf.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* One row of pixels are write to file pointed by outFile.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
inline void
|
|
rpm-build |
d2b433 |
LJpegDecompressor::PmPutRow(MCU* RowBuf, int32_t numComp, int32_t numCol, int32_t Pt)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
// TODO this might be wrong in 8 bits...
|
|
rpm-build |
d2b433 |
// original code was using putc which *i think* was a problem for
|
|
rpm-build |
d2b433 |
// 16bpp
|
|
rpm-build |
d2b433 |
int32_t comp;
|
|
rpm-build |
d2b433 |
int32_t col;
|
|
rpm-build |
d2b433 |
uint16_t v;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
for (col = 0; col < numCol; col++) {
|
|
rpm-build |
d2b433 |
for (comp = 0; comp < numComp; comp++) {
|
|
rpm-build |
d2b433 |
v = RowBuf[col][comp]<
|
|
rpm-build |
d2b433 |
m_output->append(v);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
// m_output->nextRow();
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* HuffDecode --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Taken from Figure F.16: extract next coded symbol from
|
|
rpm-build |
d2b433 |
* input stream. This should becode a macro.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* Next coded symbol
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* Bitstream is parsed.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
inline int32_t
|
|
rpm-build |
d2b433 |
LJpegDecompressor::HuffDecode(HuffmanTable *htbl)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int32_t rv;
|
|
rpm-build |
d2b433 |
int32_t l, temp;
|
|
rpm-build |
d2b433 |
int32_t code;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* If the huffman code is less than 8 bits, we can use the fast
|
|
rpm-build |
d2b433 |
* table lookup to get its value. It's more than 8 bits about
|
|
rpm-build |
d2b433 |
* 3-4% of the time.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
code = show_bits8(m_stream);
|
|
rpm-build |
d2b433 |
if (htbl->numbits[code]) {
|
|
rpm-build |
d2b433 |
flush_bits(htbl->numbits[code]);
|
|
rpm-build |
d2b433 |
rv=htbl->value[code];
|
|
rpm-build |
d2b433 |
} else {
|
|
rpm-build |
d2b433 |
flush_bits(8);
|
|
rpm-build |
d2b433 |
l = 8;
|
|
rpm-build |
d2b433 |
while (code > htbl->maxcode[l]) {
|
|
rpm-build |
d2b433 |
temp = get_bit();
|
|
rpm-build |
d2b433 |
code = (code << 1) | temp;
|
|
rpm-build |
d2b433 |
l++;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* With garbage input we may reach the sentinel value l = 17.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
if (l > 16) {
|
|
rpm-build |
d2b433 |
//LOGWARN("Corrupt JPEG data: bad Huffman code %d\n", l);
|
|
rpm-build |
d2b433 |
rv = 0; /* fake a zero as the safest result */
|
|
rpm-build |
d2b433 |
} else {
|
|
rpm-build |
d2b433 |
rv = htbl->huffval[htbl->valptr[l] +
|
|
rpm-build |
d2b433 |
((int)(code - htbl->mincode[l]))];
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
return rv;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* HuffExtend --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Code and table for Figure F.12: extend sign bit
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* The extended value.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* None.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
static const int32_t extendTest[16] = /* entry n is 2**(n-1) */
|
|
rpm-build |
d2b433 |
{0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
|
|
rpm-build |
d2b433 |
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000};
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
// we can't bitshift -1. So we use 0xffffffff as a value.
|
|
rpm-build |
d2b433 |
// gcc complain about it otherwise.
|
|
rpm-build |
d2b433 |
#define EXTEND(n) (int32_t)(0xffffffff << n) + 1
|
|
rpm-build |
d2b433 |
static const int32_t extendOffset[16] = /* entry n is (-1 << n) + 1 */
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
0, EXTEND(1), EXTEND(2), EXTEND(3),
|
|
rpm-build |
d2b433 |
EXTEND(4), EXTEND(5), EXTEND(6), EXTEND(7),
|
|
rpm-build |
d2b433 |
EXTEND(8), EXTEND(9), EXTEND(10), EXTEND(11),
|
|
rpm-build |
d2b433 |
EXTEND(12), EXTEND(13), EXTEND(14), EXTEND(15)
|
|
rpm-build |
d2b433 |
};
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
inline
|
|
rpm-build |
d2b433 |
void HuffExtend(int32_t & x, int32_t s) noexcept
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
if ((x) < extendTest[s]) {
|
|
rpm-build |
d2b433 |
(x) += extendOffset[s];
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* HuffDecoderInit --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Initialize for a Huffman-compressed scan.
|
|
rpm-build |
d2b433 |
* This is invoked after reading the SOS marker.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* None.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
void
|
|
rpm-build |
d2b433 |
LJpegDecompressor::HuffDecoderInit (DecompressInfo *dcPtr)
|
|
rpm-build |
d2b433 |
noexcept(false)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int16_t ci;
|
|
rpm-build |
d2b433 |
JpegComponentInfo *compptr;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Initialize static variables
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
m_bitsLeft = 0;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
for (ci = 0; ci < dcPtr->compsInScan; ci++) {
|
|
rpm-build |
d2b433 |
compptr = dcPtr->curCompInfo[ci];
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Make sure requested tables are present
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
if (dcPtr->dcHuffTblPtrs[compptr->dcTblNo] == NULL) {
|
|
rpm-build |
d2b433 |
throw DecodingException("Error: Use of undefined Huffman table\n");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Compute derived values for Huffman tables.
|
|
rpm-build |
d2b433 |
* We may do this more than once for same table, but it's not a
|
|
rpm-build |
d2b433 |
* big deal
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
FixHuffTbl (dcPtr->dcHuffTblPtrs[compptr->dcTblNo]);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Initialize restart stuff
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
dcPtr->restartInRows = (dcPtr->restartInterval)/(dcPtr->imageWidth);
|
|
rpm-build |
d2b433 |
dcPtr->restartRowsToGo = dcPtr->restartInRows;
|
|
rpm-build |
d2b433 |
dcPtr->nextRestartNum = 0;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* ProcessRestart --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Check for a restart marker & resynchronize decoder.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* BitStream is parsed, bit buffer is reset, etc.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
void
|
|
rpm-build |
d2b433 |
LJpegDecompressor::ProcessRestart (DecompressInfo *dcPtr)
|
|
rpm-build |
d2b433 |
noexcept(false)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int32_t c, nbytes;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Throw away any unused bits remaining in bit buffer
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
nbytes = m_bitsLeft / 8;
|
|
rpm-build |
d2b433 |
m_bitsLeft = 0;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Scan for next JPEG marker
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
do {
|
|
rpm-build |
d2b433 |
do { /* skip any non-FF bytes */
|
|
rpm-build |
d2b433 |
nbytes++;
|
|
rpm-build |
d2b433 |
c = m_stream->readByte();
|
|
rpm-build |
d2b433 |
} while (c != 0xFF);
|
|
rpm-build |
d2b433 |
do { /* skip any duplicate FFs */
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* we don't increment nbytes here since extra FFs are legal
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
c = m_stream->readByte();
|
|
rpm-build |
d2b433 |
} while (c == 0xFF);
|
|
rpm-build |
d2b433 |
} while (c == 0); /* repeat if it was a stuffed FF/00 */
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
if (c != (RST0 + dcPtr->nextRestartNum)) {
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Uh-oh, the restart markers have been messed up too.
|
|
rpm-build |
d2b433 |
* Just bail out.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
throw DecodingException("Error: Corrupt JPEG data. "
|
|
rpm-build |
d2b433 |
"Aborting decoding...\n");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Update restart state
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
dcPtr->restartRowsToGo = dcPtr->restartInRows;
|
|
rpm-build |
d2b433 |
dcPtr->nextRestartNum = (dcPtr->nextRestartNum + 1) & 7;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* DecodeFirstRow --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Decode the first raster line of samples at the start of
|
|
rpm-build |
d2b433 |
* the scan and at the beginning of each restart interval.
|
|
rpm-build |
d2b433 |
* This includes modifying the component value so the real
|
|
rpm-build |
d2b433 |
* value, not the difference is returned.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* Bitstream is parsed.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
void LJpegDecompressor::DecodeFirstRow(DecompressInfo *dcPtr,
|
|
rpm-build |
d2b433 |
MCU *curRowBuf)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
uint16_t curComp,ci;
|
|
rpm-build |
d2b433 |
int32_t s,col,compsInScan,numCOL;
|
|
rpm-build |
d2b433 |
JpegComponentInfo *compptr;
|
|
rpm-build |
d2b433 |
int32_t Pr,Pt,d;
|
|
rpm-build |
d2b433 |
HuffmanTable *dctbl;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
Pr=dcPtr->dataPrecision;
|
|
rpm-build |
d2b433 |
Pt=dcPtr->Pt;
|
|
rpm-build |
d2b433 |
compsInScan=dcPtr->compsInScan;
|
|
rpm-build |
d2b433 |
numCOL=dcPtr->imageWidth;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* the start of the scan or at the beginning of restart interval.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
for (curComp = 0; curComp < compsInScan; curComp++) {
|
|
rpm-build |
d2b433 |
ci = dcPtr->MCUmembership[curComp];
|
|
rpm-build |
d2b433 |
compptr = dcPtr->curCompInfo[ci];
|
|
rpm-build |
d2b433 |
dctbl = dcPtr->dcHuffTblPtrs[compptr->dcTblNo];
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Section F.2.2.1: decode the difference
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
s = HuffDecode (dctbl);
|
|
rpm-build |
d2b433 |
if (s) {
|
|
rpm-build |
d2b433 |
d = get_bits(s);
|
|
rpm-build |
d2b433 |
HuffExtend(d,s);
|
|
rpm-build |
d2b433 |
} else {
|
|
rpm-build |
d2b433 |
d = 0;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Add the predictor to the difference.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
curRowBuf[0][curComp]=d+(1<<(Pr-Pt-1));
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* the rest of the first row
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
for (col=1; col
|
|
rpm-build |
d2b433 |
for (curComp = 0; curComp < compsInScan; curComp++) {
|
|
rpm-build |
d2b433 |
ci = dcPtr->MCUmembership[curComp];
|
|
rpm-build |
d2b433 |
compptr = dcPtr->curCompInfo[ci];
|
|
rpm-build |
d2b433 |
dctbl = dcPtr->dcHuffTblPtrs[compptr->dcTblNo];
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Section F.2.2.1: decode the difference
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
s = HuffDecode (dctbl);
|
|
rpm-build |
d2b433 |
if (s) {
|
|
rpm-build |
d2b433 |
d = get_bits(s);
|
|
rpm-build |
d2b433 |
HuffExtend(d,s);
|
|
rpm-build |
d2b433 |
} else {
|
|
rpm-build |
d2b433 |
d = 0;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Add the predictor to the difference.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
curRowBuf[col][curComp]=d+curRowBuf[col-1][curComp];
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
if (dcPtr->restartInRows) {
|
|
rpm-build |
d2b433 |
(dcPtr->restartRowsToGo)--;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* DecodeImage --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Decode the input stream. This includes modifying
|
|
rpm-build |
d2b433 |
* the component value so the real value, not the
|
|
rpm-build |
d2b433 |
* difference is returned.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* Bitstream is parsed.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
void
|
|
rpm-build |
d2b433 |
LJpegDecompressor::DecodeImage(DecompressInfo *dcPtr)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int32_t s,d,col,row;
|
|
rpm-build |
d2b433 |
int16_t curComp, ci;
|
|
rpm-build |
d2b433 |
HuffmanTable *dctbl;
|
|
rpm-build |
d2b433 |
JpegComponentInfo *compptr;
|
|
rpm-build |
d2b433 |
int32_t predictor;
|
|
rpm-build |
d2b433 |
int32_t numCOL,numROW,compsInScan;
|
|
rpm-build |
d2b433 |
MCU *prevRowBuf,*curRowBuf;
|
|
rpm-build |
d2b433 |
int32_t imagewidth,Pt,psv;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
numCOL=imagewidth=dcPtr->imageWidth;
|
|
rpm-build |
d2b433 |
numROW=dcPtr->imageHeight;
|
|
rpm-build |
d2b433 |
compsInScan=dcPtr->compsInScan;
|
|
rpm-build |
d2b433 |
Pt=dcPtr->Pt;
|
|
rpm-build |
d2b433 |
psv=dcPtr->Ss;
|
|
rpm-build |
d2b433 |
prevRowBuf=m_mcuROW2;
|
|
rpm-build |
d2b433 |
curRowBuf=m_mcuROW1;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Decode the first row of image. Output the row and
|
|
rpm-build |
d2b433 |
* turn this row into a previous row for later predictor
|
|
rpm-build |
d2b433 |
* calculation.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
DecodeFirstRow(dcPtr,curRowBuf);
|
|
rpm-build |
d2b433 |
PmPutRow(curRowBuf,compsInScan,numCOL,Pt);
|
|
rpm-build |
d2b433 |
std::swap(prevRowBuf,curRowBuf);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
for (row=1; row
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Account for restart interval, process restart marker if needed.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
if (dcPtr->restartInRows) {
|
|
rpm-build |
d2b433 |
if (dcPtr->restartRowsToGo == 0) {
|
|
rpm-build |
d2b433 |
ProcessRestart (dcPtr);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Reset predictors at restart.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
DecodeFirstRow(dcPtr,curRowBuf);
|
|
rpm-build |
d2b433 |
PmPutRow(curRowBuf,compsInScan,numCOL,Pt);
|
|
rpm-build |
d2b433 |
std::swap(prevRowBuf,curRowBuf);
|
|
rpm-build |
d2b433 |
continue;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
dcPtr->restartRowsToGo--;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* The upper neighbors are predictors for the first column.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
for (curComp = 0; curComp < compsInScan; curComp++) {
|
|
rpm-build |
d2b433 |
ci = dcPtr->MCUmembership[curComp];
|
|
rpm-build |
d2b433 |
compptr = dcPtr->curCompInfo[ci];
|
|
rpm-build |
d2b433 |
dctbl = dcPtr->dcHuffTblPtrs[compptr->dcTblNo];
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Section F.2.2.1: decode the difference
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
s = HuffDecode (dctbl);
|
|
rpm-build |
d2b433 |
if (s) {
|
|
rpm-build |
d2b433 |
d = get_bits(s);
|
|
rpm-build |
d2b433 |
HuffExtend(d,s);
|
|
rpm-build |
d2b433 |
} else {
|
|
rpm-build |
d2b433 |
d = 0;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
curRowBuf[0][curComp]=d+prevRowBuf[0][curComp];
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* For the rest of the column on this row, predictor
|
|
rpm-build |
d2b433 |
* calculations are base on PSV.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
for (col=1; col
|
|
rpm-build |
d2b433 |
for (curComp = 0; curComp < compsInScan; curComp++) {
|
|
rpm-build |
d2b433 |
ci = dcPtr->MCUmembership[curComp];
|
|
rpm-build |
d2b433 |
compptr = dcPtr->curCompInfo[ci];
|
|
rpm-build |
d2b433 |
dctbl = dcPtr->dcHuffTblPtrs[compptr->dcTblNo];
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Section F.2.2.1: decode the difference
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
s = HuffDecode (dctbl);
|
|
rpm-build |
d2b433 |
if (s) {
|
|
rpm-build |
d2b433 |
d = get_bits(s);
|
|
rpm-build |
d2b433 |
HuffExtend(d,s);
|
|
rpm-build |
d2b433 |
} else {
|
|
rpm-build |
d2b433 |
d = 0;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
predictor = QuickPredict(col,curComp,curRowBuf,prevRowBuf,
|
|
rpm-build |
d2b433 |
psv);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
curRowBuf[col][curComp]=d+predictor;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
PmPutRow(curRowBuf,compsInScan,numCOL,Pt);
|
|
rpm-build |
d2b433 |
std::swap(prevRowBuf,curRowBuf);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Get2bytes --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Get a 2-byte unsigned integer (e.g., a marker parameter length
|
|
rpm-build |
d2b433 |
* field)
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* Next two byte of input as an integer.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* Bitstream is parsed.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
static inline uint16_t
|
|
rpm-build |
d2b433 |
Get2bytes (IO::Stream * s)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
uint16_t a;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
a = s->readByte();
|
|
rpm-build |
d2b433 |
return (a << 8) | s->readByte();
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* SkipVariable --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Skip over an unknown or uninteresting variable-length marker
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* Bitstream is parsed over marker.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
static inline void SkipVariable(IO::Stream * s)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int32_t length;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
length = Get2bytes(s) - 2;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
s->seek(length, SEEK_CUR);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* GetDht --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Process a DHT marker
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* A huffman table is read.
|
|
rpm-build |
d2b433 |
* Exits on error.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
void
|
|
rpm-build |
d2b433 |
LJpegDecompressor::GetDht (DecompressInfo *dcPtr)
|
|
rpm-build |
d2b433 |
noexcept(false)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int32_t length;
|
|
rpm-build |
d2b433 |
int32_t i, index, count;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
length = Get2bytes(m_stream) - 2;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
while (length) {
|
|
rpm-build |
d2b433 |
index = m_stream->readByte();
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
if (index < 0 || index >= 4) {
|
|
rpm-build |
d2b433 |
throw DecodingException(str(boost::format("Bogus DHT index %1%")
|
|
rpm-build |
d2b433 |
% index));
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
HuffmanTable *& htblptr = dcPtr->dcHuffTblPtrs[index];
|
|
rpm-build |
d2b433 |
if (htblptr == NULL) {
|
|
rpm-build |
d2b433 |
htblptr = (HuffmanTable *) malloc(sizeof (HuffmanTable));
|
|
rpm-build |
d2b433 |
if (htblptr==NULL) {
|
|
rpm-build |
d2b433 |
throw DecodingException("Can't malloc HuffmanTable");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
htblptr->bits[0] = 0;
|
|
rpm-build |
d2b433 |
count = 0;
|
|
rpm-build |
d2b433 |
for (i = 1; i <= 16; i++) {
|
|
rpm-build |
d2b433 |
htblptr->bits[i] = m_stream->readByte();
|
|
rpm-build |
d2b433 |
count += htblptr->bits[i];
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
if (count > 256) {
|
|
rpm-build |
d2b433 |
throw DecodingException("Bogus DHT counts");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
for (i = 0; i < count; i++)
|
|
rpm-build |
d2b433 |
htblptr->huffval[i] = m_stream->readByte();
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
length -= 1 + 16 + count;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* GetDri --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Process a DRI marker
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* Exits on error.
|
|
rpm-build |
d2b433 |
* Bitstream is parsed.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
void
|
|
rpm-build |
d2b433 |
LJpegDecompressor::GetDri(DecompressInfo *dcPtr)
|
|
rpm-build |
d2b433 |
noexcept(false)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
if (Get2bytes(m_stream) != 4) {
|
|
rpm-build |
d2b433 |
throw DecodingException("Bogus length in DRI");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
dcPtr->restartInterval = Get2bytes(m_stream);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* GetApp0 --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Process an APP0 marker.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* Bitstream is parsed
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
static void GetApp0(IO::Stream *s)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int32_t length;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
length = Get2bytes(s) - 2;
|
|
rpm-build |
d2b433 |
s->seek(length, SEEK_CUR);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* GetSof --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Process a SOFn marker
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* Bitstream is parsed
|
|
rpm-build |
d2b433 |
* Exits on error
|
|
rpm-build |
d2b433 |
* dcPtr structure is filled in
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
void
|
|
rpm-build |
d2b433 |
LJpegDecompressor::GetSof(DecompressInfo *dcPtr)
|
|
rpm-build |
d2b433 |
noexcept(false)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int32_t length;
|
|
rpm-build |
d2b433 |
int16_t ci;
|
|
rpm-build |
d2b433 |
int32_t c;
|
|
rpm-build |
d2b433 |
JpegComponentInfo *compptr;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
length = Get2bytes(m_stream);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
dcPtr->dataPrecision = m_stream->readByte();
|
|
rpm-build |
d2b433 |
dcPtr->imageHeight = Get2bytes(m_stream);
|
|
rpm-build |
d2b433 |
dcPtr->imageWidth = Get2bytes(m_stream);
|
|
rpm-build |
d2b433 |
dcPtr->numComponents = m_stream->readByte();
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* We don't support files in which the image height is initially
|
|
rpm-build |
d2b433 |
* specified as 0 and is later redefined by DNL. As long as we
|
|
rpm-build |
d2b433 |
* have to check that, might as well have a general sanity check.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
if ((dcPtr->imageHeight <= 0 ) ||
|
|
rpm-build |
d2b433 |
(dcPtr->imageWidth <= 0) ||
|
|
rpm-build |
d2b433 |
(dcPtr->numComponents <= 0)) {
|
|
rpm-build |
d2b433 |
throw DecodingException("Empty JPEG image (DNL not supported)");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
if ((dcPtr->dataPrecision
|
|
rpm-build |
d2b433 |
(dcPtr->dataPrecision>MaxPrecisionBits)) {
|
|
rpm-build |
d2b433 |
throw DecodingException("Unsupported JPEG data precision");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
if (length != (dcPtr->numComponents * 3 + 8)) {
|
|
rpm-build |
d2b433 |
throw DecodingException("Bogus SOF length");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
dcPtr->compInfo = (JpegComponentInfo *) malloc
|
|
rpm-build |
d2b433 |
(dcPtr->numComponents * sizeof (JpegComponentInfo));
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
for (ci = 0; ci < dcPtr->numComponents; ci++) {
|
|
rpm-build |
d2b433 |
compptr = &dcPtr->compInfo[ci];
|
|
rpm-build |
d2b433 |
compptr->componentIndex = ci;
|
|
rpm-build |
d2b433 |
compptr->componentId = m_stream->readByte();
|
|
rpm-build |
d2b433 |
c = m_stream->readByte();
|
|
rpm-build |
d2b433 |
compptr->hSampFactor = (int16_t)((c >> 4) & 15);
|
|
rpm-build |
d2b433 |
compptr->vSampFactor = (int16_t)((c) & 15);
|
|
rpm-build |
d2b433 |
(void) m_stream->readByte(); /* skip Tq */
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* GetSos --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Process a SOS marker
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* Bitstream is parsed.
|
|
rpm-build |
d2b433 |
* Exits on error.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
void
|
|
rpm-build |
d2b433 |
LJpegDecompressor::GetSos (DecompressInfo *dcPtr)
|
|
rpm-build |
d2b433 |
noexcept(false)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int32_t length;
|
|
rpm-build |
d2b433 |
int32_t i;
|
|
rpm-build |
d2b433 |
uint16_t n, ci, c, cc;
|
|
rpm-build |
d2b433 |
JpegComponentInfo *compptr;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
length = Get2bytes (m_stream);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Get the number of image components.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
n = m_stream->readByte();
|
|
rpm-build |
d2b433 |
dcPtr->compsInScan = n;
|
|
rpm-build |
d2b433 |
length -= 3;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
if (length != (n * 2 + 3) || n < 1 || n > 4) {
|
|
rpm-build |
d2b433 |
throw DecodingException("Bogus SOS length");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
for (i = 0; i < n; i++) {
|
|
rpm-build |
d2b433 |
cc = m_stream->readByte();
|
|
rpm-build |
d2b433 |
c = m_stream->readByte();
|
|
rpm-build |
d2b433 |
length -= 2;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
for (ci = 0; ci < dcPtr->numComponents; ci++)
|
|
rpm-build |
d2b433 |
if (cc == dcPtr->compInfo[ci].componentId) {
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
if (ci >= dcPtr->numComponents) {
|
|
rpm-build |
d2b433 |
throw DecodingException("Invalid component number in SOS");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
compptr = &dcPtr->compInfo[ci];
|
|
rpm-build |
d2b433 |
dcPtr->curCompInfo[i] = compptr;
|
|
rpm-build |
d2b433 |
compptr->dcTblNo = (c >> 4) & 15;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Get the PSV, skip Se, and get the point transform parameter.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
dcPtr->Ss = m_stream->readByte();
|
|
rpm-build |
d2b433 |
(void)m_stream->readByte();
|
|
rpm-build |
d2b433 |
c = m_stream->readByte();
|
|
rpm-build |
d2b433 |
dcPtr->Pt = c & 0x0F;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* GetSoi --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Process an SOI marker
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* Bitstream is parsed.
|
|
rpm-build |
d2b433 |
* Exits on error.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
static inline void
|
|
rpm-build |
d2b433 |
GetSoi (DecompressInfo *dcPtr)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Reset all parameters that are defined to be reset by SOI
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
dcPtr->restartInterval = 0;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* NextMarker --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Find the next JPEG marker Note that the output might not
|
|
rpm-build |
d2b433 |
* be a valid marker code but it will never be 0 or FF
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* The marker found.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* Bitstream is parsed.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
static int32_t
|
|
rpm-build |
d2b433 |
NextMarker(IO::Stream *s)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int32_t c;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
do {
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* skip any non-FF bytes
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
do {
|
|
rpm-build |
d2b433 |
c = s->readByte();
|
|
rpm-build |
d2b433 |
} while (c != 0xFF);
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* skip any duplicate FFs without incrementing nbytes, since
|
|
rpm-build |
d2b433 |
* extra FFs are legal
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
do {
|
|
rpm-build |
d2b433 |
c = s->readByte();
|
|
rpm-build |
d2b433 |
} while (c == 0xFF);
|
|
rpm-build |
d2b433 |
} while (c == 0); /* repeat if it was a stuffed FF/00 */
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
return c;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* ProcessTables --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Scan and process JPEG markers that can appear in any order
|
|
rpm-build |
d2b433 |
* Return when an SOI, EOI, SOFn, or SOS is found
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* The marker found.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* Bitstream is parsed.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
LJpegDecompressor::JpegMarker
|
|
rpm-build |
d2b433 |
LJpegDecompressor::ProcessTables (DecompressInfo *dcPtr)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int c;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
while (1) {
|
|
rpm-build |
d2b433 |
c = NextMarker (m_stream);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
switch (c) {
|
|
rpm-build |
d2b433 |
case M_SOF0:
|
|
rpm-build |
d2b433 |
case M_SOF1:
|
|
rpm-build |
d2b433 |
case M_SOF2:
|
|
rpm-build |
d2b433 |
case M_SOF3:
|
|
rpm-build |
d2b433 |
case M_SOF5:
|
|
rpm-build |
d2b433 |
case M_SOF6:
|
|
rpm-build |
d2b433 |
case M_SOF7:
|
|
rpm-build |
d2b433 |
case M_JPG:
|
|
rpm-build |
d2b433 |
case M_SOF9:
|
|
rpm-build |
d2b433 |
case M_SOF10:
|
|
rpm-build |
d2b433 |
case M_SOF11:
|
|
rpm-build |
d2b433 |
case M_SOF13:
|
|
rpm-build |
d2b433 |
case M_SOF14:
|
|
rpm-build |
d2b433 |
case M_SOF15:
|
|
rpm-build |
d2b433 |
case M_SOI:
|
|
rpm-build |
d2b433 |
case M_EOI:
|
|
rpm-build |
d2b433 |
case M_SOS:
|
|
rpm-build |
d2b433 |
return ((JpegMarker)c);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
case M_DHT:
|
|
rpm-build |
d2b433 |
GetDht (dcPtr);
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
case M_DQT:
|
|
rpm-build |
d2b433 |
LOGWARN("Not a lossless JPEG file.\n");
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
case M_DRI:
|
|
rpm-build |
d2b433 |
GetDri (dcPtr);
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
case M_APP0:
|
|
rpm-build |
d2b433 |
GetApp0(m_stream);
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
case M_RST0: /* these are all parameterless */
|
|
rpm-build |
d2b433 |
case M_RST1:
|
|
rpm-build |
d2b433 |
case M_RST2:
|
|
rpm-build |
d2b433 |
case M_RST3:
|
|
rpm-build |
d2b433 |
case M_RST4:
|
|
rpm-build |
d2b433 |
case M_RST5:
|
|
rpm-build |
d2b433 |
case M_RST6:
|
|
rpm-build |
d2b433 |
case M_RST7:
|
|
rpm-build |
d2b433 |
case M_TEM:
|
|
rpm-build |
d2b433 |
LOGWARN("Warning: unexpected marker 0x%x", c);
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
default: /* must be DNL, DHP, EXP, APPn, JPGn, COM,
|
|
rpm-build |
d2b433 |
* or RESn */
|
|
rpm-build |
d2b433 |
SkipVariable (m_stream);
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* ReadFileHeader --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Initialize and read the file header (everything through
|
|
rpm-build |
d2b433 |
* the SOF marker).
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* None
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* Exit on error.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
void
|
|
rpm-build |
d2b433 |
LJpegDecompressor::ReadFileHeader (DecompressInfo *dcPtr)
|
|
rpm-build |
d2b433 |
noexcept(false)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int c, c2;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Demand an SOI marker at the start of the file --- otherwise it's
|
|
rpm-build |
d2b433 |
* probably not a JPEG file at all.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
c = m_stream->readByte();
|
|
rpm-build |
d2b433 |
c2 = m_stream->readByte();
|
|
rpm-build |
d2b433 |
if ((c != 0xFF) || (c2 != M_SOI)) {
|
|
rpm-build |
d2b433 |
throw DecodingException(str(boost::format("Not a JPEG file. "
|
|
rpm-build |
d2b433 |
"marker is %1% %2%\n")
|
|
rpm-build |
d2b433 |
% c % c2));
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
GetSoi (dcPtr); /* OK, process SOI */
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Process markers until SOF
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
c = ProcessTables (dcPtr);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
switch (c) {
|
|
rpm-build |
d2b433 |
case M_SOF0:
|
|
rpm-build |
d2b433 |
case M_SOF1:
|
|
rpm-build |
d2b433 |
case M_SOF3:
|
|
rpm-build |
d2b433 |
GetSof(dcPtr);
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
default:
|
|
rpm-build |
d2b433 |
LOGWARN("Unsupported SOF marker type 0x%x\n", c);
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* ReadScanHeader --
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Read the start of a scan (everything through the SOS marker).
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Results:
|
|
rpm-build |
d2b433 |
* 1 if find SOS, 0 if find EOI
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
* Side effects:
|
|
rpm-build |
d2b433 |
* Bitstream is parsed, may exit on errors.
|
|
rpm-build |
d2b433 |
*
|
|
rpm-build |
d2b433 |
*--------------------------------------------------------------
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
int32_t
|
|
rpm-build |
d2b433 |
LJpegDecompressor::ReadScanHeader (DecompressInfo *dcPtr)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
int c;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
* Process markers until SOS or EOI
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
c = ProcessTables (dcPtr);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
switch (c) {
|
|
rpm-build |
d2b433 |
case M_SOS:
|
|
rpm-build |
d2b433 |
GetSos (dcPtr);
|
|
rpm-build |
d2b433 |
return 1;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
case M_EOI:
|
|
rpm-build |
d2b433 |
return 0;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
default:
|
|
rpm-build |
d2b433 |
LOGWARN("Unexpected marker 0x%x\n", c);
|
|
rpm-build |
d2b433 |
break;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
return 0;
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
RawDataPtr LJpegDecompressor::decompress()
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
DecompressInfo dcInfo;
|
|
rpm-build |
d2b433 |
try {
|
|
rpm-build |
d2b433 |
ReadFileHeader(&dcInfo);
|
|
rpm-build |
d2b433 |
ReadScanHeader (&dcInfo);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
m_output = RawDataPtr(new RawData);
|
|
rpm-build |
d2b433 |
m_output->setDataType(OR_DATA_TYPE_RAW);
|
|
rpm-build |
d2b433 |
uint32_t bpc = dcInfo.dataPrecision;
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
m_output->setBpc(bpc);
|
|
rpm-build |
d2b433 |
m_output->setWhiteLevel((1 << bpc) - 1);
|
|
rpm-build |
d2b433 |
/*uint16_t *dataPtr = (uint16_t*)*/
|
|
rpm-build |
d2b433 |
m_output->allocData(dcInfo.imageWidth
|
|
rpm-build |
d2b433 |
* sizeof(uint16_t)
|
|
rpm-build |
d2b433 |
* dcInfo.imageHeight
|
|
rpm-build |
d2b433 |
* dcInfo.numComponents);
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
LOGDBG1("dc width = %d dc height = %d\n", dcInfo.imageWidth,
|
|
rpm-build |
d2b433 |
dcInfo.imageHeight);
|
|
rpm-build |
d2b433 |
/* consistently the real width is the JPEG width * numComponent
|
|
rpm-build |
d2b433 |
* at least with all the Canon.
|
|
rpm-build |
d2b433 |
* @todo check that this is valid with DNG too.
|
|
rpm-build |
d2b433 |
*/
|
|
rpm-build |
d2b433 |
uint32_t width = dcInfo.imageWidth * dcInfo.numComponents;
|
|
rpm-build |
d2b433 |
m_output->setDimensions(width, dcInfo.imageHeight);
|
|
rpm-build |
d2b433 |
m_output->setSlices(m_slices);
|
|
rpm-build |
d2b433 |
DecoderStructInit(&dcInfo);
|
|
rpm-build |
d2b433 |
HuffDecoderInit(&dcInfo);
|
|
rpm-build |
d2b433 |
DecodeImage(&dcInfo);
|
|
rpm-build |
d2b433 |
// TODO handle the error properly
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
catch(...)
|
|
rpm-build |
d2b433 |
{
|
|
rpm-build |
d2b433 |
LOGERR("Decompression error\n");
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
return std::move(m_output);
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
}
|
|
rpm-build |
d2b433 |
|
|
rpm-build |
d2b433 |
/*
|
|
rpm-build |
d2b433 |
Local Variables:
|
|
rpm-build |
d2b433 |
mode:c++
|
|
rpm-build |
d2b433 |
c-file-style:"stroustrup"
|
|
rpm-build |
d2b433 |
c-file-offsets:((innamespace . 0))
|
|
rpm-build |
d2b433 |
indent-tabs-mode:nil
|
|
rpm-build |
d2b433 |
fill-column:80
|
|
rpm-build |
d2b433 |
End:
|
|
rpm-build |
d2b433 |
*/
|