satdump/plugins/xrit_support/DecompWT/CImage.cpp

420 lines
11 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.
*/
//:Ignore
//////////////////////////////////////////////////////////////////////////
//
// FileName: CImage.cpp
//
// Date Created: 14/8/1998
//
// Author: Van Wynsberghe Laurent
//
//
// Description: pack and unpack functions, and random packed buffer generator
//
//
// Last Modified: $Dmae: 1999/04/20 08:49:05 $
//
// RCS Id: $Id: CImage.cpp,v 1.34 1999/04/20 08:49:05 youag Exp $
//
// $Rma: CImage.cpp,v $
// Revision 1.34 1999/04/20 08:49:05 youag
// Optimizing CImage pack & unpack for NR = 8, 10, 12 and 16
//
// Revision 1.33 1999/04/16 17:03:31 youag
// Optimizing pack and unpack functions using *pointer++
//
// Revision 1.32 1999/04/16 11:03:32 youag
// Cleaning the code from commented lines
//
// Revision 1.31 1999/04/15 17:49:57 youag
// Buf correction in CImage pack(), bug introduced by previous optimization
//
// Revision 1.30 1999/04/15 15:24:20 youag
// CImage optimization of pack and unpack functions (removing un-needed masks)
//
// Revision 1.29 1999/03/24 12:53:40 youag
// Intel / Alpha optimisation tests
//
// Revision 1.28 1999/03/23 15:40:26 xne
// Optimized Cget/Cset data members for alpha
//
// Revision 1.27 1999/03/01 20:07:40 xne
// (Re)introducing CVS/RCS commit messages
//
////////////////////////////////////////////////////////////////////////////
//:End Ignore
#include <memory>
#include <iostream>
#include "CImage.h"
namespace COMP
{
//------------------------------------------------------------------------
CImage::CImage(unsigned short i_NC, unsigned short i_NL, unsigned short i_NB)
{
COMP_TRYTHIS
Resize(i_NC, i_NL, i_NB);
COMP_CATCHTHIS
}
//------------------------------------------------------------------------
CImage::CImage(const Util::CDataFieldUncompressedImage &i_cdfui)
{
COMP_TRYTHIS
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Optimized version for (NB == NR) in 8, 10 or 12 bits
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Assert(i_cdfui.GetNR() >= i_cdfui.GetNB(), Util::CParamException());
Assert((i_cdfui.GetNR() == 8) ||
(i_cdfui.GetNR() == 10) ||
(i_cdfui.GetNR() == 12) ||
(i_cdfui.GetNR() == 16),
Util::CParamException());
Resize(i_cdfui.GetNC(), i_cdfui.GetNL(), i_cdfui.GetNB());
unsigned short word_IN, word_OUT;
const unsigned char *pIn = i_cdfui.get();
unsigned short *pOut = &m_data[0];
ResetState();
switch (i_cdfui.GetNR())
{
case 16:
while (m_index < m_size)
{
word_IN = *pIn++;
word_OUT = word_IN << 8; // 1111.1111
word_IN = *pIn++;
word_OUT |= word_IN; // 1111.1111
*pOut++ = word_OUT;
m_index++;
}
break;
case 12:
while (m_index < m_size)
{
// read 2 pixels = 3 bytes and write 2 pixels = 4 bytes
word_IN = *pIn++;
word_OUT = word_IN << 4; // 1111.1111
word_IN = *pIn++;
word_OUT |= word_IN >> 4; // 1111.0000
*pOut++ = word_OUT;
m_index++;
if (m_index < m_size)
{
word_OUT = (word_IN & 0x0F) << 8; // 0000.1111
word_IN = *pIn++;
word_OUT |= word_IN; // 1111.1111
*pOut++ = word_OUT;
m_index++;
}
}
break;
case 10:
while (m_index < m_size)
{
// read 5 bytes=4 pixels and write 4 pixels=8 bytes
word_IN = *pIn++;
word_OUT = word_IN << 2; // 1111.1111
word_IN = *pIn++;
word_OUT |= word_IN >> 6; // 1100.0000
*pOut++ = word_OUT;
m_index++;
if (m_index < m_size)
{
word_OUT = (word_IN & 0x3F) << 4; // 0011.1111
word_IN = *pIn++;
word_OUT |= word_IN >> 4; // 1111.0000
*pOut++ = word_OUT;
m_index++;
if (m_index < m_size)
{
word_OUT = (word_IN & 0x0F) << 6; // 0000.1111
word_IN = *pIn++;
word_OUT |= word_IN >> 2; // 1111.1100
*pOut++ = word_OUT;
m_index++;
if (m_index < m_size)
{
word_OUT = (word_IN & 0x03) << 8; // 0000.0011
word_IN = *pIn++;
word_OUT |= word_IN; // 1111.1111
*pOut++ = word_OUT;
m_index++;
}
}
}
}
break;
case 8:
while (m_index < m_size)
{
word_IN = *pIn++;
word_OUT = word_IN; // 1111.1111
*pOut++ = word_OUT;
m_index++;
}
break;
default:
// Not (yet) implemented
Assert(0, Util::CParamException());
}
ResetState();
COMP_CATCHTHIS
}
//------------------------------------------------------------------------
void CImage::Resize(unsigned short i_NC, unsigned short i_NL, unsigned short i_NB)
{
COMP_TRYTHIS
m_NB = i_NB;
m_NC = i_NC;
m_NL = i_NL;
m_size = (unsigned long)i_NC * i_NL;
m_data.clear();
m_dataptr.clear();
if (m_size > 0)
{
m_data.resize(m_size, 0);
Assert(m_data.size() == m_size, Util::CCLibException());
m_dataptr.resize(m_NL, NULL);
Assert(m_dataptr.size() == m_NL, Util::CCLibException());
for (short i = 0; i < m_NL; i++)
m_dataptr[i] = &m_data[i * m_NC];
}
ResetState();
COMP_CATCHTHIS
}
//------------------------------------------------------------------------
void CImage::Forward_point_transform(unsigned short i_pt)
{
COMP_TRYTHIS
// Perform the point transform on every pixel
// pixel = pixel / 2^(i_pt)
Assert(i_pt <= 16, Util::CParamException());
if (i_pt)
for (unsigned long i = 0; i < m_size; i++)
m_data[i] >>= i_pt;
COMP_CATCHTHIS
}
//------------------------------------------------------------------------
void CImage::Inverse_point_transform(unsigned short i_pt)
{
COMP_TRYTHIS
// Perform the inverse point transform on every pixel
// pixel = pixel * 2^(i_pt)
Assert(i_pt <= 16, Util::CParamException());
if (i_pt)
for (unsigned long i = 0; i < m_size; i++)
m_data[i] <<= i_pt;
COMP_CATCHTHIS
}
//------------------------------------------------------------------------
Util::CDataFieldUncompressedImage CImage::pack(unsigned short i_NR)
{
COMP_TRYTHIS
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Optimized version for (NB == NR) in 8, 10 or 12 bits
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Assert(i_NR >= m_NB, Util::CParamException()); // this check is also performed in the CDFUI constructor
Assert(i_NR == 8 ||
i_NR == 10 ||
i_NR == 12 ||
i_NR == 16,
Util::CParamException());
Util::CDataFieldUncompressedImage cdfui((unsigned char)m_NB, m_NC, m_NL, (unsigned char)i_NR);
unsigned short word_IN, word_OUT;
const unsigned short *pIn = &m_data[0];
unsigned char *pOut = cdfui.get();
ResetState();
switch (i_NR)
{
case 16:
while (m_index < m_size)
{
// read 1 pixel = 2 bytes and write 1 pixel = 2 bytes
word_IN = *pIn++;
m_index++;
word_OUT = word_IN >> 8; // 1111.1111.0000.0000
*pOut++ = (unsigned char)word_OUT;
word_OUT = word_IN & 0xFF; // 0000.0000.1111.1111
*pOut++ = (unsigned char)word_OUT;
}
break;
case 12:
while (m_index < m_size)
{
// read 2 pixels = 4 bytes and write 2 pixels = 3 bytes
word_IN = *pIn++ & 0xFFF;
m_index++;
word_OUT = word_IN >> 4; // 1111.1111.0000
*pOut++ = (unsigned char)word_OUT;
word_OUT = (word_IN & 0x00F) << 4; // 0000.0000.1111
if (m_index < m_size)
{
word_IN = *pIn++ & 0xFFF;
m_index++;
word_OUT |= word_IN >> 8; // 1111.0000.0000
*pOut++ = (unsigned char)word_OUT;
word_OUT = word_IN & 0x0FF; // 0000.1111.1111
*pOut++ = (unsigned char)word_OUT;
}
else
*pOut++ = (unsigned char)word_OUT;
}
break;
case 10:
while (m_index < m_size)
{
// read 4 pixels = 8 bytes and write 4 pixels = 5 bytes
word_IN = *pIn++ & 0x3FF;
m_index++;
word_OUT = word_IN >> 2; // 11.1111.1100
*pOut++ = (unsigned char)word_OUT;
word_OUT = (word_IN & 0x003) << 6; // 00.0000.0011
if (m_index < m_size)
{
word_IN = *pIn++ & 0x3FF;
m_index++;
word_OUT |= word_IN >> 4; // 11.1111.0000
*pOut++ = (unsigned char)word_OUT;
word_OUT = (word_IN & 0x00F) << 4; // 00.0000.1111
if (m_index < m_size)
{
word_IN = *pIn++ & 0x3FF;
m_index++;
word_OUT |= word_IN >> 6; // 11.1100.0000
*pOut++ = (unsigned char)word_OUT;
word_OUT = (word_IN & 0x03F) << 2; // 00.0011.1111
if (m_index < m_size)
{
word_IN = *pIn++ & 0x3FF;
m_index++;
word_OUT |= word_IN >> 8; // 11.0000.0000
*pOut++ = (unsigned char)word_OUT;
word_OUT = word_IN & 0x0FF; // 00.1111.1111
*pOut++ = (unsigned char)word_OUT;
}
else
*pOut++ = (unsigned char)word_OUT;
}
else
*pOut++ = (unsigned char)word_OUT;
}
else
*pOut++ = (unsigned char)word_OUT;
}
break;
case 8:
while (m_index < m_size)
{
word_IN = *pIn++ & 0xFF;
m_index++;
word_OUT = word_IN; // 1111.1111
*pOut++ = (unsigned char)word_OUT;
}
break;
default:
// Not (yet) implemented
Assert(0, Util::CParamException());
}
ResetState();
return cdfui;
COMP_CATCHTHIS
}
//------------------------------------------------------------------------
void CImage::Requantize(COMP::ERequantizationMode i_mode)
{
COMP_TRYTHIS
unsigned long i;
unsigned short *pData = &m_data[0];
switch (i_mode)
{
case COMP::e_NoRequantization:
return;
case COMP::e_10to12:
Assert(m_NB == 10, Util::CParamException());
m_NB = 12;
return;
case COMP::e_10to8_floor:
Assert(m_NB == 10, Util::CParamException());
for (i = 0; i < m_size; i++)
*pData++ >>= 2;
m_NB = 8;
return;
case COMP::e_10to8_floor1:
Assert(m_NB == 10, Util::CParamException());
for (i = 0; i < m_size; i++)
{
unsigned short c = *pData;
c = (c + 1) >> 2;
if (c > 255)
c = 255;
*pData++ = c;
}
m_NB = 8;
return;
case COMP::e_10to8_round:
Assert(m_NB == 10, Util::CParamException());
for (i = 0; i < m_size; i++)
{
unsigned short c = *pData;
c = (c + 2) >> 2;
if (c > 255)
c = 255;
*pData++ = c;
}
m_NB = 8;
return;
case COMP::e_10to8_ceil:
Assert(m_NB == 10, Util::CParamException());
for (i = 0; i < m_size; i++)
{
unsigned short c = *pData;
c = (c + 3) >> 2;
if (c > 255)
c = 255;
*pData++ = c;
}
m_NB = 8;
return;
default:
Assert(0, Util::CParamException());
}
COMP_CATCHTHIS
}
//------------------------------------------------------------------------
void CImage::ResetState(void)
{
COMP_TRYTHIS
m_index = 0;
m_cur_L = 0;
m_cur_C = 0;
m_cur_RI = 0;
COMP_CATCHTHIS
}
//------------------------------------------------------------------------
} // end namespace COMP