jpeg_io_private.hpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. Copyright 2005-2007 Adobe Systems Incorporated
  3. Use, modification and distribution are subject to the Boost Software License,
  4. Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. http://www.boost.org/LICENSE_1_0.txt).
  6. See http://opensource.adobe.com/gil for most recent version including documentation.
  7. */
  8. /*************************************************************************************************/
  9. #ifndef GIL_JPEG_IO_PRIVATE_H
  10. #define GIL_JPEG_IO_PRIVATE_H
  11. /// \file
  12. /// \brief Internal support for reading and writing JPEG files
  13. /// \author Hailin Jin and Lubomir Bourdev \n
  14. /// Adobe Systems Incorporated
  15. /// \date 2005-2007 \n Last updated September 24, 2006
  16. #include <stdio.h>
  17. #include <boost/static_assert.hpp>
  18. #include <vector>
  19. #include "../../gil_all.hpp"
  20. #include "io_error.hpp"
  21. #include <jpeglib.h>
  22. namespace boost { namespace gil {
  23. namespace detail {
  24. // lbourdev: What is the advantage of having channel and colorspace together? Are there cases where they are interrelated?
  25. template <typename Channel,typename ColorSpace>
  26. struct jpeg_read_support_private {
  27. BOOST_STATIC_CONSTANT(bool,is_supported=false);
  28. BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_UNKNOWN);
  29. };
  30. template <>
  31. struct jpeg_read_support_private<bits8,gray_t> {
  32. BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
  33. BOOST_STATIC_CONSTANT(bool,is_supported=true);
  34. BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_GRAYSCALE);
  35. };
  36. template <>
  37. struct jpeg_read_support_private<bits8,rgb_t> {
  38. BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
  39. BOOST_STATIC_CONSTANT(bool,is_supported=true);
  40. BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_RGB);
  41. };
  42. template <>
  43. struct jpeg_read_support_private<bits8,cmyk_t> {
  44. BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
  45. BOOST_STATIC_CONSTANT(bool,is_supported=true);
  46. BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_CMYK);
  47. };
  48. template <typename Channel,typename ColorSpace>
  49. struct jpeg_write_support_private {
  50. BOOST_STATIC_CONSTANT(bool,is_supported=false);
  51. BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_UNKNOWN);
  52. };
  53. template <>
  54. struct jpeg_write_support_private<bits8,gray_t> {
  55. BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
  56. BOOST_STATIC_CONSTANT(bool,is_supported=true);
  57. BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_GRAYSCALE);
  58. };
  59. template <>
  60. struct jpeg_write_support_private<bits8,rgb_t> {
  61. BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
  62. BOOST_STATIC_CONSTANT(bool,is_supported=true);
  63. BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_RGB);
  64. };
  65. template <>
  66. struct jpeg_write_support_private<bits8,cmyk_t> {
  67. BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8);
  68. BOOST_STATIC_CONSTANT(bool,is_supported=true);
  69. BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_CMYK);
  70. };
  71. class jpeg_reader : public file_mgr {
  72. protected:
  73. jpeg_decompress_struct _cinfo;
  74. jpeg_error_mgr _jerr;
  75. void init() {
  76. _cinfo.err=jpeg_std_error(&_jerr);
  77. jpeg_create_decompress(&_cinfo);
  78. jpeg_stdio_src(&_cinfo,_fp.get());
  79. jpeg_read_header(&_cinfo,TRUE);
  80. }
  81. public:
  82. jpeg_reader(FILE* file) : file_mgr(file) { init(); }
  83. jpeg_reader(const char* filename) : file_mgr(filename, "rb") { init(); }
  84. ~jpeg_reader() { jpeg_destroy_decompress(&_cinfo); }
  85. template <typename View>
  86. void apply(const View& view) {
  87. jpeg_start_decompress(&_cinfo); // lbourdev: Can this return an error? You need to check and throw. Check all other library methods that can return an error state...
  88. io_error_if(_cinfo.data_precision!=8,"jpeg_reader::apply(): this image file is not supported");
  89. io_error_if(_cinfo.out_color_space!=jpeg_read_support_private<typename channel_type<View>::type,
  90. typename color_space_type<View>::type>::color_type,
  91. "jpeg_reader::apply(): input view type does not match the image file");
  92. io_error_if(view.dimensions() != get_dimensions(), "jpeg_reader::apply(): input view dimensions do not match the image file");
  93. std::vector<pixel<bits8,layout<typename color_space_type<View>::type> > > row(view.width());
  94. JSAMPLE* row_address=(JSAMPLE*)&row.front();
  95. for(int y=0;y<view.height();++y) {
  96. io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1,
  97. "jpeg_reader::apply(): fail to read JPEG file");
  98. std::copy(row.begin(),row.end(),view.row_begin(y));
  99. }
  100. jpeg_finish_decompress(&_cinfo);
  101. }
  102. template <typename Image>
  103. void read_image(Image& im) {
  104. im.recreate(get_dimensions());
  105. apply(view(im));
  106. }
  107. point2<std::ptrdiff_t> get_dimensions() const {
  108. return point2<std::ptrdiff_t>(_cinfo.image_width,_cinfo.image_height);
  109. }
  110. };
  111. // This code will be simplified...
  112. template <typename CC>
  113. class jpeg_reader_color_convert : public jpeg_reader {
  114. private:
  115. CC _cc;
  116. public:
  117. jpeg_reader_color_convert(FILE* file,CC cc_in) : jpeg_reader(file),_cc(cc_in) {}
  118. jpeg_reader_color_convert(FILE* file) : jpeg_reader(file) {}
  119. jpeg_reader_color_convert(const char* filename,CC cc_in) : jpeg_reader(filename),_cc(cc_in) {}
  120. jpeg_reader_color_convert(const char* filename) : jpeg_reader(filename) {}
  121. template <typename View>
  122. void apply(const View& view) {
  123. jpeg_start_decompress(&_cinfo); // lbourdev: Can this return an error? You need to check and throw. Check all other library methods that can return an error state...
  124. io_error_if(_cinfo.data_precision!=8,"jpeg_reader_color_covert::apply(): this image file is not supported");
  125. io_error_if(view.dimensions() != get_dimensions(), "jpeg_reader_color_covert::apply(): input view dimensions don't match the image file");
  126. switch (_cinfo.out_color_space) {
  127. case JCS_GRAYSCALE: {
  128. std::vector<gray8_pixel_t> row(view.width());
  129. JSAMPLE* row_address=(JSAMPLE*)&row.front();
  130. for(int y=0;y<view.height();++y) {
  131. io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1,
  132. "jpeg_reader_color_covert::apply(): fail to read JPEG file");
  133. std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<gray8_ref_t, typename View::value_type,CC>(_cc));
  134. }
  135. break;
  136. }
  137. case JCS_RGB: {
  138. std::vector<rgb8_pixel_t> row(view.width());
  139. JSAMPLE* row_address=(JSAMPLE*)&row.front();
  140. for(int y=0;y<view.height();++y) {
  141. io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1,
  142. "jpeg_reader_color_covert::apply(): fail to read JPEG file");
  143. std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<rgb8_ref_t, typename View::value_type,CC>(_cc));
  144. }
  145. break;
  146. }
  147. case JCS_CMYK: {
  148. std::vector<cmyk8_pixel_t> row(view.width());
  149. JSAMPLE* row_address=(JSAMPLE*)&row.front();
  150. for(int y=0;y<view.height();++y) {
  151. io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1,
  152. "jpeg_reader_color_covert::apply(): fail to read JPEG file");
  153. std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<cmyk8_ref_t, typename View::value_type,CC>(_cc));
  154. }
  155. break;
  156. }
  157. default:
  158. io_error("jpeg_reader_color_covert::apply(): unknown color type");
  159. }
  160. jpeg_finish_decompress(&_cinfo);
  161. }
  162. template <typename Image>
  163. void read_image(Image& im) {
  164. im.recreate(get_dimensions());
  165. apply(view(im));
  166. }
  167. };
  168. class jpeg_writer : public file_mgr {
  169. jpeg_compress_struct _cinfo;
  170. jpeg_error_mgr _jerr;
  171. void init() {
  172. _cinfo.err=jpeg_std_error(&_jerr);
  173. jpeg_create_compress(&_cinfo);
  174. jpeg_stdio_dest(&_cinfo,_fp.get());
  175. }
  176. public:
  177. jpeg_writer(FILE* file) : file_mgr(file) { init(); }
  178. jpeg_writer(const char* filename) : file_mgr(filename, "wb") { init(); }
  179. ~jpeg_writer() { jpeg_destroy_compress(&_cinfo); }
  180. template <typename View>
  181. void apply(const View& view,int quality=100) {
  182. _cinfo.image_width = (JDIMENSION)view.width();
  183. _cinfo.image_height = (JDIMENSION)view.height();
  184. _cinfo.input_components=num_channels<View>::value;
  185. _cinfo.in_color_space = jpeg_write_support_private<typename channel_type<View>::type,
  186. typename color_space_type<View>::type>::color_type;
  187. jpeg_set_defaults(&_cinfo);
  188. jpeg_set_quality(&_cinfo, quality, TRUE);
  189. jpeg_start_compress(&_cinfo, TRUE);
  190. std::vector<pixel<bits8,layout<typename color_space_type<View>::type> > > row(view.width());
  191. JSAMPLE* row_address=(JSAMPLE*)&row.front();
  192. for (int y=0;y<view.height(); ++y) {
  193. std::copy(view.row_begin(y),view.row_end(y),row.begin());
  194. io_error_if(jpeg_write_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1) != 1,
  195. "jpeg_writer::apply(): fail to write file");
  196. }
  197. jpeg_finish_compress(&_cinfo);
  198. }
  199. };
  200. } // namespace detail
  201. } } // namespace boost::gil
  202. #endif