1 /************************************************************************/ 2 /* */ 3 /* Copyright 2002 by Gunnar Kedenburg */ 4 /* Cognitive Systems Group, University of Hamburg, Germany */ 5 /* */ 6 /* This file is part of the VIGRA computer vision library. */ 7 /* ( Version 1.5.0, Dec 07 2006 ) */ 8 /* The VIGRA Website is */ 9 /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ 10 /* Please direct questions, bug reports, and contributions to */ 11 /* koethe@informatik.uni-hamburg.de or */ 12 /* vigra@kogs1.informatik.uni-hamburg.de */ 13 /* */ 14 /* Permission is hereby granted, free of charge, to any person */ 15 /* obtaining a copy of this software and associated documentation */ 16 /* files (the "Software"), to deal in the Software without */ 17 /* restriction, including without limitation the rights to use, */ 18 /* copy, modify, merge, publish, distribute, sublicense, and/or */ 19 /* sell copies of the Software, and to permit persons to whom the */ 20 /* Software is furnished to do so, subject to the following */ 21 /* conditions: */ 22 /* */ 23 /* The above copyright notice and this permission notice shall be */ 24 /* included in all copies or substantial portions of the */ 25 /* Software. */ 26 /* */ 27 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */ 28 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ 29 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 30 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */ 31 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ 32 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ 33 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ 34 /* OTHER DEALINGS IN THE SOFTWARE. */ 35 /* */ 36 /************************************************************************/ 37 /* Modifications by Pablo d'Angelo 38 * updated to vigra 1.4 by Douglas Wilkins 39 * as of 18 Febuary 2006: 40 * - Added UINT16 and UINT32 pixel types. 41 * - Added support for obtaining extra bands beyond RGB. 42 * - Added support for a position field that indicates the start of this 43 * image relative to some global origin. 44 * - Added support for x and y resolution fields. 45 * - Added support for ICC profiles 46 */ 47 48 #include <iostream> 49 #include <algorithm> 50 #include <iterator> 51 #include <string> 52 #include <sstream> 53 #include <vector> 54 #include <iterator> 55 #include <sys/types.h> 56 #include <errno.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include "vigra/imageinfo.hxx" 61 #include "codecmanager.hxx" 62 63 #if defined(_WIN32) 64 # include "vigra/windows.h" 65 #else 66 # include <dirent.h> 67 #endif 68 69 namespace vigra 70 { 71 72 namespace detail 73 { 74 75 struct NumberCompare 76 { 77 bool operator()(std::string const & l, std::string const & r) const 78 { 79 return atoi(l.c_str()) < atoi(r.c_str()); 80 } 81 }; 82 83 } // namespace detail 84 85 86 // find filenames matching the pattern "<path>/base[0-9]+ext" 87 #ifdef _WIN32 88 VIGRA_EXPORT void findImageSequence(const std::string &name_base, 89 const std::string &name_ext, 90 std::vector<std::string> & numbers) 91 { 92 // find out how many images we have 93 BOOL fFinished; 94 HANDLE hList; 95 TCHAR szDir[MAX_PATH+1]; 96 WIN32_FIND_DATA FileData; 97 98 std::string base, path; 99 100 // on Windows, both '/' and '\' are valid path separators 101 // note: std::basic_string.rfind() may return 'unsigned int', so explicitely cast to 'int' 102 int split = std::max(static_cast<int>(name_base.rfind('/')), static_cast<int>(name_base.rfind('\\'))); 103 if(split == static_cast<int>(std::string::npos)) 104 { 105 path = "."; 106 base = name_base; 107 } 108 else 109 { 110 for(int i=0; i<split; ++i) 111 { 112 if(name_base[i] == '/') 113 path += '\\'; 114 else 115 path += name_base[i]; 116 } 117 base.append(name_base, split+1, name_base.size() - split - 1); 118 } 119 120 std::vector<std::string> result; 121 char numbuf[21], extbuf[1024]; 122 std::string pattern = base + "%20[0-9]%1023s"; 123 124 // Get the proper directory path 125 sprintf(szDir, "%s\\%s*%s", path.c_str(), base.c_str(), name_ext.c_str()); 126 127 // Get the first file 128 hList = FindFirstFile(szDir, &FileData); 129 if (hList == INVALID_HANDLE_VALUE) 130 { 131 std::string message("importVolume(): No files matching '"); 132 message = message + szDir + "'."; 133 vigra_fail(message.c_str()); 134 } 135 else 136 { 137 // Traverse through the directory structure 138 fFinished = FALSE; 139 while (!fFinished) 140 { 141 if(sscanf(FileData.cFileName, pattern.c_str(), numbuf, extbuf) == 2) 142 { 143 if(strcmp(name_ext.c_str(), extbuf) == 0) 144 result.push_back(std::string(numbuf)); 145 } 146 if (!FindNextFile(hList, &FileData)) 147 { 148 if (GetLastError() == ERROR_NO_MORE_FILES) 149 { 150 fFinished = TRUE; 151 } 152 } 153 } 154 } 155 156 FindClose(hList); 157 158 std::sort(result.begin(), result.end(), detail::NumberCompare()); 159 numbers.swap(result); 160 } 161 162 #else // _WIN32 163 164 void findImageSequence(const std::string &name_base, 165 const std::string &name_ext, 166 std::vector<std::string> & numbers) 167 { 168 // find out how many images we have 169 std::string base, path; 170 int split = name_base.rfind('/'); 171 if(split == -1) 172 { 173 path = "."; 174 base = name_base; 175 } 176 else 177 { 178 path.append(name_base, 0, split); 179 base.append(name_base, split+1, name_base.size() - split - 1); 180 } 181 182 DIR * dir = opendir(path.c_str()); 183 if(!dir) 184 { 185 std::string message("importVolume(): Unable to open directory '"); 186 message = message + path + "'."; 187 vigra_fail(message.c_str()); 188 } 189 190 std::vector<std::string> result; 191 dirent * dp; 192 errno = 0; 193 char numbuf[21], extbuf[1024]; 194 std::string pattern = base + "%20[0-9]%1023s"; 195 while ((dp = readdir(dir)) != NULL) 196 { 197 if(sscanf(dp->d_name, pattern.c_str(), numbuf, extbuf) == 2) 198 { 199 if(strcmp(name_ext.c_str(), extbuf) == 0) 200 result.push_back(std::string(numbuf)); 201 } 202 } 203 204 closedir(dir); 205 206 vigra_precondition(errno == 0, 207 "importVolume(): I/O error while searching for images."); 208 209 std::sort(result.begin(), result.end(), detail::NumberCompare()); 210 numbers.swap(result); 211 } 212 213 #endif // _WIN32 214 215 // build a string from a sequence. 216 #if defined(_MSC_VER) && (_MSC_VER < 1300) 217 template <class iterator> 218 std::string stringify (const iterator &start, const iterator &end) 219 { 220 return stringifyImpl(start, end, *start); 221 } 222 223 template <class iterator, class Value> 224 std::string stringifyImpl (const iterator &start, const iterator &end, Value const &) 225 { 226 std::ostringstream out; 227 // do not place a space character after the last sequence element. 228 std::copy (start, end - 1, 229 std::ostream_iterator <Value> (out, " ")); 230 out << *(end-1); 231 return out.str (); 232 } 233 234 #else 235 236 template <class iterator> 237 std::string stringify (const iterator &start, const iterator &end) 238 { 239 typedef typename std::iterator_traits<iterator>::value_type value_type; 240 std::ostringstream out; 241 // do not place a space character after the last sequence element. 242 std::copy (start, end - 1, 243 std::ostream_iterator <value_type> (out, " ")); 244 out << *(end-1); 245 return out.str (); 246 } 247 248 #endif // _MSC_VER < 1300 249 250 void validate_filetype( std::string filetype ) 251 { 252 vigra_precondition( codecManager().fileTypeSupported(filetype), 253 "given file type is not supported" ); 254 } 255 256 std::string impexListFormats() 257 { 258 std::vector<std::string> ft = codecManager().supportedFileTypes(); 259 return stringify( ft.begin(), ft.end() ); 260 } 261 262 std::string impexListExtensions() 263 { 264 std::vector<std::string> ft = codecManager().supportedFileExtensions(); 265 return stringify( ft.begin(), ft.end() ); 266 } 267 268 bool isImage(char const * filename) 269 { 270 return CodecManager::manager().getFileTypeByMagicString(filename) != ""; 271 } 272 273 // class ImageExportInfo 274 275 ImageExportInfo::ImageExportInfo( const char * filename ) 276 : m_filename(filename), 277 m_x_res(0), m_y_res(0) 278 {} 279 280 ImageExportInfo::~ImageExportInfo() 281 { 282 } 283 284 ImageExportInfo & ImageExportInfo::setFileType( const char * filetype ) 285 { 286 m_filetype = filetype; 287 return *this; 288 } 289 290 ImageExportInfo & ImageExportInfo::setCompression( const char * comp ) 291 { 292 m_comp = comp; 293 return *this; 294 } 295 296 const char * ImageExportInfo::getFileName() const 297 { 298 return m_filename.c_str(); 299 } 300 301 const char * ImageExportInfo::getFileType() const 302 { 303 return m_filetype.c_str(); 304 } 305 306 ImageExportInfo & ImageExportInfo::setPixelType( const char * s ) 307 { 308 m_pixeltype = s; 309 return *this; 310 } 311 312 const char * ImageExportInfo::getPixelType() const 313 { 314 return m_pixeltype.c_str(); 315 } 316 317 const char * ImageExportInfo::getCompression() const 318 { 319 return m_comp.c_str(); 320 } 321 322 float ImageExportInfo::getXResolution() const 323 { 324 return m_x_res; 325 } 326 327 float ImageExportInfo::getYResolution() const 328 { 329 return m_y_res; 330 } 331 332 ImageExportInfo & ImageExportInfo::setXResolution( float val ) 333 { 334 m_x_res = val; 335 return *this; 336 } 337 338 ImageExportInfo & ImageExportInfo::setYResolution( float val ) 339 { 340 m_y_res = val; 341 return *this; 342 } 343 344 ImageExportInfo & ImageExportInfo::setPosition(const vigra::Diff2D & pos) 345 { 346 m_pos = pos; 347 return *this; 348 } 349 350 vigra::Size2D ImageExportInfo::getCanvasSize() const 351 { 352 return m_canvas_size ; 353 } 354 355 356 ImageExportInfo & ImageExportInfo::setCanvasSize(const Size2D & size) 357 { 358 //std::cerr << "ImageExportInfo: setting canvas size: " << size << std::endl; 359 m_canvas_size = size; 360 return *this; 361 } 362 363 364 vigra::Diff2D ImageExportInfo::getPosition() const 365 { 366 return m_pos; 367 } 368 369 const ImageExportInfo::ICCProfile & ImageExportInfo::getICCProfile() const 370 { 371 return m_icc_profile; 372 } 373 374 ImageExportInfo & ImageExportInfo::setICCProfile( 375 const ImageExportInfo::ICCProfile &profile) 376 { 377 m_icc_profile = profile; 378 return *this; 379 } 380 381 // return an encoder for a given ImageExportInfo object 382 std::auto_ptr<Encoder> encoder( const ImageExportInfo & info ) 383 { 384 std::auto_ptr<Encoder> enc; 385 386 std::string filetype = info.getFileType(); 387 if ( filetype != "" ) { 388 validate_filetype(filetype); 389 std::auto_ptr<Encoder> enc2 390 = getEncoder( std::string( info.getFileName() ), filetype ); 391 enc = enc2; 392 } else { 393 std::auto_ptr<Encoder> enc2 394 = getEncoder( std::string( info.getFileName() ) ); 395 enc = enc2; 396 } 397 398 std::string comp = info.getCompression(); 399 if ( comp != "" ) { 400 401 // check for JPEG compression 402 int quality = -1; 403 std::istringstream compstream(comp.c_str()); 404 compstream >> quality; 405 406 // FIXME: dangelo: This code might lead to strange effects (setting an invalid compression mode), 407 // if other formats also support a numerical compression parameter. 408 if ( quality != -1 ) { 409 enc->setCompressionType( "JPEG", quality ); 410 } else { 411 // leave any other compression type to the codec 412 enc->setCompressionType(comp); 413 } 414 } 415 416 std::string pixel_type = info.getPixelType(); 417 if ( pixel_type != "" ) { 418 if(!isPixelTypeSupported( enc->getFileType(), pixel_type )) 419 { 420 std::string msg("exportImage(): file type "); 421 msg += enc->getFileType() + " does not support requested pixel type " 422 + pixel_type + "."; 423 vigra_precondition(false, msg.c_str()); 424 } 425 enc->setPixelType(pixel_type); 426 } 427 428 // set other properties 429 enc->setXResolution(info.getXResolution()); 430 enc->setYResolution(info.getYResolution()); 431 enc->setPosition(info.getPosition()); 432 enc->setCanvasSize(info.getCanvasSize()); 433 434 if ( info.getICCProfile().size() > 0 ) { 435 enc->setICCProfile(info.getICCProfile()); 436 } 437 438 return enc; 439 } 440 441 // class ImageImportInfo 442 443 ImageImportInfo::ImageImportInfo( const char * filename ) 444 : m_filename(filename) 445 { 446 std::auto_ptr<Decoder> decoder = getDecoder(m_filename); 447 448 m_filetype = decoder->getFileType(); 449 m_pixeltype = decoder->getPixelType(); 450 m_width = decoder->getWidth(); 451 m_height = decoder->getHeight(); 452 m_num_bands = decoder->getNumBands(); 453 m_num_extra_bands = decoder->getNumExtraBands(); 454 m_pos = decoder->getPosition(); 455 m_canvas_size = decoder->getCanvasSize(); 456 457 m_icc_profile = decoder->getICCProfile(); 458 459 decoder->abort(); // there probably is no better way than this 460 } 461 462 ImageImportInfo::~ImageImportInfo() { 463 } 464 465 const char * ImageImportInfo::getFileName() const 466 { 467 return m_filename.c_str(); 468 } 469 470 const char * ImageImportInfo::getFileType() const 471 { 472 return m_filetype.c_str(); 473 } 474 475 const char * ImageImportInfo::getPixelType() const 476 { 477 return m_pixeltype.c_str(); 478 } 479 480 ImageImportInfo::PixelType ImageImportInfo::pixelType() const 481 { 482 const std::string pixeltype=getPixelType(); 483 if (pixeltype == "UINT8") 484 return UINT8; 485 if (pixeltype == "INT16") 486 return INT16; 487 if (pixeltype == "UINT16") 488 return UINT16; 489 if (pixeltype == "INT32") 490 return INT32; 491 if (pixeltype == "UINT32") 492 return UINT32; 493 if (pixeltype == "FLOAT") 494 return FLOAT; 495 if (pixeltype == "DOUBLE") 496 return DOUBLE; 497 vigra_fail( "internal error: unknown pixel type" ); 498 return ImageImportInfo::PixelType(); 499 } 500 501 int ImageImportInfo::width() const 502 { 503 return m_width; 504 } 505 506 int ImageImportInfo::height() const 507 { 508 return m_height; 509 } 510 511 int ImageImportInfo::numBands() const 512 { 513 return m_num_bands; 514 } 515 516 int ImageImportInfo::numExtraBands() const 517 { 518 return m_num_extra_bands; 519 } 520 521 Size2D ImageImportInfo::size() const 522 { 523 return Size2D( m_width, m_height ); 524 } 525 526 bool ImageImportInfo::isGrayscale() const 527 { 528 return m_num_bands == 1; 529 } 530 531 bool ImageImportInfo::isColor() const 532 { 533 return (m_num_bands - m_num_extra_bands) == 3; 534 } 535 536 bool ImageImportInfo::isByte() const 537 { 538 return m_pixeltype == "UINT8"; 539 } 540 541 Diff2D ImageImportInfo::getPosition() const 542 { 543 return m_pos; 544 } 545 546 Size2D ImageImportInfo::getCanvasSize() const 547 { 548 return m_canvas_size; 549 } 550 551 552 float ImageImportInfo::getXResolution() const 553 { 554 return m_x_res; 555 } 556 557 float ImageImportInfo::getYResolution() const 558 { 559 return m_y_res; 560 } 561 562 const ImageImportInfo::ICCProfile & ImageImportInfo::getICCProfile() const 563 { 564 return m_icc_profile; 565 } 566 567 // return a decoder for a given ImageImportInfo object 568 std::auto_ptr<Decoder> decoder( const ImageImportInfo & info ) 569 { 570 std::string filetype = info.getFileType(); 571 validate_filetype(filetype); 572 return getDecoder( std::string( info.getFileName() ), filetype ); 573 } 574 575 } // namespace vigra 576