diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index a62c42e24..1085943a7 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -26,6 +26,10 @@ // boost #include #include +// iostreams +#include +#include +#include extern "C" { @@ -35,12 +39,75 @@ extern "C" namespace mapnik { -using std::min; -using std::max; +namespace impl { +static toff_t tiff_seek_proc(thandle_t fd, toff_t off, int whence) +{ + std::istream* in = reinterpret_cast(fd); + + switch(whence) + { + case SEEK_SET: + in->seekg(off, std::ios_base::beg); + break; + case SEEK_CUR: + in->seekg(off, std::ios_base::cur); + break; + case SEEK_END: + in->seekg(off, std::ios_base::end); + break; + } + return static_cast(in->tellg()); +} + +static int tiff_close_proc(thandle_t fd) +{ + return 0; +} + +static toff_t tiff_size_proc(thandle_t fd) +{ + std::istream* in = reinterpret_cast(fd); + std::ios::pos_type pos = in->tellg(); + in->seekg(0, std::ios::end); + std::ios::pos_type len = in->tellg(); + in->seekg(pos); + return static_cast(len); +} + +static tsize_t tiff_read_proc(thandle_t fd, tdata_t buf, tsize_t size) +{ + std::istream * in = reinterpret_cast(fd); + std::streamsize request_size = size; + if (static_cast(request_size) != size) + return static_cast(-1); + in->read(reinterpret_cast(buf), request_size); + return static_cast(in->gcount()); +} + +static tsize_t tiff_write_proc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return 0; +} + +static void tiff_unmap_proc(thandle_t fd, tdata_t base, toff_t size) +{ +} + +static int tiff_map_proc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + return 0; +} + +} + +template class tiff_reader : public image_reader { typedef boost::shared_ptr tiff_ptr; + typedef T source_type; + typedef boost::iostreams::stream input_stream; + struct tiff_closer { void operator() (TIFF * tif) @@ -53,10 +120,11 @@ class tiff_reader : public image_reader }; private: - std::string file_name_; + source_type source_; + input_stream stream_; int read_method_; - unsigned width_; - unsigned height_; + std::size_t width_; + std::size_t height_; int rows_per_strip_; int tile_width_; int tile_height_; @@ -69,6 +137,7 @@ public: tiled }; explicit tiff_reader(std::string const& file_name); + tiff_reader(char const* data, std::size_t size); virtual ~tiff_reader(); unsigned width() const; unsigned height() const; @@ -81,22 +150,32 @@ private: void read_generic(unsigned x,unsigned y,image_data_32& image); void read_stripped(unsigned x,unsigned y,image_data_32& image); void read_tiled(unsigned x,unsigned y,image_data_32& image); - TIFF* load_if_exists(std::string const& filename); + TIFF* open(std::istream & input); static void on_error(const char* /*module*/, const char* fmt, va_list argptr); }; namespace { + image_reader* create_tiff_reader(std::string const& file) { - return new tiff_reader(file); + return new tiff_reader(file); +} + +image_reader* create_tiff_reader2(char const * data, std::size_t size) +{ + return new tiff_reader(data, size); } const bool registered = register_image_reader("tiff",create_tiff_reader); +const bool registered2 = register_image_reader("tiff", create_tiff_reader2); + } -tiff_reader::tiff_reader(std::string const& file_name) - : file_name_(file_name), +template +tiff_reader::tiff_reader(std::string const& file_name) + : source_(file_name, std::ios_base::in | std::ios_base::binary), + stream_(source_), read_method_(generic), width_(0), height_(0), @@ -105,25 +184,48 @@ tiff_reader::tiff_reader(std::string const& file_name) tile_height_(0), premultiplied_alpha_(false) { + if (!stream_) throw image_reader_exception("TIFF reader: cannot open file "+ file_name); init(); } -void tiff_reader::on_error(const char* /*module*/, const char* fmt, va_list argptr) +template +tiff_reader::tiff_reader(char const* data, std::size_t size) + : source_(data, size), + stream_(source_), + read_method_(generic), + width_(0), + height_(0), + rows_per_strip_(0), + tile_width_(0), + tile_height_(0), + premultiplied_alpha_(false) +{ + if (!stream_) throw image_reader_exception("TIFF reader: cannot open image stream "); + stream_.seekg(0, std::ios::beg); + init(); +} + +template +void tiff_reader::on_error(const char* /*module*/, const char* fmt, va_list argptr) { char msg[10240]; vsprintf(msg, fmt, argptr); throw image_reader_exception(msg); } -void tiff_reader::init() +template +void tiff_reader::init() { TIFFSetWarningHandler(0); // Note - we intentially set the error handling to null // when opening the image for the first time to avoid // leaking in TiffOpen: https://github.com/mapnik/mapnik/issues/1783 TIFFSetErrorHandler(0); - TIFF* tif = load_if_exists(file_name_); - if (!tif) throw image_reader_exception( std::string("Can't load tiff file: '") + file_name_ + "'"); + + TIFF* tif = open(stream_); + + if (!tif) throw image_reader_exception("Can't open tiff file"); + TIFFSetErrorHandler(on_error); char msg[1024]; @@ -159,29 +261,31 @@ void tiff_reader::init() } } - -tiff_reader::~tiff_reader() +template +tiff_reader::~tiff_reader() { } - -unsigned tiff_reader::width() const +template +unsigned tiff_reader::width() const { return width_; } - -unsigned tiff_reader::height() const +template +unsigned tiff_reader::height() const { return height_; } -bool tiff_reader::premultiplied_alpha() const +template +bool tiff_reader::premultiplied_alpha() const { return premultiplied_alpha_; } -void tiff_reader::read(unsigned x,unsigned y,image_data_32& image) +template +void tiff_reader::read(unsigned x,unsigned y,image_data_32& image) { if (read_method_==stripped) { @@ -197,20 +301,20 @@ void tiff_reader::read(unsigned x,unsigned y,image_data_32& image) } } - -void tiff_reader::read_generic(unsigned /*x*/,unsigned /*y*/,image_data_32& /*image*/) +template +void tiff_reader::read_generic(unsigned /*x*/,unsigned /*y*/,image_data_32& /*image*/) { - TIFF* tif = load_if_exists(file_name_); + TIFF* tif = open(stream_); if (tif) { MAPNIK_LOG_DEBUG(tiff_reader) << "tiff_reader: TODO - tiff is not stripped or tiled"; } } - -void tiff_reader::read_tiled(unsigned x0,unsigned y0,image_data_32& image) +template +void tiff_reader::read_tiled(unsigned x0,unsigned y0,image_data_32& image) { - TIFF* tif = load_if_exists(file_name_); + TIFF* tif = open(stream_); if (tif) { uint32* buf = (uint32*)_TIFFmalloc(tile_width_*tile_height_*sizeof(uint32)); @@ -226,8 +330,8 @@ void tiff_reader::read_tiled(unsigned x0,unsigned y0,image_data_32& image) for (int y=start_y;y=n0;--n) { @@ -251,10 +355,10 @@ void tiff_reader::read_tiled(unsigned x0,unsigned y0,image_data_32& image) } } - -void tiff_reader::read_stripped(unsigned x0,unsigned y0,image_data_32& image) +template +void tiff_reader::read_stripped(unsigned x0,unsigned y0,image_data_32& image) { - TIFF* tif = load_if_exists(file_name_); + TIFF* tif = open(stream_); if (tif) { uint32* buf = (uint32*)_TIFFmalloc(width_*rows_per_strip_*sizeof(uint32)); @@ -268,12 +372,12 @@ void tiff_reader::read_stripped(unsigned x0,unsigned y0,image_data_32& image) int row,tx0,tx1,ty0,ty1; tx0=x0; - tx1=min(width+x0,(unsigned)width_); + tx1=std::min(width+x0,(unsigned)width_); for (unsigned y=start_y; y < end_y; y+=rows_per_strip_) { - ty0 = max(y0,y)-y; - ty1 = min(height+y0,y+rows_per_strip_)-y; + ty0 = std::max(y0,y)-y; + ty1 = std::min(height+y0,y+rows_per_strip_)-y; if (!TIFFReadRGBAStrip(tif,y,buf)) break; @@ -291,16 +395,20 @@ void tiff_reader::read_stripped(unsigned x0,unsigned y0,image_data_32& image) } } -TIFF* tiff_reader::load_if_exists(std::string const& filename) +template +TIFF* tiff_reader::open(std::istream & input) { if (!tif_) { - boost::filesystem::path path(file_name_); - if (boost::filesystem::is_regular(path)) // exists and regular file - { - // File path is a full file path and does exist - tif_ = tiff_ptr(TIFFOpen(filename.c_str(), "rb"), tiff_closer()); - } + tif_ = tiff_ptr(TIFFClientOpen("tiff_input_stream", "rm", + reinterpret_cast(&input), + impl::tiff_read_proc, + impl::tiff_write_proc, + impl::tiff_seek_proc, + impl::tiff_close_proc, + impl::tiff_size_proc, + impl::tiff_map_proc, + impl::tiff_unmap_proc), tiff_closer()); } return tif_.get(); }