mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
284 lines
7.2 KiB
C++
284 lines
7.2 KiB
C++
/*
|
|
* Copyright 2011-2019, European Organisation for the Exploitation of Meteorological Satellites (EUMETSAT)
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define NOMINMAX
|
|
|
|
#include <iostream>
|
|
|
|
#include "CDataField.h"
|
|
#include "ErrorHandling.h"
|
|
#include "CompressT4.h"
|
|
#include "RMAErrorHandling.h"
|
|
#include "T4Codes.h"
|
|
#include "T4Decoder.h"
|
|
|
|
namespace COMP
|
|
{
|
|
|
|
// Initialize the decoder structures. If the image size given does not
|
|
// make sense, auto determination of the size if tried.
|
|
CT4Decoder::CT4Decoder(const Util::CDataFieldCompressedImage &i_datafield) : m_ibuf(i_datafield),
|
|
m_QualityInfo(i_datafield.GetNL())
|
|
{
|
|
COMP_TRYTHIS
|
|
Assert(i_datafield.GetNB() == 1, Util::CParamException());
|
|
m_height = i_datafield.GetNL();
|
|
m_width = i_datafield.GetNC();
|
|
if ((m_height <= 0) || (m_width <= 0))
|
|
{
|
|
DecodeBuffer(); // Autodetermine the size of the input image
|
|
m_QualityInfo.resize(m_height);
|
|
}
|
|
m_opbm = std::unique_ptr<CBitBuffer>(new CBitBuffer((unsigned long)m_height * m_width));
|
|
Assert(m_opbm.get(), Util::CCLibException());
|
|
for (unsigned int i = 0; i < m_QualityInfo.size(); i++)
|
|
m_QualityInfo[i] = 0;
|
|
COMP_CATCHTHIS
|
|
}
|
|
|
|
// Reads the input buffer till an EOL symbol is encountered.
|
|
void CT4Decoder::SkipToEOL()
|
|
{
|
|
COMP_TRYTHIS
|
|
short Z = 0;
|
|
bool b = false;
|
|
do
|
|
{
|
|
Z = m_ibuf.GetNbZeroes();
|
|
b = m_ibuf.ReadNextBitZ();
|
|
} while (!((Z > 10) && b));
|
|
COMP_CATCHTHIS
|
|
}
|
|
|
|
// Decode the buffer (if the m_height & m_width have sensible values)
|
|
// otherwize, runs without filling the buffer and try to determine
|
|
// the image size from the data in the input buffer.
|
|
void CT4Decoder::DecodeBuffer()
|
|
{
|
|
COMP_TRYTHIS
|
|
// size & position managment
|
|
//short height = 0;
|
|
short width = 0;
|
|
short i = 0;
|
|
short j = 0;
|
|
// EOF / EOL managmend
|
|
bool EndOfFile = false;
|
|
short NbEOL = 0;
|
|
short Z = 0; // nb of consecutive zeroes found
|
|
// misc.
|
|
bool isWhite = true; // lines always begin with a white code
|
|
bool b = false;
|
|
// T4 codes managment
|
|
short code = 0;
|
|
short length = 0;
|
|
short count = 0;
|
|
|
|
// do we do the thing for real?
|
|
bool real = ((m_height > 0) && (m_width > 0));
|
|
try
|
|
{
|
|
SkipToEOL(); // skip the first EOL
|
|
while (!EndOfFile)
|
|
{
|
|
Z = m_ibuf.GetNbZeroes();
|
|
b = m_ibuf.ReadNextBitZ();
|
|
if (Z > 10) // eat eventual fill bits
|
|
{
|
|
if (b) // we found an EOL marker
|
|
{
|
|
if (j == 0) // are we at the begining of a line ?
|
|
{
|
|
NbEOL++;
|
|
if (NbEOL > 5)
|
|
EndOfFile = true;
|
|
}
|
|
else
|
|
{
|
|
NbEOL = 1;
|
|
if ((i != 0) // we are not at the begining of the file
|
|
&& ((real && (j != m_width)) // we are not at the end of a line
|
|
|| (!real && (j < width)) // we found a line shorter than expected
|
|
))
|
|
{ // then, we shouldn't find an EOL.
|
|
#ifdef _DEBUG
|
|
std::cout << "Unexpected EOL at line " << i << std::endl;
|
|
#endif
|
|
if (real)
|
|
{
|
|
m_opbm->ResetNextNBit(m_width - j);
|
|
SetLineValidity(i, -j);
|
|
}
|
|
}
|
|
else // expected EOL
|
|
{
|
|
SetLineValidity(i, j); // here, j==m_width
|
|
}
|
|
|
|
i++;
|
|
if (real && (i > m_height))
|
|
{
|
|
#ifdef _DEBUG
|
|
std::cout << "File too long...\n";
|
|
#endif
|
|
EndOfFile = true;
|
|
}
|
|
}
|
|
// if we are dummy-running, capture the maximum width
|
|
// this does not allow for detecting bit errors in the file...
|
|
if (!real && (j > width))
|
|
width = j;
|
|
j = 0;
|
|
isWhite = true;
|
|
code = 0;
|
|
length = 0;
|
|
}
|
|
}
|
|
else // we are shure it is not an EOL
|
|
{
|
|
code <<= 1;
|
|
if (b)
|
|
{
|
|
code |= 1;
|
|
}
|
|
length++;
|
|
if (length > 13) // it is certainly a non valid code
|
|
{
|
|
#ifdef _DEBUG
|
|
std::cout << "Error decoding line " << i << " at col " << j << std::endl;
|
|
#endif
|
|
if (real)
|
|
{
|
|
m_opbm->ResetNextNBit(m_width - j);
|
|
SetLineValidity(i, -j);
|
|
}
|
|
j = m_width; // to guard us agains a second COutOfBuffer if SkipToEOL fails...
|
|
SkipToEOL();
|
|
NbEOL++;
|
|
code = 0;
|
|
length = 0;
|
|
j = 0;
|
|
isWhite = true;
|
|
i++;
|
|
if (real && (i > m_height))
|
|
{
|
|
#ifdef _DEBUG
|
|
std::cout << "File too long...\n";
|
|
#endif
|
|
EndOfFile = true;
|
|
}
|
|
}
|
|
else if ((isWhite && (length >= 4)) || (!isWhite && (length >= 2)))
|
|
{
|
|
count = m_AllDecodes.GetCount(code, length, isWhite);
|
|
if (count >= 0)
|
|
{
|
|
code = 0;
|
|
length = 0;
|
|
if (real)
|
|
{
|
|
if (j + count > m_width)
|
|
{
|
|
#ifdef _DEBUG
|
|
std::cout << "Line " << i << " too long.\n";
|
|
#endif
|
|
m_opbm->ResetNextNBit(m_width - j);
|
|
SetLineValidity(i, -j);
|
|
j = m_width; // to guard us agains a second COutOfBuffer if SkipToEOL fails...
|
|
SkipToEOL();
|
|
NbEOL++;
|
|
count = 1000; // to avoid triggering the color reversal if count < 64
|
|
j = -count; // to cover the j+=count later.
|
|
isWhite = true;
|
|
i++;
|
|
if (i >= m_height)
|
|
{
|
|
#ifdef _DEBUG
|
|
std::cout << "File too long...\n";
|
|
#endif
|
|
EndOfFile = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (isWhite)
|
|
{
|
|
m_opbm->ResetNextNBit(count);
|
|
}
|
|
else
|
|
{
|
|
m_opbm->SetNextNBit(count);
|
|
}
|
|
}
|
|
}
|
|
j += count;
|
|
if (count < 64)
|
|
isWhite = !isWhite;
|
|
}
|
|
count = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (COutOfBufferException&)
|
|
{
|
|
// If we get here, it means (at least) we lost the 6 EOL markers
|
|
// So fill the rest of the image with white
|
|
|
|
// Util::LogReason("Expected",Util::CNamedException("Out of buffer exception successfully handled"));
|
|
#ifdef _DEBUG
|
|
std::cout << "Exception at (" << i << "," << j << "). Lost eof (at least)\n";
|
|
#endif
|
|
}
|
|
if (real)
|
|
{
|
|
// this is only needed in case of OutOfBuffer exception or of prematurate
|
|
// EOF (due to a missing EOL or a bad code in the file.
|
|
if (i < m_height)
|
|
{
|
|
#ifdef _DEBUG
|
|
std::cout << "There was a problem while decoding the file\n";
|
|
#endif
|
|
//these loops should NEVER generate an OutOfBuffer Exceptions
|
|
m_opbm->ResetNextNBit(m_width - j);
|
|
SetLineValidity(i, -j);
|
|
i++;
|
|
for (; i < m_height; i++)
|
|
{
|
|
m_opbm->ResetNextNBit(m_width);
|
|
SetLineValidity(i, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!real)
|
|
{
|
|
m_height = i;
|
|
m_width = width;
|
|
}
|
|
m_ibuf.ResetBitIndex();
|
|
COMP_CATCHTHIS
|
|
}
|
|
|
|
// create the CDataFieldUncompressedImage from the CBitBuffer and returns it
|
|
Util::CDataFieldUncompressedImage CT4Decoder::GetDecompressedImage()
|
|
{
|
|
COMP_TRYTHIS
|
|
Util::CDataFieldUncompressedImage dfui((Util::CDataField)(*m_opbm), 1, m_width, m_height, 1);
|
|
return dfui;
|
|
COMP_CATCHTHIS
|
|
}
|
|
|
|
} // end namespace
|