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 45static const char* fmtSignBmp = "BM"; 46 47GrFmtBmp::GrFmtBmp() 48{ 49 m_sign_len = 2; 50 m_signature = fmtSignBmp; 51 m_description = "Windows bitmap (*.bmp;*.dib)"; 52} 53 54 55GrFmtBmp::~GrFmtBmp() 56{ 57} 58 59 60GrFmtReader* GrFmtBmp::NewReader( const char* filename ) 61{ 62 return new GrFmtBmpReader( filename ); 63} 64 65 66GrFmtWriter* GrFmtBmp::NewWriter( const char* filename ) 67{ 68 return new GrFmtBmpWriter( filename ); 69} 70 71 72/************************ BMP reader *****************************/ 73 74GrFmtBmpReader::GrFmtBmpReader( const char* filename ) : GrFmtReader( filename ) 75{ 76 m_offset = -1; 77} 78 79 80GrFmtBmpReader::~GrFmtBmpReader() 81{ 82} 83 84 85void GrFmtBmpReader::Close() 86{ 87 m_strm.Close(); 88 GrFmtReader::Close(); 89} 90 91 92bool 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 187bool 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; 321decode_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; 420decode_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 483GrFmtBmpWriter::GrFmtBmpWriter( const char* filename ) : GrFmtWriter( filename ) 484{ 485} 486 487 488GrFmtBmpWriter::~GrFmtBmpWriter() 489{ 490} 491 492 493bool 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