Skip to content

Commit

Permalink
Merge pull request #9376 from alalek:imgcodecs_refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
alalek committed Aug 22, 2017
2 parents cc5b99c + 78a3106 commit f0fb665
Show file tree
Hide file tree
Showing 12 changed files with 281 additions and 129 deletions.
2 changes: 2 additions & 0 deletions modules/imgcodecs/src/bitstrm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ int RLByteStream::getByte()
current = m_current;
}

CV_Assert(current < m_end);

val = *((uchar*)current);
m_current = current + 1;
return val;
Expand Down
19 changes: 13 additions & 6 deletions modules/imgcodecs/src/bitstrm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,20 @@
namespace cv
{

enum
{
RBS_THROW_EOS=-123, // <end of stream> exception code
RBS_THROW_FORB=-124, // <forrbidden huffman code> exception code
RBS_HUFF_FORB=2047, // forrbidden huffman code "value"
RBS_BAD_HEADER=-125 // invalid header
#define DECLARE_RBS_EXCEPTION(name) \
class RBS_ ## name ## _Exception : public cv::Exception \
{ \
public: \
RBS_ ## name ## _Exception(int code_, const String& err_, const String& func_, const String& file_, int line_) : \
cv::Exception(code_, err_, func_, file_, line_) \
{} \
};
DECLARE_RBS_EXCEPTION(THROW_EOS)
#define RBS_THROW_EOS RBS_THROW_EOS_Exception(cv::Error::StsError, "Unexpected end of input stream", CV_Func, __FILE__, __LINE__)
DECLARE_RBS_EXCEPTION(THROW_FORB)
#define RBS_THROW_FORB RBS_THROW_FORB_Exception(cv::Error::StsError, "Forrbidden huffman code", CV_Func, __FILE__, __LINE__)
DECLARE_RBS_EXCEPTION(BAD_HEADER)
#define RBS_BAD_HEADER RBS_BAD_HEADER_Exception(cv::Error::StsError, "Invalid header", CV_Func, __FILE__, __LINE__)

typedef unsigned long ulong;

Expand Down
13 changes: 9 additions & 4 deletions modules/imgcodecs/src/grfmt_bmp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,9 @@ bool BmpDecoder::readHeader()

if( m_bpp <= 8 )
{
memset( m_palette, 0, sizeof(m_palette));
m_strm.getBytes( m_palette, (clrused == 0? 1<<m_bpp : clrused)*4 );
CV_Assert(clrused < 256);
memset(m_palette, 0, sizeof(m_palette));
m_strm.getBytes(m_palette, (clrused == 0? 1<<m_bpp : clrused)*4 );
iscolor = IsColorPalette( m_palette, m_bpp );
}
else if( m_bpp == 16 && m_rle_code == BMP_BITFIELDS )
Expand Down Expand Up @@ -290,7 +291,9 @@ bool BmpDecoder::readData( Mat& img )
else if( code > 2 ) // absolute mode
{
if( data + code*nch > line_end ) goto decode_rle4_bad;
m_strm.getBytes( src, (((code + 1)>>1) + 1) & -2 );
int sz = (((code + 1)>>1) + 1) & (~1);
CV_Assert((size_t)sz < _src.size());
m_strm.getBytes(src, sz);
if( color )
data = FillColorRow4( data, src, code, m_palette );
else
Expand Down Expand Up @@ -379,7 +382,9 @@ decode_rle4_bad: ;

if( data + code3 > line_end )
goto decode_rle8_bad;
m_strm.getBytes( src, (code + 1) & -2 );
int sz = (code + 1) & (~1);
CV_Assert((size_t)sz < _src.size());
m_strm.getBytes(src, sz);
if( color )
data = FillColorRow8( data, src, code, m_palette );
else
Expand Down
122 changes: 75 additions & 47 deletions modules/imgcodecs/src/grfmt_pxm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,50 +43,58 @@
#include "precomp.hpp"
#include "utils.hpp"
#include "grfmt_pxm.hpp"
#include <iostream>

namespace cv
{

///////////////////////// P?M reader //////////////////////////////

static int ReadNumber( RLByteStream& strm, int maxdigits )
static int ReadNumber(RLByteStream& strm, int maxdigits = 0)
{
int code;
int val = 0;
int64 val = 0;
int digits = 0;

code = strm.getByte();

if( !isdigit(code))
while (!isdigit(code))
{
do
if (code == '#' )
{
if( code == '#' )
do
{
do
{
code = strm.getByte();
}
while( code != '\n' && code != '\r' );
code = strm.getByte();
}

while (code != '\n' && code != '\r');
code = strm.getByte();

while( isspace(code))
}
else if (isspace(code))
{
while (isspace(code))
code = strm.getByte();
}
while( !isdigit( code ));
else
{
#if 1
CV_ErrorNoReturn_(Error::StsError, ("PXM: Unexpected code in ReadNumber(): 0x%x (%d)", code, code));
#else
code = strm.getByte();
#endif
}
}

do
{
val = val*10 + code - '0';
if( ++digits >= maxdigits ) break;
val = val*10 + (code - '0');
CV_Assert(val <= INT_MAX && "PXM: ReadNumber(): result is too large");
digits++;
if (maxdigits != 0 && digits >= maxdigits) break;
code = strm.getByte();
}
while( isdigit(code));
while (isdigit(code));

return val;
return (int)val;
}


Expand Down Expand Up @@ -122,13 +130,13 @@ ImageDecoder PxMDecoder::newDecoder() const
return makePtr<PxMDecoder>();
}

void PxMDecoder::close()
void PxMDecoder::close()
{
m_strm.close();
}


bool PxMDecoder::readHeader()
bool PxMDecoder::readHeader()
{
bool result = false;

Expand Down Expand Up @@ -158,10 +166,10 @@ bool PxMDecoder::readHeader()
m_binary = code >= '4';
m_type = m_bpp > 8 ? CV_8UC3 : CV_8UC1;

m_width = ReadNumber( m_strm, INT_MAX );
m_height = ReadNumber( m_strm, INT_MAX );
m_width = ReadNumber(m_strm);
m_height = ReadNumber(m_strm);

m_maxval = m_bpp == 1 ? 1 : ReadNumber( m_strm, INT_MAX );
m_maxval = m_bpp == 1 ? 1 : ReadNumber(m_strm);
if( m_maxval > 65535 )
throw RBS_BAD_HEADER;

Expand All @@ -175,8 +183,14 @@ bool PxMDecoder::readHeader()
result = true;
}
}
catch(...)
catch (const cv::Exception&)
{
throw;
}
catch (...)
{
std::cerr << "PXM::readHeader(): unknown C++ exception" << std::endl << std::flush;
throw;
}

if( !result )
Expand All @@ -189,33 +203,28 @@ bool PxMDecoder::readHeader()
}


bool PxMDecoder::readData( Mat& img )
bool PxMDecoder::readData( Mat& img )
{
int color = img.channels() > 1;
uchar* data = img.ptr();
PaletteEntry palette[256];
bool result = false;
int bit_depth = CV_ELEM_SIZE1(m_type)*8;
int src_pitch = (m_width*m_bpp*bit_depth/8 + 7)/8;
const int bit_depth = CV_ELEM_SIZE1(m_type)*8;
const int src_pitch = divUp(m_width*m_bpp*(bit_depth/8), 8);
int nch = CV_MAT_CN(m_type);
int width3 = m_width*nch;
int i, x, y;

if( m_offset < 0 || !m_strm.isOpened())
return false;

AutoBuffer<uchar> _src(src_pitch + 32);
uchar* src = _src;
AutoBuffer<uchar> _gray_palette;
uchar* gray_palette = _gray_palette;
uchar gray_palette[256] = {0};

// create LUT for converting colors
if( bit_depth == 8 )
{
_gray_palette.allocate(m_maxval + 1);
gray_palette = _gray_palette;
CV_Assert(m_maxval < 256);

for( i = 0; i <= m_maxval; i++ )
for (int i = 0; i <= m_maxval; i++)
gray_palette[i] = (uchar)((i*255/m_maxval)^(m_bpp == 1 ? 255 : 0));

FillGrayPalette( palette, m_bpp==1 ? 1 : 8 , m_bpp == 1 );
Expand All @@ -229,12 +238,16 @@ bool PxMDecoder::readData( Mat& img )
{
////////////////////////// 1 BPP /////////////////////////
case 1:
CV_Assert(CV_MAT_DEPTH(m_type) == CV_8U);
if( !m_binary )
{
for( y = 0; y < m_height; y++, data += img.step )
AutoBuffer<uchar> _src(m_width);
uchar* src = _src;

for (int y = 0; y < m_height; y++, data += img.step)
{
for( x = 0; x < m_width; x++ )
src[x] = ReadNumber( m_strm, 1 ) != 0;
for (int x = 0; x < m_width; x++)
src[x] = ReadNumber(m_strm, 1) != 0;

if( color )
FillColorRow8( data, src, m_width, palette );
Expand All @@ -244,7 +257,10 @@ bool PxMDecoder::readData( Mat& img )
}
else
{
for( y = 0; y < m_height; y++, data += img.step )
AutoBuffer<uchar> _src(src_pitch);
uchar* src = _src;

for (int y = 0; y < m_height; y++, data += img.step)
{
m_strm.getBytes( src, src_pitch );

Expand All @@ -260,13 +276,17 @@ bool PxMDecoder::readData( Mat& img )
////////////////////////// 8 BPP /////////////////////////
case 8:
case 24:
for( y = 0; y < m_height; y++, data += img.step )
{
AutoBuffer<uchar> _src(std::max<size_t>(width3*2, src_pitch));
uchar* src = _src;

for (int y = 0; y < m_height; y++, data += img.step)
{
if( !m_binary )
{
for( x = 0; x < width3; x++ )
for (int x = 0; x < width3; x++)
{
int code = ReadNumber( m_strm, INT_MAX );
int code = ReadNumber(m_strm);
if( (unsigned)code > (unsigned)m_maxval ) code = m_maxval;
if( bit_depth == 8 )
src[x] = gray_palette[code];
Expand All @@ -279,7 +299,7 @@ bool PxMDecoder::readData( Mat& img )
m_strm.getBytes( src, src_pitch );
if( bit_depth == 16 && !isBigEndian() )
{
for( x = 0; x < width3; x++ )
for (int x = 0; x < width3; x++)
{
uchar v = src[x * 2];
src[x * 2] = src[x * 2 + 1];
Expand All @@ -290,7 +310,7 @@ bool PxMDecoder::readData( Mat& img )

if( img.depth() == CV_8U && bit_depth == 16 )
{
for( x = 0; x < width3; x++ )
for (int x = 0; x < width3; x++)
{
int v = ((ushort *)src)[x];
src[x] = (uchar)(v >> 8);
Expand Down Expand Up @@ -331,12 +351,19 @@ bool PxMDecoder::readData( Mat& img )
}
result = true;
break;
}
default:
assert(0);
CV_ErrorNoReturn(Error::StsError, "m_bpp is not supported");
}
}
catch(...)
catch (const cv::Exception&)
{
throw;
}
catch (...)
{
std::cerr << "PXM::readData(): unknown exception" << std::endl << std::flush;
throw;
}

return result;
Expand Down Expand Up @@ -412,8 +439,9 @@ bool PxMEncoder::write( const Mat& img, const std::vector<int>& params )
char* buffer = _buffer;

// write header;
sprintf( buffer, "P%c\n%d %d\n%d\n",
sprintf( buffer, "P%c\n# Generated by OpenCV %s\n%d %d\n%d\n",
'2' + (channels > 1 ? 1 : 0) + (isBinary ? 3 : 0),
CV_VERSION,
width, height, (1 << depth) - 1 );

strm.putBytes( buffer, (int)strlen(buffer) );
Expand Down
Loading

0 comments on commit f0fb665

Please sign in to comment.