tiff io: avoid over-allocation + add more tests

This commit is contained in:
Dane Springmeyer 2014-12-09 00:17:02 -05:00
parent dc1ed0ae29
commit fcf71c36d9
2 changed files with 60 additions and 4 deletions

View file

@ -136,6 +136,8 @@ private:
unsigned photometric_;
unsigned bands_;
bool is_tiled_;
unsigned planar_config_;
unsigned compression_;
public:
enum TiffType {
@ -158,6 +160,9 @@ public:
bool is_tiled() const { return is_tiled_; }
unsigned tile_width() const { return tile_width_; }
unsigned tile_height() const { return tile_height_; }
unsigned rows_per_strip() const { return rows_per_strip_; }
unsigned planar_config() const { return planar_config_; }
unsigned compression() const { return compression_; }
private:
tiff_reader(const tiff_reader&);
tiff_reader& operator=(const tiff_reader&);
@ -207,7 +212,9 @@ tiff_reader<T>::tiff_reader(std::string const& file_name)
bps_(0),
photometric_(0),
bands_(1),
is_tiled_(false)
is_tiled_(false),
planar_config_(PLANARCONFIG_CONTIG),
compression_(COMPRESSION_NONE)
{
if (!stream_) throw image_reader_exception("TIFF reader: cannot open file "+ file_name);
init();
@ -228,7 +235,9 @@ tiff_reader<T>::tiff_reader(char const* data, std::size_t size)
bps_(0),
photometric_(0),
bands_(1),
is_tiled_(false)
is_tiled_(false),
planar_config_(PLANARCONFIG_CONTIG),
compression_(COMPRESSION_NONE)
{
if (!stream_) throw image_reader_exception("TIFF reader: cannot open image stream ");
stream_.seekg(0, std::ios::beg);
@ -257,6 +266,15 @@ void tiff_reader<T>::init()
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width_);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height_);
if (width_ > 10000 || height_ > 10000)
{
throw image_reader_exception("Can't allocate tiff > 10000x10000");
}
TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planar_config_);
TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression_ );
TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rows_per_strip_);
std::uint16_t orientation;
if (TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation) == 0)
{
@ -273,7 +291,7 @@ void tiff_reader<T>::init()
MAPNIK_LOG_DEBUG(tiff_reader) << "reading tiled tiff";
read_method_ = tiled;
}
else if (TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rows_per_strip_)!=0)
else if (rows_per_strip_ > 0)
{
MAPNIK_LOG_DEBUG(tiff_reader) << "reading striped tiff";
read_method_ = stripped;
@ -291,6 +309,23 @@ void tiff_reader<T>::init()
premultiplied_alpha_ = true;
}
}
if (!is_tiled_ &&
compression_ == COMPRESSION_NONE &&
planar_config_ == PLANARCONFIG_CONTIG)
{
if (height_ > 128 * 1024 * 1024)
{
std::size_t line_size = (bands_ * width_ * bps_ + 7) / 8;
std::size_t default_strip_height = 8192 / line_size;
if (default_strip_height == 0) default_strip_height = 1;
std::size_t num_strips = height_ / default_strip_height;
if (num_strips > 128 * 1024 * 1024)
{
throw image_reader_exception("Can't allocate tiff");
}
}
}
}
template <typename T>
@ -606,7 +641,7 @@ void tiff_reader<T>::read_stripped(unsigned x0,unsigned y0,image_data_rgba8& ima
if (!TIFFReadRGBAStrip(tif,y,buf.get()))
{
std::clog << "TIFFReadRGBAStrip failed";
std::clog << "TIFFReadRGBAStrip failed at " << y << " for " << width_ << "/" << height_ << "\n";
break;
}
row=y+ty0-y0;

View file

@ -10,6 +10,7 @@
mapnik::tiff_reader<boost::iostreams::file_source> tiff_reader(filename); \
REQUIRE( tiff_reader.width() == 256 ); \
REQUIRE( tiff_reader.height() == 256 ); \
REQUIRE( tiff_reader.planar_config() == PLANARCONFIG_CONTIG ); \
std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(filename,"tiff")); \
REQUIRE( reader->width() == 256 ); \
REQUIRE( reader->height() == 256 ); \
@ -54,11 +55,13 @@ TEST_CASE("tiff io") {
SECTION("rgba8 striped") {
TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_rgba8_striped.tif")
REQUIRE( tiff_reader.rows_per_strip() == 1 );
REQUIRE( tiff_reader.bits_per_sample() == 8 );
REQUIRE( tiff_reader.is_tiled() == false );
REQUIRE( tiff_reader.tile_width() == 0 );
REQUIRE( tiff_reader.tile_height() == 0 );
REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB );
REQUIRE( tiff_reader.compression() == COMPRESSION_ADOBE_DEFLATE );
mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height());
REQUIRE( data.is<mapnik::image_data_rgba8>() == true );
TIFF_ASSERT_SIZE( data,reader );
@ -68,11 +71,13 @@ SECTION("rgba8 striped") {
SECTION("rgba8 tiled") {
TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_rgba8_tiled.tif")
REQUIRE( tiff_reader.rows_per_strip() == 0 );
REQUIRE( tiff_reader.bits_per_sample() == 8 );
REQUIRE( tiff_reader.is_tiled() == true );
REQUIRE( tiff_reader.tile_width() == 256 );
REQUIRE( tiff_reader.tile_height() == 256 );
REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB );
REQUIRE( tiff_reader.compression() == COMPRESSION_LZW );
mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height());
REQUIRE( data.is<mapnik::image_data_rgba8>() == true );
TIFF_ASSERT_SIZE( data,reader );
@ -82,11 +87,13 @@ SECTION("rgba8 tiled") {
SECTION("rgb8 striped") {
TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_rgb8_striped.tif")
REQUIRE( tiff_reader.rows_per_strip() == 10 );
REQUIRE( tiff_reader.bits_per_sample() == 8 );
REQUIRE( tiff_reader.is_tiled() == false );
REQUIRE( tiff_reader.tile_width() == 0 );
REQUIRE( tiff_reader.tile_height() == 0 );
REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB );
REQUIRE( tiff_reader.compression() == COMPRESSION_NONE );
mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height());
REQUIRE( data.is<mapnik::image_data_rgba8>() == true );
TIFF_ASSERT_SIZE( data,reader );
@ -96,11 +103,13 @@ SECTION("rgb8 striped") {
SECTION("rgb8 tiled") {
TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_rgb8_tiled.tif")
REQUIRE( tiff_reader.rows_per_strip() == 0 );
REQUIRE( tiff_reader.bits_per_sample() == 8 );
REQUIRE( tiff_reader.is_tiled() == true );
REQUIRE( tiff_reader.tile_width() == 256 );
REQUIRE( tiff_reader.tile_height() == 256 );
REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB );
REQUIRE( tiff_reader.compression() == COMPRESSION_LZW );
mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height());
REQUIRE( data.is<mapnik::image_data_rgba8>() == true );
TIFF_ASSERT_SIZE( data,reader );
@ -110,11 +119,13 @@ SECTION("rgb8 tiled") {
SECTION("gray8 striped") {
TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_gray8_striped.tif")
REQUIRE( tiff_reader.rows_per_strip() == 32 );
REQUIRE( tiff_reader.bits_per_sample() == 8 );
REQUIRE( tiff_reader.is_tiled() == false );
REQUIRE( tiff_reader.tile_width() == 0 );
REQUIRE( tiff_reader.tile_height() == 0 );
REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK );
REQUIRE( tiff_reader.compression() == COMPRESSION_NONE );
mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height());
REQUIRE( data.is<mapnik::image_data_gray8>() == true );
TIFF_ASSERT_SIZE( data,reader );
@ -124,11 +135,13 @@ SECTION("gray8 striped") {
SECTION("gray8 tiled") {
TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_gray8_tiled.tif")
REQUIRE( tiff_reader.rows_per_strip() == 0 );
REQUIRE( tiff_reader.bits_per_sample() == 8 );
REQUIRE( tiff_reader.is_tiled() == true );
REQUIRE( tiff_reader.tile_width() == 256 );
REQUIRE( tiff_reader.tile_height() == 256 );
REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK );
REQUIRE( tiff_reader.compression() == COMPRESSION_LZW );
mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height());
REQUIRE( data.is<mapnik::image_data_gray8>() == true );
TIFF_ASSERT_SIZE( data,reader );
@ -138,11 +151,13 @@ SECTION("gray8 tiled") {
SECTION("gray16 striped") {
TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_gray16_striped.tif")
REQUIRE( tiff_reader.rows_per_strip() == 16 );
REQUIRE( tiff_reader.bits_per_sample() == 16 );
REQUIRE( tiff_reader.is_tiled() == false );
REQUIRE( tiff_reader.tile_width() == 0 );
REQUIRE( tiff_reader.tile_height() == 0 );
REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK );
REQUIRE( tiff_reader.compression() == COMPRESSION_NONE );
mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height());
REQUIRE( data.is<mapnik::image_data_gray16>() == true );
TIFF_ASSERT_SIZE( data,reader );
@ -152,11 +167,13 @@ SECTION("gray16 striped") {
SECTION("gray16 tiled") {
TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_gray16_tiled.tif")
REQUIRE( tiff_reader.rows_per_strip() == 0 );
REQUIRE( tiff_reader.bits_per_sample() == 16 );
REQUIRE( tiff_reader.is_tiled() == true );
REQUIRE( tiff_reader.tile_width() == 256 );
REQUIRE( tiff_reader.tile_height() == 256 );
REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK );
REQUIRE( tiff_reader.compression() == COMPRESSION_LZW );
mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height());
REQUIRE( data.is<mapnik::image_data_gray16>() == true );
TIFF_ASSERT_SIZE( data,reader );
@ -166,11 +183,13 @@ SECTION("gray16 tiled") {
SECTION("gray32f striped") {
TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_gray32f_striped.tif")
REQUIRE( tiff_reader.rows_per_strip() == 8 );
REQUIRE( tiff_reader.bits_per_sample() == 32 );
REQUIRE( tiff_reader.is_tiled() == false );
REQUIRE( tiff_reader.tile_width() == 0 );
REQUIRE( tiff_reader.tile_height() == 0 );
REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK );
REQUIRE( tiff_reader.compression() == COMPRESSION_NONE );
mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height());
REQUIRE( data.is<mapnik::image_data_gray32f>() == true );
TIFF_ASSERT_SIZE( data,reader );
@ -180,11 +199,13 @@ SECTION("gray32f striped") {
SECTION("gray32f tiled") {
TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_gray32f_tiled.tif")
REQUIRE( tiff_reader.rows_per_strip() == 0 );
REQUIRE( tiff_reader.bits_per_sample() == 32 );
REQUIRE( tiff_reader.is_tiled() == true );
REQUIRE( tiff_reader.tile_width() == 256 );
REQUIRE( tiff_reader.tile_height() == 256 );
REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK );
REQUIRE( tiff_reader.compression() == COMPRESSION_LZW );
mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height());
REQUIRE( data.is<mapnik::image_data_gray32f>() == true );
TIFF_ASSERT_SIZE( data,reader );