Home | History | Annotate | Download | only in highgui
      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 //                        Intel License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
     14 // Third party copyrights are property of their respective owners.
     15 //
     16 // Redistribution and use in source and binary forms, with or without modification,
     17 // are permitted provided that the following conditions are met:
     18 //
     19 //   * Redistribution's of source code must retain the above copyright notice,
     20 //     this list of conditions and the following disclaimer.
     21 //
     22 //   * Redistribution's in binary form must reproduce the above copyright notice,
     23 //     this list of conditions and the following disclaimer in the documentation
     24 //     and/or other materials provided with the distribution.
     25 //
     26 //   * The name of Intel Corporation may not be used to endorse or promote products
     27 //     derived from this software without specific prior written permission.
     28 //
     29 // This software is provided by the copyright holders and contributors "as is" and
     30 // any express or implied warranties, including, but not limited to, the implied
     31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     32 // In no event shall the Intel Corporation or contributors be liable for any direct,
     33 // indirect, incidental, special, exemplary, or consequential damages
     34 // (including, but not limited to, procurement of substitute goods or services;
     35 // loss of use, data, or profits; or business interruption) however caused
     36 // and on any theory of liability, whether in contract, strict liability,
     37 // or tort (including negligence or otherwise) arising in any way out of
     38 // the use of this software, even if advised of the possibility of such damage.
     39 //
     40 //M*/
     41 
     42 #include "_highgui.h"
     43 #include "grfmt_bmp.h"
     44 
     45 static const char* fmtSignBmp = "BM";
     46 
     47 GrFmtBmp::GrFmtBmp()
     48 {
     49     m_sign_len = 2;
     50     m_signature = fmtSignBmp;
     51     m_description = "Windows bitmap (*.bmp;*.dib)";
     52 }
     53 
     54 
     55 GrFmtBmp::~GrFmtBmp()
     56 {
     57 }
     58 
     59 
     60 GrFmtReader* GrFmtBmp::NewReader( const char* filename )
     61 {
     62     return new GrFmtBmpReader( filename );
     63 }
     64 
     65 
     66 GrFmtWriter* GrFmtBmp::NewWriter( const char* filename )
     67 {
     68     return new GrFmtBmpWriter( filename );
     69 }
     70 
     71 
     72 /************************ BMP reader *****************************/
     73 
     74 GrFmtBmpReader::GrFmtBmpReader( const char* filename ) : GrFmtReader( filename )
     75 {
     76     m_offset = -1;
     77 }
     78 
     79 
     80 GrFmtBmpReader::~GrFmtBmpReader()
     81 {
     82 }
     83 
     84 
     85 void  GrFmtBmpReader::Close()
     86 {
     87     m_strm.Close();
     88     GrFmtReader::Close();
     89 }
     90 
     91 
     92 bool  GrFmtBmpReader::ReadHeader()
     93 {
     94     bool result = false;
     95 
     96     assert( strlen(m_filename) != 0 );
     97     if( !m_strm.Open( m_filename )) return false;
     98 
     99     if( setjmp( m_strm.JmpBuf()) == 0 )
    100     {
    101         m_strm.Skip( 10 );
    102         m_offset = m_strm.GetDWord();
    103 
    104         int  size = m_strm.GetDWord();
    105 
    106         if( size >= 36 )
    107         {
    108             m_width  = m_strm.GetDWord();
    109             m_height = m_strm.GetDWord();
    110             m_bpp    = m_strm.GetDWord() >> 16;
    111             m_rle_code = (BmpCompression)m_strm.GetDWord();
    112             m_strm.Skip(12);
    113             int clrused = m_strm.GetDWord();
    114             m_strm.Skip( size - 36 );
    115 
    116             if( m_width > 0 && m_height > 0 &&
    117              (((m_bpp == 1 || m_bpp == 4 || m_bpp == 8 ||
    118                 m_bpp == 24 || m_bpp == 32 ) && m_rle_code == BMP_RGB) ||
    119                (m_bpp == 16 && (m_rle_code == BMP_RGB || m_rle_code == BMP_BITFIELDS)) ||
    120                (m_bpp == 4 && m_rle_code == BMP_RLE4) ||
    121                (m_bpp == 8 && m_rle_code == BMP_RLE8)))
    122             {
    123                 m_iscolor = true;
    124                 result = true;
    125 
    126                 if( m_bpp <= 8 )
    127                 {
    128                     memset( m_palette, 0, sizeof(m_palette));
    129                     m_strm.GetBytes( m_palette, (clrused == 0? 1<<m_bpp : clrused)*4 );
    130                     m_iscolor = IsColorPalette( m_palette, m_bpp );
    131                 }
    132                 else if( m_bpp == 16 && m_rle_code == BMP_BITFIELDS )
    133                 {
    134                     int redmask = m_strm.GetDWord();
    135                     int greenmask = m_strm.GetDWord();
    136                     int bluemask = m_strm.GetDWord();
    137 
    138                     if( bluemask == 0x1f && greenmask == 0x3e0 && redmask == 0x7c00 )
    139                         m_bpp = 15;
    140                     else if( bluemask == 0x1f && greenmask == 0x7e0 && redmask == 0xf800 )
    141                         ;
    142                     else
    143                         result = false;
    144                 }
    145                 else if( m_bpp == 16 && m_rle_code == BMP_RGB )
    146                     m_bpp = 15;
    147             }
    148         }
    149         else if( size == 12 )
    150         {
    151             m_width  = m_strm.GetWord();
    152             m_height = m_strm.GetWord();
    153             m_bpp    = m_strm.GetDWord() >> 16;
    154             m_rle_code = BMP_RGB;
    155 
    156             if( m_width > 0 && m_height > 0 &&
    157                (m_bpp == 1 || m_bpp == 4 || m_bpp == 8 ||
    158                 m_bpp == 24 || m_bpp == 32 ))
    159             {
    160                 if( m_bpp <= 8 )
    161                 {
    162                     uchar buffer[256*3];
    163                     int j, clrused = 1 << m_bpp;
    164                     m_strm.GetBytes( buffer, clrused*3 );
    165                     for( j = 0; j < clrused; j++ )
    166                     {
    167                         m_palette[j].b = buffer[3*j+0];
    168                         m_palette[j].g = buffer[3*j+1];
    169                         m_palette[j].r = buffer[3*j+2];
    170                     }
    171                 }
    172                 result = true;
    173             }
    174         }
    175     }
    176 
    177     if( !result )
    178     {
    179         m_offset = -1;
    180         m_width = m_height = -1;
    181         m_strm.Close();
    182     }
    183     return result;
    184 }
    185 
    186 
    187 bool  GrFmtBmpReader::ReadData( uchar* data, int step, int color )
    188 {
    189     const  int buffer_size = 1 << 12;
    190     uchar  buffer[buffer_size];
    191     uchar  bgr_buffer[buffer_size];
    192     uchar  gray_palette[256];
    193     bool   result = false;
    194     uchar* src = buffer;
    195     uchar* bgr = bgr_buffer;
    196     int  src_pitch = ((m_width*(m_bpp != 15 ? m_bpp : 16) + 7)/8 + 3) & -4;
    197     int  nch = color ? 3 : 1;
    198     int  width3 = m_width*nch;
    199     int  y;
    200 
    201     if( m_offset < 0 || !m_strm.IsOpened())
    202         return false;
    203 
    204     data += (m_height - 1)*step;
    205     step = -step;
    206 
    207     if( (m_bpp != 24 || !color) && src_pitch+32 > buffer_size )
    208         src = new uchar[src_pitch+32];
    209 
    210     if( !color )
    211     {
    212         if( m_bpp <= 8 )
    213         {
    214             CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp );
    215         }
    216         if( m_width*3 + 32 > buffer_size ) bgr = new uchar[m_width*3 + 32];
    217     }
    218 
    219     if( setjmp( m_strm.JmpBuf()) == 0 )
    220     {
    221         m_strm.SetPos( m_offset );
    222 
    223         switch( m_bpp )
    224         {
    225         /************************* 1 BPP ************************/
    226         case 1:
    227             for( y = 0; y < m_height; y++, data += step )
    228             {
    229                 m_strm.GetBytes( src, src_pitch );
    230                 FillColorRow1( color ? data : bgr, src, m_width, m_palette );
    231                 if( !color )
    232                     icvCvt_BGR2Gray_8u_C3C1R( bgr, 0, data, 0, cvSize(m_width,1) );
    233             }
    234             result = true;
    235             break;
    236 
    237         /************************* 4 BPP ************************/
    238         case 4:
    239             if( m_rle_code == BMP_RGB )
    240             {
    241                 for( y = 0; y < m_height; y++, data += step )
    242                 {
    243                     m_strm.GetBytes( src, src_pitch );
    244                     if( color )
    245                         FillColorRow4( data, src, m_width, m_palette );
    246                     else
    247                         FillGrayRow4( data, src, m_width, gray_palette );
    248                 }
    249                 result = true;
    250             }
    251             else if( m_rle_code == BMP_RLE4 ) // rle4 compression
    252             {
    253                 uchar* line_end = data + width3;
    254                 y = 0;
    255 
    256                 for(;;)
    257                 {
    258                     int code = m_strm.GetWord();
    259                     int len = code & 255;
    260                     code >>= 8;
    261                     if( len != 0 ) // encoded mode
    262                     {
    263                         PaletteEntry clr[2];
    264                         uchar gray_clr[2];
    265                         int t = 0;
    266 
    267                         clr[0] = m_palette[code >> 4];
    268                         clr[1] = m_palette[code & 15];
    269                         gray_clr[0] = gray_palette[code >> 4];
    270                         gray_clr[1] = gray_palette[code & 15];
    271 
    272                         uchar* end = data + len*nch;
    273                         if( end > line_end ) goto decode_rle4_bad;
    274                         do
    275                         {
    276                             if( color )
    277                                 WRITE_PIX( data, clr[t] );
    278                             else
    279                                 *data = gray_clr[t];
    280                             t ^= 1;
    281                         }
    282                         while( (data += nch) < end );
    283                     }
    284                     else if( code > 2 ) // absolute mode
    285                     {
    286                         if( data + code*nch > line_end ) goto decode_rle4_bad;
    287                         m_strm.GetBytes( src, (((code + 1)>>1) + 1) & -2 );
    288                         if( color )
    289                             data = FillColorRow4( data, src, code, m_palette );
    290                         else
    291                             data = FillGrayRow4( data, src, code, gray_palette );
    292                     }
    293                     else
    294                     {
    295                         int x_shift3 = (int)(line_end - data);
    296                         int y_shift = m_height - y;
    297 
    298                         if( code == 2 )
    299                         {
    300                             x_shift3 = m_strm.GetByte()*nch;
    301                             y_shift = m_strm.GetByte();
    302                         }
    303 
    304                         len = x_shift3 + (y_shift * width3) & ((code == 0) - 1);
    305 
    306                         if( color )
    307                             data = FillUniColor( data, line_end, step, width3,
    308                                                  y, m_height, x_shift3,
    309                                                  m_palette[0] );
    310                         else
    311                             data = FillUniGray( data, line_end, step, width3,
    312                                                 y, m_height, x_shift3,
    313                                                 gray_palette[0] );
    314 
    315                         if( y >= m_height )
    316                             break;
    317                     }
    318                 }
    319 
    320                 result = true;
    321 decode_rle4_bad: ;
    322             }
    323             break;
    324 
    325         /************************* 8 BPP ************************/
    326         case 8:
    327             if( m_rle_code == BMP_RGB )
    328             {
    329                 for( y = 0; y < m_height; y++, data += step )
    330                 {
    331                     m_strm.GetBytes( src, src_pitch );
    332                     if( color )
    333                         FillColorRow8( data, src, m_width, m_palette );
    334                     else
    335                         FillGrayRow8( data, src, m_width, gray_palette );
    336                 }
    337                 result = true;
    338             }
    339             else if( m_rle_code == BMP_RLE8 ) // rle8 compression
    340             {
    341                 uchar* line_end = data + width3;
    342                 int line_end_flag = 0;
    343                 y = 0;
    344 
    345                 for(;;)
    346                 {
    347                     int code = m_strm.GetWord();
    348                     int len = code & 255;
    349                     code >>= 8;
    350                     if( len != 0 ) // encoded mode
    351                     {
    352                         int prev_y = y;
    353                         len *= nch;
    354 
    355                         if( data + len > line_end )
    356                             goto decode_rle8_bad;
    357 
    358                         if( color )
    359                             data = FillUniColor( data, line_end, step, width3,
    360                                                  y, m_height, len,
    361                                                  m_palette[code] );
    362                         else
    363                             data = FillUniGray( data, line_end, step, width3,
    364                                                 y, m_height, len,
    365                                                 gray_palette[code] );
    366 
    367                         line_end_flag = y - prev_y;
    368                     }
    369                     else if( code > 2 ) // absolute mode
    370                     {
    371                         int prev_y = y;
    372                         int code3 = code*nch;
    373 
    374                         if( data + code3 > line_end )
    375                             goto decode_rle8_bad;
    376                         m_strm.GetBytes( src, (code + 1) & -2 );
    377                         if( color )
    378                             data = FillColorRow8( data, src, code, m_palette );
    379                         else
    380                             data = FillGrayRow8( data, src, code, gray_palette );
    381 
    382                         line_end_flag = y - prev_y;
    383                     }
    384                     else
    385                     {
    386                         int x_shift3 = (int)(line_end - data);
    387                         int y_shift = m_height - y;
    388 
    389                         if( code || !line_end_flag || x_shift3 < width3 )
    390                         {
    391                             if( code == 2 )
    392                             {
    393                                 x_shift3 = m_strm.GetByte()*nch;
    394                                 y_shift = m_strm.GetByte();
    395                             }
    396 
    397                             x_shift3 += (y_shift * width3) & ((code == 0) - 1);
    398 
    399                             if( y >= m_height )
    400                                 break;
    401 
    402                             if( color )
    403                                 data = FillUniColor( data, line_end, step, width3,
    404                                                      y, m_height, x_shift3,
    405                                                      m_palette[0] );
    406                             else
    407                                 data = FillUniGray( data, line_end, step, width3,
    408                                                     y, m_height, x_shift3,
    409                                                     gray_palette[0] );
    410 
    411                             if( y >= m_height )
    412                                 break;
    413                         }
    414 
    415                         line_end_flag = 0;
    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( color ? data : src, src_pitch );
    452                 if( !color )
    453                     icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, cvSize(m_width,1) );
    454             }
    455             result = true;
    456             break;
    457         /************************* 32 BPP ************************/
    458         case 32:
    459             for( y = 0; y < m_height; y++, data += step )
    460             {
    461                 m_strm.GetBytes( src, src_pitch );
    462 
    463                 if( !color )
    464                     icvCvt_BGRA2Gray_8u_C4C1R( src, 0, data, 0, cvSize(m_width,1) );
    465                 else
    466                     icvCvt_BGRA2BGR_8u_C4C3R( src, 0, data, 0, cvSize(m_width,1) );
    467             }
    468             result = true;
    469             break;
    470         default:
    471             assert(0);
    472         }
    473     }
    474 
    475     if( src != buffer ) delete[] src;
    476     if( bgr != bgr_buffer ) delete[] bgr;
    477     return result;
    478 }
    479 
    480 
    481 //////////////////////////////////////////////////////////////////////////////////////////
    482 
    483 GrFmtBmpWriter::GrFmtBmpWriter( const char* filename ) : GrFmtWriter( filename )
    484 {
    485 }
    486 
    487 
    488 GrFmtBmpWriter::~GrFmtBmpWriter()
    489 {
    490 }
    491 
    492 
    493 bool  GrFmtBmpWriter::WriteImage( const uchar* data, int step,
    494                                   int width, int height, int /*depth*/, int channels )
    495 {
    496     bool result = false;
    497     int fileStep = (width*channels + 3) & -4;
    498     uchar zeropad[] = "\0\0\0\0";
    499 
    500     assert( data && width > 0 && height > 0 && step >= fileStep );
    501 
    502     if( m_strm.Open( m_filename ) )
    503     {
    504         int  bitmapHeaderSize = 40;
    505         int  paletteSize = channels > 1 ? 0 : 1024;
    506         int  headerSize = 14 /* fileheader */ + bitmapHeaderSize + paletteSize;
    507         PaletteEntry palette[256];
    508 
    509         // write signature 'BM'
    510         m_strm.PutBytes( fmtSignBmp, (int)strlen(fmtSignBmp) );
    511 
    512         // write file header
    513         m_strm.PutDWord( fileStep*height + headerSize ); // file size
    514         m_strm.PutDWord( 0 );
    515         m_strm.PutDWord( headerSize );
    516 
    517         // write bitmap header
    518         m_strm.PutDWord( bitmapHeaderSize );
    519         m_strm.PutDWord( width );
    520         m_strm.PutDWord( height );
    521         m_strm.PutWord( 1 );
    522         m_strm.PutWord( channels << 3 );
    523         m_strm.PutDWord( BMP_RGB );
    524         m_strm.PutDWord( 0 );
    525         m_strm.PutDWord( 0 );
    526         m_strm.PutDWord( 0 );
    527         m_strm.PutDWord( 0 );
    528         m_strm.PutDWord( 0 );
    529 
    530         if( channels == 1 )
    531         {
    532             FillGrayPalette( palette, 8 );
    533             m_strm.PutBytes( palette, sizeof(palette));
    534         }
    535 
    536         width *= channels;
    537         data += step*(height - 1);
    538         for( ; height--; data -= step )
    539         {
    540             m_strm.PutBytes( data, width );
    541             if( fileStep > width )
    542                 m_strm.PutBytes( zeropad, fileStep - width );
    543         }
    544 
    545         m_strm.Close();
    546         result = true;
    547     }
    548     return result;
    549 }
    550 
    551 
    552