support nodata for paletted images and allow user to set nodata on-the-fly - closes #1160 and #1161 - refs #688 and refs #730 and refs #50 and refs #1018
This commit is contained in:
parent
a7e150a593
commit
46b16c917e
11 changed files with 196 additions and 16 deletions
|
@ -9,6 +9,10 @@ For a complete change history, see the SVN log.
|
|||
|
||||
## Mapnik 2.1.0
|
||||
|
||||
- GDAL: allow setting nodata value on the fly (will override value if nodata is set in data) (#1161)
|
||||
|
||||
- GDAL: respect nodata for paletted/colormapped images (#1160)
|
||||
|
||||
- PostGIS: the primary key, for tables containing one, is now auto-detected allowing for globally unique feature id values (#804)
|
||||
|
||||
- Fix Markers rendering so that ellipse height/width units are pixels (previously were unintentially radii)
|
||||
|
|
|
@ -78,7 +78,8 @@ inline GDALDataset* gdal_datasource::open_dataset() const
|
|||
gdal_datasource::gdal_datasource(parameters const& params, bool bind)
|
||||
: datasource(params),
|
||||
desc_(*params.get<std::string>("type"), "utf-8"),
|
||||
filter_factor_(*params_.get<double>("filter_factor", 0.0))
|
||||
filter_factor_(*params_.get<double>("filter_factor", 0.0)),
|
||||
nodata_value_(params_.get<double>("nodata"))
|
||||
{
|
||||
#ifdef MAPNIK_DEBUG
|
||||
std::clog << "GDAL Plugin: Initializing..." << std::endl;
|
||||
|
@ -242,7 +243,8 @@ featureset_ptr gdal_datasource::features(query const& q) const
|
|||
nbands_,
|
||||
dx_,
|
||||
dy_,
|
||||
filter_factor_));
|
||||
filter_factor_,
|
||||
nodata_value_));
|
||||
}
|
||||
|
||||
featureset_ptr gdal_datasource::features_at_point(coord2d const& pt) const
|
||||
|
@ -261,5 +263,6 @@ featureset_ptr gdal_datasource::features_at_point(coord2d const& pt) const
|
|||
nbands_,
|
||||
dx_,
|
||||
dy_,
|
||||
filter_factor_));
|
||||
filter_factor_,
|
||||
nodata_value_));
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ private:
|
|||
mutable int nbands_;
|
||||
mutable bool shared_dataset_;
|
||||
double filter_factor_;
|
||||
boost::optional<double> nodata_value_;
|
||||
inline GDALDataset* open_dataset() const;
|
||||
};
|
||||
|
||||
|
|
|
@ -53,7 +53,8 @@ gdal_featureset::gdal_featureset(GDALDataset& dataset,
|
|||
int nbands,
|
||||
double dx,
|
||||
double dy,
|
||||
double filter_factor)
|
||||
double filter_factor,
|
||||
boost::optional<double> const& nodata)
|
||||
: dataset_(dataset),
|
||||
ctx_(boost::make_shared<mapnik::context_type>()),
|
||||
band_(band),
|
||||
|
@ -65,6 +66,7 @@ gdal_featureset::gdal_featureset(GDALDataset& dataset,
|
|||
dy_(dy),
|
||||
nbands_(nbands),
|
||||
filter_factor_(filter_factor),
|
||||
nodata_value_(nodata),
|
||||
first_(true)
|
||||
{
|
||||
ctx_->push("value");
|
||||
|
@ -241,8 +243,17 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
|
|||
|
||||
float* imageData = (float*)image.getBytes();
|
||||
GDALRasterBand * band = dataset_.GetRasterBand(band_);
|
||||
int hasNoData;
|
||||
double nodata = band->GetNoDataValue(&hasNoData);
|
||||
int hasNoData(0);
|
||||
double nodata(0);
|
||||
if (nodata_value_)
|
||||
{
|
||||
hasNoData = 1;
|
||||
nodata = *nodata_value_;
|
||||
}
|
||||
else
|
||||
{
|
||||
nodata = band->GetNoDataValue(&hasNoData);
|
||||
}
|
||||
band->RasterIO(GF_Read, x_off, y_off, width, height,
|
||||
imageData, image.width(), image.height(),
|
||||
GDT_Float32, 0, 0);
|
||||
|
@ -340,8 +351,21 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
|
|||
#ifdef MAPNIK_DEBUG
|
||||
std::clog << "GDAL Plugin: processing rgb bands..." << std::endl;
|
||||
#endif
|
||||
int hasNoData;
|
||||
float nodata = red->GetNoDataValue(&hasNoData);
|
||||
int hasNoData(0);
|
||||
double nodata(0);
|
||||
if (nodata_value_)
|
||||
{
|
||||
hasNoData = 1;
|
||||
nodata = *nodata_value_;
|
||||
}
|
||||
else
|
||||
{
|
||||
nodata = red->GetNoDataValue(&hasNoData);
|
||||
}
|
||||
if (hasNoData)
|
||||
{
|
||||
feature->put("NODATA",nodata);
|
||||
}
|
||||
GDALColorTable *color_table = red->GetColorTable();
|
||||
|
||||
if (! alpha && hasNoData && ! color_table)
|
||||
|
@ -380,12 +404,25 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
|
|||
#ifdef MAPNIK_DEBUG
|
||||
std::clog << "GDAL Plugin: processing gray band..." << std::endl;
|
||||
#endif
|
||||
int hasNoData;
|
||||
float nodata = grey->GetNoDataValue(&hasNoData);
|
||||
int hasNoData(0);
|
||||
double nodata(0);
|
||||
if (nodata_value_)
|
||||
{
|
||||
hasNoData = 1;
|
||||
nodata = *nodata_value_;
|
||||
}
|
||||
else
|
||||
{
|
||||
nodata = grey->GetNoDataValue(&hasNoData);
|
||||
}
|
||||
GDALColorTable* color_table = grey->GetColorTable();
|
||||
|
||||
if (hasNoData && ! color_table)
|
||||
{
|
||||
if (hasNoData)
|
||||
{
|
||||
feature->put("NODATA",nodata);
|
||||
}
|
||||
#ifdef MAPNIK_DEBUG
|
||||
std::clog << "\tno data value for layer: " << nodata << std::endl;
|
||||
#endif
|
||||
|
@ -422,23 +459,41 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
|
|||
#ifdef MAPNIK_DEBUG
|
||||
std::clog << "GDAL Plugin: Loading colour table..." << std::endl;
|
||||
#endif
|
||||
unsigned nodata_value = static_cast<unsigned>(nodata);
|
||||
if (hasNoData)
|
||||
{
|
||||
feature->put("NODATA",static_cast<int>(nodata_value));
|
||||
}
|
||||
for (unsigned y = 0; y < image.height(); ++y)
|
||||
{
|
||||
unsigned int* row = image.getRow(y);
|
||||
for (unsigned x = 0; x < image.width(); ++x)
|
||||
{
|
||||
unsigned value = row[x] & 0xff;
|
||||
const GDALColorEntry *ce = color_table->GetColorEntry(value);
|
||||
if (ce )
|
||||
if (hasNoData && (value == nodata_value))
|
||||
{
|
||||
// TODO - big endian support
|
||||
row[x] = (ce->c4 << 24)| (ce->c3 << 16) | (ce->c2 << 8) | (ce->c1) ;
|
||||
// make no data fully alpha
|
||||
row[x] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const GDALColorEntry *ce = color_table->GetColorEntry(value);
|
||||
if (ce)
|
||||
{
|
||||
// TODO - big endian support
|
||||
row[x] = (ce->c4 << 24)| (ce->c3 << 16) | (ce->c2 << 8) | (ce->c1) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
// make lacking color entry fully alpha
|
||||
// note - gdal_translate makes black
|
||||
row[x] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (alpha)
|
||||
{
|
||||
#ifdef MAPNIK_DEBUG
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
// boost
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
class GDALDataset;
|
||||
class GDALRasterBand;
|
||||
|
@ -47,7 +48,8 @@ public:
|
|||
int nbands,
|
||||
double dx,
|
||||
double dy,
|
||||
double filter_factor);
|
||||
double filter_factor,
|
||||
boost::optional<double> const& nodata);
|
||||
virtual ~gdal_featureset();
|
||||
mapnik::feature_ptr next();
|
||||
private:
|
||||
|
@ -67,6 +69,7 @@ private:
|
|||
double dy_;
|
||||
int nbands_;
|
||||
double filter_factor_;
|
||||
boost::optional<double> nodata_value_;
|
||||
bool first_;
|
||||
};
|
||||
|
||||
|
|
16
tests/data/good_maps/tiff_colortable.xml
Normal file
16
tests/data/good_maps/tiff_colortable.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Map srs="+init=epsg:32630" background-color="rgb(255,255,255)">
|
||||
<Style name="2011_5km_vrt_nodata_style">
|
||||
<Rule>
|
||||
<RasterSymbolizer/>
|
||||
</Rule>
|
||||
</Style>
|
||||
<Layer name="2011_5km_vrt_nodata" srs="+init=epsg:32630">
|
||||
<StyleName>2011_5km_vrt_nodata_style</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="file">../raster/dataraster.tif</Parameter>
|
||||
<Parameter name="nodata">20</Parameter>
|
||||
<Parameter name="type">gdal</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
</Map>
|
15
tests/data/good_maps/vrt_colortable.xml
Normal file
15
tests/data/good_maps/vrt_colortable.xml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Map srs="+init=epsg:32630" background-color="rgb(255,255,255)">
|
||||
<Style name="2011_5km_vrt_nodata_style">
|
||||
<Rule>
|
||||
<RasterSymbolizer/>
|
||||
</Rule>
|
||||
</Style>
|
||||
<Layer name="2011_5km_vrt_nodata" srs="+init=epsg:32630">
|
||||
<StyleName>2011_5km_vrt_nodata_style</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="file">../raster/dataraster.vrt</Parameter>
|
||||
<Parameter name="type">gdal</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
</Map>
|
45
tests/data/raster/dataraster.vrt
Normal file
45
tests/data/raster/dataraster.vrt
Normal file
|
@ -0,0 +1,45 @@
|
|||
<VRTDataset rasterXSize="2283" rasterYSize="1913">
|
||||
<SRS>PROJCS["WGS 84 / UTM zone 30N",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433],AUTHORITY["EPSG","4326"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",-3],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AUTHORITY["EPSG","32630"]]</SRS>
|
||||
<GeoTransform> -1.4637000000000000e+04, 5.0000000000000000e+02, 0.0000000000000000e+00, 4.8596780000000000e+06, 0.0000000000000000e+00, -5.0000000000000000e+02</GeoTransform>
|
||||
<VRTRasterBand dataType="Int16" band="1">
|
||||
<NoDataValue>-9.99000000000000E+02</NoDataValue>
|
||||
<HideNoDataValue>0</HideNoDataValue>
|
||||
<ColorInterp>Palette</ColorInterp>
|
||||
<ColorTable>
|
||||
<Entry c1="0" c2="0" c3="0" c4="0"/>
|
||||
<Entry c1="0" c2="0" c3="255"/>
|
||||
<Entry c1="0" c2="255" c3="0"/>
|
||||
<Entry c1="255" c2="0" c3="0"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="128" c2="128" c3="128"/>
|
||||
<Entry c1="0" c2="0" c3="255"/>
|
||||
<Entry c1="0" c2="255" c3="0"/>
|
||||
<Entry c1="255" c2="0" c3="0"/>
|
||||
</ColorTable>
|
||||
<ComplexSource>
|
||||
<SourceFilename relativeToVRT="1">dataraster.tif</SourceFilename>
|
||||
<SourceBand>1</SourceBand>
|
||||
<SourceProperties RasterXSize="2283" RasterYSize="1913" DataType="Int16" BlockXSize="256" BlockYSize="256" />
|
||||
<SrcRect xOff="0" yOff="0" xSize="2283" ySize="1913" />
|
||||
<DstRect xOff="0" yOff="0" xSize="2283" ySize="1913" />
|
||||
<NODATA>-999</NODATA>
|
||||
</ComplexSource>
|
||||
</VRTRasterBand>
|
||||
</VRTDataset>
|
BIN
tests/python_tests/images/support/tif_colortable.png
Normal file
BIN
tests/python_tests/images/support/tif_colortable.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
BIN
tests/python_tests/images/support/vrt_colortable.png
Normal file
BIN
tests/python_tests/images/support/vrt_colortable.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
38
tests/python_tests/raster_colormapped_test.py
Normal file
38
tests/python_tests/raster_colormapped_test.py
Normal file
|
@ -0,0 +1,38 @@
|
|||
#coding=utf8
|
||||
import os
|
||||
import mapnik
|
||||
from utilities import execution_path
|
||||
from nose.tools import *
|
||||
|
||||
def setup():
|
||||
# All of the paths used are relative, if we run the tests
|
||||
# from another directory we need to chdir()
|
||||
os.chdir(execution_path('.'))
|
||||
|
||||
def test_vrt_rendering():
|
||||
m = mapnik.Map(512,512)
|
||||
mapnik.load_map(m,'../data/good_maps/vrt_colortable.xml')
|
||||
m.zoom_all()
|
||||
im = mapnik.Image(512,512)
|
||||
mapnik.render(m,im)
|
||||
actual = '/tmp/vrt_colortable.png'
|
||||
expected = 'images/support/vrt_colortable.png'
|
||||
im.save(actual)
|
||||
expected_im = mapnik.Image.open(expected)
|
||||
eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected(%s)' % (actual,'tests/python_tests/'+ expected))
|
||||
|
||||
def test_tif_rendering_nodata():
|
||||
m = mapnik.Map(512,512)
|
||||
mapnik.load_map(m,'../data/good_maps/tiff_colortable.xml')
|
||||
m.zoom_all()
|
||||
im = mapnik.Image(512,512)
|
||||
mapnik.render(m,im)
|
||||
actual = '/tmp/tif_colortable.png'
|
||||
expected = 'images/support/tif_colortable.png'
|
||||
im.save(actual)
|
||||
expected_im = mapnik.Image.open(expected)
|
||||
eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected(%s)' % (actual,'tests/python_tests/'+ expected))
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup()
|
||||
[eval(run)() for run in dir() if 'test_' in run]
|
Loading…
Reference in a new issue