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 "utils.h" 44 #include "grfmt_pxm.h" 45 46 // P?M filter factory 47 48 GrFmtPxM::GrFmtPxM() 49 { 50 m_sign_len = 3; 51 m_signature = ""; 52 m_description = "Portable image format (*.pbm;*.pgm;*.ppm;*.pxm;*.pnm)"; 53 } 54 55 56 GrFmtPxM::~GrFmtPxM() 57 { 58 } 59 60 61 bool GrFmtPxM::CheckSignature( const char* signature ) 62 { 63 return signature[0] == 'P' && 64 '1' <= signature[1] && signature[1] <= '6' && 65 isspace(signature[2]); 66 } 67 68 69 GrFmtReader* GrFmtPxM::NewReader( const char* filename ) 70 { 71 return new GrFmtPxMReader( filename ); 72 } 73 74 75 GrFmtWriter* GrFmtPxM::NewWriter( const char* filename ) 76 { 77 return new GrFmtPxMWriter( filename ); 78 } 79 80 81 ///////////////////////// P?M reader ////////////////////////////// 82 83 static int ReadNumber( RLByteStream& strm, int maxdigits ) 84 { 85 int code; 86 int val = 0; 87 int digits = 0; 88 89 code = strm.GetByte(); 90 91 if( !isdigit(code)) 92 { 93 do 94 { 95 if( code == '#' ) 96 { 97 do 98 { 99 code = strm.GetByte(); 100 } 101 while( code != '\n' && code != '\r' ); 102 } 103 104 code = strm.GetByte(); 105 106 while( isspace(code)) 107 code = strm.GetByte(); 108 } 109 while( !isdigit( code )); 110 } 111 112 do 113 { 114 val = val*10 + code - '0'; 115 if( ++digits >= maxdigits ) break; 116 code = strm.GetByte(); 117 } 118 while( isdigit(code)); 119 120 return val; 121 } 122 123 124 GrFmtPxMReader::GrFmtPxMReader( const char* filename ) : GrFmtReader( filename ) 125 { 126 m_offset = -1; 127 } 128 129 130 GrFmtPxMReader::~GrFmtPxMReader() 131 { 132 } 133 134 135 void GrFmtPxMReader::Close() 136 { 137 m_strm.Close(); 138 } 139 140 141 bool GrFmtPxMReader::ReadHeader() 142 { 143 bool result = false; 144 145 assert( strlen(m_filename) != 0 ); 146 if( !m_strm.Open( m_filename )) return false; 147 148 if( setjmp( m_strm.JmpBuf()) == 0 ) 149 { 150 int code = m_strm.GetByte(); 151 if( code != 'P' ) 152 BAD_HEADER_ERR(); 153 154 code = m_strm.GetByte(); 155 switch( code ) 156 { 157 case '1': case '4': m_bpp = 1; break; 158 case '2': case '5': m_bpp = 8; break; 159 case '3': case '6': m_bpp = 24; break; 160 default: BAD_HEADER_ERR(); 161 } 162 163 m_binary = code >= '4'; 164 m_iscolor = m_bpp > 8; 165 166 m_width = ReadNumber( m_strm, INT_MAX ); 167 m_height = ReadNumber( m_strm, INT_MAX ); 168 169 m_maxval = m_bpp == 1 ? 1 : ReadNumber( m_strm, INT_MAX ); 170 if( m_maxval > 65535 ) 171 BAD_HEADER_ERR(); 172 173 //if( m_maxval > 255 ) m_binary = false; nonsense 174 if( m_maxval > 255 ) 175 m_bit_depth = 16; 176 177 if( m_width > 0 && m_height > 0 && m_maxval > 0 && m_maxval < (1 << 16)) 178 { 179 m_offset = m_strm.GetPos(); 180 result = true; 181 } 182 bad_header_exit: 183 ; 184 } 185 186 if( !result ) 187 { 188 m_offset = -1; 189 m_width = m_height = -1; 190 m_strm.Close(); 191 } 192 return result; 193 } 194 195 196 bool GrFmtPxMReader::ReadData( uchar* data, int step, int color ) 197 { 198 const int buffer_size = 1 << 12; 199 uchar buffer[buffer_size]; 200 uchar pal_buffer[buffer_size]; 201 PaletteEntry palette[256]; 202 bool result = false; 203 uchar* src = buffer; 204 uchar* gray_palette = pal_buffer; 205 int src_pitch = (m_width*m_bpp*m_bit_depth/8 + 7)/8; 206 int nch = m_iscolor ? 3 : 1; 207 int width3 = m_width*nch; 208 int i, x, y; 209 210 if( m_offset < 0 || !m_strm.IsOpened()) 211 return false; 212 213 if( src_pitch+32 > buffer_size ) 214 src = new uchar[width3*m_bit_depth/8 + 32]; 215 216 // create LUT for converting colors 217 if( m_bit_depth == 8 ) 218 { 219 if( m_maxval + 1 > buffer_size ) 220 gray_palette = new uchar[m_maxval + 1]; 221 222 for( i = 0; i <= m_maxval; i++ ) 223 { 224 gray_palette[i] = (uchar)((i*255/m_maxval)^(m_bpp == 1 ? 255 : 0)); 225 } 226 227 FillGrayPalette( palette, m_bpp==1 ? 1 : 8 , m_bpp == 1 ); 228 } 229 230 if( setjmp( m_strm.JmpBuf()) == 0 ) 231 { 232 m_strm.SetPos( m_offset ); 233 234 switch( m_bpp ) 235 { 236 ////////////////////////// 1 BPP ///////////////////////// 237 case 1: 238 if( !m_binary ) 239 { 240 for( y = 0; y < m_height; y++, data += step ) 241 { 242 for( x = 0; x < m_width; x++ ) 243 src[x] = ReadNumber( m_strm, 1 ) != 0; 244 245 if( color ) 246 FillColorRow8( data, src, m_width, palette ); 247 else 248 FillGrayRow8( data, src, m_width, gray_palette ); 249 } 250 } 251 else 252 { 253 for( y = 0; y < m_height; y++, data += step ) 254 { 255 m_strm.GetBytes( src, src_pitch ); 256 257 if( color ) 258 FillColorRow1( data, src, m_width, palette ); 259 else 260 FillGrayRow1( data, src, m_width, gray_palette ); 261 } 262 } 263 result = true; 264 break; 265 266 ////////////////////////// 8 BPP ///////////////////////// 267 case 8: 268 case 24: 269 for( y = 0; y < m_height; y++, data += step ) 270 { 271 if( !m_binary ) 272 { 273 for( x = 0; x < width3; x++ ) 274 { 275 int code = ReadNumber( m_strm, INT_MAX ); 276 if( (unsigned)code > (unsigned)m_maxval ) code = m_maxval; 277 if( m_bit_depth == 8 ) 278 src[x] = gray_palette[code]; 279 else 280 ((ushort *)src)[x] = (ushort)code; 281 } 282 } 283 else 284 { 285 m_strm.GetBytes( src, src_pitch ); 286 if( m_bit_depth == 16 && !isBigEndian() ) 287 { 288 for( x = 0; x < width3; x++ ) 289 { 290 uchar v = src[x * 2]; 291 src[x * 2] = src[x * 2 + 1]; 292 src[x * 2 + 1] = v; 293 } 294 } 295 } 296 297 if( !m_native_depth && m_bit_depth == 16 ) 298 { 299 for( x = 0; x < width3; x++ ) 300 { 301 int v = ((ushort *)src)[x]; 302 src[x] = (uchar)(v >> 8); 303 } 304 } 305 306 if( m_bpp == 8 ) // image has one channel 307 { 308 if( color ) 309 { 310 if( m_bit_depth == 8 || !m_native_depth ) { 311 uchar *d = data, *s = src, *end = src + m_width; 312 for( ; s < end; d += 3, s++) 313 d[0] = d[1] = d[2] = *s; 314 } else { 315 ushort *d = (ushort *)data, *s = (ushort *)src, *end = ((ushort *)src) + m_width; 316 for( ; s < end; s++, d += 3) 317 d[0] = d[1] = d[2] = *s; 318 } 319 } 320 else if( m_native_depth ) 321 memcpy( data, src, m_width*m_bit_depth/8 ); 322 else 323 memcpy( data, src, m_width ); 324 } 325 else 326 { 327 if( color ) 328 { 329 if( m_bit_depth == 8 || !m_native_depth ) 330 icvCvt_RGB2BGR_8u_C3R( src, 0, data, 0, cvSize(m_width,1) ); 331 else 332 icvCvt_RGB2BGR_16u_C3R( (ushort *)src, 0, (ushort *)data, 0, cvSize(m_width,1) ); 333 } 334 else if( m_bit_depth == 8 || !m_native_depth ) 335 icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, cvSize(m_width,1), 2 ); 336 else 337 icvCvt_BGR2Gray_16u_C3C1R( (ushort *)src, 0, (ushort *)data, 0, cvSize(m_width,1), 2 ); 338 } 339 } 340 result = true; 341 break; 342 default: 343 assert(0); 344 } 345 } 346 347 if( src != buffer ) 348 delete[] src; 349 350 if( gray_palette != pal_buffer ) 351 delete[] gray_palette; 352 353 return result; 354 } 355 356 357 ////////////////////////////////////////////////////////////////////////////////////////// 358 359 GrFmtPxMWriter::GrFmtPxMWriter( const char* filename ) : GrFmtWriter( filename ) 360 { 361 } 362 363 364 GrFmtPxMWriter::~GrFmtPxMWriter() 365 { 366 } 367 368 369 bool GrFmtPxMWriter::IsFormatSupported( int depth ) 370 { 371 return depth == IPL_DEPTH_8U || depth == IPL_DEPTH_16U; 372 } 373 374 375 bool GrFmtPxMWriter::WriteImage( const uchar* data, int step, 376 int width, int height, int depth, int _channels ) 377 { 378 bool isBinary = true; 379 bool result = false; 380 381 int channels = _channels > 1 ? 3 : 1; 382 int fileStep = width*channels*(depth/8); 383 int x, y; 384 385 assert( data && width > 0 && height > 0 && step >= fileStep ); 386 387 if( m_strm.Open( m_filename ) ) 388 { 389 int lineLength; 390 int bufferSize = 128; // buffer that should fit a header 391 char* buffer = 0; 392 393 if( isBinary ) 394 lineLength = channels * width * depth / 8; 395 else 396 lineLength = (6 * channels + (channels > 1 ? 2 : 0)) * width + 32; 397 398 if( bufferSize < lineLength ) 399 bufferSize = lineLength; 400 401 buffer = new char[bufferSize]; 402 if( !buffer ) 403 { 404 m_strm.Close(); 405 return false; 406 } 407 408 // write header; 409 sprintf( buffer, "P%c\n%d %d\n%d\n", 410 '2' + (channels > 1 ? 1 : 0) + (isBinary ? 3 : 0), 411 width, height, (1 << depth) - 1 ); 412 413 m_strm.PutBytes( buffer, (int)strlen(buffer) ); 414 415 for( y = 0; y < height; y++, data += step ) 416 { 417 if( isBinary ) 418 { 419 if( _channels == 3 ) 420 { 421 if( depth == 8 ) 422 icvCvt_BGR2RGB_8u_C3R( (uchar*)data, 0, 423 (uchar*)buffer, 0, cvSize(width,1) ); 424 else 425 icvCvt_BGR2RGB_16u_C3R( (ushort*)data, 0, 426 (ushort*)buffer, 0, cvSize(width,1) ); 427 } 428 429 // swap endianness if necessary 430 if( depth == 16 && !isBigEndian() ) 431 { 432 if( _channels == 1 ) 433 memcpy( buffer, data, fileStep ); 434 for( x = 0; x < width*channels*2; x += 2 ) 435 { 436 uchar v = buffer[x]; 437 buffer[x] = buffer[x + 1]; 438 buffer[x + 1] = v; 439 } 440 } 441 m_strm.PutBytes( (channels > 1 || depth > 8) ? buffer : (char*)data, fileStep ); 442 } 443 else 444 { 445 char* ptr = buffer; 446 447 if( channels > 1 ) 448 { 449 if( depth == 8 ) 450 { 451 for( x = 0; x < width*channels; x += channels ) 452 { 453 sprintf( ptr, "% 4d", data[x + 2] ); 454 ptr += 4; 455 sprintf( ptr, "% 4d", data[x + 1] ); 456 ptr += 4; 457 sprintf( ptr, "% 4d", data[x] ); 458 ptr += 4; 459 *ptr++ = ' '; 460 *ptr++ = ' '; 461 } 462 } 463 else 464 { 465 for( x = 0; x < width*channels; x += channels ) 466 { 467 sprintf( ptr, "% 6d", ((ushort *)data)[x + 2] ); 468 ptr += 6; 469 sprintf( ptr, "% 6d", ((ushort *)data)[x + 1] ); 470 ptr += 6; 471 sprintf( ptr, "% 6d", ((ushort *)data)[x] ); 472 ptr += 6; 473 *ptr++ = ' '; 474 *ptr++ = ' '; 475 } 476 } 477 } 478 else 479 { 480 if( depth == 8 ) 481 { 482 for( x = 0; x < width; x++ ) 483 { 484 sprintf( ptr, "% 4d", data[x] ); 485 ptr += 4; 486 } 487 } 488 else 489 { 490 for( x = 0; x < width; x++ ) 491 { 492 sprintf( ptr, "% 6d", ((ushort *)data)[x] ); 493 ptr += 6; 494 } 495 } 496 } 497 498 *ptr++ = '\n'; 499 500 m_strm.PutBytes( buffer, (int)(ptr - buffer) ); 501 } 502 } 503 delete[] buffer; 504 m_strm.Close(); 505 result = true; 506 } 507 508 return result; 509 } 510 511