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