ImageFile.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  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 ) {
  128. Magick::Image magick_image;
  129. // checking whether we have not a simple aligned image (block in memory)
  130. if ( image->rowStepsize() != image->width() ) {
  131. // this means that we have a sub image or an IPP image
  132. // (i.e. some pixels are skipped in each row)
  133. // The Blob interface of ImageMagick is not flexible enough to handle this case
  134. //
  135. // Solution: we have to copy the image :(
  136. // We do this by creating an empty NICE image
  137. ImageT<unsigned char> image_noalignment;
  138. // Setting the memory alignment and copying from image
  139. image_noalignment.copyFrom ( *image, GrayColorImageCommonImplementation::noAlignment );
  140. // and doing the conversion to a Magick image
  141. // the alternative would be to directly copy from image to magick_image without memory
  142. // operations, but this could be slower
  143. Magick::Blob blob ( image_noalignment.getPixelPointer(), image_noalignment.width()*image_noalignment.height() );
  144. magick_image.magick ("GRAY");
  145. magick_image.read ( blob, Magick::Geometry ( image_noalignment.width(), image_noalignment.height() ), 8 );
  146. magick_image.write ( filename );
  147. } else {
  148. Magick::Blob blob ( image->getPixelPointer(), image->width()*image->height() );
  149. magick_image.magick ("GRAY");
  150. magick_image.read ( blob, Magick::Geometry ( image->width(), image->height() ), 8 );
  151. magick_image.write ( filename );
  152. }
  153. } else {
  154. // see above, the same problems occur for RGB images
  155. if ( image->rowStepsize() != image->width() ) {
  156. ColorImageT<unsigned char> image_noalignment;
  157. image_noalignment.copyFrom ( *image, GrayColorImageCommonImplementation::noAlignment );
  158. Magick::Image magick_image ( image_noalignment.width(), image_noalignment.height(),
  159. "RGB", Magick::CharPixel, image_noalignment.getPixelPointer() );
  160. magick_image.write ( filename );
  161. } else {
  162. // we do not need the Blob definition here (somehow strange)
  163. Magick::Image magick_image ( image->width(), image->height(),
  164. "RGB", Magick::CharPixel, image->getPixelPointer() );
  165. magick_image.write ( filename );
  166. }
  167. }
  168. }
  169. #endif
  170. ImageFile::Format ImageFile::name2Format(const std::string &filename)
  171. {
  172. std::string magic;
  173. #ifdef NICE_USELIB_LIMUN_IOCOMPRESSION
  174. magic=magicString(filename);
  175. if(magic!="ERROR")
  176. {
  177. if(magic=="Netpbm PGM \"rawbits\" image data")
  178. return ImageFile::PGM_RAW;
  179. if(magic=="Netpbm PPM \"rawbits\" image data")
  180. return ImageFile::PPM_RAW;
  181. if(magic=="PNG image data")
  182. return ImageFile::PNG;
  183. if(magic=="JPG image data")
  184. return ImageFile::JPG;
  185. };
  186. #endif
  187. int pos=filename.find_last_of('.');
  188. magic=filename.substr(pos);
  189. if(magic==".pgm" || magic==".PGM")
  190. return ImageFile::PGM_RAW;
  191. if(magic==".ppm" || magic==".PPM")
  192. return ImageFile::PPM_RAW;
  193. if(magic==".png" || magic==".PNG")
  194. return ImageFile::PNG;
  195. if(magic==".jpg" || magic==".JPG")
  196. return ImageFile::JPG;
  197. return ImageFile::FormatUnknown;
  198. }
  199. std::string ImageFile::getComment()
  200. {
  201. if(fileformat==FormatUnknown) {
  202. fileformat=ImageFile::name2Format(filename);
  203. }
  204. std::string comment="";
  205. #ifdef NICE_USELIB_LIMUN_IOCOMPRESSION
  206. std::string cmdstring="identify -format \"\%c\" ";
  207. cmdstring+=filename;
  208. ipipestream cmd(cmdstring.c_str());
  209. while(!cmd.eof()) {
  210. std::string line;
  211. getline(cmd,line);
  212. comment += line;
  213. }
  214. #endif
  215. return comment;
  216. }
  217. bool ImageFile::isGray() const
  218. {
  219. #ifdef NICE_USELIB_LIMUN_IOCOMPRESSION
  220. std::string cmdstring="identify -ping ";
  221. cmdstring+=filename;
  222. cmdstring+= "| cut -d' ' -f 4";
  223. ipipestream cmd(cmdstring.c_str());
  224. while(!cmd.eof()) {
  225. std::string line;
  226. getline(cmd,line);
  227. if(line=="PseudoClass")
  228. return true;
  229. }
  230. #endif
  231. return false;
  232. }
  233. uint ImageFile::width()
  234. {
  235. if ( fileheader.width < 0 )
  236. getMyHeader();
  237. if ( fileheader.width < 0 )
  238. fthrow(Exception, "Negative image width found in file header.");
  239. return (uint)fileheader.width;
  240. }
  241. uint ImageFile::height()
  242. {
  243. if ( fileheader.height < 0 )
  244. getMyHeader();
  245. if ( fileheader.height < 0 )
  246. fthrow(Exception, "Negative image width found in file header.");
  247. return (uint)fileheader.height;
  248. }
  249. const ImageFile::Header &ImageFile::getHeader()
  250. {
  251. getMyHeader();
  252. return fileheader;
  253. }
  254. void ImageFile::getMyHeader()
  255. {
  256. if(fileformat==FormatUnknown) {
  257. fileformat=ImageFile::name2Format(filename);
  258. }
  259. if(static_cast<int>(fileformat)>0 && static_cast<int>(fileformat)<8) {
  260. getPXMHeader();
  261. #ifdef NICE_USELIB_PNG
  262. } else if ( fileformat == ImageFile::PNG ) {
  263. getPNGHeader();
  264. #endif
  265. #ifdef NICE_USELIB_JPG
  266. } else if ( fileformat == ImageFile::JPG ) {
  267. getJPGHeader();
  268. #endif
  269. } else {
  270. #ifdef NICE_USELIB_LIBMAGICK
  271. MagickCore::ImageInfo *image_info=CloneImageInfo((MagickCore::ImageInfo *) NULL);
  272. strcpy(image_info->filename, filename.c_str());
  273. image_info->ping=MagickCore::MagickBooleanType(1);
  274. MagickCore::ExceptionInfo exc_info;
  275. GetExceptionInfo(&exc_info);
  276. MagickCore::Image *image=MagickCore::PingImage(image_info, &exc_info);
  277. fileheader.width = image->columns;
  278. fileheader.height = image->rows;
  279. MagickCore::DestroyImage(image);
  280. MagickCore::DestroyImageInfo(image_info);
  281. #else
  282. fthrow(ImageException,"Not implemented without Libmagick");
  283. #endif
  284. }
  285. }
  286. void ImageFile::getPXMHeader() {
  287. using namespace std;
  288. ifstream file(filename.c_str(), ios::binary);
  289. // error handling
  290. if(!file.good()) {
  291. fthrow(ImageException,string("getPXMHeader: Cannot open ") + filename);
  292. }
  293. char val;
  294. file.get(val);
  295. if(val!='P') {
  296. file.putback(val);
  297. fileformat=ImageFile::FormatUnknown;
  298. }
  299. file.get(val);
  300. if(val>'0' && val<'8') {
  301. fileformat=static_cast<ImageFile::Format>(val-'0');
  302. }
  303. if(fileformat==PPM_IMAGE_TEXT || fileformat==PPM_RAW)
  304. fileheader.channel=3;
  305. else
  306. fileheader.channel=1;
  307. int values=3; // fileheader values
  308. if(fileformat==PBM_IMAGE_TEXT || fileformat==PBM_RAW) {
  309. values=2;
  310. fileheader.bitdepth=1;
  311. }
  312. int status=0;
  313. int i=0, num=0;
  314. const int bsize = 1024;
  315. char buffer[bsize];
  316. while (file.good()&&num<values) {
  317. file.get(val);
  318. if(val=='#') { // omit comment
  319. while (file.good() && val!='\n') {
  320. file.get(val);
  321. }
  322. continue;
  323. }
  324. if(val>='0'&& val<='9') {
  325. status=1;
  326. buffer[i++]=val;
  327. } else if(status==1) {
  328. num++;
  329. buffer[i++]=' ';
  330. status=0;
  331. }
  332. }
  333. datapos = file.tellg();
  334. buffer[i]=0;
  335. std::stringstream stream;
  336. stream << buffer;
  337. int maxval;
  338. if(values==3)
  339. stream >> fileheader.width >> fileheader.height >> maxval;
  340. else
  341. stream >> fileheader.width >> fileheader.height;
  342. if(maxval<256)
  343. fileheader.bitdepth=8;
  344. else if (maxval<65536)
  345. fileheader.bitdepth=16;
  346. else
  347. fileformat=ImageFile::FormatUnknown;
  348. }
  349. #ifdef NICE_USELIB_PNG
  350. void ImageFile::getPNGHeader ()
  351. {
  352. FILE* pFile;
  353. // open image file
  354. if ((pFile = fopen(filename.c_str(), "rb")) == NULL) {
  355. fthrow(ImageException,"ImageFile::getPNGHeader: Cannot open " + filename);
  356. }
  357. // read header
  358. const int headersize=8; // 8 is the maximum size that can be checked
  359. png_byte header[headersize];
  360. fread(header, 1, headersize, pFile);
  361. if (png_sig_cmp(header, 0, headersize)) {
  362. fclose(pFile);
  363. fthrow(ImageException,"Image is not a PNG file.");
  364. }
  365. /* initialize stuff */
  366. png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  367. if (!png_ptr) {
  368. fclose(pFile);
  369. fthrow(ImageException,"png_create_read_struct failed");
  370. }
  371. png_infop info_ptr = png_create_info_struct(png_ptr);
  372. if (!info_ptr) {
  373. fclose(pFile);
  374. fthrow(ImageException,"png_create_info_struct failed");
  375. }
  376. if (setjmp(png_jmpbuf(png_ptr))) {
  377. fclose(pFile);
  378. fthrow(ImageException,"Error during init_io");
  379. }
  380. png_init_io(png_ptr, pFile);
  381. png_set_sig_bytes(png_ptr, headersize);
  382. png_read_info(png_ptr, info_ptr);
  383. fileheader.width = info_ptr->width;
  384. fileheader.height = info_ptr->height;
  385. fileheader.bitdepth = info_ptr->bit_depth;
  386. png_byte color_type = info_ptr->color_type;
  387. if ( color_type == PNG_COLOR_TYPE_GRAY )
  388. fileheader.channel = 1;
  389. else
  390. fileheader.channel = 3;
  391. png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
  392. fclose(pFile);
  393. }
  394. #endif
  395. #ifdef NICE_USELIB_JPG
  396. void ImageFile::getJPGHeader()
  397. {
  398. struct jpeg_decompress_struct cinfo;
  399. struct jpeg_error_mgr jerr;
  400. FILE* pFile;
  401. if ((pFile = fopen(filename.c_str(), "rb")) == NULL)
  402. fthrow(ImageException,"ImageFile::readerJPG: Cannot open " + filename);
  403. cinfo.err = jpeg_std_error(&jerr);
  404. jpeg_create_decompress(&cinfo);
  405. jpeg_stdio_src(&cinfo, pFile);
  406. jpeg_read_header(&cinfo, FALSE);
  407. // this statement is important also to read
  408. // image width and height
  409. jpeg_start_decompress(&cinfo);
  410. fileheader.width = cinfo.output_width;
  411. fileheader.height = cinfo.output_height;
  412. fileheader.channel = cinfo.out_color_components;
  413. fileheader.bitdepth = cinfo.num_components;
  414. fclose(pFile);
  415. }
  416. #endif
  417. } // namespace NICE
  418. /*****************************************************************************/
  419. /*
  420. * $Log: ImageFile.cpp,v $
  421. * Revision 1.7 2010/06/04 08:53:52 rodner
  422. * - bugfixes
  423. *
  424. * Revision 1.6 2009/11/30 12:25:50 rodner
  425. * - ImageMagick warning / error issue
  426. * - indent problem in SimpleSelector
  427. *
  428. * Revision 1.5 2009/07/22 12:12:01 rodner
  429. * - added ImageMagick functionality
  430. *
  431. * Revision 1.4 2009/06/10 08:06:34 rodner
  432. * - getHeader support for png/jpg without system("identify ..");
  433. *
  434. * Revision 1.3 2009/06/09 14:02:32 rodner
  435. * - bugfix: rect .cpp -> .tcc
  436. *
  437. * Revision 1.2 2009/05/28 11:36:30 bajramov
  438. * renamed a few things for consistency
  439. *
  440. * Revision 1.1.1.1 2007/05/22 19:26:35 bajramov
  441. * limun2
  442. *
  443. * Revision 1.16 2006/10/23 11:30:40 zimmermann
  444. * * more general jpg io
  445. *
  446. * Revision 1.15 2006/10/20 17:14:04 zimmermann
  447. * * improved jpg io / test
  448. *
  449. * Revision 1.14 2006/10/06 13:21:39 mattern
  450. * .
  451. *
  452. * Revision 1.13 2006/08/22 15:59:32 zimmermann
  453. * * added required #ifdef NICE_USELIB_PNG
  454. *
  455. * Revision 1.12 2006/08/21 15:55:28 mattern
  456. * - is gray implemented
  457. *
  458. * Revision 1.11 2006/08/21 14:01:33 zimmermann
  459. * *fixed some errors
  460. *
  461. * Revision 1.10 2006/07/13 12:50:09 mattern
  462. * - small fixes
  463. *
  464. * Revision 1.9 2006/07/13 11:53:51 mattern
  465. * - large bug fixes
  466. *
  467. * Revision 1.8 2006/05/24 13:03:43 mattern
  468. * - jpg bugfix
  469. * - unsigned signed errors fixed
  470. *
  471. * Revision 1.7 2006/05/22 16:13:24 zimmermann
  472. * * added jpeg io to ColorImage/Image/ImageFile
  473. *
  474. * Revision 1.6 2006/04/01 14:41:43 mattern
  475. * - new copy mode
  476. *
  477. * Revision 1.5 2006/03/31 22:26:35 mattern
  478. * *** empty log message ***
  479. *
  480. * Revision 1.4 2006/03/27 19:06:56 mattern
  481. * .
  482. *
  483. * Revision 1.3 2006/03/26 01:48:05 mattern
  484. * .
  485. *
  486. * Revision 1.2 2006/03/02 14:54:54 mattern
  487. * - documenation improved
  488. *
  489. * Revision 1.1 2006/03/02 14:50:33 mattern
  490. * - ImageFile added
  491. * - more template methods
  492. * - ippwrapper improved
  493. * - png support
  494. *
  495. * Revision 1.2 2006/02/09 09:39:14 mattern
  496. * * template update
  497. *
  498. * Revision 1.3 2006/02/02 10:50:12 mattern
  499. * * Template changed
  500. *
  501. * Revision 1.2 2005/07/28 09:56:34 bajramov
  502. * License
  503. *
  504. * Revision 1.1.1.1 2005/07/22 13:53:17 mattern
  505. * Librarys for IMage UNderstanding
  506. *
  507. */