ImageFile.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  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. magic=filename.substr(pos);
  218. if(magic==".pgm" || magic==".PGM")
  219. return ImageFile::PGM_RAW;
  220. if(magic==".ppm" || magic==".PPM")
  221. return ImageFile::PPM_RAW;
  222. if(magic==".png" || magic==".PNG")
  223. return ImageFile::PNG;
  224. if(magic==".jpg" || magic==".JPG")
  225. return ImageFile::JPG;
  226. return ImageFile::FormatUnknown;
  227. }
  228. std::string ImageFile::getComment()
  229. {
  230. if(fileformat==FormatUnknown) {
  231. fileformat=ImageFile::name2Format(filename);
  232. }
  233. std::string comment="";
  234. #ifdef NICE_USELIB_LIMUN_IOCOMPRESSION
  235. std::string cmdstring="identify -format \"\%c\" ";
  236. cmdstring+=filename;
  237. ipipestream cmd(cmdstring.c_str());
  238. while(!cmd.eof()) {
  239. std::string line;
  240. getline(cmd,line);
  241. comment += line;
  242. }
  243. #endif
  244. return comment;
  245. }
  246. bool ImageFile::isGray() const
  247. {
  248. #ifdef NICE_USELIB_LIMUN_IOCOMPRESSION
  249. std::string cmdstring="identify -ping ";
  250. cmdstring+=filename;
  251. cmdstring+= "| cut -d' ' -f 4";
  252. ipipestream cmd(cmdstring.c_str());
  253. while(!cmd.eof()) {
  254. std::string line;
  255. getline(cmd,line);
  256. if(line=="PseudoClass")
  257. return true;
  258. }
  259. #endif
  260. return false;
  261. }
  262. uint ImageFile::width()
  263. {
  264. if ( fileheader.width < 0 )
  265. getMyHeader();
  266. if ( fileheader.width < 0 )
  267. fthrow(Exception, "Negative image width found in file header.");
  268. return (uint)fileheader.width;
  269. }
  270. uint ImageFile::height()
  271. {
  272. if ( fileheader.height < 0 )
  273. getMyHeader();
  274. if ( fileheader.height < 0 )
  275. fthrow(Exception, "Negative image width found in file header.");
  276. return (uint)fileheader.height;
  277. }
  278. const ImageFile::Header &ImageFile::getHeader()
  279. {
  280. getMyHeader();
  281. return fileheader;
  282. }
  283. void ImageFile::getMyHeader()
  284. {
  285. if(fileformat==FormatUnknown) {
  286. fileformat=ImageFile::name2Format(filename);
  287. }
  288. if(static_cast<int>(fileformat)>0 && static_cast<int>(fileformat)<8) {
  289. getPXMHeader();
  290. #ifdef NICE_USELIB_PNG
  291. } else if ( fileformat == ImageFile::PNG ) {
  292. getPNGHeader();
  293. #endif
  294. #ifdef NICE_USELIB_JPG
  295. } else if ( fileformat == ImageFile::JPG ) {
  296. getJPGHeader();
  297. #endif
  298. } else {
  299. #ifdef NICE_USELIB_LIBMAGICK
  300. MagickCore::ImageInfo *image_info=CloneImageInfo((MagickCore::ImageInfo *) NULL);
  301. strcpy(image_info->filename, filename.c_str());
  302. image_info->ping=MagickCore::MagickBooleanType(1);
  303. MagickCore::ExceptionInfo exc_info;
  304. GetExceptionInfo(&exc_info);
  305. MagickCore::Image *image=MagickCore::PingImage(image_info, &exc_info);
  306. fileheader.width = image->columns;
  307. fileheader.height = image->rows;
  308. MagickCore::DestroyImage(image);
  309. MagickCore::DestroyImageInfo(image_info);
  310. #else
  311. fthrow(ImageException,"Not implemented without Libmagick");
  312. #endif
  313. }
  314. }
  315. void ImageFile::getPXMHeader() {
  316. using namespace std;
  317. ifstream file(filename.c_str(), ios::binary);
  318. // error handling
  319. if(!file.good()) {
  320. fthrow(ImageException,string("getPXMHeader: Cannot open ") + filename);
  321. }
  322. char val;
  323. file.get(val);
  324. if(val!='P') {
  325. file.putback(val);
  326. fileformat=ImageFile::FormatUnknown;
  327. }
  328. file.get(val);
  329. if(val>'0' && val<'8') {
  330. fileformat=static_cast<ImageFile::Format>(val-'0');
  331. }
  332. if(fileformat==PPM_IMAGE_TEXT || fileformat==PPM_RAW)
  333. fileheader.channel=3;
  334. else
  335. fileheader.channel=1;
  336. int values=3; // fileheader values
  337. if(fileformat==PBM_IMAGE_TEXT || fileformat==PBM_RAW) {
  338. values=2;
  339. fileheader.bitdepth=1;
  340. }
  341. int status=0;
  342. int i=0, num=0;
  343. const int bsize = 1024;
  344. char buffer[bsize];
  345. while (file.good()&&num<values) {
  346. file.get(val);
  347. if(val=='#') { // omit comment
  348. while (file.good() && val!='\n') {
  349. file.get(val);
  350. }
  351. continue;
  352. }
  353. if(val>='0'&& val<='9') {
  354. status=1;
  355. buffer[i++]=val;
  356. } else if(status==1) {
  357. num++;
  358. buffer[i++]=' ';
  359. status=0;
  360. }
  361. }
  362. datapos = file.tellg();
  363. buffer[i]=0;
  364. std::stringstream stream;
  365. stream << buffer;
  366. int maxval;
  367. if(values==3)
  368. stream >> fileheader.width >> fileheader.height >> maxval;
  369. else
  370. stream >> fileheader.width >> fileheader.height;
  371. if(maxval<256)
  372. fileheader.bitdepth=8;
  373. else if (maxval<65536)
  374. fileheader.bitdepth=16;
  375. else
  376. fileformat=ImageFile::FormatUnknown;
  377. }
  378. #ifdef NICE_USELIB_PNG
  379. void ImageFile::getPNGHeader ()
  380. {
  381. FILE* pFile;
  382. // open image file
  383. if ((pFile = fopen(filename.c_str(), "rb")) == NULL) {
  384. fthrow(ImageException,"ImageFile::getPNGHeader: Cannot open " + filename);
  385. }
  386. // read header
  387. const int headersize=8; // 8 is the maximum size that can be checked
  388. png_byte header[headersize];
  389. fread(header, 1, headersize, pFile);
  390. if (png_sig_cmp(header, 0, headersize)) {
  391. fclose(pFile);
  392. fthrow(ImageException,"Image is not a PNG file.");
  393. }
  394. /* initialize stuff */
  395. png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  396. if (!png_ptr) {
  397. fclose(pFile);
  398. fthrow(ImageException,"png_create_read_struct failed");
  399. }
  400. png_infop info_ptr = png_create_info_struct(png_ptr);
  401. if (!info_ptr) {
  402. fclose(pFile);
  403. fthrow(ImageException,"png_create_info_struct failed");
  404. }
  405. if (setjmp(png_jmpbuf(png_ptr))) {
  406. fclose(pFile);
  407. fthrow(ImageException,"Error during init_io");
  408. }
  409. png_init_io(png_ptr, pFile);
  410. png_set_sig_bytes(png_ptr, headersize);
  411. png_read_info(png_ptr, info_ptr);
  412. fileheader.width = info_ptr->width;
  413. fileheader.height = info_ptr->height;
  414. fileheader.bitdepth = info_ptr->bit_depth;
  415. png_byte color_type = info_ptr->color_type;
  416. if ( color_type == PNG_COLOR_TYPE_GRAY )
  417. fileheader.channel = 1;
  418. else
  419. fileheader.channel = 3;
  420. png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
  421. fclose(pFile);
  422. }
  423. #endif
  424. #ifdef NICE_USELIB_JPG
  425. void ImageFile::getJPGHeader()
  426. {
  427. struct jpeg_decompress_struct cinfo;
  428. struct jpeg_error_mgr jerr;
  429. FILE* pFile;
  430. if ((pFile = fopen(filename.c_str(), "rb")) == NULL)
  431. fthrow(ImageException,"ImageFile::readerJPG: Cannot open " + filename);
  432. cinfo.err = jpeg_std_error(&jerr);
  433. jpeg_create_decompress(&cinfo);
  434. jpeg_stdio_src(&cinfo, pFile);
  435. jpeg_read_header(&cinfo, FALSE);
  436. // this statement is important also to read
  437. // image width and height
  438. jpeg_start_decompress(&cinfo);
  439. fileheader.width = cinfo.output_width;
  440. fileheader.height = cinfo.output_height;
  441. fileheader.channel = cinfo.out_color_components;
  442. fileheader.bitdepth = cinfo.num_components;
  443. fclose(pFile);
  444. }
  445. #endif
  446. } // namespace NICE
  447. /*****************************************************************************/
  448. /*
  449. * $Log: ImageFile.cpp,v $
  450. * Revision 1.7 2010/06/04 08:53:52 rodner
  451. * - bugfixes
  452. *
  453. * Revision 1.6 2009/11/30 12:25:50 rodner
  454. * - ImageMagick warning / error issue
  455. * - indent problem in SimpleSelector
  456. *
  457. * Revision 1.5 2009/07/22 12:12:01 rodner
  458. * - added ImageMagick functionality
  459. *
  460. * Revision 1.4 2009/06/10 08:06:34 rodner
  461. * - getHeader support for png/jpg without system("identify ..");
  462. *
  463. * Revision 1.3 2009/06/09 14:02:32 rodner
  464. * - bugfix: rect .cpp -> .tcc
  465. *
  466. * Revision 1.2 2009/05/28 11:36:30 bajramov
  467. * renamed a few things for consistency
  468. *
  469. * Revision 1.1.1.1 2007/05/22 19:26:35 bajramov
  470. * limun2
  471. *
  472. * Revision 1.16 2006/10/23 11:30:40 zimmermann
  473. * * more general jpg io
  474. *
  475. * Revision 1.15 2006/10/20 17:14:04 zimmermann
  476. * * improved jpg io / test
  477. *
  478. * Revision 1.14 2006/10/06 13:21:39 mattern
  479. * .
  480. *
  481. * Revision 1.13 2006/08/22 15:59:32 zimmermann
  482. * * added required #ifdef NICE_USELIB_PNG
  483. *
  484. * Revision 1.12 2006/08/21 15:55:28 mattern
  485. * - is gray implemented
  486. *
  487. * Revision 1.11 2006/08/21 14:01:33 zimmermann
  488. * *fixed some errors
  489. *
  490. * Revision 1.10 2006/07/13 12:50:09 mattern
  491. * - small fixes
  492. *
  493. * Revision 1.9 2006/07/13 11:53:51 mattern
  494. * - large bug fixes
  495. *
  496. * Revision 1.8 2006/05/24 13:03:43 mattern
  497. * - jpg bugfix
  498. * - unsigned signed errors fixed
  499. *
  500. * Revision 1.7 2006/05/22 16:13:24 zimmermann
  501. * * added jpeg io to ColorImage/Image/ImageFile
  502. *
  503. * Revision 1.6 2006/04/01 14:41:43 mattern
  504. * - new copy mode
  505. *
  506. * Revision 1.5 2006/03/31 22:26:35 mattern
  507. * *** empty log message ***
  508. *
  509. * Revision 1.4 2006/03/27 19:06:56 mattern
  510. * .
  511. *
  512. * Revision 1.3 2006/03/26 01:48:05 mattern
  513. * .
  514. *
  515. * Revision 1.2 2006/03/02 14:54:54 mattern
  516. * - documenation improved
  517. *
  518. * Revision 1.1 2006/03/02 14:50:33 mattern
  519. * - ImageFile added
  520. * - more template methods
  521. * - ippwrapper improved
  522. * - png support
  523. *
  524. * Revision 1.2 2006/02/09 09:39:14 mattern
  525. * * template update
  526. *
  527. * Revision 1.3 2006/02/02 10:50:12 mattern
  528. * * Template changed
  529. *
  530. * Revision 1.2 2005/07/28 09:56:34 bajramov
  531. * License
  532. *
  533. * Revision 1.1.1.1 2005/07/22 13:53:17 mattern
  534. * Librarys for IMage UNderstanding
  535. *
  536. */