From 77da5d919c80933dd4ca71ad093f81f43cb44f6d Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 17 Jan 2014 19:13:53 -0800 Subject: [PATCH] further gdal nodata handling improvements - refs #2023 Conflicts: plugins/input/gdal/gdal_featureset.cpp --- CHANGELOG.md | 6 +++++ plugins/input/gdal/gdal_datasource.cpp | 33 ++++++++++++++++------- plugins/input/gdal/gdal_datasource.hpp | 1 + plugins/input/gdal/gdal_featureset.cpp | 36 +++++++++++++++----------- plugins/input/gdal/gdal_featureset.hpp | 4 ++- 5 files changed, 55 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92629c520..5d33e79b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,12 @@ Released ... Summary: TODO +- GDAL plugin: Added back support for user driven `nodata` on rgb(a) images (#2023) + +- GDAL plugin: Allowed nodata to override alpha band if set on rgba images (#2023) + +- GDAL plugin: Added `nodata_tolerance` option to set nearby pixels transparent (has similar effect to the `nearblack` program) (#2023) + - Added support for web fonts: .woff format (#2113) - Added missing support for `geometry-transform` in `line-pattern` and `polygon-pattern` symbolizers (#2065) diff --git a/plugins/input/gdal/gdal_datasource.cpp b/plugins/input/gdal/gdal_datasource.cpp index a69af804b..41f944d8a 100644 --- a/plugins/input/gdal/gdal_datasource.cpp +++ b/plugins/input/gdal/gdal_datasource.cpp @@ -77,7 +77,8 @@ inline GDALDataset* gdal_datasource::open_dataset() const gdal_datasource::gdal_datasource(parameters const& params) : datasource(params), desc_(*params.get("type"), "utf-8"), - nodata_value_(params.get("nodata")) + nodata_value_(params.get("nodata")), + nodata_tolerance_(*params.get("nodata_tolerance",1e-12)) { MAPNIK_LOG_DEBUG(gdal) << "gdal_datasource: Initializing..."; @@ -132,17 +133,29 @@ gdal_datasource::gdal_datasource(parameters const& params) tr[3] = extent_.maxy(); tr[4] = 0; tr[5] = -extent_.height() / (double)height_; + MAPNIK_LOG_DEBUG(gdal) << "gdal_datasource extent override gives Geotransform=" + << tr[0] << "," << tr[1] << "," + << tr[2] << "," << tr[3] << "," + << tr[4] << "," << tr[5]; } else { - dataset->GetGeoTransform(tr); + if (dataset->GetGeoTransform(tr) != CPLE_None) + { + MAPNIK_LOG_DEBUG(gdal) << "gdal_datasource GetGeotransform failure gives=" + << tr[0] << "," << tr[1] << "," + << tr[2] << "," << tr[3] << "," + << tr[4] << "," << tr[5]; + } + else + { + MAPNIK_LOG_DEBUG(gdal) << "gdal_datasource Geotransform=" + << tr[0] << "," << tr[1] << "," + << tr[2] << "," << tr[3] << "," + << tr[4] << "," << tr[5]; + } } - MAPNIK_LOG_DEBUG(gdal) << "gdal_datasource Geotransform=" - << tr[0] << "," << tr[1] << "," - << tr[2] << "," << tr[3] << "," - << tr[4] << "," << tr[5]; - // TODO - We should throw for true non-north up images, but the check // below is clearly too restrictive. // https://github.com/mapnik/mapnik/issues/970 @@ -228,7 +241,8 @@ featureset_ptr gdal_datasource::features(query const& q) const nbands_, dx_, dy_, - nodata_value_)); + nodata_value_, + nodata_tolerance_)); } featureset_ptr gdal_datasource::features_at_point(coord2d const& pt, double tol) const @@ -249,5 +263,6 @@ featureset_ptr gdal_datasource::features_at_point(coord2d const& pt, double tol) nbands_, dx_, dy_, - nodata_value_)); + nodata_value_, + nodata_tolerance_)); } diff --git a/plugins/input/gdal/gdal_datasource.hpp b/plugins/input/gdal/gdal_datasource.hpp index d73682682..bb43b95bd 100644 --- a/plugins/input/gdal/gdal_datasource.hpp +++ b/plugins/input/gdal/gdal_datasource.hpp @@ -67,6 +67,7 @@ private: int nbands_; bool shared_dataset_; boost::optional nodata_value_; + double nodata_tolerance_; }; #endif // GDAL_DATASOURCE_HPP diff --git a/plugins/input/gdal/gdal_featureset.cpp b/plugins/input/gdal/gdal_featureset.cpp index 2d3e4a64e..8ec0f004b 100644 --- a/plugins/input/gdal/gdal_featureset.cpp +++ b/plugins/input/gdal/gdal_featureset.cpp @@ -34,6 +34,7 @@ #include // stl #include +#include #include "gdal_featureset.hpp" #include @@ -60,7 +61,8 @@ gdal_featureset::gdal_featureset(GDALDataset& dataset, int nbands, double dx, double dy, - boost::optional const& nodata) + boost::optional const& nodata, + double nodata_tolerance) : dataset_(dataset), ctx_(std::make_shared()), band_(band), @@ -72,6 +74,7 @@ gdal_featureset::gdal_featureset(GDALDataset& dataset, dy_(dy), nbands_(nbands), nodata_value_(nodata), + nodata_tolerance_(nodata_tolerance), first_(true) { ctx_->push("nodata"); @@ -185,9 +188,9 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) int im_width = int(width_res * intersect.width() + 0.5); int im_height = int(height_res * intersect.height() + 0.5); - double sym_downsample_factor = q.get_filter_factor(); - im_width = int(im_width * sym_downsample_factor + 0.5); - im_height = int(im_height * sym_downsample_factor + 0.5); + double filter_factor = q.get_filter_factor(); + im_width = int(im_width * filter_factor + 0.5); + im_height = int(im_height * filter_factor + 0.5); // case where we need to avoid upsampling so that the // image can be later scaled within raster_symbolizer @@ -287,13 +290,13 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Processing rgb bands..."; raster_nodata = red->GetNoDataValue(&raster_has_nodata); GDALColorTable *color_table = red->GetColorTable(); - if (!alpha && raster_has_nodata && !color_table) + bool has_nodata = nodata_value_ || raster_has_nodata; + if (has_nodata && !color_table) { + double apply_nodata = nodata_value_ ? *nodata_value_ : raster_nodata; // read the data in and create an alpha channel from the nodata values - // NOTE: we intentionally ignore user supplied nodata value since it only - // works for grayscale images or a single band (as a double) - // TODO - we assume here the nodata value for the red band applies to all band - // but that may not always be the case: http://trac.osgeo.org/gdal/ticket/2734 + // TODO - we assume here the nodata value for the red band applies to all bands + // more details about this at http://trac.osgeo.org/gdal/ticket/2734 float* imageData = (float*)image.getBytes(); red->RasterIO(GF_Read, x_off, y_off, width, height, imageData, image.width(), image.height(), @@ -301,7 +304,7 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) int len = image.width() * image.height(); for (int i = 0; i < len; ++i) { - if (std::fabs(raster_nodata - imageData[i]) < 1e-12) + if (std::fabs(apply_nodata - imageData[i]) < nodata_tolerance_) { *reinterpret_cast(&imageData[i]) = 0; } @@ -336,7 +339,7 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) int len = image.width() * image.height(); for (int i = 0; i < len; ++i) { - if (std::fabs(apply_nodata - imageData[i]) < 1e-12) + if (std::fabs(apply_nodata - imageData[i]) < nodata_tolerance_) { *reinterpret_cast(&imageData[i]) = 0; } @@ -380,12 +383,15 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) if (alpha) { MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: processing alpha band..."; - if (raster_has_nodata) + if (!raster_has_nodata) { - MAPNIK_LOG_ERROR(gdal) << "warning: alpha channel being used instead of nodata value"; + alpha->RasterIO(GF_Read, x_off, y_off, width, height, image.getBytes() + 3, + image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); + } + else + { + MAPNIK_LOG_ERROR(gdal) << "warning: nodata value (" << raster_nodata << ") used to set transparency instead of alpha band"; } - alpha->RasterIO(GF_Read, x_off, y_off, width, height, image.getBytes() + 3, - image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); } } // set nodata value to be used in raster colorizer diff --git a/plugins/input/gdal/gdal_featureset.hpp b/plugins/input/gdal/gdal_featureset.hpp index b97730995..c7aeb645b 100644 --- a/plugins/input/gdal/gdal_featureset.hpp +++ b/plugins/input/gdal/gdal_featureset.hpp @@ -67,7 +67,8 @@ public: int nbands, double dx, double dy, - boost::optional const& nodata); + boost::optional const& nodata, + double nodata_tolerance); virtual ~gdal_featureset(); mapnik::feature_ptr next(); @@ -90,6 +91,7 @@ private: double dy_; int nbands_; boost::optional nodata_value_; + double nodata_tolerance_; bool first_; };