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 "grfmt_bmp.hpp"
     45 
     46 namespace cv
     47 {
     48 
     49 static const char* fmtSignBmp = "BM";
     50 
     51 /************************ BMP decoder *****************************/
     52 
     53 BmpDecoder::BmpDecoder()
     54 {
     55     m_signature = fmtSignBmp;
     56     m_offset = -1;
     57     m_buf_supported = true;
     58 }
     59 
     60 
     61 BmpDecoder::~BmpDecoder()
     62 {
     63 }
     64 
     65 
     66 void  BmpDecoder::close()
     67 {
     68     m_strm.close();
     69 }
     70 
     71 ImageDecoder BmpDecoder::newDecoder() const
     72 {
     73     return makePtr<BmpDecoder>();
     74 }
     75 
     76 bool  BmpDecoder::readHeader()
     77 {
     78     bool result = false;
     79     bool iscolor = false;
     80 
     81     if( !m_buf.empty() )
     82     {
     83         if( !m_strm.open( m_buf ) )
     84             return false;
     85     }
     86     else if( !m_strm.open( m_filename ))
     87         return false;
     88 
     89     try
     90     {
     91         m_strm.skip( 10 );
     92         m_offset = m_strm.getDWord();
     93 
     94         int  size = m_strm.getDWord();
     95 
     96         if( size >= 36 )
     97         {
     98             m_width  = m_strm.getDWord();
     99             m_height = m_strm.getDWord();
    100             m_bpp    = m_strm.getDWord() >> 16;
    101             m_rle_code = (BmpCompression)m_strm.getDWord();
    102             m_strm.skip(12);
    103             int clrused = m_strm.getDWord();
    104             m_strm.skip( size - 36 );
    105 
    106             if( m_width > 0 && m_height != 0 &&
    107              (((m_bpp == 1 || m_bpp == 4 || m_bpp == 8 ||
    108                 m_bpp == 24 || m_bpp == 32 ) && m_rle_code == BMP_RGB) ||
    109                (m_bpp == 16 && (m_rle_code == BMP_RGB || m_rle_code == BMP_BITFIELDS)) ||
    110                (m_bpp == 4 && m_rle_code == BMP_RLE4) ||
    111                (m_bpp == 8 && m_rle_code == BMP_RLE8)))
    112             {
    113                 iscolor = true;
    114                 result = true;
    115 
    116                 if( m_bpp <= 8 )
    117                 {
    118                     memset( m_palette, 0, sizeof(m_palette));
    119                     m_strm.getBytes( m_palette, (clrused == 0? 1<<m_bpp : clrused)*4 );
    120                     iscolor = IsColorPalette( m_palette, m_bpp );
    121                 }
    122                 else if( m_bpp == 16 && m_rle_code == BMP_BITFIELDS )
    123                 {
    124                     int redmask = m_strm.getDWord();
    125                     int greenmask = m_strm.getDWord();
    126                     int bluemask = m_strm.getDWord();
    127 
    128                     if( bluemask == 0x1f && greenmask == 0x3e0 && redmask == 0x7c00 )
    129                         m_bpp = 15;
    130                     else if( bluemask == 0x1f && greenmask == 0x7e0 && redmask == 0xf800 )
    131                         ;
    132                     else
    133                         result = false;
    134                 }
    135                 else if( m_bpp == 16 && m_rle_code == BMP_RGB )
    136                     m_bpp = 15;
    137             }
    138         }
    139         else if( size == 12 )
    140         {
    141             m_width  = m_strm.getWord();
    142             m_height = m_strm.getWord();
    143             m_bpp    = m_strm.getDWord() >> 16;
    144             m_rle_code = BMP_RGB;
    145 
    146             if( m_width > 0 && m_height != 0 &&
    147                (m_bpp == 1 || m_bpp == 4 || m_bpp == 8 ||
    148                 m_bpp == 24 || m_bpp == 32 ))
    149             {
    150                 if( m_bpp <= 8 )
    151                 {
    152                     uchar buffer[256*3];
    153                     int j, clrused = 1 << m_bpp;
    154                     m_strm.getBytes( buffer, clrused*3 );
    155                     for( j = 0; j < clrused; j++ )
    156                     {
    157                         m_palette[j].b = buffer[3*j+0];
    158                         m_palette[j].g = buffer[3*j+1];
    159                         m_palette[j].r = buffer[3*j+2];
    160                     }
    161                 }
    162                 result = true;
    163             }
    164         }
    165     }
    166     catch(...)
    167     {
    168     }
    169 
    170     m_type = iscolor ? CV_8UC3 : CV_8UC1;
    171     m_origin = m_height > 0 ? IPL_ORIGIN_BL : IPL_ORIGIN_TL;
    172     m_height = std::abs(m_height);
    173 
    174     if( !result )
    175     {
    176         m_offset = -1;
    177         m_width = m_height = -1;
    178         m_strm.close();
    179     }
    180     return result;
    181 }
    182 
    183 
    184 bool  BmpDecoder::readData( Mat& img )
    185 {
    186     uchar* data = img.ptr();
    187     int step = (int)img.step;
    188     bool color = img.channels() > 1;
    189     uchar  gray_palette[256];
    190     bool   result = false;
    191     int  src_pitch = ((m_width*(m_bpp != 15 ? m_bpp : 16) + 7)/8 + 3) & -4;
    192     int  nch = color ? 3 : 1;
    193     int  y, width3 = m_width*nch;
    194 
    195     if( m_offset < 0 || !m_strm.isOpened())
    196         return false;
    197 
    198     if( m_origin == IPL_ORIGIN_BL )
    199     {
    200         data += (m_height - 1)*step;
    201         step = -step;
    202     }
    203 
    204     AutoBuffer<uchar> _src, _bgr;
    205     _src.allocate(src_pitch + 32);
    206 
    207     if( !color )
    208     {
    209         if( m_bpp <= 8 )
    210         {
    211             CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp );
    212         }
    213         _bgr.allocate(m_width*3 + 32);
    214     }
    215     uchar *src = _src, *bgr = _bgr;
    216 
    217     try
    218     {
    219         m_strm.setPos( m_offset );
    220 
    221         switch( m_bpp )
    222         {
    223         /************************* 1 BPP ************************/
    224         case 1:
    225             for( y = 0; y < m_height; y++, data += step )
    226             {
    227                 m_strm.getBytes( src, src_pitch );
    228                 FillColorRow1( color ? data : bgr, src, m_width, m_palette );
    229                 if( !color )
    230                     icvCvt_BGR2Gray_8u_C3C1R( bgr, 0, data, 0, cvSize(m_width,1) );
    231             }
    232             result = true;
    233             break;
    234 
    235         /************************* 4 BPP ************************/
    236         case 4:
    237             if( m_rle_code == BMP_RGB )
    238             {
    239                 for( y = 0; y < m_height; y++, data += step )
    240                 {
    241                     m_strm.getBytes( src, src_pitch );
    242                     if( color )
    243                         FillColorRow4( data, src, m_width, m_palette );
    244                     else
    245                         FillGrayRow4( data, src, m_width, gray_palette );
    246                 }
    247                 result = true;
    248             }
    249             else if( m_rle_code == BMP_RLE4 ) // rle4 compression
    250             {
    251                 uchar* line_end = data + width3;
    252                 y = 0;
    253 
    254                 for(;;)
    255                 {
    256                     int code = m_strm.getWord();
    257                     int len = code & 255;
    258                     code >>= 8;
    259                     if( len != 0 ) // encoded mode
    260                     {
    261                         PaletteEntry clr[2];
    262                         uchar gray_clr[2];
    263                         int t = 0;
    264 
    265                         clr[0] = m_palette[code >> 4];
    266                         clr[1] = m_palette[code & 15];
    267                         gray_clr[0] = gray_palette[code >> 4];
    268                         gray_clr[1] = gray_palette[code & 15];
    269 
    270                         uchar* end = data + len*nch;
    271                         if( end > line_end ) goto decode_rle4_bad;
    272                         do
    273                         {
    274                             if( color )
    275                                 WRITE_PIX( data, clr[t] );
    276                             else
    277                                 *data = gray_clr[t];
    278                             t ^= 1;
    279                         }
    280                         while( (data += nch) < end );
    281                     }
    282                     else if( code > 2 ) // absolute mode
    283                     {
    284                         if( data + code*nch > line_end ) goto decode_rle4_bad;
    285                         m_strm.getBytes( src, (((code + 1)>>1) + 1) & -2 );
    286                         if( color )
    287                             data = FillColorRow4( data, src, code, m_palette );
    288                         else
    289                             data = FillGrayRow4( data, src, code, gray_palette );
    290                     }
    291                     else
    292                     {
    293                         int x_shift3 = (int)(line_end - data);
    294                         int y_shift = m_height - y;
    295 
    296                         if( code == 2 )
    297                         {
    298                             x_shift3 = m_strm.getByte()*nch;
    299                             y_shift = m_strm.getByte();
    300                         }
    301 
    302                         len = x_shift3 + ((y_shift * width3) & ((code == 0) - 1));
    303 
    304                         if( color )
    305                             data = FillUniColor( data, line_end, step, width3,
    306                                                  y, m_height, x_shift3,
    307                                                  m_palette[0] );
    308                         else
    309                             data = FillUniGray( data, line_end, step, width3,
    310                                                 y, m_height, x_shift3,
    311                                                 gray_palette[0] );
    312 
    313                         if( y >= m_height )
    314                             break;
    315                     }
    316                 }
    317 
    318                 result = true;
    319 decode_rle4_bad: ;
    320             }
    321             break;
    322 
    323         /************************* 8 BPP ************************/
    324         case 8:
    325             if( m_rle_code == BMP_RGB )
    326             {
    327                 for( y = 0; y < m_height; y++, data += step )
    328                 {
    329                     m_strm.getBytes( src, src_pitch );
    330                     if( color )
    331                         FillColorRow8( data, src, m_width, m_palette );
    332                     else
    333                         FillGrayRow8( data, src, m_width, gray_palette );
    334                 }
    335                 result = true;
    336             }
    337             else if( m_rle_code == BMP_RLE8 ) // rle8 compression
    338             {
    339                 uchar* line_end = data + width3;
    340                 int line_end_flag = 0;
    341                 y = 0;
    342 
    343                 for(;;)
    344                 {
    345                     int code = m_strm.getWord();
    346                     int len = code & 255;
    347                     code >>= 8;
    348                     if( len != 0 ) // encoded mode
    349                     {
    350                         int prev_y = y;
    351                         len *= nch;
    352 
    353                         if( data + len > line_end )
    354                             goto decode_rle8_bad;
    355 
    356                         if( color )
    357                             data = FillUniColor( data, line_end, step, width3,
    358                                                  y, m_height, len,
    359                                                  m_palette[code] );
    360                         else
    361                             data = FillUniGray( data, line_end, step, width3,
    362                                                 y, m_height, len,
    363                                                 gray_palette[code] );
    364 
    365                         line_end_flag = y - prev_y;
    366                     }
    367                     else if( code > 2 ) // absolute mode
    368                     {
    369                         int prev_y = y;
    370                         int code3 = code*nch;
    371 
    372                         if( data + code3 > line_end )
    373                             goto decode_rle8_bad;
    374                         m_strm.getBytes( src, (code + 1) & -2 );
    375                         if( color )
    376                             data = FillColorRow8( data, src, code, m_palette );
    377                         else
    378                             data = FillGrayRow8( data, src, code, gray_palette );
    379 
    380                         line_end_flag = y - prev_y;
    381                     }
    382                     else
    383                     {
    384                         int x_shift3 = (int)(line_end - data);
    385                         int y_shift = m_height - y;
    386 
    387                         if( code || !line_end_flag || x_shift3 < width3 )
    388                         {
    389                             if( code == 2 )
    390                             {
    391                                 x_shift3 = m_strm.getByte()*nch;
    392                                 y_shift = m_strm.getByte();
    393                             }
    394 
    395                             x_shift3 += (y_shift * width3) & ((code == 0) - 1);
    396 
    397                             if( y >= m_height )
    398                                 break;
    399 
    400                             if( color )
    401                                 data = FillUniColor( data, line_end, step, width3,
    402                                                      y, m_height, x_shift3,
    403                                                      m_palette[0] );
    404                             else
    405                                 data = FillUniGray( data, line_end, step, width3,
    406                                                     y, m_height, x_shift3,
    407                                                     gray_palette[0] );
    408 
    409                             if( y >= m_height )
    410                                 break;
    411                         }
    412 
    413                         line_end_flag = 0;
    414                         if( y >= m_height )
    415                             break;
    416                     }
    417                 }
    418 
    419                 result = true;
    420 decode_rle8_bad: ;
    421             }
    422             break;
    423         /************************* 15 BPP ************************/
    424         case 15:
    425             for( y = 0; y < m_height; y++, data += step )
    426             {
    427                 m_strm.getBytes( src, src_pitch );
    428                 if( !color )
    429                     icvCvt_BGR5552Gray_8u_C2C1R( src, 0, data, 0, cvSize(m_width,1) );
    430                 else
    431                     icvCvt_BGR5552BGR_8u_C2C3R( src, 0, data, 0, cvSize(m_width,1) );
    432             }
    433             result = true;
    434             break;
    435         /************************* 16 BPP ************************/
    436         case 16:
    437             for( y = 0; y < m_height; y++, data += step )
    438             {
    439                 m_strm.getBytes( src, src_pitch );
    440                 if( !color )
    441                     icvCvt_BGR5652Gray_8u_C2C1R( src, 0, data, 0, cvSize(m_width,1) );
    442                 else
    443                     icvCvt_BGR5652BGR_8u_C2C3R( src, 0, data, 0, cvSize(m_width,1) );
    444             }
    445             result = true;
    446             break;
    447         /************************* 24 BPP ************************/
    448         case 24:
    449             for( y = 0; y < m_height; y++, data += step )
    450             {
    451                 m_strm.getBytes( src, src_pitch );
    452                 if(!color)
    453                     icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, cvSize(m_width,1) );
    454                 else
    455                     memcpy( data, src, m_width*3 );
    456             }
    457             result = true;
    458             break;
    459         /************************* 32 BPP ************************/
    460         case 32:
    461             for( y = 0; y < m_height; y++, data += step )
    462             {
    463                 m_strm.getBytes( src, src_pitch );
    464 
    465                 if( !color )
    466                     icvCvt_BGRA2Gray_8u_C4C1R( src, 0, data, 0, cvSize(m_width,1) );
    467                 else
    468                     icvCvt_BGRA2BGR_8u_C4C3R( src, 0, data, 0, cvSize(m_width,1) );
    469             }
    470             result = true;
    471             break;
    472         default:
    473             assert(0);
    474         }
    475     }
    476     catch(...)
    477     {
    478     }
    479 
    480     return result;
    481 }
    482 
    483 
    484 //////////////////////////////////////////////////////////////////////////////////////////
    485 
    486 BmpEncoder::BmpEncoder()
    487 {
    488     m_description = "Windows bitmap (*.bmp;*.dib)";
    489     m_buf_supported = true;
    490 }
    491 
    492 
    493 BmpEncoder::~BmpEncoder()
    494 {
    495 }
    496 
    497 ImageEncoder BmpEncoder::newEncoder() const
    498 {
    499     return makePtr<BmpEncoder>();
    500 }
    501 
    502 bool  BmpEncoder::write( const Mat& img, const std::vector<int>& )
    503 {
    504     int width = img.cols, height = img.rows, channels = img.channels();
    505     int fileStep = (width*channels + 3) & -4;
    506     uchar zeropad[] = "\0\0\0\0";
    507     WLByteStream strm;
    508 
    509     if( m_buf )
    510     {
    511         if( !strm.open( *m_buf ) )
    512             return false;
    513     }
    514     else if( !strm.open( m_filename ))
    515         return false;
    516 
    517     int  bitmapHeaderSize = 40;
    518     int  paletteSize = channels > 1 ? 0 : 1024;
    519     int  headerSize = 14 /* fileheader */ + bitmapHeaderSize + paletteSize;
    520     int  fileSize = fileStep*height + headerSize;
    521     PaletteEntry palette[256];
    522 
    523     if( m_buf )
    524         m_buf->reserve( alignSize(fileSize + 16, 256) );
    525 
    526     // write signature 'BM'
    527     strm.putBytes( fmtSignBmp, (int)strlen(fmtSignBmp) );
    528 
    529     // write file header
    530     strm.putDWord( fileSize ); // file size
    531     strm.putDWord( 0 );
    532     strm.putDWord( headerSize );
    533 
    534     // write bitmap header
    535     strm.putDWord( bitmapHeaderSize );
    536     strm.putDWord( width );
    537     strm.putDWord( height );
    538     strm.putWord( 1 );
    539     strm.putWord( channels << 3 );
    540     strm.putDWord( BMP_RGB );
    541     strm.putDWord( 0 );
    542     strm.putDWord( 0 );
    543     strm.putDWord( 0 );
    544     strm.putDWord( 0 );
    545     strm.putDWord( 0 );
    546 
    547     if( channels == 1 )
    548     {
    549         FillGrayPalette( palette, 8 );
    550         strm.putBytes( palette, sizeof(palette));
    551     }
    552 
    553     width *= channels;
    554     for( int y = height - 1; y >= 0; y-- )
    555     {
    556         strm.putBytes( img.ptr(y), width );
    557         if( fileStep > width )
    558             strm.putBytes( zeropad, fileStep - width );
    559     }
    560 
    561     strm.close();
    562     return true;
    563 }
    564 
    565 }
    566