device.hpp 16 KB

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