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 3cb238974..78ca37a59 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..."; @@ -101,7 +102,7 @@ gdal_datasource::gdal_datasource(parameters const& params) } shared_dataset_ = *params.get("shared", false); - band_ = *params.get("band", -1); + band_ = *params.get("band", -1); GDALDataset *dataset = open_dataset(); @@ -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 5c22eddcb..751381e1b 100644 --- a/plugins/input/gdal/gdal_featureset.cpp +++ b/plugins/input/gdal/gdal_featureset.cpp @@ -32,7 +32,7 @@ // boost #include #include - +#include // stl #include @@ -61,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_(boost::make_shared()), band_(band), @@ -73,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"); @@ -90,23 +92,8 @@ feature_ptr gdal_featureset::next() if (first_) { first_ = false; - MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Next feature in Dataset=" << &dataset_; - - query *q = boost::get(&gquery_); - if (q) - { - return get_feature(*q); - } - else - { - coord2d *p = boost::get(&gquery_); - if (p) - { - return get_feature_at_point(*p); - } - } - // should never reach here + return boost::apply_visitor(query_dispatch(*this), gquery_); } return feature_ptr(); } @@ -201,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 @@ -303,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(), @@ -317,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; } @@ -352,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; } @@ -396,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 7315d1279..c7aeb645b 100644 --- a/plugins/input/gdal/gdal_featureset.hpp +++ b/plugins/input/gdal/gdal_featureset.hpp @@ -39,6 +39,24 @@ typedef boost::variant gdal_query; class gdal_featureset : public mapnik::Featureset { + struct query_dispatch : public boost::static_visitor + { + query_dispatch( gdal_featureset & featureset) + : featureset_(featureset) {} + + mapnik::feature_ptr operator() (mapnik::query const& q) const + { + return featureset_.get_feature(q); + } + + mapnik::feature_ptr operator() (mapnik::coord2d const& p) const + { + return featureset_.get_feature_at_point(p); + } + + gdal_featureset & featureset_; + }; + public: gdal_featureset(GDALDataset& dataset, int band, @@ -49,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(); @@ -72,6 +91,7 @@ private: double dy_; int nbands_; boost::optional nodata_value_; + double nodata_tolerance_; bool first_; };