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