device.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. //
  2. // Copyright 2007-2012 Christian Henning, Andreas Pokorny
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. #ifndef BOOST_GIL_IO_DEVICE_HPP
  9. #define BOOST_GIL_IO_DEVICE_HPP
  10. #include <boost/gil/io/base.hpp>
  11. #include <boost/assert.hpp>
  12. #include <boost/core/ignore_unused.hpp>
  13. #include <cstdio>
  14. #include <memory>
  15. #include <type_traits>
  16. namespace boost { namespace gil {
  17. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  18. #pragma warning(push)
  19. #pragma warning(disable:4512) //assignment operator could not be generated
  20. #endif
  21. namespace detail {
  22. template < typename T > struct buff_item
  23. {
  24. static const unsigned int size = sizeof( T );
  25. };
  26. template <> struct buff_item< void >
  27. {
  28. static const unsigned int size = 1;
  29. };
  30. /*!
  31. * Implements the IODevice concept c.f. to \ref IODevice required by Image libraries like
  32. * libjpeg and libpng.
  33. *
  34. * \todo switch to a sane interface as soon as there is
  35. * something good in boost. I.E. the IOChains library
  36. * would fit very well here.
  37. *
  38. * This implementation is based on FILE*.
  39. */
  40. template< typename FormatTag >
  41. class file_stream_device
  42. {
  43. public:
  44. using format_tag_t = FormatTag;
  45. public:
  46. /// Used to overload the constructor.
  47. struct read_tag {};
  48. struct write_tag {};
  49. ///
  50. /// Constructor
  51. ///
  52. file_stream_device( const std::string& file_name
  53. , read_tag = read_tag()
  54. )
  55. {
  56. FILE* file = nullptr;
  57. io_error_if( ( file = fopen( file_name.c_str(), "rb" )) == nullptr
  58. , "file_stream_device: failed to open file"
  59. );
  60. _file = file_ptr_t( file
  61. , file_deleter
  62. );
  63. }
  64. ///
  65. /// Constructor
  66. ///
  67. file_stream_device( const char* file_name
  68. , read_tag = read_tag()
  69. )
  70. {
  71. FILE* file = nullptr;
  72. io_error_if( ( file = fopen( file_name, "rb" )) == nullptr
  73. , "file_stream_device: failed to open file"
  74. );
  75. _file = file_ptr_t( file
  76. , file_deleter
  77. );
  78. }
  79. ///
  80. /// Constructor
  81. ///
  82. file_stream_device( const std::string& file_name
  83. , write_tag
  84. )
  85. {
  86. FILE* file = nullptr;
  87. io_error_if( ( file = fopen( file_name.c_str(), "wb" )) == nullptr
  88. , "file_stream_device: failed to open file"
  89. );
  90. _file = file_ptr_t( file
  91. , file_deleter
  92. );
  93. }
  94. ///
  95. /// Constructor
  96. ///
  97. file_stream_device( const char* file_name
  98. , write_tag
  99. )
  100. {
  101. FILE* file = nullptr;
  102. io_error_if( ( file = fopen( file_name, "wb" )) == nullptr
  103. , "file_stream_device: failed to open file"
  104. );
  105. _file = file_ptr_t( file
  106. , file_deleter
  107. );
  108. }
  109. ///
  110. /// Constructor
  111. ///
  112. file_stream_device( FILE* file )
  113. : _file( file
  114. , file_deleter
  115. )
  116. {}
  117. FILE* get() { return _file.get(); }
  118. const FILE* get() const { return _file.get(); }
  119. int getc_unchecked()
  120. {
  121. return std::getc( get() );
  122. }
  123. char getc()
  124. {
  125. int ch;
  126. if(( ch = std::getc( get() )) == EOF )
  127. io_error( "file_stream_device: unexpected EOF" );
  128. return ( char ) ch;
  129. }
  130. ///@todo: change byte_t* to void*
  131. std::size_t read( byte_t* data
  132. , std::size_t count
  133. )
  134. {
  135. std::size_t num_elements = fread( data
  136. , 1
  137. , static_cast<int>( count )
  138. , get()
  139. );
  140. ///@todo: add compiler symbol to turn error checking on and off.
  141. if(ferror( get() ))
  142. {
  143. BOOST_ASSERT(false);
  144. }
  145. //libjpeg sometimes reads blocks in 4096 bytes even when the file is smaller than that.
  146. //assert( num_elements == count );
  147. BOOST_ASSERT(num_elements > 0 );
  148. return num_elements;
  149. }
  150. /// Reads array
  151. template< typename T
  152. , int N
  153. >
  154. std::size_t read( T (&buf)[N] )
  155. {
  156. return read( buf, N );
  157. }
  158. /// Reads byte
  159. uint8_t read_uint8() throw()
  160. {
  161. byte_t m[1];
  162. read( m );
  163. return m[0];
  164. }
  165. /// Reads 16 bit little endian integer
  166. uint16_t read_uint16() throw()
  167. {
  168. byte_t m[2];
  169. read( m );
  170. return (m[1] << 8) | m[0];
  171. }
  172. /// Reads 32 bit little endian integer
  173. uint32_t read_uint32() throw()
  174. {
  175. byte_t m[4];
  176. read( m );
  177. return (m[3] << 24) | (m[2] << 16) | (m[1] << 8) | m[0];
  178. }
  179. /// Writes number of elements from a buffer
  180. template < typename T >
  181. std::size_t write( const T* buf
  182. , std::size_t count
  183. )
  184. throw()
  185. {
  186. std::size_t num_elements = fwrite( buf
  187. , buff_item<T>::size
  188. , count
  189. , get()
  190. );
  191. BOOST_ASSERT(num_elements == count);
  192. return num_elements;
  193. }
  194. /// Writes array
  195. template < typename T
  196. , std::size_t N
  197. >
  198. std::size_t write( const T (&buf)[N] ) throw()
  199. {
  200. return write( buf, N );
  201. }
  202. /// Writes byte
  203. void write_uint8( uint8_t x ) throw()
  204. {
  205. byte_t m[1] = { x };
  206. write(m);
  207. }
  208. /// Writes 16 bit little endian integer
  209. void write_uint16( uint16_t x ) throw()
  210. {
  211. byte_t m[2];
  212. m[0] = byte_t( x >> 0 );
  213. m[1] = byte_t( x >> 8 );
  214. write( m );
  215. }
  216. /// Writes 32 bit little endian integer
  217. void write_uint32( uint32_t x ) throw()
  218. {
  219. byte_t m[4];
  220. m[0] = byte_t( x >> 0 );
  221. m[1] = byte_t( x >> 8 );
  222. m[2] = byte_t( x >> 16 );
  223. m[3] = byte_t( x >> 24 );
  224. write( m );
  225. }
  226. void seek( long count, int whence = SEEK_SET )
  227. {
  228. io_error_if( fseek( get()
  229. , count
  230. , whence
  231. ) != 0
  232. , "file read error"
  233. );
  234. }
  235. long int tell()
  236. {
  237. long int pos = ftell( get() );
  238. io_error_if( pos == -1L
  239. , "file read error"
  240. );
  241. return pos;
  242. }
  243. void flush()
  244. {
  245. fflush( get() );
  246. }
  247. /// Prints formatted ASCII text
  248. void print_line( const std::string& line )
  249. {
  250. std::size_t num_elements = fwrite( line.c_str()
  251. , sizeof( char )
  252. , line.size()
  253. , get()
  254. );
  255. BOOST_ASSERT(num_elements == line.size());
  256. boost::ignore_unused(num_elements);
  257. }
  258. int error()
  259. {
  260. return ferror( get() );
  261. }
  262. private:
  263. static void file_deleter( FILE* file )
  264. {
  265. if( file )
  266. {
  267. fclose( file );
  268. }
  269. }
  270. private:
  271. using file_ptr_t = std::shared_ptr<FILE> ;
  272. file_ptr_t _file;
  273. };
  274. /**
  275. * Input stream device
  276. */
  277. template< typename FormatTag >
  278. class istream_device
  279. {
  280. public:
  281. istream_device( std::istream& in )
  282. : _in( in )
  283. {
  284. if (!in)
  285. {
  286. // does the file exists?
  287. io_error("Stream is not valid.");
  288. }
  289. }
  290. int getc_unchecked()
  291. {
  292. return _in.get();
  293. }
  294. char getc()
  295. {
  296. int ch;
  297. if(( ch = _in.get() ) == EOF )
  298. io_error( "file_stream_device: unexpected EOF" );
  299. return ( char ) ch;
  300. }
  301. std::size_t read( byte_t* data
  302. , std::size_t count )
  303. {
  304. std::streamsize cr = 0;
  305. do
  306. {
  307. _in.peek();
  308. std::streamsize c = _in.readsome( reinterpret_cast< char* >( data )
  309. , static_cast< std::streamsize >( count ));
  310. count -= static_cast< std::size_t >( c );
  311. data += c;
  312. cr += c;
  313. } while( count && _in );
  314. return static_cast< std::size_t >( cr );
  315. }
  316. /// Reads array
  317. template< typename T
  318. , int N
  319. >
  320. size_t read( T (&buf)[N] )
  321. {
  322. return read( buf, N );
  323. }
  324. /// Reads byte
  325. uint8_t read_uint8() throw()
  326. {
  327. byte_t m[1];
  328. read( m );
  329. return m[0];
  330. }
  331. /// Reads 16 bit little endian integer
  332. uint16_t read_uint16() throw()
  333. {
  334. byte_t m[2];
  335. read( m );
  336. return (m[1] << 8) | m[0];
  337. }
  338. /// Reads 32 bit little endian integer
  339. uint32_t read_uint32() throw()
  340. {
  341. byte_t m[4];
  342. read( m );
  343. return (m[3] << 24) | (m[2] << 16) | (m[1] << 8) | m[0];
  344. }
  345. void seek( long count, int whence = SEEK_SET )
  346. {
  347. _in.seekg( count
  348. , whence == SEEK_SET ? std::ios::beg
  349. :( whence == SEEK_CUR ? std::ios::cur
  350. : std::ios::end )
  351. );
  352. }
  353. void write(const byte_t*, std::size_t)
  354. {
  355. io_error( "Bad io error." );
  356. }
  357. void flush() {}
  358. private:
  359. std::istream& _in;
  360. };
  361. /**
  362. * Output stream device
  363. */
  364. template< typename FormatTag >
  365. class ostream_device
  366. {
  367. public:
  368. ostream_device( std::ostream & out )
  369. : _out( out )
  370. {
  371. }
  372. std::size_t read(byte_t *, std::size_t)
  373. {
  374. io_error( "Bad io error." );
  375. return 0;
  376. }
  377. void seek( long count, int whence )
  378. {
  379. _out.seekp( count
  380. , whence == SEEK_SET
  381. ? std::ios::beg
  382. : ( whence == SEEK_CUR
  383. ?std::ios::cur
  384. :std::ios::end )
  385. );
  386. }
  387. void write( const byte_t* data
  388. , std::size_t count )
  389. {
  390. _out.write( reinterpret_cast<char const*>( data )
  391. , static_cast<std::streamsize>( count )
  392. );
  393. }
  394. /// Writes array
  395. template < typename T
  396. , std::size_t N
  397. >
  398. void write( const T (&buf)[N] ) throw()
  399. {
  400. write( buf, N );
  401. }
  402. /// Writes byte
  403. void write_uint8( uint8_t x ) throw()
  404. {
  405. byte_t m[1] = { x };
  406. write(m);
  407. }
  408. /// Writes 16 bit little endian integer
  409. void write_uint16( uint16_t x ) throw()
  410. {
  411. byte_t m[2];
  412. m[0] = byte_t( x >> 0 );
  413. m[1] = byte_t( x >> 8 );
  414. write( m );
  415. }
  416. /// Writes 32 bit little endian integer
  417. void write_uint32( uint32_t x ) throw()
  418. {
  419. byte_t m[4];
  420. m[0] = byte_t( x >> 0 );
  421. m[1] = byte_t( x >> 8 );
  422. m[2] = byte_t( x >> 16 );
  423. m[3] = byte_t( x >> 24 );
  424. write( m );
  425. }
  426. void flush()
  427. {
  428. _out << std::flush;
  429. }
  430. /// Prints formatted ASCII text
  431. void print_line( const std::string& line )
  432. {
  433. _out << line;
  434. }
  435. private:
  436. std::ostream& _out;
  437. };
  438. /**
  439. * Metafunction to detect input devices.
  440. * Should be replaced by an external facility in the future.
  441. */
  442. template< typename IODevice > struct is_input_device : mpl::false_{};
  443. template< typename FormatTag > struct is_input_device< file_stream_device< FormatTag > > : mpl::true_{};
  444. template< typename FormatTag > struct is_input_device< istream_device< FormatTag > > : mpl::true_{};
  445. template< typename FormatTag
  446. , typename T
  447. , typename D = void
  448. >
  449. struct is_adaptable_input_device : mpl::false_{};
  450. template <typename FormatTag, typename T>
  451. struct is_adaptable_input_device
  452. <
  453. FormatTag,
  454. T,
  455. typename std::enable_if
  456. <
  457. mpl::or_
  458. <
  459. is_base_and_derived<std::istream, T>,
  460. is_same<std::istream, T>
  461. >::value
  462. >::type
  463. > : mpl::true_
  464. {
  465. using device_type = istream_device<FormatTag>;
  466. };
  467. template< typename FormatTag >
  468. struct is_adaptable_input_device< FormatTag
  469. , FILE*
  470. , void
  471. >
  472. : mpl::true_
  473. {
  474. using device_type = file_stream_device<FormatTag>;
  475. };
  476. ///
  477. /// Metafunction to decide if a given type is an acceptable read device type.
  478. ///
  479. template< typename FormatTag
  480. , typename T
  481. , typename D = void
  482. >
  483. struct is_read_device : mpl::false_
  484. {};
  485. template <typename FormatTag, typename T>
  486. struct is_read_device
  487. <
  488. FormatTag,
  489. T,
  490. typename std::enable_if
  491. <
  492. mpl::or_
  493. <
  494. is_input_device<FormatTag>,
  495. is_adaptable_input_device<FormatTag, T>
  496. >::value
  497. >::type
  498. > : mpl::true_
  499. {
  500. };
  501. /**
  502. * Metafunction to detect output devices.
  503. * Should be replaced by an external facility in the future.
  504. */
  505. template<typename IODevice> struct is_output_device : mpl::false_{};
  506. template< typename FormatTag > struct is_output_device< file_stream_device< FormatTag > > : mpl::true_{};
  507. template< typename FormatTag > struct is_output_device< ostream_device < FormatTag > > : mpl::true_{};
  508. template< typename FormatTag
  509. , typename IODevice
  510. , typename D = void
  511. >
  512. struct is_adaptable_output_device : mpl::false_ {};
  513. template <typename FormatTag, typename T>
  514. struct is_adaptable_output_device
  515. <
  516. FormatTag,
  517. T,
  518. typename std::enable_if
  519. <
  520. mpl::or_
  521. <
  522. is_base_and_derived<std::ostream, T>,
  523. is_same<std::ostream, T>
  524. >::value
  525. >::type
  526. > : mpl::true_
  527. {
  528. using device_type = ostream_device<FormatTag>;
  529. };
  530. template<typename FormatTag> struct is_adaptable_output_device<FormatTag,FILE*,void>
  531. : mpl::true_
  532. {
  533. using device_type = file_stream_device<FormatTag>;
  534. };
  535. ///
  536. /// Metafunction to decide if a given type is an acceptable read device type.
  537. ///
  538. template< typename FormatTag
  539. , typename T
  540. , typename D = void
  541. >
  542. struct is_write_device : mpl::false_
  543. {};
  544. template <typename FormatTag, typename T>
  545. struct is_write_device
  546. <
  547. FormatTag,
  548. T,
  549. typename std::enable_if
  550. <
  551. mpl::or_
  552. <
  553. is_output_device<FormatTag>,
  554. is_adaptable_output_device<FormatTag, T>
  555. >::value
  556. >::type
  557. > : mpl::true_
  558. {
  559. };
  560. } // namespace detail
  561. template< typename Device, typename FormatTag > class scanline_reader;
  562. template< typename Device, typename FormatTag, typename ConversionPolicy > class reader;
  563. template< typename Device, typename FormatTag, typename Log = no_log > class writer;
  564. template< typename Device, typename FormatTag > class dynamic_image_reader;
  565. template< typename Device, typename FormatTag, typename Log = no_log > class dynamic_image_writer;
  566. namespace detail {
  567. template< typename T >
  568. struct is_reader : mpl::false_
  569. {};
  570. template< typename Device
  571. , typename FormatTag
  572. , typename ConversionPolicy
  573. >
  574. struct is_reader< reader< Device
  575. , FormatTag
  576. , ConversionPolicy
  577. >
  578. > : mpl::true_
  579. {};
  580. template< typename T >
  581. struct is_dynamic_image_reader : mpl::false_
  582. {};
  583. template< typename Device
  584. , typename FormatTag
  585. >
  586. struct is_dynamic_image_reader< dynamic_image_reader< Device
  587. , FormatTag
  588. >
  589. > : mpl::true_
  590. {};
  591. template< typename T >
  592. struct is_writer : mpl::false_
  593. {};
  594. template< typename Device
  595. , typename FormatTag
  596. >
  597. struct is_writer< writer< Device
  598. , FormatTag
  599. >
  600. > : mpl::true_
  601. {};
  602. template< typename T >
  603. struct is_dynamic_image_writer : mpl::false_
  604. {};
  605. template< typename Device
  606. , typename FormatTag
  607. >
  608. struct is_dynamic_image_writer< dynamic_image_writer< Device
  609. , FormatTag
  610. >
  611. > : mpl::true_
  612. {};
  613. } // namespace detail
  614. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  615. #pragma warning(pop)
  616. #endif
  617. } // namespace gil
  618. } // namespace boost
  619. #endif