From efcb667f039dd88a5126c3c5563e71985f89ee43 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 17 May 2017 17:06:40 -0500 Subject: [PATCH 1/2] The last stripe of a tiff could be read incorrectly due to a swap --- src/tiff_reader.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index 0740d31b6..c28eb5953 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -169,6 +169,8 @@ private: template void read_stripped(std::size_t x,std::size_t y, ImageData & image); + void read_stripped(std::size_t x,std::size_t y, image_rgba8 & image); + template void read_tiled(std::size_t x,std::size_t y, ImageData & image); @@ -530,10 +532,11 @@ struct tiff_reader_traits { if (TIFFReadRGBAStrip(tif, y, buf) != -1) { + /* for (std::size_t y = 0; y < rows_per_strip/2; ++y) { std::swap_ranges(buf + y * strip_width, buf + (y + 1) * strip_width, buf + (rows_per_strip - y - 1) * strip_width); - } + }*/ return true; } return false; @@ -719,6 +722,54 @@ void tiff_reader::read_tiled(std::size_t x0,std::size_t y0, ImageData & image } } +template +void tiff_reader::read_stripped(std::size_t x0, std::size_t y0, image_rgba8 & image) +{ + using pixel_type = typename detail::tiff_reader_traits::pixel_type; + TIFF* tif = open(stream_); + if (tif) + { + std::uint32_t strip_size = TIFFStripSize(tif); + std::unique_ptr strip(new pixel_type[strip_size]); + std::size_t width = image.width(); + std::size_t height = image.height(); + + std::size_t start_y = (y0 / rows_per_strip_) * rows_per_strip_; + std::size_t end_y = std::min(y0 + height, height_); + std::size_t tx0, tx1, ty0, ty1, rows_on_strip; + + tx0 = x0; + tx1 = std::min(width + x0, width_); + rows_on_strip = rows_per_strip_; + std::size_t row = 0; + bool pick_first_band = (bands_ > 1) && (strip_size / (width_ * rows_per_strip_ * sizeof(pixel_type)) == bands_); + for (std::size_t y = start_y; y < end_y; y += rows_per_strip_) + { + ty0 = std::max(y0, y) - y; + ty1 = std::min(end_y, y + rows_per_strip_) - y; + rows_on_strip = std::min(end_y - y, static_cast(rows_per_strip_)); + + if (!detail::tiff_reader_traits::read_strip(tif, y, rows_per_strip_, width_, strip.get())) + { + MAPNIK_LOG_DEBUG(tiff_reader) << "TIFFRead(Encoded|RGBA)Strip failed at " << y << " for " << width_ << "/" << height_ << "\n"; + break; + } + if (pick_first_band) + { + std::uint32_t size = width_ * rows_per_strip_ * sizeof(pixel_type); + for (std::uint32_t n = 0; n < size; ++n) + { + strip[n] = strip[bands_ * n]; + } + } + for (std::size_t ty = ty0; ty < ty1; ++ty) + { + image.set_row(row++, tx0 - x0, tx1 - x0, &strip[(rows_on_strip - ty - 1) * width_ + tx0]); + } + } + } +} + template template void tiff_reader::read_stripped(std::size_t x0, std::size_t y0, ImageData & image) From cb7a3abfcb67c1a07140c75331cbba8c853cc08f Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 18 May 2017 13:12:52 +0200 Subject: [PATCH 2/2] follow up fix for the bug reported by @flippmoke + fix return value check in `TIFFReadRGBAStrip` --- src/tiff_reader.cpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index c28eb5953..9c137357e 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -497,6 +497,7 @@ struct tiff_reader_traits using image_type = T; using pixel_type = typename image_type::pixel_type; + constexpr static bool reverse = false; static bool read_tile(TIFF * tif, std::size_t x, std::size_t y, pixel_type* buf, std::size_t tile_width, std::size_t tile_height) { std::uint32_t tile_size = TIFFTileSize(tif); @@ -513,8 +514,9 @@ struct tiff_reader_traits template <> struct tiff_reader_traits { + using image_type = image_rgba8; using pixel_type = std::uint32_t; - + constexpr static bool reverse = true; static bool read_tile(TIFF * tif, std::size_t x0, std::size_t y0, pixel_type* buf, std::size_t tile_width, std::size_t tile_height) { if (TIFFReadRGBATile(tif, x0, y0, buf) != -1) @@ -530,16 +532,7 @@ struct tiff_reader_traits static bool read_strip(TIFF * tif, std::size_t y, std::size_t rows_per_strip, std::size_t strip_width, pixel_type * buf) { - if (TIFFReadRGBAStrip(tif, y, buf) != -1) - { - /* - for (std::size_t y = 0; y < rows_per_strip/2; ++y) - { - std::swap_ranges(buf + y * strip_width, buf + (y + 1) * strip_width, buf + (rows_per_strip - y - 1) * strip_width); - }*/ - return true; - } - return false; + return (TIFFReadRGBAStrip(tif, y, buf) != 0); } }; @@ -809,9 +802,22 @@ void tiff_reader::read_stripped(std::size_t x0, std::size_t y0, ImageData & i strip[n] = strip[bands_ * n]; } } - for (std::size_t ty = ty0; ty < ty1; ++ty) + + if (detail::tiff_reader_traits::reverse) { - image.set_row(row++, tx0 - x0, tx1 - x0, &strip[ty * width_ + tx0]); + std::size_t num_rows = std::min(end_y - y, static_cast(rows_per_strip_)); + for (std::size_t ty = ty0; ty < ty1; ++ty) + { + // This is in reverse because the TIFFReadRGBAStrip reads are inverted + image.set_row(row++, tx0 - x0, tx1 - x0, &strip[(num_rows - ty - 1) * width_ + tx0]); + } + } + else + { + for (std::size_t ty = ty0; ty < ty1; ++ty) + { + image.set_row(row++, tx0 - x0, tx1 - x0, &strip[ty * width_ + tx0]); + } } } }