00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #ifndef PNGPP_CONSUMER_HPP_INCLUDED
00032 #define PNGPP_CONSUMER_HPP_INCLUDED
00033
00034 #include <cassert>
00035 #include <stdexcept>
00036 #include <iostream>
00037 #include <istream>
00038
00039 #include <endian.h>
00040
00041 #include "error.hpp"
00042 #include "streaming_base.hpp"
00043 #include "reader.hpp"
00044 #include "pixel_buffer.hpp"
00045
00046 namespace png
00047 {
00048
00122 template< typename pixel,
00123 class pixcon,
00124 class info_holder = def_image_info_holder,
00125 bool interlacing_supported = false >
00126 class consumer
00127 : public streaming_base< pixel, info_holder >
00128 {
00129 public:
00130 typedef pixel_traits< pixel > traits;
00131
00135 struct transform_identity
00136 {
00137 void operator()(io_base&) const {}
00138 };
00139
00144 template< typename istream >
00145 void read(istream& stream)
00146 {
00147 read(stream, transform_identity());
00148 }
00149
00158 template< typename istream, class transformation >
00159 void read(istream& stream, transformation const& transform)
00160 {
00161 reader< istream > rd(stream);
00162 rd.read_info();
00163 transform(rd);
00164
00165 #if __BYTE_ORDER == __LITTLE_ENDIAN
00166 if (pixel_traits< pixel >::get_bit_depth() == 16)
00167 {
00168 #ifdef PNG_READ_SWAP_SUPPORTED
00169 rd.set_swap();
00170 #else
00171 throw error("Cannot read 16-bit image --"
00172 " recompile with PNG_READ_SWAP_SUPPORTED.");
00173 #endif
00174 }
00175 #endif
00176
00177
00178 size_t pass_count;
00179 if (rd.get_interlace_type() != interlace_none)
00180 {
00181 #ifdef PNG_READ_INTERLACING_SUPPORTED
00182 pass_count = rd.set_interlace_handling();
00183 #else
00184 throw error("Cannot read interlaced image --"
00185 " interlace handling disabled.");
00186 #endif
00187 }
00188 else
00189 {
00190 pass_count = 1;
00191 }
00192
00193 rd.update_info();
00194 if (rd.get_color_type() != traits::get_color_type()
00195 || rd.get_bit_depth() != traits::get_bit_depth())
00196 {
00197 throw std::logic_error("color type and/or bit depth mismatch"
00198 " in png::consumer::read()");
00199 }
00200
00201 this->get_info() = rd.get_image_info();
00202
00203 pixcon* pixel_con = static_cast< pixcon* >(this);
00204 if (pass_count > 1 && !interlacing_supported)
00205 {
00206 skip_interlaced_rows(rd, pass_count);
00207 pass_count = 1;
00208 }
00209 read_rows(rd, pass_count, pixel_con);
00210
00211 rd.read_end_info();
00212 }
00213
00214 protected:
00215 typedef streaming_base< pixel, info_holder > base;
00216
00221 explicit consumer(image_info& info)
00222 : base(info)
00223 {
00224 }
00225
00226 private:
00227 template< typename istream >
00228 void skip_interlaced_rows(reader< istream >& rd, size_t pass_count)
00229 {
00230 typedef std::vector< pixel > row;
00231 typedef row_traits< row > row_traits_type;
00232 row dummy_row(this->get_info().get_width());
00233 for (size_t pass = 1; pass < pass_count; ++pass)
00234 {
00235 rd.read_row(reinterpret_cast< byte* >
00236 (row_traits_type::get_data(dummy_row)));
00237 }
00238 }
00239
00240 template< typename istream >
00241 void read_rows(reader< istream >& rd, size_t pass_count,
00242 pixcon* pixel_con)
00243 {
00244 for (size_t pass = 0; pass < pass_count; ++pass)
00245 {
00246 pixel_con->reset(pass);
00247
00248 for (size_t pos = 0; pos < this->get_info().get_height(); ++pos)
00249 {
00250 rd.read_row(pixel_con->get_next_row(pos));
00251 }
00252 }
00253 }
00254 };
00255
00256 }
00257
00258 #endif // PNGPP_CONSUMER_HPP_INCLUDED