ImageFile.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. /*
  2. * NICE-Core - efficient algebra and computer vision methods
  3. * - libimage - An image/template for new NICE libraries
  4. * See file License for license information.
  5. */
  6. /*****************************************************************************/
  7. /*! \file ImageFile.cpp
  8. \brief ImageFile class definitions
  9. */
  10. /*****************************************************************************/
  11. /*
  12. * $Author: rodner $
  13. * $Date: 2010/06/04 08:53:52 $
  14. * $Revision: 1.7 $
  15. */
  16. /*****************************************************************************/
  17. #include <sstream>
  18. #include "core/image/ImageFile.h"
  19. #include "core/image/Convert.h"
  20. #ifdef NICE_USELIB_LIMUN_IOCOMPRESSION
  21. #include "iocompression/pipestream.h"
  22. #include "iocompression/magic.h"
  23. #endif
  24. #ifdef NICE_USELIB_LIBMAGICK
  25. #include <Magick++.h>
  26. #endif
  27. namespace NICE {
  28. // Constructors:
  29. // -------------
  30. ImageFile::ImageFile(const std::string &filename, Format type)
  31. {
  32. this->filename=filename;
  33. if(type==FormatUnknown)
  34. {
  35. fileformat=ImageFile::name2Format(filename);
  36. }
  37. else
  38. {
  39. fileformat=type;
  40. }
  41. datapos=0;
  42. }
  43. ImageFile::ImageFile()
  44. {
  45. filename = "";
  46. fileformat = FormatUnknown;
  47. datapos=0;
  48. }
  49. ImageFile::ImageFile(const ImageFile& ex)
  50. {
  51. *this=ex;
  52. }
  53. // Operators:
  54. // ----------
  55. ImageFile& ImageFile::operator=(const ImageFile& ex)
  56. {
  57. filename=ex.filename;
  58. fileformat=ex.fileformat;
  59. fileheader=ex.fileheader;
  60. datapos=ex.datapos;
  61. return *this;
  62. }
  63. // Destructor:
  64. // -----------
  65. ImageFile::~ImageFile()
  66. {
  67. }
  68. #include <iostream>
  69. #ifdef NICE_USELIB_PNG
  70. template<>
  71. void ImageFile::readerPNG(GrayColorImageCommonImplementationT<Ipp32f> *image)
  72. {
  73. switch(image->channels())
  74. {
  75. case 1:
  76. {
  77. Image buffer;
  78. readerPNG(&buffer);
  79. if(image->widthInline()!=buffer.width() || image->heightInline()!=buffer.height()) {
  80. image->resize(buffer.width(), buffer.height());
  81. }
  82. grayToFloat(buffer,dynamic_cast<ImageT<Ipp32f>* >(image));
  83. break;
  84. }
  85. case 3:
  86. {
  87. ColorImage buffer;
  88. readerPNG(&buffer);
  89. if(image->widthInline()!=buffer.width() || image->heightInline()!=buffer.height()) {
  90. image->resize(buffer.width(), buffer.height());
  91. }
  92. convertBitDepth(buffer,dynamic_cast<ColorImageT<Ipp32f>* >(image));
  93. break;
  94. }
  95. default: fthrow(ImageException,"No or invalid color image->channels()");
  96. break;
  97. }
  98. }
  99. #endif //NICE_USELIB_PNG
  100. #ifdef NICE_USELIB_LIBMAGICK
  101. template<>
  102. void ImageFile::readerMagick(GrayColorImageCommonImplementationT<unsigned char> *image)
  103. {
  104. Magick::Image magick_image;
  105. try {
  106. magick_image.read ( filename );
  107. } catch ( Magick::Warning &error) {
  108. std::cerr << "libMagick++ warning: " << error.what() << std::endl;
  109. }
  110. // FIXME: maybe we should provide the possibility to read images with arbitary memory alignment
  111. if(image->widthInline()!=(int)magick_image.baseColumns() || image->heightInline()!=(int)magick_image.baseRows()
  112. || image->getMemoryLayout() != GrayColorImageCommonImplementation::noAlignment )
  113. image->resize ( magick_image.baseColumns(), magick_image.baseRows(), GrayColorImageCommonImplementation::noAlignment );
  114. if ( image->channels() == 1 ) {
  115. // gray value
  116. magick_image.type( Magick::GrayscaleType );
  117. magick_image.write ( 0, 0, magick_image.baseColumns(), magick_image.baseRows(),
  118. "R", Magick::CharPixel, image->getPixelPointer() );
  119. } else { // rgb image
  120. magick_image.write ( 0, 0, magick_image.baseColumns(), magick_image.baseRows(),
  121. "RGB", Magick::CharPixel, image->getPixelPointer() );
  122. }
  123. }
  124. template<>
  125. void ImageFile::writerMagick(const GrayColorImageCommonImplementationT<unsigned char> *image) const
  126. {
  127. if ( image->channels() == 1 ) // gray image
  128. {
  129. Magick::Image magick_image;
  130. // checking whether we have not a simple aligned image (block in memory)
  131. if ( image->rowStepsize() != image->width() )
  132. {
  133. // this means that we have a sub image or an IPP image
  134. // (i.e. some pixels are skipped in each row)
  135. // The Blob interface of ImageMagick is not flexible enough to handle this case
  136. //
  137. // Solution: we have to copy the image :(
  138. // We do this by creating an empty NICE image
  139. ImageT<unsigned char> image_noalignment;
  140. // Setting the memory alignment and copying from image
  141. image_noalignment.copyFrom ( *image, GrayColorImageCommonImplementation::noAlignment );
  142. // and doing the conversion to a Magick image
  143. // the alternative would be to directly copy from image to magick_image without memory
  144. // operations, but this could be slower
  145. Magick::Blob blob ( image_noalignment.getPixelPointer(), image_noalignment.width()*image_noalignment.height() );
  146. magick_image.magick ("GRAY");
  147. magick_image.read ( blob, Magick::Geometry ( image_noalignment.width(), image_noalignment.height() ), 8 );
  148. magick_image.write ( filename );
  149. }
  150. else
  151. {
  152. Magick::Blob blob ( image->getPixelPointer(), image->width()*image->height() );
  153. magick_image.magick ("GRAY");
  154. magick_image.read ( blob, Magick::Geometry ( image->width(), image->height() ), 8 );
  155. magick_image.write ( filename );
  156. }
  157. }
  158. else // color image
  159. {
  160. // see above, the same problems occur for RGB images
  161. if ( image->rowStepsize() != image->width() )
  162. {
  163. ColorImageT<unsigned char> image_noalignment;
  164. image_noalignment.copyFrom ( *image, GrayColorImageCommonImplementation::noAlignment );
  165. Magick::Image magick_image ( image_noalignment.width(), image_noalignment.height(),
  166. "RGB", Magick::CharPixel, image_noalignment.getPixelPointer() );
  167. std::string pngEnding ( ".png" );
  168. // do we currently want to write a png file?
  169. // if so, adapt writing parameters accordingly
  170. //
  171. // needed for compatibility with png writer
  172. if ( filename.compare( filename.length() - pngEnding.length(), pngEnding.length(), pngEnding) == 0)
  173. {
  174. magick_image.defineValue( "png", "bit-depth", "8");
  175. magick_image.defineValue( "png", "format", "png8");
  176. }
  177. magick_image.write ( filename );
  178. }
  179. else
  180. {
  181. // we do not need the Blob definition here (somehow strange)
  182. Magick::Image magick_image ( image->width(), image->height(),
  183. "RGB", Magick::CharPixel, image->getPixelPointer() );
  184. std::string pngEnding ( ".png" );
  185. // do we currently want to write a png file?
  186. // if so, adapt writing parameters accordingly
  187. //
  188. // needed for compatibility with png writer
  189. if ( filename.compare( filename.length() - pngEnding.length(), pngEnding.length(), pngEnding) == 0)
  190. {
  191. magick_image.defineValue( "png", "bit-depth", "8");
  192. magick_image.defineValue( "png", "format", "png8");
  193. }
  194. magick_image.write ( filename );
  195. }
  196. }
  197. }
  198. #endif
  199. ImageFile::Format ImageFile::name2Format(const std::string &filename)
  200. {
  201. std::string magic;
  202. #ifdef NICE_USELIB_LIMUN_IOCOMPRESSION
  203. magic=magicString(filename);
  204. if(magic!="ERROR")
  205. {
  206. if(magic=="Netpbm PGM \"rawbits\" image data")
  207. return ImageFile::PGM_RAW;
  208. if(magic=="Netpbm PPM \"rawbits\" image data")
  209. return ImageFile::PPM_RAW;
  210. if(magic=="PNG image data")
  211. return ImageFile::PNG;
  212. if(magic=="JPG image data")
  213. return ImageFile::JPG;
  214. };
  215. #endif
  216. int pos=filename.find_last_of('.');
  217. if(pos==std::string::npos)
  218. return ImageFile::FormatUnknown;
  219. magic=filename.substr(pos);
  220. if(magic==".pgm" || magic==".PGM")
  221. return ImageFile::PGM_RAW;
  222. if(magic==".ppm" || magic==".PPM")
  223. return ImageFile::PPM_RAW;
  224. if(magic==".png" || magic==".PNG")
  225. return ImageFile::PNG;
  226. if(magic==".jpg" || magic==".JPG")
  227. return ImageFile::JPG;
  228. return ImageFile::FormatUnknown;
  229. }
  230. std::string ImageFile::getComment()
  231. {
  232. if(fileformat==FormatUnknown) {
  233. fileformat=ImageFile::name2Format(filename);
  234. }
  235. std::string comment="";
  236. #ifdef NICE_USELIB_LIMUN_IOCOMPRESSION
  237. std::string cmdstring="identify -format \"\%c\" ";
  238. cmdstring+=filename;
  239. ipipestream cmd(cmdstring.c_str());
  240. while(!cmd.eof()) {
  241. std::string line;
  242. getline(cmd,line);
  243. comment += line;
  244. }
  245. #endif
  246. return comment;
  247. }
  248. bool ImageFile::isGray() const
  249. {
  250. #ifdef NICE_USELIB_LIMUN_IOCOMPRESSION
  251. std::string cmdstring="identify -ping ";
  252. cmdstring+=filename;
  253. cmdstring+= "| cut -d' ' -f 4";
  254. ipipestream cmd(cmdstring.c_str());
  255. while(!cmd.eof()) {
  256. std::string line;
  257. getline(cmd,line);
  258. if(line=="PseudoClass")
  259. return true;
  260. }
  261. #endif
  262. return false;
  263. }
  264. uint ImageFile::width()
  265. {
  266. if ( fileheader.width < 0 )
  267. getMyHeader();
  268. if ( fileheader.width < 0 )
  269. fthrow(Exception, "Negative image width found in file header.");
  270. return (uint)fileheader.width;
  271. }
  272. uint ImageFile::height()
  273. {
  274. if ( fileheader.height < 0 )
  275. getMyHeader();
  276. if ( fileheader.height < 0 )
  277. fthrow(Exception, "Negative image width found in file header.");
  278. return (uint)fileheader.height;
  279. }
  280. const ImageFile::Header &ImageFile::getHeader()
  281. {
  282. getMyHeader();
  283. return fileheader;
  284. }
  285. void ImageFile::getMyHeader()
  286. {
  287. if(fileformat==FormatUnknown) {
  288. fileformat=ImageFile::name2Format(filename);
  289. }
  290. if(static_cast<int>(fileformat)>0 && static_cast<int>(fileformat)<8) {
  291. getPXMHeader();
  292. #ifdef NICE_USELIB_PNG
  293. } else if ( fileformat == ImageFile::PNG ) {
  294. getPNGHeader();
  295. #endif
  296. #ifdef NICE_USELIB_JPG
  297. } else if ( fileformat == ImageFile::JPG ) {
  298. getJPGHeader();
  299. #endif
  300. } else {
  301. #ifdef NICE_USELIB_LIBMAGICK
  302. MagickCore::ImageInfo *image_info=CloneImageInfo((MagickCore::ImageInfo *) NULL);
  303. strcpy(image_info->filename, filename.c_str());
  304. image_info->ping=MagickCore::MagickBooleanType(1);
  305. MagickCore::ExceptionInfo exc_info;
  306. GetExceptionInfo(&exc_info);
  307. MagickCore::Image *image=MagickCore::PingImage(image_info, &exc_info);
  308. fileheader.width = image->columns;
  309. fileheader.height = image->rows;
  310. MagickCore::DestroyImage(image);
  311. MagickCore::DestroyImageInfo(image_info);
  312. #else
  313. fthrow(ImageException,"Not implemented without Libmagick");
  314. #endif
  315. }
  316. }
  317. void ImageFile::getPXMHeader() {
  318. using namespace std;
  319. ifstream file(filename.c_str(), ios::binary);
  320. // error handling
  321. if(!file.good()) {
  322. fthrow(ImageException,string("getPXMHeader: Cannot open ") + filename);
  323. }
  324. char val;
  325. file.get(val);
  326. if(val!='P') {
  327. file.putback(val);
  328. fileformat=ImageFile::FormatUnknown;
  329. }
  330. file.get(val);
  331. if(val>'0' && val<'8') {
  332. fileformat=static_cast<ImageFile::Format>(val-'0');
  333. }
  334. if(fileformat==PPM_IMAGE_TEXT || fileformat==PPM_RAW)
  335. fileheader.channel=3;
  336. else
  337. fileheader.channel=1;
  338. int values=3; // fileheader values
  339. if(fileformat==PBM_IMAGE_TEXT || fileformat==PBM_RAW) {
  340. values=2;
  341. fileheader.bitdepth=1;
  342. }
  343. int status=0;
  344. int i=0, num=0;
  345. const int bsize = 1024;
  346. char buffer[bsize];
  347. while (file.good()&&num<values) {
  348. file.get(val);
  349. if(val=='#') { // omit comment
  350. while (file.good() && val!='\n') {
  351. file.get(val);
  352. }
  353. continue;
  354. }
  355. if(val>='0'&& val<='9') {
  356. status=1;
  357. buffer[i++]=val;
  358. } else if(status==1) {
  359. num++;
  360. buffer[i++]=' ';
  361. status=0;
  362. }
  363. }
  364. datapos = file.tellg();
  365. buffer[i]=0;
  366. std::stringstream stream;
  367. stream << buffer;
  368. int maxval;
  369. if(values==3)
  370. stream >> fileheader.width >> fileheader.height >> maxval;
  371. else
  372. stream >> fileheader.width >> fileheader.height;
  373. if(maxval<256)
  374. fileheader.bitdepth=8;
  375. else if (maxval<65536)
  376. fileheader.bitdepth=16;
  377. else
  378. fileformat=ImageFile::FormatUnknown;
  379. }
  380. #ifdef NICE_USELIB_PNG
  381. void ImageFile::getPNGHeader ()
  382. {
  383. FILE* pFile;
  384. // open image file
  385. if ((pFile = fopen(filename.c_str(), "rb")) == NULL) {
  386. fthrow(ImageException,"ImageFile::getPNGHeader: Cannot open " + filename);
  387. }
  388. // read header
  389. const int headersize=8; // 8 is the maximum size that can be checked
  390. png_byte header[headersize];
  391. fread(header, 1, headersize, pFile);
  392. if (png_sig_cmp(header, 0, headersize)) {
  393. fclose(pFile);
  394. fthrow(ImageException,"Image is not a PNG file.");
  395. }
  396. /* initialize stuff */
  397. png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  398. if (!png_ptr) {
  399. fclose(pFile);
  400. fthrow(ImageException,"png_create_read_struct failed");
  401. }
  402. png_infop info_ptr = png_create_info_struct(png_ptr);
  403. if (!info_ptr) {
  404. fclose(pFile);
  405. fthrow(ImageException,"png_create_info_struct failed");
  406. }
  407. if (setjmp(png_jmpbuf(png_ptr))) {
  408. fclose(pFile);
  409. fthrow(ImageException,"Error during init_io");
  410. }
  411. png_init_io(png_ptr, pFile);
  412. png_set_sig_bytes(png_ptr, headersize);
  413. png_read_info(png_ptr, info_ptr);
  414. fileheader.width = png_get_image_width(png_ptr, info_ptr);
  415. fileheader.height = png_get_image_height(png_ptr, info_ptr);
  416. fileheader.bitdepth = png_get_bit_depth(png_ptr, info_ptr);
  417. png_byte color_type = png_get_color_type(png_ptr, info_ptr);
  418. if ( color_type == PNG_COLOR_TYPE_GRAY )
  419. fileheader.channel = 1;
  420. else
  421. fileheader.channel = 3;
  422. png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
  423. fclose(pFile);
  424. }
  425. #endif
  426. #ifdef NICE_USELIB_JPG
  427. void ImageFile::getJPGHeader()
  428. {
  429. struct jpeg_decompress_struct cinfo;
  430. struct jpeg_error_mgr jerr;
  431. FILE* pFile;
  432. if ((pFile = fopen(filename.c_str(), "rb")) == NULL)
  433. fthrow(ImageException,"ImageFile::readerJPG: Cannot open " + filename);
  434. cinfo.err = jpeg_std_error(&jerr);
  435. jpeg_create_decompress(&cinfo);
  436. jpeg_stdio_src(&cinfo, pFile);
  437. jpeg_read_header(&cinfo, FALSE);
  438. // this statement is important also to read
  439. // image width and height
  440. jpeg_start_decompress(&cinfo);
  441. fileheader.width = cinfo.output_width;
  442. fileheader.height = cinfo.output_height;
  443. fileheader.channel = cinfo.out_color_components;
  444. fileheader.bitdepth = cinfo.num_components;
  445. fclose(pFile);
  446. }
  447. #endif
  448. } // namespace NICE
  449. /*****************************************************************************/
  450. /*
  451. * $Log: ImageFile.cpp,v $
  452. * Revision 1.7 2010/06/04 08:53:52 rodner
  453. * - bugfixes
  454. *
  455. * Revision 1.6 2009/11/30 12:25:50 rodner
  456. * - ImageMagick warning / error issue
  457. * - indent problem in SimpleSelector
  458. *
  459. * Revision 1.5 2009/07/22 12:12:01 rodner
  460. * - added ImageMagick functionality
  461. *
  462. * Revision 1.4 2009/06/10 08:06:34 rodner
  463. * - getHeader support for png/jpg without system("identify ..");
  464. *
  465. * Revision 1.3 2009/06/09 14:02:32 rodner
  466. * - bugfix: rect .cpp -> .tcc
  467. *
  468. * Revision 1.2 2009/05/28 11:36:30 bajramov
  469. * renamed a few things for consistency
  470. *
  471. * Revision 1.1.1.1 2007/05/22 19:26:35 bajramov
  472. * limun2
  473. *
  474. * Revision 1.16 2006/10/23 11:30:40 zimmermann
  475. * * more general jpg io
  476. *
  477. * Revision 1.15 2006/10/20 17:14:04 zimmermann
  478. * * improved jpg io / test
  479. *
  480. * Revision 1.14 2006/10/06 13:21:39 mattern
  481. * .
  482. *
  483. * Revision 1.13 2006/08/22 15:59:32 zimmermann
  484. * * added required #ifdef NICE_USELIB_PNG
  485. *
  486. * Revision 1.12 2006/08/21 15:55:28 mattern
  487. * - is gray implemented
  488. *
  489. * Revision 1.11 2006/08/21 14:01:33 zimmermann
  490. * *fixed some errors
  491. *
  492. * Revision 1.10 2006/07/13 12:50:09 mattern
  493. * - small fixes
  494. *
  495. * Revision 1.9 2006/07/13 11:53:51 mattern
  496. * - large bug fixes
  497. *
  498. * Revision 1.8 2006/05/24 13:03:43 mattern
  499. * - jpg bugfix
  500. * - unsigned signed errors fixed
  501. *
  502. * Revision 1.7 2006/05/22 16:13:24 zimmermann
  503. * * added jpeg io to ColorImage/Image/ImageFile
  504. *
  505. * Revision 1.6 2006/04/01 14:41:43 mattern
  506. * - new copy mode
  507. *
  508. * Revision 1.5 2006/03/31 22:26:35 mattern
  509. * *** empty log message ***
  510. *
  511. * Revision 1.4 2006/03/27 19:06:56 mattern
  512. * .
  513. *
  514. * Revision 1.3 2006/03/26 01:48:05 mattern
  515. * .
  516. *
  517. * Revision 1.2 2006/03/02 14:54:54 mattern
  518. * - documenation improved
  519. *
  520. * Revision 1.1 2006/03/02 14:50:33 mattern
  521. * - ImageFile added
  522. * - more template methods
  523. * - ippwrapper improved
  524. * - png support
  525. *
  526. * Revision 1.2 2006/02/09 09:39:14 mattern
  527. * * template update
  528. *
  529. * Revision 1.3 2006/02/02 10:50:12 mattern
  530. * * Template changed
  531. *
  532. * Revision 1.2 2005/07/28 09:56:34 bajramov
  533. * License
  534. *
  535. * Revision 1.1.1.1 2005/07/22 13:53:17 mattern
  536. * Librarys for IMage UNderstanding
  537. *
  538. */