/// Frame::ComputeMCUSizes // Compute the MCU sizes of the components from the subsampling values void Frame::ComputeMCUSizes(void) { UBYTE i; UWORD maxx,maxy; // Compute the maximum MCU width and height. assert(m_ppComponent[0]); maxx = m_ppComponent[0]->SubXOf(); maxy = m_ppComponent[0]->SubYOf(); for(i = 1;i < m_ucDepth;i++) { assert(m_ppComponent[i]); maxx = m_ppComponent[i]->SubXOf() * maxx / gcd(m_ppComponent[i]->SubXOf(),maxx); maxy = m_ppComponent[i]->SubYOf() * maxy / gcd(m_ppComponent[i]->SubYOf(),maxy); if (maxx > MAX_UBYTE || maxy > MAX_UBYTE) JPG_THROW(OVERFLOW_PARAMETER,"Frame::ComputeMCUSizes", "the smallest common multiple of all subsampling factors must be smaller than 255"); } m_ucMaxMCUWidth = maxx; m_ucMaxMCUHeight = maxy; for(i = 0;i < m_ucDepth;i++) { m_ppComponent[i]->SetMCUSize(maxx,maxy); } // // Check whether the scm is actually part of the MCU sizes written. If not, // then JPEG cannot support this subsampling setting. Wierd. for(i = 0;i < m_ucDepth;i++) { if (m_ppComponent[i]->SubXOf() != m_ucMaxMCUWidth / m_ppComponent[i]->MCUWidthOf() || m_ppComponent[i]->SubYOf() != m_ucMaxMCUHeight / m_ppComponent[i]->MCUHeightOf()) JPG_THROW(INVALID_PARAMETER,"Frame::ComputeMCUSizes", "the given set of subsampling parameters is not supported by JPEG"); } }
/// HuffmanTemplate::ParseMarker void HuffmanTemplate::ParseMarker(class ByteStream *io) { ULONG i,total = 0; // A new decoder chain is required here. delete m_pDecoder; m_pDecoder = NULL; delete m_pEncoder; m_pEncoder = NULL; // Read the number of huffman codes of length i-1 for(i = 0; i < 16U; i++) { LONG cnt = io->Get(); if (cnt == ByteStream::EOF) JPG_THROW(MALFORMED_STREAM,"HuffmanTemplate::ParseMarker","huffman table marker run out of data"); m_ucLengths[i] = cnt; total += cnt; } m_ulCodewords = total; assert(m_pucValues == NULL); m_pucValues = (UBYTE *)m_pEnviron->AllocMem(sizeof(UBYTE) * total); for(i = 0; i < total; i++) { LONG v = io->Get(); if (v == ByteStream::EOF) JPG_THROW(MALFORMED_STREAM,"HuffmanTemplate::ParseMarker","huffman table marker run out of data"); m_pucValues[i] = v; } }
/// Frame::DefineComponent // Define a component for writing. Must be called exactly once per component for encoding. // idx is the component index (not its label, which is generated automatically), and // the component subsampling factors. class Component *Frame::DefineComponent(UBYTE idx,UBYTE subx,UBYTE suby) { if (m_ucDepth == 0) JPG_THROW(OBJECT_DOESNT_EXIST,"Frame::DefineComponent", "Frame depth must be specified first before defining the component properties"); if (m_ucPrecision == 0) JPG_THROW(OBJECT_DOESNT_EXIST,"Frame::DefineComponent", "Frame precision must be specified first before defining the component properties"); if (idx >= m_ucDepth) JPG_THROW(OVERFLOW_PARAMETER,"Frame::DefineComponent", "component index is out of range, must be between 0 and depth-1"); if (m_ppComponent == NULL) { m_ppComponent = (class Component **)m_pEnviron->AllocMem(sizeof(class Component *) * m_ucDepth); memset(m_ppComponent,0,sizeof(class Component *) * m_ucDepth); } if (m_ppComponent[idx]) JPG_THROW(OBJECT_EXISTS,"Frame::DefineComponent", "the indicated component is already defined"); m_ppComponent[idx] = new(m_pEnviron) Component(m_pEnviron,idx,m_ucPrecision,subx,suby); return m_ppComponent[idx]; }
/// Tables::FindQuantizationTable // Find the quantization table of the given index. const UWORD *Tables::FindQuantizationTable(UBYTE idx) const { const UWORD *t; if (m_pQuant == NULL) JPG_THROW(OBJECT_DOESNT_EXIST,"Tables::FindQuantizationTable","DQT marker missing, no quantization table defined"); t = m_pQuant->QuantizationTable(idx); if (t == NULL) JPG_THROW(OBJECT_DOESNT_EXIST,"Tables::FindQuantizationTable","requested quantization matrix not defined"); return t; }
/// Tables::FindACHuffmanTable // Find the AC huffman table of the indicated index. class HuffmanTemplate *Tables::FindACHuffmanTable(UBYTE idx,ScanType type,UBYTE depth,UBYTE hidden,bool residual) const { class HuffmanTemplate *t; if (m_pHuffman == NULL) JPG_THROW(OBJECT_DOESNT_EXIST,"Tables::FindACHuffmanTable","DHT marker missing for huffman encoded scan"); t = m_pHuffman->ACTemplateOf(idx,type,depth,hidden,residual); if (t == NULL) JPG_THROW(OBJECT_DOESNT_EXIST,"Tables::FindACHuffmanTable","requested AC huffman coding table not defined"); return t; }
void BitStream<bitstuffing>::ReportError(void) { class Environ *m_pEnviron = m_pIO->EnvironOf(); if (m_bEOF) JPG_THROW(UNEXPECTED_EOF,"BitStream::ReportError", "invalid stream, found EOF within entropy coded segment"); if (m_bMarker) JPG_THROW(UNEXPECTED_EOF,"BitStream::ReportError", "invalid stream, found marker in entropy coded segment"); JPG_THROW(MALFORMED_STREAM,"BitStream::ReportError", "invalid stream, found invalid huffman code in entropy coded segment"); }
/// ACTemplate::ParseACMarker // Parse off an AC conditioning parameter. void ACTemplate::ParseACMarker(class ByteStream *io) { LONG ac = io->Get(); if (ac == ByteStream::EOF) JPG_THROW(MALFORMED_STREAM,"ACTemplate::ParseACMarker", "unexpected EOF while parsing off the AC conditioning parameters"); if (ac < 1 || ac > 63) JPG_THROW(MALFORMED_STREAM,"ACTemplate::ParseACMarker", "AC conditoning parameter must be between 1 and 63"); m_ucBlockEnd = ac; }
/// PredictorBase::CreatePredictorChain // Create a prediction chain for the given neutral value and // the given prediction mode. The mode "none" is used to // indicate the differential mode. // This requires an array of four predictors to be used for // life-time management. The first element is the initial predictor. void PredictorBase::CreatePredictorChain(class Environ *m_pEnviron,class PredictorBase *chain[4], PredictionMode mode,UBYTE preshift, LONG neutral) { if (preshift > 20) JPG_THROW(OVERFLOW_PARAMETER,"PredictorBase::CreatePredictorChain", "lossless predictive point transformation value is out of range, no code provisioned for it"); assert(chain[0] == NULL && chain[1] == NULL && chain[2] == NULL && chain[3] == NULL); switch(mode) { case None: // This is differential. It only requires a single predictor. chain[0] = CreatePredictor(m_pEnviron,mode,preshift,0); assert(chain[0]); // This predictor stays the same no matter how we move. chain[0]->m_pNextRight = chain[0]; chain[0]->m_pNextDown = chain[0]; break; case Left: case Top: case LeftTop: case Linear: case WeightA: case WeightB: case Diagonal: // It starts with the neutral predictor top left. chain[0] = CreatePredictor(m_pEnviron,Neutral,preshift,neutral); chain[1] = CreatePredictor(m_pEnviron,Left ,preshift,0); chain[2] = CreatePredictor(m_pEnviron,Top ,preshift,0); chain[3] = CreatePredictor(m_pEnviron,mode ,preshift,0); assert(chain[0] && chain[1] && chain[2] && chain[3]); // // Now link them in. chain[0]->m_pNextRight = chain[1]; chain[1]->m_pNextRight = chain[1]; chain[0]->m_pNextDown = chain[2]; chain[1]->m_pNextDown = chain[3]; chain[2]->m_pNextRight = chain[3]; chain[2]->m_pNextDown = chain[2]; chain[3]->m_pNextRight = chain[3]; chain[3]->m_pNextDown = chain[3]; break; default: JPG_THROW(INVALID_PARAMETER,"PredictorBase::CreatePredictorChain", "unable to initiate a lossless predictive scan, invalid prediction mode specified"); break; } }
/// Frame::StartMeasureScan // Start a measurement scan class Scan *Frame::StartMeasureScan(void) { if (m_pCurrent == NULL) JPG_THROW(OBJECT_DOESNT_EXIST,"Frame::StartMeasureScan", "scan parameters have not been defined yet"); if (m_pImage == NULL) JPG_THROW(OBJECT_DOESNT_EXIST,"Frame::StartMeasureScan", "frame is currently not available for measurements"); // // Create a compatible image buffer and put it into BitmapCtrl, // or re-use it. m_pCurrent->StartMeasureScan(m_pImage); return m_pCurrent; }
/// RestartIntervalMarker::ParseMarker // Parse the marker from the stream. void RestartIntervalMarker::ParseMarker(class ByteStream *io) { LONG len = io->GetWord(); if (len != 4) JPG_THROW(MALFORMED_STREAM,"RestartIntervalMarker::ParseMarker", "DRI restart interval definition marker size is invalid"); len = io->GetWord(); if (len == ByteStream::EOF) JPG_THROW(UNEXPECTED_EOF,"RestartIntervalMarker::ParseMarker", "DRI restart interval definition marker run out of data"); m_usRestartInterval = UWORD(len); }
/// NameSpace::AllocateMatrixID // Allocate an ID for a nonlinarity. UBYTE NameSpace::AllocateMatrixID(void) const { UBYTE idx = MergingSpecBox::FreeForm; if (m_ppPrimaryList) { const class Box *box = *m_ppPrimaryList; while(box) { const class MatrixBox *matrix = dynamic_cast<const MatrixBox *>(box); if (matrix) { if (matrix->IdOf() >= idx) idx = matrix->IdOf() + 1; } box = box->NextOf(); } } if (m_ppSecondaryList) { const class Box *box = *m_ppSecondaryList; while(box) { const class MatrixBox *matrix = dynamic_cast<const MatrixBox *>(box); if (matrix) { if (matrix->IdOf() >= idx) idx = matrix->IdOf() + 1; } box = box->NextOf(); } } if (idx > 15) JPG_THROW(OVERFLOW_PARAMETER,"NameSpace::AllocateNonlinearityID", "cannot create more than 11 linear transformations"); return idx; }
/// NameSpace::AllocateNonlinearityID // Allocate an ID for a nonlinarity. UBYTE NameSpace::AllocateNonlinearityID(void) const { UBYTE idx = 0; if (m_ppPrimaryList) { const class Box *box = *m_ppPrimaryList; while(box) { const class ToneMapperBox *tmo = dynamic_cast<const ToneMapperBox *>(box); if (tmo) { if (tmo->TableDestinationOf() >= idx) idx = tmo->TableDestinationOf() + 1; } box = box->NextOf(); } } if (m_ppSecondaryList) { const class Box *box = *m_ppSecondaryList; while(box) { const class ToneMapperBox *tmo = dynamic_cast<const ToneMapperBox *>(box); if (tmo) { if (tmo->TableDestinationOf() >= idx) idx = tmo->TableDestinationOf() + 1; } box = box->NextOf(); } } if (idx > 15) JPG_THROW(OVERFLOW_PARAMETER,"NameSpace::AllocateNonlinearityID", "cannot create more than 16 nonlinear point transformations"); return idx; }
/// ACRefinementScan::StartWriteScan void ACRefinementScan::StartWriteScan(class ByteStream *io,class Checksum *chk,class BufferCtrl *ctrl) { #if ACCUSOFT_CODE int i; for(i = 0;i < m_ucCount;i++) { m_ulX[i] = 0; } m_Context.Init(); assert(!ctrl->isLineBased()); m_pBlockCtrl = dynamic_cast<BlockCtrl *>(ctrl); m_pBlockCtrl->ResetToStartOfScan(m_pScan); // // Actually, always: m_bMeasure = false; EntropyParser::StartWriteScan(io,chk,ctrl); m_pScan->WriteMarker(io); m_Coder.OpenForWrite(io,chk); #else NOREF(io); NOREF(chk); NOREF(ctrl); JPG_THROW(NOT_IMPLEMENTED,"ACRefinementScan::StartWriteScan", "Lossless JPEG not available in your code release, please contact Accusoft for a full version"); #endif }
/// LosslessScan::StartWriteScan void LosslessScan::StartWriteScan(class ByteStream *io,class Checksum *chk,class BufferCtrl *ctrl) { #if ACCUSOFT_CODE int i; FindComponentDimensions(); for(i = 0;i < m_ucCount;i++) { m_pDCCoder[i] = m_pScan->DCHuffmanCoderOf(i); m_pDCStatistics[i] = NULL; } assert(ctrl->isLineBased()); m_pLineCtrl = dynamic_cast<LineBuffer *>(ctrl); m_pLineCtrl->ResetToStartOfScan(m_pScan); EntropyParser::StartWriteScan(io,chk,ctrl); m_pScan->WriteMarker(io); m_Stream.OpenForWrite(io,chk); m_bMeasure = false; #else NOREF(io); NOREF(chk); NOREF(ctrl); JPG_THROW(NOT_IMPLEMENTED,"LosslessScan::StartWriteScan", "Lossless JPEG not available in your code release, please contact Accusoft for a full version"); #endif }
/// Frame::BuildImage // Build the image buffer type fitting to the frame type. class BitmapCtrl *Frame::BuildImage(void) { switch(m_Type) { case Baseline: // also sequential case Sequential: case Progressive: case ACSequential: case ACProgressive: { if (m_pTables->ResidualDataOf()) { m_pBlockHelper = new(m_pEnviron) class ResidualBlockHelper(this); } class BlockBitmapRequester *bb = new(m_pEnviron) class BlockBitmapRequester(this); bb->SetBlockHelper(m_pBlockHelper); return bb; } case Lossless: case ACLossless: case DifferentialLossless: case ACDifferentialLossless: case JPEG_LS: return new(m_pEnviron) class LineBitmapRequester(this); case Dimensions: return new(m_pEnviron) class HierarchicalBitmapRequester(this); default: break; // Everything else is part of a hierarchical scan and does not have a full image buffer by itself. } JPG_THROW(MALFORMED_STREAM,"Frame::BuildLineAdapter","found illegal or unsupported frame type"); return NULL; }
/// Frame::BuildLineAdapter // Build the line adapter fitting to the frame type. class LineAdapter *Frame::BuildLineAdapter(void) { switch(m_Type) { case Baseline: // also sequential case Sequential: case Progressive: case DifferentialSequential: case DifferentialProgressive: case ACSequential: case ACProgressive: case ACDifferentialSequential: case ACDifferentialProgressive: case Residual: case ACResidual: return new(m_pEnviron) class BlockLineAdapter(this); // all block based. case Lossless: case ACLossless: case DifferentialLossless: case ACDifferentialLossless: case JPEG_LS: return new(m_pEnviron) class LineLineAdapter(this); // all line based. case Dimensions: break; } JPG_THROW(INVALID_PARAMETER,"Frame::BuildLineAdapter","found illegal or unsupported frame type"); return NULL; }
// // Buffer the original data unaltered. Required for residual coding, for some modes of // it at least. virtual void RGB2RGB(const RectAngle<LONG> &,const struct ImageBitMap *const *, Buffer) { // This does not implement residual coding, code should not go here. JPG_THROW(INVALID_PARAMETER,"LSLosslessTrafo::RGB2RGB", "JPEG LS lossless color transformation does not allow residual coding"); }
/// Frame::NextScan class Scan *Frame::NextScan(void) { if (m_pCurrent == NULL) JPG_THROW(OBJECT_DOESNT_EXIST,"Frame::NextScan","no scan iteration has been started, cannot advance the scan"); return m_pCurrent = m_pCurrent->NextOf(); }
/// Frame::WriteFrameType // Write the marker that identifies this type of frame, and all the scans within it. void Frame::WriteFrameType(class ByteStream *io) const { if (m_pScan == NULL) JPG_THROW(OBJECT_DOESNT_EXIST,"Frame::WriteFrameType", "frame parameters have not yet been installed, cannot write frame type"); m_pScan->WriteFrameType(io); }
/// ACRefinementScan::StartMeasureScan // Measure scan statistics. void ACRefinementScan::StartMeasureScan(class BufferCtrl *) { // // This is not required. JPG_THROW(NOT_IMPLEMENTED,"ACRefinementScan::StartMeasureScan", "arithmetic coding is always adaptive and does not require " "to measure the statistics"); }
/// ACTemplate::ParseDCMarker // Parse off DC conditioning parameters. void ACTemplate::ParseDCMarker(class ByteStream *io) { LONG dc = io->Get(); UBYTE l,u; if (dc == ByteStream::EOF) JPG_THROW(MALFORMED_STREAM,"ACTemplate::ParseDCMarker", "unexpected EOF while parsing off the AC conditioning parameters"); l = dc & 0x0f; u = dc >> 4; if (u < l) JPG_THROW(MALFORMED_STREAM,"ACTemplate::ParseDCMarker", "upper DC conditioning parameter must be larger or equal to the lower one"); m_ucLower = l; m_ucUpper = u; }
/// Thresholds::ParseMarker // Parse the marker contents of a LSE marker. void Thresholds::ParseMarker(class ByteStream *io,UWORD len) { if (len != 13) JPG_THROW(MALFORMED_STREAM,"Thresholds::ParseMarker","LSE marker length is invalid"); m_usMaxVal = io->GetWord(); m_usT1 = io->GetWord(); m_usT2 = io->GetWord(); m_usT3 = io->GetWord(); m_usReset = io->GetWord(); }
/// Frame::FindComponent // Find a component by a component identifier. Throws if the component does not exist. class Component *Frame::FindComponent(UBYTE id) const { int i; for(i = 0;i < m_ucDepth;i++) { if (m_ppComponent[i]->IDOf() == id) return m_ppComponent[i]; } JPG_THROW(OBJECT_DOESNT_EXIST,"Frame::FindComponent","found a component ID that does not exist"); return NULL; // dummy. }
/// EXIFMarker::ParseMarker // Parse the adobe marker from the stream // This will throw in case the marker is not // recognized. The caller will have to catch // the exception. void EXIFMarker::ParseMarker(class ByteStream *io,UWORD len) { if (len < 2 + 4 + 2 + 2 + 2 + 4 + 2 + 4) JPG_THROW(MALFORMED_STREAM,"EXIFMarker::ParseMarker","misformed EXIF marker"); // // The exif header has already been parsed off. len -= 2 + 4 + 2; // Skip the rest of the marker. if (len > 0) io->SkipBytes(len); }
/// EntropyParser::ParseDNLMarker // Parse the DNL marker, update the frame height. If // the result is true, the marker has been found. bool EntropyParser::ParseDNLMarker(class ByteStream *io) { LONG dt; if (m_bDNLFound) return true; dt = io->PeekWord(); while(dt == 0xffff) { // A filler byte followed by the marker (hopefully). Skip the // filler and try again. io->Get(); dt = io->PeekWord(); } if (dt == 0xffdc) { dt = io->GetWord(); dt = io->GetWord(); if (dt != 4) JPG_THROW(MALFORMED_STREAM,"EntropyParser::ParseDNLMarker", "DNL marker size is out of range, must be exactly four bytes long"); dt = io->GetWord(); if (dt == ByteStream::EOF) JPG_THROW(UNEXPECTED_EOF,"EntropyParser::ParseDNLMarker", "stream is truncated, could not read the DNL marker"); if (dt == 0) JPG_THROW(MALFORMED_STREAM,"EntropyParser::ParseDNLMarker", "frame height as indicated by the DNL marker is corrupt, must be > 0"); m_pFrame->PostImageHeight(dt); m_bDNLFound = true; return true; } else { return false; } }
/// BitmapCtrl::RequestUserData // Request data from the user through the indicated bitmap hook // for the given rectangle. The rectangle is first clipped to // range (as appropriate, if the height is already known) and // then the desired n'th component of the scan (not the component // index) is requested. void BitmapCtrl::RequestUserData(class BitMapHook *bmh,const RectAngle<LONG> &r,UBYTE comp) { assert(comp < m_ucCount && bmh); bmh->RequestClientData(r,m_ppBitmap[comp],m_pFrame->ComponentOf(comp)); if (m_ucPixelType == 0) { // Not yet defined m_ucPixelType = m_ppBitmap[comp]->ibm_ucPixelType; } else if (m_ppBitmap[comp]->ibm_ucPixelType) { if (m_ucPixelType != m_ppBitmap[comp]->ibm_ucPixelType) { JPG_THROW(INVALID_PARAMETER,"BitmapCtrl::RequestUserData","pixel types must be consistent accross components"); } } }
/// Component::ParseMarker void Component::ParseMarker(class ByteStream *io) { LONG data; data = io->Get(); if (data == ByteStream::EOF) JPG_THROW(MALFORMED_STREAM,"Component::ParseMarker","frame marker incomplete, no component identifier found"); m_ucID = data; data = io->Get(); if (data == ByteStream::EOF) JPG_THROW(MALFORMED_STREAM,"Component::ParseMarker","frame marker incomplete, subsamling information missing"); m_ucMCUWidth = data >> 4; m_ucMCUHeight = data & 0x0f; data = io->Get(); if (data < 0 || data > 3) JPG_THROW(MALFORMED_STREAM,"Component::ParseMarker","quantization table identifier corrupt, must be >= 0 and <= 3"); m_ucQuantTable = data; }
/// HuffmanTemplate::BuildDecoder // Build the huffman decoder given the template data. void HuffmanTemplate::BuildDecoder(void) { class HuffmanDecoder *prev = NULL; ULONG i,lastbits = 0; UBYTE *values; ULONG code = 0; assert(m_pDecoder == NULL); if (m_pucValues) { // If the decoder is not used, do not build it. assert(m_ucLengths); for(i = 0,values = m_pucValues; i < 16U; i++) { if (m_ucLengths[i]) { if (values + m_ucLengths[i] > m_pucValues + m_ulCodewords) JPG_THROW(MALFORMED_STREAM,"HuffmanTemplate::ParseMarker","Huffman table marker depends on undefined data"); // There are codes of this lengths. code += m_ucLengths[i]; if (code >= 1UL << (i + 1)) JPG_THROW(MALFORMED_STREAM,"HuffmanTemplate::ParseMarker", "Huffman table corrupt - entry depends on more bits than available for the bit length"); class HuffmanDecoder *huff = new(m_pEnviron) class HuffmanDecoder(values,i+1-lastbits, m_ucLengths[i]); if (prev) { prev->ExtendBy(huff); } else { assert(m_pDecoder == NULL); m_pDecoder = huff; } prev = huff; values += m_ucLengths[i]; lastbits = i+1; } code <<= 1; } } }
/// Frame::PostImageHeight // Define the image size if it is not yet known here. This is // called whenever the DNL marker is parsed in. void Frame::PostImageHeight(ULONG height) { assert(height > 0 && m_pImage); if (m_ulHeight == 0) { m_ulHeight = height; m_pImage->PostImageHeight(height); } else if (m_ulHeight == height) { JPG_WARN(MALFORMED_STREAM,"Frame::PostImageHeight", "found a double DNL marker for a frame, frame size is known already"); } else { JPG_THROW(MALFORMED_STREAM,"Frame::PostImageHeight", "found a double DNL marker for a frame, indicating an inconsistent frame height"); } }
/// ChecksumBox::ParseBoxContent // Second level parsing stage: This is called from the first level // parser as soon as the data is complete. Must be implemented // by the concrete box. Returns true in case the contents is // parsed and the stream can go away. bool ChecksumBox::ParseBoxContent(class ByteStream *stream,UQUAD boxsize) { LONG pack1,pack2; if (boxsize != 4) JPG_THROW(MALFORMED_STREAM,"ChecksumBox::ParseBoxContent", "Malformed JPEG stream, the checksum box size is invalid"); pack1 = stream->GetWord(); pack2 = stream->GetWord(); m_ulCheck = ULONG(pack1 << 16) | ULONG(pack2); return true; }