Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                           License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
     14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
     15 // Third party copyrights are property of their respective owners.
     16 //
     17 // Redistribution and use in source and binary forms, with or without modification,
     18 // are permitted provided that the following conditions are met:
     19 //
     20 //   * Redistribution's of source code must retain the above copyright notice,
     21 //     this list of conditions and the following disclaimer.
     22 //
     23 //   * Redistribution's in binary form must reproduce the above copyright notice,
     24 //     this list of conditions and the following disclaimer in the documentation
     25 //     and/or other materials provided with the distribution.
     26 //
     27 //   * The name of the copyright holders may not be used to endorse or promote products
     28 //     derived from this software without specific prior written permission.
     29 //
     30 // This software is provided by the copyright holders and contributors "as is" and
     31 // any express or implied warranties, including, but not limited to, the implied
     32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     33 // In no event shall the Intel Corporation or contributors be liable for any direct,
     34 // indirect, incidental, special, exemplary, or consequential damages
     35 // (including, but not limited to, procurement of substitute goods or services;
     36 // loss of use, data, or profits; or business interruption) however caused
     37 // and on any theory of liability, whether in contract, strict liability,
     38 // or tort (including negligence or otherwise) arising in any way out of
     39 // the use of this software, even if advised of the possibility of such damage.
     40 //
     41 //M*/
     42 
     43 #include "precomp.hpp"
     44 #include "utils.hpp"
     45 #include "grfmt_pxm.hpp"
     46 
     47 namespace cv
     48 {
     49 
     50 ///////////////////////// P?M reader //////////////////////////////
     51 
     52 static int ReadNumber( RLByteStream& strm, int maxdigits )
     53 {
     54     int code;
     55     int val = 0;
     56     int digits = 0;
     57 
     58     code = strm.getByte();
     59 
     60     if( !isdigit(code))
     61     {
     62         do
     63         {
     64             if( code == '#' )
     65             {
     66                 do
     67                 {
     68                     code = strm.getByte();
     69                 }
     70                 while( code != '\n' && code != '\r' );
     71             }
     72 
     73             code = strm.getByte();
     74 
     75             while( isspace(code))
     76                 code = strm.getByte();
     77         }
     78         while( !isdigit( code ));
     79     }
     80 
     81     do
     82     {
     83         val = val*10 + code - '0';
     84         if( ++digits >= maxdigits ) break;
     85         code = strm.getByte();
     86     }
     87     while( isdigit(code));
     88 
     89     return val;
     90 }
     91 
     92 
     93 PxMDecoder::PxMDecoder()
     94 {
     95     m_offset = -1;
     96     m_buf_supported = true;
     97 }
     98 
     99 
    100 PxMDecoder::~PxMDecoder()
    101 {
    102     close();
    103 }
    104 
    105 size_t PxMDecoder::signatureLength() const
    106 {
    107     return 3;
    108 }
    109 
    110 bool PxMDecoder::checkSignature( const String& signature ) const
    111 {
    112     return signature.size() >= 3 && signature[0] == 'P' &&
    113            '1' <= signature[1] && signature[1] <= '6' &&
    114            isspace(signature[2]);
    115 }
    116 
    117 ImageDecoder PxMDecoder::newDecoder() const
    118 {
    119     return makePtr<PxMDecoder>();
    120 }
    121 
    122 void  PxMDecoder::close()
    123 {
    124     m_strm.close();
    125 }
    126 
    127 
    128 bool  PxMDecoder::readHeader()
    129 {
    130     bool result = false;
    131 
    132     if( !m_buf.empty() )
    133     {
    134         if( !m_strm.open(m_buf) )
    135             return false;
    136     }
    137     else if( !m_strm.open( m_filename ))
    138         return false;
    139 
    140     try
    141     {
    142         int code = m_strm.getByte();
    143         if( code != 'P' )
    144             throw RBS_BAD_HEADER;
    145 
    146         code = m_strm.getByte();
    147         switch( code )
    148         {
    149         case '1': case '4': m_bpp = 1; break;
    150         case '2': case '5': m_bpp = 8; break;
    151         case '3': case '6': m_bpp = 24; break;
    152         default: throw RBS_BAD_HEADER;
    153         }
    154 
    155         m_binary = code >= '4';
    156         m_type = m_bpp > 8 ? CV_8UC3 : CV_8UC1;
    157 
    158         m_width = ReadNumber( m_strm, INT_MAX );
    159         m_height = ReadNumber( m_strm, INT_MAX );
    160 
    161         m_maxval = m_bpp == 1 ? 1 : ReadNumber( m_strm, INT_MAX );
    162         if( m_maxval > 65535 )
    163             throw RBS_BAD_HEADER;
    164 
    165         //if( m_maxval > 255 ) m_binary = false; nonsense
    166         if( m_maxval > 255 )
    167             m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type));
    168 
    169         if( m_width > 0 && m_height > 0 && m_maxval > 0 && m_maxval < (1 << 16))
    170         {
    171             m_offset = m_strm.getPos();
    172             result = true;
    173         }
    174     }
    175     catch(...)
    176     {
    177     }
    178 
    179     if( !result )
    180     {
    181         m_offset = -1;
    182         m_width = m_height = -1;
    183         m_strm.close();
    184     }
    185     return result;
    186 }
    187 
    188 
    189 bool  PxMDecoder::readData( Mat& img )
    190 {
    191     int color = img.channels() > 1;
    192     uchar* data = img.ptr();
    193     int step = (int)img.step;
    194     PaletteEntry palette[256];
    195     bool   result = false;
    196     int  bit_depth = CV_ELEM_SIZE1(m_type)*8;
    197     int  src_pitch = (m_width*m_bpp*bit_depth/8 + 7)/8;
    198     int  nch = CV_MAT_CN(m_type);
    199     int  width3 = m_width*nch;
    200     int  i, x, y;
    201 
    202     if( m_offset < 0 || !m_strm.isOpened())
    203         return false;
    204 
    205     AutoBuffer<uchar> _src(src_pitch + 32);
    206     uchar* src = _src;
    207     AutoBuffer<uchar> _gray_palette;
    208     uchar* gray_palette = _gray_palette;
    209 
    210     // create LUT for converting colors
    211     if( bit_depth == 8 )
    212     {
    213         _gray_palette.allocate(m_maxval + 1);
    214         gray_palette = _gray_palette;
    215 
    216         for( i = 0; i <= m_maxval; i++ )
    217             gray_palette[i] = (uchar)((i*255/m_maxval)^(m_bpp == 1 ? 255 : 0));
    218 
    219         FillGrayPalette( palette, m_bpp==1 ? 1 : 8 , m_bpp == 1 );
    220     }
    221 
    222     try
    223     {
    224         m_strm.setPos( m_offset );
    225 
    226         switch( m_bpp )
    227         {
    228         ////////////////////////// 1 BPP /////////////////////////
    229         case 1:
    230             if( !m_binary )
    231             {
    232                 for( y = 0; y < m_height; y++, data += step )
    233                 {
    234                     for( x = 0; x < m_width; x++ )
    235                         src[x] = ReadNumber( m_strm, 1 ) != 0;
    236 
    237                     if( color )
    238                         FillColorRow8( data, src, m_width, palette );
    239                     else
    240                         FillGrayRow8( data, src, m_width, gray_palette );
    241                 }
    242             }
    243             else
    244             {
    245                 for( y = 0; y < m_height; y++, data += step )
    246                 {
    247                     m_strm.getBytes( src, src_pitch );
    248 
    249                     if( color )
    250                         FillColorRow1( data, src, m_width, palette );
    251                     else
    252                         FillGrayRow1( data, src, m_width, gray_palette );
    253                 }
    254             }
    255             result = true;
    256             break;
    257 
    258         ////////////////////////// 8 BPP /////////////////////////
    259         case 8:
    260         case 24:
    261             for( y = 0; y < m_height; y++, data += step )
    262             {
    263                 if( !m_binary )
    264                 {
    265                     for( x = 0; x < width3; x++ )
    266                     {
    267                         int code = ReadNumber( m_strm, INT_MAX );
    268                         if( (unsigned)code > (unsigned)m_maxval ) code = m_maxval;
    269                         if( bit_depth == 8 )
    270                             src[x] = gray_palette[code];
    271                         else
    272                             ((ushort *)src)[x] = (ushort)code;
    273                     }
    274                 }
    275                 else
    276                 {
    277                     m_strm.getBytes( src, src_pitch );
    278                     if( bit_depth == 16 && !isBigEndian() )
    279                     {
    280                         for( x = 0; x < width3; x++ )
    281                         {
    282                             uchar v = src[x * 2];
    283                             src[x * 2] = src[x * 2 + 1];
    284                             src[x * 2 + 1] = v;
    285                         }
    286                     }
    287                 }
    288 
    289                 if( img.depth() == CV_8U && bit_depth == 16 )
    290                 {
    291                     for( x = 0; x < width3; x++ )
    292                     {
    293                         int v = ((ushort *)src)[x];
    294                         src[x] = (uchar)(v >> 8);
    295                     }
    296                 }
    297 
    298                 if( m_bpp == 8 ) // image has one channel
    299                 {
    300                     if( color )
    301                     {
    302                         if( img.depth() == CV_8U ) {
    303                             uchar *d = data, *s = src, *end = src + m_width;
    304                             for( ; s < end; d += 3, s++)
    305                                 d[0] = d[1] = d[2] = *s;
    306                         } else {
    307                             ushort *d = (ushort *)data, *s = (ushort *)src, *end = ((ushort *)src) + m_width;
    308                             for( ; s < end; s++, d += 3)
    309                                 d[0] = d[1] = d[2] = *s;
    310                         }
    311                     }
    312                     else
    313                         memcpy( data, src, m_width*(bit_depth/8) );
    314                 }
    315                 else
    316                 {
    317                     if( color )
    318                     {
    319                         if( img.depth() == CV_8U )
    320                             icvCvt_RGB2BGR_8u_C3R( src, 0, data, 0, cvSize(m_width,1) );
    321                         else
    322                             icvCvt_RGB2BGR_16u_C3R( (ushort *)src, 0, (ushort *)data, 0, cvSize(m_width,1) );
    323                     }
    324                     else if( img.depth() == CV_8U )
    325                         icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, cvSize(m_width,1), 2 );
    326                     else
    327                         icvCvt_BGRA2Gray_16u_CnC1R( (ushort *)src, 0, (ushort *)data, 0, cvSize(m_width,1), 3, 2 );
    328                 }
    329             }
    330             result = true;
    331             break;
    332         default:
    333             assert(0);
    334         }
    335     }
    336     catch(...)
    337     {
    338     }
    339 
    340     return result;
    341 }
    342 
    343 
    344 //////////////////////////////////////////////////////////////////////////////////////////
    345 
    346 PxMEncoder::PxMEncoder()
    347 {
    348     m_description = "Portable image format (*.pbm;*.pgm;*.ppm;*.pxm;*.pnm)";
    349     m_buf_supported = true;
    350 }
    351 
    352 
    353 PxMEncoder::~PxMEncoder()
    354 {
    355 }
    356 
    357 
    358 ImageEncoder  PxMEncoder::newEncoder() const
    359 {
    360     return makePtr<PxMEncoder>();
    361 }
    362 
    363 
    364 bool  PxMEncoder::isFormatSupported( int depth ) const
    365 {
    366     return depth == CV_8U || depth == CV_16U;
    367 }
    368 
    369 
    370 bool  PxMEncoder::write( const Mat& img, const std::vector<int>& params )
    371 {
    372     bool isBinary = true;
    373 
    374     int  width = img.cols, height = img.rows;
    375     int  _channels = img.channels(), depth = (int)img.elemSize1()*8;
    376     int  channels = _channels > 1 ? 3 : 1;
    377     int  fileStep = width*(int)img.elemSize();
    378     int  x, y;
    379 
    380     for( size_t i = 0; i < params.size(); i += 2 )
    381         if( params[i] == CV_IMWRITE_PXM_BINARY )
    382             isBinary = params[i+1] != 0;
    383 
    384     WLByteStream strm;
    385 
    386     if( m_buf )
    387     {
    388         if( !strm.open(*m_buf) )
    389             return false;
    390         int t = CV_MAKETYPE(img.depth(), channels);
    391         m_buf->reserve( alignSize(256 + (isBinary ? fileStep*height :
    392             ((t == CV_8UC1 ? 4 : t == CV_8UC3 ? 4*3+2 :
    393             t == CV_16UC1 ? 6 : 6*3+2)*width+1)*height), 256));
    394     }
    395     else if( !strm.open(m_filename) )
    396         return false;
    397 
    398     int  lineLength;
    399     int  bufferSize = 128; // buffer that should fit a header
    400 
    401     if( isBinary )
    402         lineLength = width * (int)img.elemSize();
    403     else
    404         lineLength = (6 * channels + (channels > 1 ? 2 : 0)) * width + 32;
    405 
    406     if( bufferSize < lineLength )
    407         bufferSize = lineLength;
    408 
    409     AutoBuffer<char> _buffer(bufferSize);
    410     char* buffer = _buffer;
    411 
    412     // write header;
    413     sprintf( buffer, "P%c\n%d %d\n%d\n",
    414              '2' + (channels > 1 ? 1 : 0) + (isBinary ? 3 : 0),
    415              width, height, (1 << depth) - 1 );
    416 
    417     strm.putBytes( buffer, (int)strlen(buffer) );
    418 
    419     for( y = 0; y < height; y++ )
    420     {
    421         const uchar* const data = img.ptr(y);
    422         if( isBinary )
    423         {
    424             if( _channels == 3 )
    425             {
    426                 if( depth == 8 )
    427                     icvCvt_BGR2RGB_8u_C3R( (const uchar*)data, 0,
    428                         (uchar*)buffer, 0, cvSize(width,1) );
    429                 else
    430                     icvCvt_BGR2RGB_16u_C3R( (const ushort*)data, 0,
    431                         (ushort*)buffer, 0, cvSize(width,1) );
    432             }
    433 
    434             // swap endianness if necessary
    435             if( depth == 16 && !isBigEndian() )
    436             {
    437                 if( _channels == 1 )
    438                     memcpy( buffer, data, fileStep );
    439                 for( x = 0; x < width*channels*2; x += 2 )
    440                 {
    441                     uchar v = buffer[x];
    442                     buffer[x] = buffer[x + 1];
    443                     buffer[x + 1] = v;
    444                 }
    445             }
    446             strm.putBytes( (channels > 1 || depth > 8) ? buffer : (const char*)data, fileStep );
    447         }
    448         else
    449         {
    450             char* ptr = buffer;
    451 
    452             if( channels > 1 )
    453             {
    454                 if( depth == 8 )
    455                 {
    456                     for( x = 0; x < width*channels; x += channels )
    457                     {
    458                         sprintf( ptr, "% 4d", data[x + 2] );
    459                         ptr += 4;
    460                         sprintf( ptr, "% 4d", data[x + 1] );
    461                         ptr += 4;
    462                         sprintf( ptr, "% 4d", data[x] );
    463                         ptr += 4;
    464                         *ptr++ = ' ';
    465                         *ptr++ = ' ';
    466                     }
    467                 }
    468                 else
    469                 {
    470                     for( x = 0; x < width*channels; x += channels )
    471                     {
    472                         sprintf( ptr, "% 6d", ((const ushort *)data)[x + 2] );
    473                         ptr += 6;
    474                         sprintf( ptr, "% 6d", ((const ushort *)data)[x + 1] );
    475                         ptr += 6;
    476                         sprintf( ptr, "% 6d", ((const ushort *)data)[x] );
    477                         ptr += 6;
    478                         *ptr++ = ' ';
    479                         *ptr++ = ' ';
    480                     }
    481                 }
    482             }
    483             else
    484             {
    485                 if( depth == 8 )
    486                 {
    487                     for( x = 0; x < width; x++ )
    488                     {
    489                         sprintf( ptr, "% 4d", data[x] );
    490                         ptr += 4;
    491                     }
    492                 }
    493                 else
    494                 {
    495                     for( x = 0; x < width; x++ )
    496                     {
    497                         sprintf( ptr, "% 6d", ((const ushort *)data)[x] );
    498                         ptr += 6;
    499                     }
    500                 }
    501             }
    502 
    503             *ptr++ = '\n';
    504 
    505             strm.putBytes( buffer, (int)(ptr - buffer) );
    506         }
    507     }
    508 
    509     strm.close();
    510     return true;
    511 }
    512 
    513 }
    514