commit
b0f94bff44
242 changed files with 15111 additions and 1999 deletions
|
@ -1988,6 +1988,7 @@ if not HELP_REQUESTED:
|
|||
|
||||
# build C++ tests
|
||||
SConscript('tests/cpp_tests/build.py')
|
||||
SConscript('tests/cxx/build.py')
|
||||
|
||||
if env['BENCHMARK']:
|
||||
SConscript('benchmark/build.py')
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
return iterations_;
|
||||
}
|
||||
virtual bool validate() const = 0;
|
||||
virtual void operator()() const = 0;
|
||||
virtual bool operator()() const = 0;
|
||||
virtual ~test_case() {}
|
||||
};
|
||||
|
||||
|
@ -85,6 +85,10 @@ int run(T const& test_runner, std::string const& name)
|
|||
std::clog << "test did not validate: " << name << "\n";
|
||||
return -1;
|
||||
}
|
||||
// run test once before timing
|
||||
// if it returns false then we'll abort timing
|
||||
if (test_runner())
|
||||
{
|
||||
std::chrono::high_resolution_clock::time_point start;
|
||||
std::chrono::high_resolution_clock::duration elapsed;
|
||||
std::stringstream s;
|
||||
|
@ -114,6 +118,7 @@ int run(T const& test_runner, std::string const& name)
|
|||
s << std::setw(65 - (int)s.tellp()) << std::right
|
||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count() << " milliseconds\n";
|
||||
std::clog << s.str();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
|
|
|
@ -28,8 +28,8 @@ namespace benchmark {
|
|||
std::shared_ptr<image_32> image_ptr2 = std::make_shared<image_32>(reader2->width(),reader2->height());
|
||||
reader2->read(0,0,image_ptr2->data());
|
||||
|
||||
image_data_32 const& dest = image_ptr1->data();
|
||||
image_data_32 const& src = image_ptr2->data();
|
||||
image_data_rgba8 const& dest = image_ptr1->data();
|
||||
image_data_rgba8 const& src = image_ptr2->data();
|
||||
|
||||
unsigned int width = src.width();
|
||||
unsigned int height = src.height();
|
||||
|
|
21
benchmark/data/gdal-wgs.xml
Normal file
21
benchmark/data/gdal-wgs.xml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE Map[]>
|
||||
<Map
|
||||
srs="+init=epsg:4326"
|
||||
background-color="#dfd8c9">
|
||||
|
||||
<Style name="style">
|
||||
<Rule>
|
||||
<RasterSymbolizer />
|
||||
</Rule>
|
||||
</Style>
|
||||
<Layer name="layer"
|
||||
srs="+init=epsg:4326">
|
||||
<StyleName>style</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="file">./valid.geotiff.tif</Parameter>
|
||||
<Parameter name="type">gdal</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
|
||||
</Map>
|
21
benchmark/data/raster-wgs.xml
Normal file
21
benchmark/data/raster-wgs.xml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE Map[]>
|
||||
<Map
|
||||
srs="+init=epsg:4326"
|
||||
background-color="#dfd8c9">
|
||||
|
||||
<Style name="style">
|
||||
<Rule>
|
||||
<RasterSymbolizer />
|
||||
</Rule>
|
||||
</Style>
|
||||
<Layer name="layer"
|
||||
srs="+init=epsg:4326">
|
||||
<StyleName>style</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="file">./valid.geotiff.tif</Parameter>
|
||||
<Parameter name="type">raster</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
|
||||
</Map>
|
BIN
benchmark/data/valid.geotiff.tif
Normal file
BIN
benchmark/data/valid.geotiff.tif
Normal file
Binary file not shown.
|
@ -30,3 +30,21 @@ run test_font_registration 10 1000
|
|||
--height 600 \
|
||||
--iterations 20 \
|
||||
--threads 10
|
||||
|
||||
./benchmark/out/test_rendering \
|
||||
--name "gdal tiff rendering" \
|
||||
--map benchmark/data/gdal-wgs.xml \
|
||||
--extent -180.0,-120.0,180.0,120.0 \
|
||||
--width 600 \
|
||||
--height 600 \
|
||||
--iterations 20 \
|
||||
--threads 10
|
||||
|
||||
./benchmark/out/test_rendering \
|
||||
--name "raster tiff rendering" \
|
||||
--map benchmark/data/raster-wgs.xml \
|
||||
--extent -180.0,-120.0,180.0,120.0 \
|
||||
--width 600 \
|
||||
--height 600 \
|
||||
--iterations 20 \
|
||||
--threads 10
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
{
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
// NOTE: sizeof(uint8_t) == 1
|
||||
|
@ -50,6 +50,7 @@ public:
|
|||
ensure_zero(data,size_);
|
||||
free(data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -66,7 +67,7 @@ public:
|
|||
{
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
// NOTE: sizeof(uint8_t) == 1
|
||||
|
@ -75,6 +76,7 @@ public:
|
|||
ensure_zero(data,size_);
|
||||
free(data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -91,7 +93,7 @@ public:
|
|||
{
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
uint8_t *data = static_cast<uint8_t *>(::operator new(sizeof(uint8_t) * size_));
|
||||
|
@ -99,6 +101,7 @@ public:
|
|||
ensure_zero(data,size_);
|
||||
::operator delete(data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -116,7 +119,7 @@ public:
|
|||
{
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
uint8_t * data = static_cast<uint8_t*>(::operator new(sizeof(uint8_t)*size_));
|
||||
|
@ -124,6 +127,7 @@ public:
|
|||
ensure_zero(data,size_);
|
||||
::operator delete(data),data=0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -140,12 +144,13 @@ public:
|
|||
{
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
std::vector<uint8_t> data(size_);
|
||||
ensure_zero(&data[0],data.size());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -163,13 +168,14 @@ public:
|
|||
{
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
std::vector<uint8_t> data(0);
|
||||
data.resize(size_,0);
|
||||
ensure_zero(&data[0],data.size());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -187,13 +193,41 @@ public:
|
|||
{
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
std::vector<uint8_t> data(0);
|
||||
data.assign(size_,0);
|
||||
ensure_zero(&data[0],data.size());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class test3d : public benchmark::test_case
|
||||
{
|
||||
public:
|
||||
uint32_t size_;
|
||||
std::vector<uint8_t> array_;
|
||||
test3d(mapnik::parameters const& params)
|
||||
: test_case(params),
|
||||
size_(*params.get<mapnik::value_integer>("size",256*256)),
|
||||
array_(size_,0) { }
|
||||
bool validate() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
std::deque<uint8_t> data(size_);
|
||||
for (std::size_t i=0;i<size_;++i) {
|
||||
if (data[i] != 0) {
|
||||
throw std::runtime_error("found non zero value");
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -237,13 +271,14 @@ public:
|
|||
{
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
uint8_t *data = (uint8_t *)calloc(size_,sizeof(uint8_t));
|
||||
ensure_zero(data,size_);
|
||||
free(data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -260,12 +295,13 @@ public:
|
|||
{
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
std::string data(array_.begin(),array_.end());
|
||||
ensure_zero((uint8_t *)&data[0],size_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -282,12 +318,13 @@ public:
|
|||
{
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
std::string data(&array_[0],array_.size());
|
||||
ensure_zero((uint8_t *)&data[0],size_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -309,12 +346,13 @@ public:
|
|||
{
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
std::valarray<uint8_t> data(static_cast<uint8_t>(0),static_cast<size_t>(size_));
|
||||
ensure_zero(&data[0],size_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -335,12 +373,13 @@ public:
|
|||
{
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
boost::container::static_vector<uint8_t,256*256> data(size_,0);
|
||||
ensure_zero(&data[0],size_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -22,11 +22,12 @@ public:
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
mapnik::expression_ptr expr = mapnik::parse_expression(expr_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
}
|
||||
return count == expected_count;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
std::size_t expected_count = mapnik::freetype_engine::face_names().size();
|
||||
for (unsigned i=0;i<iterations_;++i)
|
||||
|
@ -49,6 +49,7 @@ public:
|
|||
std::clog << "warning: face creation not working as expected\n";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ public:
|
|||
{
|
||||
return mapnik::freetype_engine::register_fonts("./fonts", true);
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
unsigned long count = 0;
|
||||
for (unsigned i=0;i<iterations_;++i)
|
||||
|
@ -20,6 +20,7 @@ public:
|
|||
mapnik::freetype_engine::register_fonts("./fonts", true);
|
||||
count++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
class test : public benchmark::test_case
|
||||
{
|
||||
mapnik::image_data_32 im_;
|
||||
mapnik::image_data_rgba8 im_;
|
||||
public:
|
||||
test(mapnik::parameters const& params)
|
||||
: test_case(params),
|
||||
|
@ -13,7 +13,7 @@ public:
|
|||
{
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
std::string out;
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
|
@ -21,6 +21,7 @@ public:
|
|||
out = mapnik::save_to_string(im_,"png8:m=h:z=1");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
BENCHMARK(test,"encoding blank png")
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
mapnik::save_to_file(im_->data(),actual, "png8:m=h:z=1");
|
||||
return benchmark::compare_images(actual,expected);
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
std::string out;
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
|
@ -31,6 +31,7 @@ public:
|
|||
out = mapnik::save_to_string(im_->data(),"png8:m=h:z=1");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
BENCHMARK(test,"encoding multicolor png")
|
||||
|
|
|
@ -108,7 +108,7 @@ public:
|
|||
render(geom2,geom.envelope(),actual);
|
||||
return benchmark::compare_images(actual,expect);
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
boost::ptr_vector<mapnik::geometry_type> paths;
|
||||
if (!mapnik::from_wkt(wkt_in_, paths))
|
||||
|
@ -130,6 +130,7 @@ public:
|
|||
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -189,7 +190,7 @@ public:
|
|||
render(geom2,geom.envelope(),actual);
|
||||
return benchmark::compare_images(actual,expect);
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
boost::ptr_vector<mapnik::geometry_type> paths;
|
||||
if (!mapnik::from_wkt(wkt_in_, paths))
|
||||
|
@ -217,6 +218,7 @@ public:
|
|||
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -265,7 +267,7 @@ public:
|
|||
render(geom2,geom.envelope(),actual);
|
||||
return benchmark::compare_images(actual,expect);
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
boost::ptr_vector<mapnik::geometry_type> paths;
|
||||
if (!mapnik::from_wkt(wkt_in_, paths))
|
||||
|
@ -282,6 +284,7 @@ public:
|
|||
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
//mapnik::save_to_file(im,"test.png");
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
mapnik::Map m(256,256);
|
||||
mapnik::load_map(m,xml_);
|
||||
|
@ -39,6 +39,7 @@ public:
|
|||
mapnik::agg_renderer<mapnik::image_32> ren(m,im);
|
||||
ren.apply();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
(std::fabs(bbox.maxy() - to_.maxy()) < .5)
|
||||
);
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
for (int i=-180;i<180;i=i+5)
|
||||
|
@ -51,6 +51,7 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -58,11 +58,17 @@ public:
|
|||
mapnik::image_32 im(m.width(),m.height());
|
||||
mapnik::agg_renderer<mapnik::image_32> ren(m,im,scale_factor_);
|
||||
ren.apply();
|
||||
if (!preview_.empty()) mapnik::save_to_file(im,preview_);
|
||||
if (!preview_.empty()) {
|
||||
std::clog << "preview available at " << preview_ << "\n";
|
||||
mapnik::save_to_file(im,preview_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
if (!preview_.empty()) {
|
||||
return false;
|
||||
}
|
||||
mapnik::Map m(width_,height_);
|
||||
mapnik::load_map(m,xml_);
|
||||
if (extent_.valid()) {
|
||||
|
@ -76,6 +82,7 @@ public:
|
|||
mapnik::agg_renderer<mapnik::image_32> ren(m,im,scale_factor_);
|
||||
ren.apply();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -26,13 +26,7 @@ template <typename Renderer> void process_layers(Renderer & ren,
|
|||
if (lyr.visible(scale_denom))
|
||||
{
|
||||
std::set<std::string> names;
|
||||
mapnik::parameters p;
|
||||
p["type"]="csv";
|
||||
p["file"]="benchmark/data/roads.csv";
|
||||
mapnik::datasource_ptr ds = mapnik::datasource_cache::instance().create(p);
|
||||
mapnik::layer l(lyr);
|
||||
l.set_datasource(ds);
|
||||
l.add_style("labels");
|
||||
ren.apply_to_layer(l,
|
||||
ren,
|
||||
map_proj,
|
||||
|
@ -56,6 +50,7 @@ class test : public benchmark::test_case
|
|||
std::shared_ptr<mapnik::Map> m_;
|
||||
double scale_factor_;
|
||||
std::string preview_;
|
||||
mutable mapnik::image_32 im_;
|
||||
public:
|
||||
test(mapnik::parameters const& params)
|
||||
: test_case(params),
|
||||
|
@ -65,7 +60,8 @@ public:
|
|||
height_(*params.get<mapnik::value_integer>("height",256)),
|
||||
m_(new mapnik::Map(width_,height_)),
|
||||
scale_factor_(*params.get<mapnik::value_double>("scale_factor",2.0)),
|
||||
preview_(*params.get<std::string>("preview",""))
|
||||
preview_(*params.get<std::string>("preview","")),
|
||||
im_(m_->width(),m_->height())
|
||||
{
|
||||
boost::optional<std::string> map = params.get<std::string>("map");
|
||||
if (!map)
|
||||
|
@ -75,6 +71,7 @@ public:
|
|||
xml_ = *map;
|
||||
|
||||
boost::optional<std::string> ext = params.get<std::string>("extent");
|
||||
mapnik::load_map(*m_,xml_,true);
|
||||
if (ext && !ext->empty())
|
||||
{
|
||||
if (!extent_.from_string(*ext))
|
||||
|
@ -82,35 +79,38 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("please provide a --extent=<minx,miny,maxx,maxy> arg");
|
||||
m_->zoom_all();
|
||||
extent_ = m_->get_current_extent();
|
||||
std::clog << "Defaulting to max extent " << extent_ << "\n";
|
||||
std::clog << " (pass --extent=<minx,miny,maxx,maxy> to restrict bounds)\n";
|
||||
}
|
||||
mapnik::load_map(*m_,xml_,true);
|
||||
}
|
||||
|
||||
bool validate() const
|
||||
{
|
||||
mapnik::request m_req(width_,height_,extent_);
|
||||
mapnik::image_32 im(m_->width(),m_->height());
|
||||
mapnik::attributes variables;
|
||||
m_req.set_buffer_size(m_->buffer_size());
|
||||
mapnik::projection map_proj(m_->srs(),true);
|
||||
double scale_denom = mapnik::scale_denominator(m_req.scale(),map_proj.is_geographic());
|
||||
scale_denom *= scale_factor_;
|
||||
mapnik::agg_renderer<mapnik::image_32> ren(*m_,m_req,variables,im,scale_factor_);
|
||||
mapnik::agg_renderer<mapnik::image_32> ren(*m_,m_req,variables,im_,scale_factor_);
|
||||
ren.start_map_processing(*m_);
|
||||
std::vector<mapnik::layer> const& layers = m_->layers();
|
||||
process_layers(ren,m_req,map_proj,layers,scale_denom);
|
||||
ren.end_map_processing(*m_);
|
||||
if (!preview_.empty()) {
|
||||
std::clog << "preview available at " << preview_ << "\n";
|
||||
mapnik::save_to_file(im,preview_);
|
||||
mapnik::save_to_file(im_,preview_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
if (preview_.empty()) {
|
||||
if (!preview_.empty()) {
|
||||
return false;
|
||||
}
|
||||
for (unsigned i=0;i<iterations_;++i)
|
||||
{
|
||||
mapnik::request m_req(width_,height_,extent_);
|
||||
|
@ -125,8 +125,21 @@ public:
|
|||
std::vector<mapnik::layer> const& layers = m_->layers();
|
||||
process_layers(ren,m_req,map_proj,layers,scale_denom);
|
||||
ren.end_map_processing(*m_);
|
||||
bool diff = false;
|
||||
mapnik::image_data_rgba8 const& dest = im.data();
|
||||
mapnik::image_data_rgba8 const& src = im_.data();
|
||||
for (unsigned int y = 0; y < height_; ++y)
|
||||
{
|
||||
const unsigned int* row_from = src.getRow(y);
|
||||
const unsigned int* row_to = dest.getRow(y);
|
||||
for (unsigned int x = 0; x < width_; ++x)
|
||||
{
|
||||
if (row_from[x] != row_to[x]) diff = true;
|
||||
}
|
||||
}
|
||||
if (diff) throw std::runtime_error("images differ");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -16,13 +16,14 @@ public:
|
|||
mapnik::util::string2bool(value_,result);
|
||||
return (result == true);
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
bool result = false;
|
||||
mapnik::util::string2bool(value_,result);
|
||||
mapnik::util::string2bool(value_.data(),value_.data()+value_.size(),result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -18,13 +18,14 @@ public:
|
|||
if (result != 1.23456789) return false;
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
double result = 0;
|
||||
mapnik::util::string2double(value_,result);
|
||||
mapnik::util::string2double(value_.data(),value_.data()+value_.size(),result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -18,13 +18,14 @@ public:
|
|||
if (result != 123456789) return false;
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
mapnik::value_integer result = 0;
|
||||
mapnik::util::string2int(value_,result);
|
||||
mapnik::util::string2int(value_.data(),value_.data()+value_.size(),result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -14,13 +14,14 @@ public:
|
|||
mapnik::util::to_string(s,value_);
|
||||
return (s == "-0.1234");
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
std::string out;
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
out.clear();
|
||||
mapnik::util::to_string(out,value_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ public:
|
|||
s << value_;
|
||||
return (s.str() == "-0.1234");
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
std::string out;
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
|
@ -22,6 +22,7 @@ public:
|
|||
s << value_;
|
||||
out = s.str();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -23,13 +23,14 @@ public:
|
|||
utf32[3] != 0x5dd) return false;
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
std::u32string utf32;
|
||||
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> utf32conv;
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
utf32 = utf32conv.from_bytes(utf8_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -52,12 +53,13 @@ public:
|
|||
utf32[3] != 0x5dd) return false;
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
std::u32string utf32;
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
utf32 = boost::locale::conv::utf_to_utf<char32_t>(utf8_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -80,13 +82,14 @@ public:
|
|||
utf32[3] != 0x5dd) return false;
|
||||
return true;
|
||||
}
|
||||
void operator()() const
|
||||
bool operator()() const
|
||||
{
|
||||
mapnik::transcoder tr_("utf-8");
|
||||
mapnik::value_unicode_string utf32;
|
||||
for (std::size_t i=0;i<iterations_;++i) {
|
||||
utf32 = tr_.transcode(utf8_.data(),utf8_.size());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -120,12 +120,12 @@ bool is_solid(mapnik::image_32 const& im)
|
|||
{
|
||||
if (im.width() > 0 && im.height() > 0)
|
||||
{
|
||||
mapnik::image_data_32 const & data = im.data();
|
||||
mapnik::image_data_32::pixel_type const* first_row = data.getRow(0);
|
||||
mapnik::image_data_32::pixel_type const first_pixel = first_row[0];
|
||||
mapnik::image_data_rgba8 const & data = im.data();
|
||||
mapnik::image_data_rgba8::pixel_type const* first_row = data.getRow(0);
|
||||
mapnik::image_data_rgba8::pixel_type const first_pixel = first_row[0];
|
||||
for (unsigned y = 0; y < im.height(); ++y)
|
||||
{
|
||||
mapnik::image_data_32::pixel_type const * row = data.getRow(y);
|
||||
mapnik::image_data_rgba8::pixel_type const * row = data.getRow(y);
|
||||
for (unsigned x = 0; x < im.width(); ++x)
|
||||
{
|
||||
if (first_pixel != row[x])
|
||||
|
@ -142,7 +142,7 @@ unsigned get_pixel(mapnik::image_32 const& im, int x, int y)
|
|||
{
|
||||
if (x < static_cast<int>(im.width()) && y < static_cast<int>(im.height()))
|
||||
{
|
||||
mapnik::image_data_32 const & data = im.data();
|
||||
mapnik::image_data_rgba8 const & data = im.data();
|
||||
return data(x,y);
|
||||
}
|
||||
PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions");
|
||||
|
|
|
@ -42,18 +42,18 @@
|
|||
#include <mapnik/image_view.hpp>
|
||||
#include <sstream>
|
||||
|
||||
using mapnik::image_data_32;
|
||||
using mapnik::image_data_rgba8;
|
||||
using mapnik::image_view;
|
||||
using mapnik::save_to_file;
|
||||
|
||||
// output 'raw' pixels
|
||||
PyObject* view_tostring1(image_view<image_data_32> const& view)
|
||||
PyObject* view_tostring1(image_view<image_data_rgba8> const& view)
|
||||
{
|
||||
std::ostringstream ss(std::ios::out|std::ios::binary);
|
||||
for (unsigned i=0;i<view.height();i++)
|
||||
{
|
||||
ss.write(reinterpret_cast<const char*>(view.getRow(i)),
|
||||
view.width() * sizeof(image_view<image_data_32>::pixel_type));
|
||||
view.width() * sizeof(image_view<image_data_rgba8>::pixel_type));
|
||||
}
|
||||
return
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
|
@ -65,7 +65,7 @@ PyObject* view_tostring1(image_view<image_data_32> const& view)
|
|||
}
|
||||
|
||||
// encode (png,jpeg)
|
||||
PyObject* view_tostring2(image_view<image_data_32> const & view, std::string const& format)
|
||||
PyObject* view_tostring2(image_view<image_data_rgba8> const & view, std::string const& format)
|
||||
{
|
||||
std::string s = save_to_string(view, format);
|
||||
return
|
||||
|
@ -77,7 +77,7 @@ PyObject* view_tostring2(image_view<image_data_32> const & view, std::string con
|
|||
(s.data(),s.size());
|
||||
}
|
||||
|
||||
PyObject* view_tostring3(image_view<image_data_32> const & view, std::string const& format, mapnik::rgba_palette const& pal)
|
||||
PyObject* view_tostring3(image_view<image_data_rgba8> const & view, std::string const& format, mapnik::rgba_palette const& pal)
|
||||
{
|
||||
std::string s = save_to_string(view, format, pal);
|
||||
return
|
||||
|
@ -89,15 +89,15 @@ PyObject* view_tostring3(image_view<image_data_32> const & view, std::string con
|
|||
(s.data(),s.size());
|
||||
}
|
||||
|
||||
bool is_solid(image_view<image_data_32> const& view)
|
||||
bool is_solid(image_view<image_data_rgba8> const& view)
|
||||
{
|
||||
if (view.width() > 0 && view.height() > 0)
|
||||
{
|
||||
mapnik::image_view<image_data_32>::pixel_type const* first_row = view.getRow(0);
|
||||
mapnik::image_view<image_data_32>::pixel_type const first_pixel = first_row[0];
|
||||
mapnik::image_view<image_data_rgba8>::pixel_type const* first_row = view.getRow(0);
|
||||
mapnik::image_view<image_data_rgba8>::pixel_type const first_pixel = first_row[0];
|
||||
for (unsigned y = 0; y < view.height(); ++y)
|
||||
{
|
||||
mapnik::image_view<image_data_32>::pixel_type const * row = view.getRow(y);
|
||||
mapnik::image_view<image_data_rgba8>::pixel_type const * row = view.getRow(y);
|
||||
for (unsigned x = 0; x < view.width(); ++x)
|
||||
{
|
||||
if (first_pixel != row[x])
|
||||
|
@ -110,20 +110,20 @@ bool is_solid(image_view<image_data_32> const& view)
|
|||
return true;
|
||||
}
|
||||
|
||||
void save_view1(image_view<image_data_32> const& view,
|
||||
void save_view1(image_view<image_data_rgba8> const& view,
|
||||
std::string const& filename)
|
||||
{
|
||||
save_to_file(view,filename);
|
||||
}
|
||||
|
||||
void save_view2(image_view<image_data_32> const& view,
|
||||
void save_view2(image_view<image_data_rgba8> const& view,
|
||||
std::string const& filename,
|
||||
std::string const& type)
|
||||
{
|
||||
save_to_file(view,filename,type);
|
||||
}
|
||||
|
||||
void save_view3(image_view<image_data_32> const& view,
|
||||
void save_view3(image_view<image_data_rgba8> const& view,
|
||||
std::string const& filename,
|
||||
std::string const& type,
|
||||
mapnik::rgba_palette const& pal)
|
||||
|
@ -135,9 +135,9 @@ void save_view3(image_view<image_data_32> const& view,
|
|||
void export_image_view()
|
||||
{
|
||||
using namespace boost::python;
|
||||
class_<image_view<image_data_32> >("ImageView","A view into an image.",no_init)
|
||||
.def("width",&image_view<image_data_32>::width)
|
||||
.def("height",&image_view<image_data_32>::height)
|
||||
class_<image_view<image_data_rgba8> >("ImageView","A view into an image.",no_init)
|
||||
.def("width",&image_view<image_data_rgba8>::width)
|
||||
.def("height",&image_view<image_data_rgba8>::height)
|
||||
.def("is_solid",&is_solid)
|
||||
.def("tostring",&view_tostring1)
|
||||
.def("tostring",&view_tostring2)
|
||||
|
|
|
@ -201,7 +201,7 @@ struct symbolizer_icon : public mapnik::util::static_visitor<QIcon>
|
|||
{
|
||||
// FIXME!
|
||||
/*
|
||||
std::shared_ptr<mapnik::image_data_32> symbol = sym.get_image();
|
||||
std::shared_ptr<mapnik::image_data_rgba8> symbol = sym.get_image();
|
||||
if (symbol)
|
||||
{
|
||||
QImage image(symbol->getBytes(),
|
||||
|
|
995
deps/agg/include/agg_color_gray.h
vendored
995
deps/agg/include/agg_color_gray.h
vendored
File diff suppressed because it is too large
Load diff
1159
deps/agg/include/agg_color_rgba.h
vendored
1159
deps/agg/include/agg_color_rgba.h
vendored
File diff suppressed because it is too large
Load diff
9
deps/agg/include/agg_gamma_functions.h
vendored
9
deps/agg/include/agg_gamma_functions.h
vendored
|
@ -120,6 +120,15 @@ namespace agg
|
|||
double m_mul;
|
||||
};
|
||||
|
||||
inline double sRGB_to_linear(double x)
|
||||
{
|
||||
return (x <= 0.04045) ? (x / 12.92) : pow((x + 0.055) / (1.055), 2.4);
|
||||
}
|
||||
|
||||
inline double linear_to_sRGB(double x)
|
||||
{
|
||||
return (x <= 0.0031308) ? (x * 12.92) : (1.055 * pow(x, 1 / 2.4) - 0.055);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
184
deps/agg/include/agg_gamma_lut.h
vendored
184
deps/agg/include/agg_gamma_lut.h
vendored
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <cmath>
|
||||
#include "agg_basics.h"
|
||||
#include "agg_gamma_functions.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
@ -116,6 +117,189 @@ namespace agg
|
|||
HiResT* m_dir_gamma;
|
||||
LoResT* m_inv_gamma;
|
||||
};
|
||||
|
||||
//
|
||||
// sRGB support classes
|
||||
//
|
||||
|
||||
// Optimized sRGB lookup table. The direct conversion (sRGB to linear)
|
||||
// is a straightforward lookup. The inverse conversion (linear to sRGB)
|
||||
// is implemented using binary search.
|
||||
template<class LinearType>
|
||||
class sRGB_lut_base
|
||||
{
|
||||
public:
|
||||
LinearType dir(int8u v) const
|
||||
{
|
||||
return m_dir_table[v];
|
||||
}
|
||||
|
||||
int8u inv(LinearType v) const
|
||||
{
|
||||
// Unrolled binary search.
|
||||
int8u x = 0;
|
||||
if (v > m_inv_table[128]) x = 128;
|
||||
if (v > m_inv_table[x + 64]) x += 64;
|
||||
if (v > m_inv_table[x + 32]) x += 32;
|
||||
if (v > m_inv_table[x + 16]) x += 16;
|
||||
if (v > m_inv_table[x + 8]) x += 8;
|
||||
if (v > m_inv_table[x + 4]) x += 4;
|
||||
if (v > m_inv_table[x + 2]) x += 2;
|
||||
if (v > m_inv_table[x + 1]) x += 1;
|
||||
return x;
|
||||
}
|
||||
|
||||
protected:
|
||||
LinearType m_dir_table[256];
|
||||
LinearType m_inv_table[256];
|
||||
|
||||
// Only derived classes may instantiate.
|
||||
sRGB_lut_base()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// sRGB_lut - implements sRGB conversion for the various types.
|
||||
// Base template is undefined, specializations are provided below.
|
||||
template<class LinearType>
|
||||
class sRGB_lut;
|
||||
|
||||
template<>
|
||||
class sRGB_lut<float> : public sRGB_lut_base<float>
|
||||
{
|
||||
public:
|
||||
sRGB_lut()
|
||||
{
|
||||
// Generate lookup tables.
|
||||
m_dir_table[0] = 0;
|
||||
m_inv_table[0] = 0;
|
||||
for (unsigned i = 1; i <= 255; ++i)
|
||||
{
|
||||
// Floating-point RGB is in range [0,1].
|
||||
m_dir_table[i] = float(sRGB_to_linear(i / 255.0));
|
||||
m_inv_table[i] = float(sRGB_to_linear((i - 0.5) / 255.0));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class sRGB_lut<int16u> : public sRGB_lut_base<int16u>
|
||||
{
|
||||
public:
|
||||
sRGB_lut()
|
||||
{
|
||||
// Generate lookup tables.
|
||||
m_dir_table[0] = 0;
|
||||
m_inv_table[0] = 0;
|
||||
for (unsigned i = 1; i <= 255; ++i)
|
||||
{
|
||||
// 16-bit RGB is in range [0,65535].
|
||||
m_dir_table[i] = uround(65535.0 * sRGB_to_linear(i / 255.0));
|
||||
m_inv_table[i] = uround(65535.0 * sRGB_to_linear((i - 0.5) / 255.0));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class sRGB_lut<int8u> : public sRGB_lut_base<int8u>
|
||||
{
|
||||
public:
|
||||
sRGB_lut()
|
||||
{
|
||||
// Generate lookup tables.
|
||||
m_dir_table[0] = 0;
|
||||
m_inv_table[0] = 0;
|
||||
for (unsigned i = 1; i <= 255; ++i)
|
||||
{
|
||||
// 8-bit RGB is handled with simple bidirectional lookup tables.
|
||||
m_dir_table[i] = uround(255.0 * sRGB_to_linear(i / 255.0));
|
||||
m_inv_table[i] = uround(255.0 * linear_to_sRGB(i / 255.0));
|
||||
}
|
||||
}
|
||||
|
||||
int8u inv(int8u v) const
|
||||
{
|
||||
// In this case, the inverse transform is a simple lookup.
|
||||
return m_inv_table[v];
|
||||
}
|
||||
};
|
||||
|
||||
// Common base class for sRGB_conv objects. Defines an internal
|
||||
// sRGB_lut object so that users don't have to.
|
||||
template<class T>
|
||||
class sRGB_conv_base
|
||||
{
|
||||
public:
|
||||
static T rgb_from_sRGB(int8u x)
|
||||
{
|
||||
return lut.dir(x);
|
||||
}
|
||||
|
||||
static int8u rgb_to_sRGB(T x)
|
||||
{
|
||||
return lut.inv(x);
|
||||
}
|
||||
|
||||
private:
|
||||
static sRGB_lut<T> lut;
|
||||
};
|
||||
|
||||
// Definition of sRGB_conv_base::lut. Due to the fact that this a template,
|
||||
// we don't need to place the definition in a cpp file. Hurrah.
|
||||
template<class T>
|
||||
sRGB_lut<T> sRGB_conv_base<T>::lut;
|
||||
|
||||
// Wrapper for sRGB-linear conversion.
|
||||
// Base template is undefined, specializations are provided below.
|
||||
template<class T>
|
||||
class sRGB_conv;
|
||||
|
||||
template<>
|
||||
class sRGB_conv<float> : public sRGB_conv_base<float>
|
||||
{
|
||||
public:
|
||||
static float alpha_from_sRGB(int8u x)
|
||||
{
|
||||
return float(x / 255.0);
|
||||
}
|
||||
|
||||
static int8u alpha_to_sRGB(float x)
|
||||
{
|
||||
if (x <= 0) return 0;
|
||||
else if (x >= 1) return 255;
|
||||
else return int8u(0.5 + x * 255);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class sRGB_conv<int16u> : public sRGB_conv_base<int16u>
|
||||
{
|
||||
public:
|
||||
static int16u alpha_from_sRGB(int8u x)
|
||||
{
|
||||
return (x << 8) | x;
|
||||
}
|
||||
|
||||
static int8u alpha_to_sRGB(int16u x)
|
||||
{
|
||||
return x >> 8;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class sRGB_conv<int8u> : public sRGB_conv_base<int8u>
|
||||
{
|
||||
public:
|
||||
static int8u alpha_from_sRGB(int8u x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
static int8u alpha_to_sRGB(int8u x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
97
deps/agg/include/agg_pixfmt_base.h
vendored
Normal file
97
deps/agg/include/agg_pixfmt_base.h
vendored
Normal file
|
@ -0,0 +1,97 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies.
|
||||
// This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: mcseem@antigrain.com
|
||||
// mcseemagg@yahoo.com
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_PIXFMT_BASE_INCLUDED
|
||||
#define AGG_PIXFMT_BASE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_color_gray.h"
|
||||
#include "agg_color_rgba.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
struct pixfmt_gray_tag
|
||||
{
|
||||
};
|
||||
|
||||
struct pixfmt_rgb_tag
|
||||
{
|
||||
};
|
||||
|
||||
struct pixfmt_rgba_tag
|
||||
{
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------blender_base
|
||||
template<class ColorT, class Order = void>
|
||||
struct blender_base
|
||||
{
|
||||
typedef ColorT color_type;
|
||||
typedef Order order_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
|
||||
static rgba get(value_type r, value_type g, value_type b, value_type a, cover_type cover = cover_full)
|
||||
{
|
||||
if (cover > cover_none)
|
||||
{
|
||||
rgba c(
|
||||
color_type::to_double(r),
|
||||
color_type::to_double(g),
|
||||
color_type::to_double(b),
|
||||
color_type::to_double(a));
|
||||
|
||||
if (cover < cover_full)
|
||||
{
|
||||
double x = double(cover) / cover_full;
|
||||
c.r *= x;
|
||||
c.g *= x;
|
||||
c.b *= x;
|
||||
c.a *= x;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
else return rgba::no_color();
|
||||
}
|
||||
|
||||
static rgba get(const value_type* p, cover_type cover = cover_full)
|
||||
{
|
||||
return get(
|
||||
p[order_type::R],
|
||||
p[order_type::G],
|
||||
p[order_type::B],
|
||||
p[order_type::A],
|
||||
cover);
|
||||
}
|
||||
|
||||
static void set(value_type* p, value_type r, value_type g, value_type b, value_type a)
|
||||
{
|
||||
p[order_type::R] = r;
|
||||
p[order_type::G] = g;
|
||||
p[order_type::B] = b;
|
||||
p[order_type::A] = a;
|
||||
}
|
||||
|
||||
static void set(value_type* p, const rgba& c)
|
||||
{
|
||||
p[order_type::R] = color_type::from_double(c.r);
|
||||
p[order_type::G] = color_type::from_double(c.g);
|
||||
p[order_type::B] = color_type::from_double(c.b);
|
||||
p[order_type::A] = color_type::from_double(c.a);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
465
deps/agg/include/agg_pixfmt_gray.h
vendored
465
deps/agg/include/agg_pixfmt_gray.h
vendored
|
@ -25,8 +25,7 @@
|
|||
#define AGG_PIXFMT_GRAY_INCLUDED
|
||||
|
||||
#include <cstring>
|
||||
#include "agg_basics.h"
|
||||
#include "agg_color_gray.h"
|
||||
#include "agg_pixfmt_base.h"
|
||||
#include "agg_rendering_buffer.h"
|
||||
|
||||
namespace agg
|
||||
|
@ -38,12 +37,22 @@ namespace agg
|
|||
typedef ColorT color_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
enum base_scale_e { base_shift = color_type::base_shift };
|
||||
typedef typename color_type::long_type long_type;
|
||||
|
||||
static AGG_INLINE void blend_pix(value_type* p, unsigned cv,
|
||||
unsigned alpha, unsigned cover=0)
|
||||
// Blend pixels using the non-premultiplied form of Alvy-Ray Smith's
|
||||
// compositing function. Since the render buffer is opaque we skip the
|
||||
// initial premultiply and final demultiply.
|
||||
|
||||
static AGG_INLINE void blend_pix(value_type* p,
|
||||
value_type cv, value_type alpha, cover_type cover)
|
||||
{
|
||||
*p = (value_type)((((cv - calc_type(*p)) * alpha) + (calc_type(*p) << base_shift)) >> base_shift);
|
||||
blend_pix(p, cv, color_type::mult_cover(alpha, cover));
|
||||
}
|
||||
|
||||
static AGG_INLINE void blend_pix(value_type* p,
|
||||
value_type cv, value_type alpha)
|
||||
{
|
||||
*p = color_type::lerp(*p, cv, alpha);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -54,20 +63,21 @@ namespace agg
|
|||
typedef ColorT color_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
enum base_scale_e { base_shift = color_type::base_shift };
|
||||
typedef typename color_type::long_type long_type;
|
||||
|
||||
static AGG_INLINE void blend_pix(value_type* p, unsigned cv,
|
||||
unsigned alpha, unsigned cover)
|
||||
// Blend pixels using the premultiplied form of Alvy-Ray Smith's
|
||||
// compositing function.
|
||||
|
||||
static AGG_INLINE void blend_pix(value_type* p,
|
||||
value_type cv, value_type alpha, cover_type cover)
|
||||
{
|
||||
alpha = color_type::base_mask - alpha;
|
||||
cover = (cover + 1) << (base_shift - 8);
|
||||
*p = (value_type)((*p * alpha + cv * cover) >> base_shift);
|
||||
blend_pix(p, color_type::mult_cover(cv, cover), color_type::mult_cover(alpha, cover));
|
||||
}
|
||||
|
||||
static AGG_INLINE void blend_pix(value_type* p, unsigned cv,
|
||||
unsigned alpha)
|
||||
static AGG_INLINE void blend_pix(value_type* p,
|
||||
value_type cv, value_type alpha)
|
||||
{
|
||||
*p = (value_type)(((*p * (color_type::base_mask - alpha)) >> base_shift) + cv);
|
||||
*p = color_type::prelerp(*p, cv, alpha);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -112,10 +122,11 @@ namespace agg
|
|||
|
||||
|
||||
//=================================================pixfmt_alpha_blend_gray
|
||||
template<class Blender, class RenBuf, unsigned Step=1, unsigned Offset=0>
|
||||
template<class Blender, class RenBuf, unsigned Step = 1, unsigned Offset = 0>
|
||||
class pixfmt_alpha_blend_gray
|
||||
{
|
||||
public:
|
||||
typedef pixfmt_gray_tag pixfmt_category;
|
||||
typedef RenBuf rbuf_type;
|
||||
typedef typename rbuf_type::row_data row_data;
|
||||
typedef Blender blender_type;
|
||||
|
@ -123,54 +134,117 @@ namespace agg
|
|||
typedef int order_type; // A fake one
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
enum base_scale_e
|
||||
enum
|
||||
{
|
||||
base_shift = color_type::base_shift,
|
||||
base_scale = color_type::base_scale,
|
||||
base_mask = color_type::base_mask,
|
||||
pix_width = sizeof(value_type),
|
||||
num_components = 1,
|
||||
pix_width = sizeof(value_type) * Step,
|
||||
pix_step = Step,
|
||||
pix_offset = Offset
|
||||
pix_offset = Offset,
|
||||
};
|
||||
struct pixel_type
|
||||
{
|
||||
value_type c[num_components];
|
||||
|
||||
void set(value_type v)
|
||||
{
|
||||
c[0] = v;
|
||||
}
|
||||
|
||||
void set(const color_type& color)
|
||||
{
|
||||
set(color.v);
|
||||
}
|
||||
|
||||
void get(value_type& v) const
|
||||
{
|
||||
v = c[0];
|
||||
}
|
||||
|
||||
color_type get() const
|
||||
{
|
||||
return color_type(c[0]);
|
||||
}
|
||||
|
||||
pixel_type* next()
|
||||
{
|
||||
return (pixel_type*)(c + pix_step);
|
||||
}
|
||||
|
||||
const pixel_type* next() const
|
||||
{
|
||||
return (const pixel_type*)(c + pix_step);
|
||||
}
|
||||
|
||||
pixel_type* advance(int n)
|
||||
{
|
||||
return (pixel_type*)(c + n * pix_step);
|
||||
}
|
||||
|
||||
const pixel_type* advance(int n) const
|
||||
{
|
||||
return (const pixel_type*)(c + n * pix_step);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
//--------------------------------------------------------------------
|
||||
static AGG_INLINE void copy_or_blend_pix(value_type* p,
|
||||
const color_type& c,
|
||||
AGG_INLINE void blend_pix(pixel_type* p,
|
||||
value_type v, value_type a,
|
||||
unsigned cover)
|
||||
{
|
||||
if (c.a)
|
||||
blender_type::blend_pix(p->c, v, a, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void blend_pix(pixel_type* p, value_type v, value_type a)
|
||||
{
|
||||
calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8;
|
||||
if(alpha == base_mask)
|
||||
blender_type::blend_pix(p->c, v, a);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover)
|
||||
{
|
||||
*p = c.v;
|
||||
blender_type::blend_pix(p->c, c.v, c.a, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void blend_pix(pixel_type* p, const color_type& c)
|
||||
{
|
||||
blender_type::blend_pix(p->c, c.v, c.a);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover)
|
||||
{
|
||||
if (!c.is_transparent())
|
||||
{
|
||||
if (c.is_opaque() && cover == cover_mask)
|
||||
{
|
||||
p->set(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
Blender::blend_pix(p, c.v, alpha, cover);
|
||||
blend_pix(p, c, cover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static AGG_INLINE void copy_or_blend_pix(value_type* p,
|
||||
const color_type& c)
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c)
|
||||
{
|
||||
if (c.a)
|
||||
if (!c.is_transparent())
|
||||
{
|
||||
if(c.a == base_mask)
|
||||
if (c.is_opaque())
|
||||
{
|
||||
*p = c.v;
|
||||
p->set(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
Blender::blend_pix(p, c.v, c.a);
|
||||
blend_pix(p, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
//--------------------------------------------------------------------
|
||||
explicit pixfmt_alpha_blend_gray(rbuf_type& rb) :
|
||||
|
@ -183,7 +257,7 @@ namespace agg
|
|||
bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2)
|
||||
{
|
||||
rect_i r(x1, y1, x2, y2);
|
||||
if(r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1)))
|
||||
if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1)))
|
||||
{
|
||||
int stride = pixf.stride();
|
||||
m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1),
|
||||
|
@ -205,57 +279,94 @@ namespace agg
|
|||
const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); }
|
||||
row_data row(int y) const { return m_rbuf->row(y); }
|
||||
|
||||
const int8u* pix_ptr(int x, int y) const
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE int8u* pix_ptr(int x, int y)
|
||||
{
|
||||
return m_rbuf->row_ptr(y) + x * Step + Offset;
|
||||
return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset);
|
||||
}
|
||||
|
||||
int8u* pix_ptr(int x, int y)
|
||||
AGG_INLINE const int8u* pix_ptr(int x, int y) const
|
||||
{
|
||||
return m_rbuf->row_ptr(y) + x * Step + Offset;
|
||||
return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset);
|
||||
}
|
||||
|
||||
// Return pointer to pixel value, forcing row to be allocated.
|
||||
AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len)
|
||||
{
|
||||
return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step + pix_offset));
|
||||
}
|
||||
|
||||
// Return pointer to pixel value, or null if row not allocated.
|
||||
AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const
|
||||
{
|
||||
int8u* p = m_rbuf->row_ptr(y);
|
||||
return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step + pix_offset)) : 0;
|
||||
}
|
||||
|
||||
// Get pixel pointer from raw buffer pointer.
|
||||
AGG_INLINE static pixel_type* pix_value_ptr(void* p)
|
||||
{
|
||||
return (pixel_type*)((value_type*)p + pix_offset);
|
||||
}
|
||||
|
||||
// Get pixel pointer from raw buffer pointer.
|
||||
AGG_INLINE static const pixel_type* pix_value_ptr(const void* p)
|
||||
{
|
||||
return (const pixel_type*)((const value_type*)p + pix_offset);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE static void write_plain_color(void* p, color_type c)
|
||||
{
|
||||
// Grayscale formats are implicitly premultiplied.
|
||||
c.premultiply();
|
||||
pix_value_ptr(p)->set(c);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE static color_type read_plain_color(const void* p)
|
||||
{
|
||||
return pix_value_ptr(p)->get();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE static void make_pix(int8u* p, const color_type& c)
|
||||
{
|
||||
*(value_type*)p = c.v;
|
||||
((pixel_type*)p)->set(c);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE color_type pixel(int x, int y) const
|
||||
{
|
||||
value_type* p = (value_type*)m_rbuf->row_ptr(y) + x * Step + Offset;
|
||||
return color_type(*p);
|
||||
if (const pixel_type* p = pix_value_ptr(x, y))
|
||||
{
|
||||
return p->get();
|
||||
}
|
||||
return color_type::no_color();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void copy_pixel(int x, int y, const color_type& c)
|
||||
{
|
||||
*((value_type*)m_rbuf->row_ptr(x, y, 1) + x * Step + Offset) = c.v;
|
||||
pix_value_ptr(x, y, 1)->set(c);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover)
|
||||
{
|
||||
copy_or_blend_pix((value_type*)
|
||||
m_rbuf->row_ptr(x, y, 1) + x * Step + Offset,
|
||||
c,
|
||||
cover);
|
||||
copy_or_blend_pix(pix_value_ptr(x, y, 1), c, cover);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void copy_hline(int x, int y,
|
||||
unsigned len,
|
||||
const color_type& c)
|
||||
{
|
||||
value_type* p = (value_type*)
|
||||
m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
|
||||
|
||||
pixel_type* p = pix_value_ptr(x, y, len);
|
||||
do
|
||||
{
|
||||
*p = c.v;
|
||||
p += Step;
|
||||
p->set(c);
|
||||
p = p->next();
|
||||
}
|
||||
while(--len);
|
||||
}
|
||||
|
@ -268,12 +379,9 @@ namespace agg
|
|||
{
|
||||
do
|
||||
{
|
||||
value_type* p = (value_type*)
|
||||
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
|
||||
|
||||
*p = c.v;
|
||||
pix_value_ptr(x, y++, 1)->set(c);
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
|
||||
|
||||
|
@ -283,29 +391,27 @@ namespace agg
|
|||
const color_type& c,
|
||||
int8u cover)
|
||||
{
|
||||
if (c.a)
|
||||
if (!c.is_transparent())
|
||||
{
|
||||
value_type* p = (value_type*)
|
||||
m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
|
||||
pixel_type* p = pix_value_ptr(x, y, len);
|
||||
|
||||
calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8;
|
||||
if(alpha == base_mask)
|
||||
if (c.is_opaque() && cover == cover_mask)
|
||||
{
|
||||
do
|
||||
{
|
||||
*p = c.v;
|
||||
p += Step;
|
||||
p->set(c);
|
||||
p = p->next();
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
Blender::blend_pix(p, c.v, alpha, cover);
|
||||
p += Step;
|
||||
blend_pix(p, c, cover);
|
||||
p = p->next();
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -317,31 +423,23 @@ namespace agg
|
|||
const color_type& c,
|
||||
int8u cover)
|
||||
{
|
||||
if (c.a)
|
||||
if (!c.is_transparent())
|
||||
{
|
||||
value_type* p;
|
||||
calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8;
|
||||
if(alpha == base_mask)
|
||||
if (c.is_opaque() && cover == cover_mask)
|
||||
{
|
||||
do
|
||||
{
|
||||
p = (value_type*)
|
||||
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
|
||||
|
||||
*p = c.v;
|
||||
pix_value_ptr(x, y++, 1)->set(c);
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
p = (value_type*)
|
||||
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
|
||||
|
||||
Blender::blend_pix(p, c.v, alpha, cover);
|
||||
blend_pix(pix_value_ptr(x, y++, 1), c, cover);
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -353,26 +451,24 @@ namespace agg
|
|||
const color_type& c,
|
||||
const int8u* covers)
|
||||
{
|
||||
if (c.a)
|
||||
if (!c.is_transparent())
|
||||
{
|
||||
value_type* p = (value_type*)
|
||||
m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
|
||||
pixel_type* p = pix_value_ptr(x, y, len);
|
||||
|
||||
do
|
||||
{
|
||||
calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8;
|
||||
if(alpha == base_mask)
|
||||
if (c.is_opaque() && *covers == cover_mask)
|
||||
{
|
||||
*p = c.v;
|
||||
p->set(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
Blender::blend_pix(p, c.v, alpha, *covers);
|
||||
blend_pix(p, c, *covers);
|
||||
}
|
||||
p += Step;
|
||||
p = p->next();
|
||||
++covers;
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,26 +479,23 @@ namespace agg
|
|||
const color_type& c,
|
||||
const int8u* covers)
|
||||
{
|
||||
if (c.a)
|
||||
if (!c.is_transparent())
|
||||
{
|
||||
do
|
||||
{
|
||||
calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8;
|
||||
pixel_type* p = pix_value_ptr(x, y++, 1);
|
||||
|
||||
value_type* p = (value_type*)
|
||||
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
|
||||
|
||||
if(alpha == base_mask)
|
||||
if (c.is_opaque() && *covers == cover_mask)
|
||||
{
|
||||
*p = c.v;
|
||||
p->set(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
Blender::blend_pix(p, c.v, alpha, *covers);
|
||||
blend_pix(p, c, *covers);
|
||||
}
|
||||
++covers;
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -412,16 +505,14 @@ namespace agg
|
|||
unsigned len,
|
||||
const color_type* colors)
|
||||
{
|
||||
value_type* p = (value_type*)
|
||||
m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
|
||||
pixel_type* p = pix_value_ptr(x, y, len);
|
||||
|
||||
do
|
||||
{
|
||||
*p = colors->v;
|
||||
p += Step;
|
||||
++colors;
|
||||
p->set(*colors++);
|
||||
p = p->next();
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
|
||||
|
||||
|
@ -432,12 +523,9 @@ namespace agg
|
|||
{
|
||||
do
|
||||
{
|
||||
value_type* p = (value_type*)
|
||||
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
|
||||
*p = colors->v;
|
||||
++colors;
|
||||
pix_value_ptr(x, y++, 1)->set(*colors++);
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
|
||||
|
||||
|
@ -448,51 +536,41 @@ namespace agg
|
|||
const int8u* covers,
|
||||
int8u cover)
|
||||
{
|
||||
value_type* p = (value_type*)
|
||||
m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
|
||||
pixel_type* p = pix_value_ptr(x, y, len);
|
||||
|
||||
if(covers)
|
||||
if (covers)
|
||||
{
|
||||
do
|
||||
{
|
||||
copy_or_blend_pix(p, *colors++, *covers++);
|
||||
p += Step;
|
||||
p = p->next();
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(cover == 255)
|
||||
if (cover == cover_mask)
|
||||
{
|
||||
do
|
||||
{
|
||||
if(colors->a == base_mask)
|
||||
{
|
||||
*p = colors->v;
|
||||
copy_or_blend_pix(p, *colors++);
|
||||
p = p->next();
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_or_blend_pix(p, *colors);
|
||||
}
|
||||
p += Step;
|
||||
++colors;
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
copy_or_blend_pix(p, *colors++, cover);
|
||||
p += Step;
|
||||
p = p->next();
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_color_vspan(int x, int y,
|
||||
unsigned len,
|
||||
|
@ -500,49 +578,31 @@ namespace agg
|
|||
const int8u* covers,
|
||||
int8u cover)
|
||||
{
|
||||
value_type* p;
|
||||
if(covers)
|
||||
if (covers)
|
||||
{
|
||||
do
|
||||
{
|
||||
p = (value_type*)
|
||||
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
|
||||
|
||||
copy_or_blend_pix(p, *colors++, *covers++);
|
||||
copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++);
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(cover == 255)
|
||||
if (cover == cover_mask)
|
||||
{
|
||||
do
|
||||
{
|
||||
p = (value_type*)
|
||||
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
|
||||
|
||||
if(colors->a == base_mask)
|
||||
{
|
||||
*p = colors->v;
|
||||
copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++);
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_or_blend_pix(p, *colors);
|
||||
}
|
||||
++colors;
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
p = (value_type*)
|
||||
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
|
||||
|
||||
copy_or_blend_pix(p, *colors++, cover);
|
||||
copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover);
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -551,22 +611,19 @@ namespace agg
|
|||
template<class Function> void for_each_pixel(Function f)
|
||||
{
|
||||
unsigned y;
|
||||
for(y = 0; y < height(); ++y)
|
||||
for (y = 0; y < height(); ++y)
|
||||
{
|
||||
row_data r = m_rbuf->row(y);
|
||||
if(r.ptr)
|
||||
if (r.ptr)
|
||||
{
|
||||
unsigned len = r.x2 - r.x1 + 1;
|
||||
|
||||
value_type* p = (value_type*)
|
||||
m_rbuf->row_ptr(r.x1, y, len) + r.x1 * Step + Offset;
|
||||
|
||||
pixel_type* p = pix_value_ptr(r.x1, y, len);
|
||||
do
|
||||
{
|
||||
f(p);
|
||||
p += Step;
|
||||
f(p->c);
|
||||
p = p->next();
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -590,8 +647,7 @@ namespace agg
|
|||
int xsrc, int ysrc,
|
||||
unsigned len)
|
||||
{
|
||||
const int8u* p = from.row_ptr(ysrc);
|
||||
if(p)
|
||||
if (const int8u* p = from.row_ptr(ysrc))
|
||||
{
|
||||
memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width,
|
||||
p + xsrc * pix_width,
|
||||
|
@ -600,6 +656,7 @@ namespace agg
|
|||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Blend from single color, using grayscale surface as alpha channel.
|
||||
template<class SrcPixelFormatRenderer>
|
||||
void blend_from_color(const SrcPixelFormatRenderer& from,
|
||||
const color_type& color,
|
||||
|
@ -608,25 +665,26 @@ namespace agg
|
|||
unsigned len,
|
||||
int8u cover)
|
||||
{
|
||||
typedef typename SrcPixelFormatRenderer::value_type src_value_type;
|
||||
const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc);
|
||||
if(psrc)
|
||||
typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
|
||||
typedef typename SrcPixelFormatRenderer::color_type src_color_type;
|
||||
|
||||
if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
|
||||
{
|
||||
value_type* pdst =
|
||||
(value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst;
|
||||
pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
|
||||
|
||||
do
|
||||
{
|
||||
copy_or_blend_pix(pdst,
|
||||
color,
|
||||
(*psrc * cover + base_mask) >> base_shift);
|
||||
++psrc;
|
||||
++pdst;
|
||||
copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0]));
|
||||
psrc = psrc->next();
|
||||
pdst = pdst->next();
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Blend from color table, using grayscale surface as indexes into table.
|
||||
// Obviously, this only works for integer value types.
|
||||
template<class SrcPixelFormatRenderer>
|
||||
void blend_from_lut(const SrcPixelFormatRenderer& from,
|
||||
const color_type* color_lut,
|
||||
|
@ -635,19 +693,19 @@ namespace agg
|
|||
unsigned len,
|
||||
int8u cover)
|
||||
{
|
||||
typedef typename SrcPixelFormatRenderer::value_type src_value_type;
|
||||
const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc);
|
||||
if(psrc)
|
||||
typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
|
||||
|
||||
if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
|
||||
{
|
||||
value_type* pdst =
|
||||
(value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst;
|
||||
pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
|
||||
|
||||
do
|
||||
{
|
||||
copy_or_blend_pix(pdst, color_lut[*psrc], cover);
|
||||
++psrc;
|
||||
++pdst;
|
||||
copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover);
|
||||
psrc = psrc->next();
|
||||
pdst = pdst->next();
|
||||
}
|
||||
while(--len);
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -656,15 +714,24 @@ namespace agg
|
|||
};
|
||||
|
||||
typedef blender_gray<gray8> blender_gray8;
|
||||
typedef blender_gray_pre<gray8> blender_gray8_pre;
|
||||
typedef blender_gray<sgray8> blender_sgray8;
|
||||
typedef blender_gray<gray16> blender_gray16;
|
||||
typedef blender_gray_pre<gray16> blender_gray16_pre;
|
||||
typedef blender_gray<gray32> blender_gray32;
|
||||
|
||||
typedef pixfmt_alpha_blend_gray<blender_gray8, rendering_buffer> pixfmt_gray8; //----pixfmt_gray8
|
||||
typedef pixfmt_alpha_blend_gray<blender_gray8_pre, rendering_buffer> pixfmt_gray8_pre; //----pixfmt_gray8_pre
|
||||
typedef pixfmt_alpha_blend_gray<blender_gray16, rendering_buffer> pixfmt_gray16; //----pixfmt_gray16
|
||||
typedef pixfmt_alpha_blend_gray<blender_gray16_pre, rendering_buffer> pixfmt_gray16_pre; //----pixfmt_gray16_pre
|
||||
typedef blender_gray_pre<gray8> blender_gray8_pre;
|
||||
typedef blender_gray_pre<sgray8> blender_sgray8_pre;
|
||||
typedef blender_gray_pre<gray16> blender_gray16_pre;
|
||||
typedef blender_gray_pre<gray32> blender_gray32_pre;
|
||||
|
||||
typedef pixfmt_alpha_blend_gray<blender_gray8, rendering_buffer> pixfmt_gray8;
|
||||
typedef pixfmt_alpha_blend_gray<blender_sgray8, rendering_buffer> pixfmt_sgray8;
|
||||
typedef pixfmt_alpha_blend_gray<blender_gray16, rendering_buffer> pixfmt_gray16;
|
||||
typedef pixfmt_alpha_blend_gray<blender_gray32, rendering_buffer> pixfmt_gray32;
|
||||
|
||||
typedef pixfmt_alpha_blend_gray<blender_gray8_pre, rendering_buffer> pixfmt_gray8_pre;
|
||||
typedef pixfmt_alpha_blend_gray<blender_sgray8_pre, rendering_buffer> pixfmt_sgray8_pre;
|
||||
typedef pixfmt_alpha_blend_gray<blender_gray16_pre, rendering_buffer> pixfmt_gray16_pre;
|
||||
typedef pixfmt_alpha_blend_gray<blender_gray32_pre, rendering_buffer> pixfmt_gray32_pre;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -133,6 +133,9 @@ which triggers locks
|
|||
|
||||
void my_function(std::string const& val); // if std::string or user type, pass by const&
|
||||
|
||||
#### Use unique_ptr instead of new/delete
|
||||
|
||||
#### Use std::copy instead of memcpy
|
||||
|
||||
#### When to use shared_ptr and unique_ptr
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace mapnik
|
|||
class pattern_source : private mapnik::noncopyable
|
||||
{
|
||||
public:
|
||||
pattern_source(image_data_32 const& pattern, double opacity = 1.0)
|
||||
pattern_source(image_data_rgba8 const& pattern, double opacity = 1.0)
|
||||
: pattern_(pattern),
|
||||
opacity_(opacity) {}
|
||||
|
||||
|
@ -57,7 +57,7 @@ public:
|
|||
static_cast<unsigned>(((c >> 24) & 0xff) * opacity_));
|
||||
}
|
||||
private:
|
||||
image_data_32 const& pattern_;
|
||||
image_data_rgba8 const& pattern_;
|
||||
double opacity_;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ private:
|
|||
class cairo_pattern : private mapnik::noncopyable
|
||||
{
|
||||
public:
|
||||
explicit cairo_pattern(image_data_32 const& data, double opacity = 1.0)
|
||||
explicit cairo_pattern(image_data_rgba8 const& data, double opacity = 1.0)
|
||||
{
|
||||
int pixels = data.width() * data.height();
|
||||
const unsigned int *in_ptr = data.getData();
|
||||
|
@ -308,8 +308,8 @@ public:
|
|||
void paint();
|
||||
void set_pattern(cairo_pattern const& pattern);
|
||||
void set_gradient(cairo_gradient const& pattern, box2d<double> const& bbox);
|
||||
void add_image(double x, double y, image_data_32 & data, double opacity = 1.0);
|
||||
void add_image(agg::trans_affine const& tr, image_data_32 & data, double opacity = 1.0);
|
||||
void add_image(double x, double y, image_data_rgba8 & data, double opacity = 1.0);
|
||||
void add_image(agg::trans_affine const& tr, image_data_rgba8 & data, double opacity = 1.0);
|
||||
void set_font_face(cairo_face_manager & manager, face_ptr face);
|
||||
void set_font_matrix(cairo_matrix_t const& matrix);
|
||||
void set_matrix(cairo_matrix_t const& matrix);
|
||||
|
|
|
@ -53,7 +53,7 @@ private:
|
|||
unsigned width_;
|
||||
unsigned height_;
|
||||
boost::optional<color> background_;
|
||||
image_data_32 data_;
|
||||
image_data_rgba8 data_;
|
||||
bool painted_;
|
||||
bool premultiplied_;
|
||||
public:
|
||||
|
@ -98,12 +98,12 @@ public:
|
|||
|
||||
void set_alpha(float opacity);
|
||||
|
||||
inline const image_data_32& data() const
|
||||
inline const image_data_rgba8& data() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
inline image_data_32& data()
|
||||
inline image_data_rgba8& data()
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
@ -118,9 +118,9 @@ public:
|
|||
return data_.getBytes();
|
||||
}
|
||||
|
||||
inline image_view<image_data_32> get_view(unsigned x,unsigned y, unsigned w,unsigned h)
|
||||
inline image_view<image_data_rgba8> get_view(unsigned x,unsigned y, unsigned w,unsigned h)
|
||||
{
|
||||
return image_view<image_data_32>(x,y,w,h,data_);
|
||||
return image_view<image_data_rgba8>(x,y,w,h,data_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -151,7 +151,7 @@ public:
|
|||
return height_;
|
||||
}
|
||||
|
||||
inline void set_rectangle(int x0,int y0,image_data_32 const& data)
|
||||
inline void set_rectangle(int x0,int y0,image_data_rgba8 const& data)
|
||||
{
|
||||
box2d<int> ext0(0,0,width_,height_);
|
||||
box2d<int> ext1(x0,y0,x0+data.width(),y0+data.height());
|
||||
|
@ -175,7 +175,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
inline void set_rectangle_alpha(int x0,int y0,const image_data_32& data)
|
||||
inline void set_rectangle_alpha(int x0,int y0,const image_data_rgba8& data)
|
||||
{
|
||||
box2d<int> ext0(0,0,width_,height_);
|
||||
box2d<int> ext1(x0,y0,x0 + data.width(),y0 + data.height());
|
||||
|
@ -219,7 +219,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
inline void set_rectangle_alpha2(image_data_32 const& data, unsigned x0, unsigned y0, float opacity)
|
||||
inline void set_rectangle_alpha2(image_data_rgba8 const& data, unsigned x0, unsigned y0, float opacity)
|
||||
{
|
||||
box2d<int> ext0(0,0,width_,height_);
|
||||
box2d<int> ext1(x0,y0,x0 + data.width(),y0 + data.height());
|
||||
|
@ -267,7 +267,7 @@ public:
|
|||
}
|
||||
|
||||
template <typename MergeMethod>
|
||||
inline void merge_rectangle(image_data_32 const& data, unsigned x0, unsigned y0, float opacity)
|
||||
inline void merge_rectangle(image_data_rgba8 const& data, unsigned x0, unsigned y0, float opacity)
|
||||
{
|
||||
box2d<int> ext0(0,0,width_,height_);
|
||||
box2d<int> ext1(x0,y0,x0 + data.width(),y0 + data.height());
|
||||
|
|
|
@ -195,7 +195,7 @@ public:
|
|||
return height_;
|
||||
}
|
||||
|
||||
inline void set_rectangle(value_type id,image_data_32 const& data,int x0,int y0)
|
||||
inline void set_rectangle(value_type id,image_data_rgba8 const& data,int x0,int y0)
|
||||
{
|
||||
box2d<int> ext0(0,0,width_,height_);
|
||||
box2d<int> ext1(x0,y0,x0+data.width(),y0+data.height());
|
||||
|
|
|
@ -51,7 +51,7 @@ struct raster_markers_rasterizer_dispatch_grid : mapnik::noncopyable
|
|||
using RasterizerType = typename std::tuple_element<1,RendererContext>::type;
|
||||
using PixMapType = typename std::tuple_element<2,RendererContext>::type;
|
||||
|
||||
raster_markers_rasterizer_dispatch_grid(image_data_32 const& src,
|
||||
raster_markers_rasterizer_dispatch_grid(image_data_rgba8 const& src,
|
||||
agg::trans_affine const& marker_trans,
|
||||
markers_symbolizer const& sym,
|
||||
Detector & detector,
|
||||
|
@ -130,7 +130,7 @@ private:
|
|||
pixfmt_type pixf_;
|
||||
RendererBase renb_;
|
||||
RasterizerType & ras_;
|
||||
image_data_32 const& src_;
|
||||
image_data_rgba8 const& src_;
|
||||
agg::trans_affine const& marker_trans_;
|
||||
markers_symbolizer const& sym_;
|
||||
Detector & detector_;
|
||||
|
|
|
@ -82,21 +82,13 @@ enum composite_mode_e
|
|||
MAPNIK_DECL boost::optional<composite_mode_e> comp_op_from_string(std::string const& name);
|
||||
MAPNIK_DECL boost::optional<std::string> comp_op_to_string(composite_mode_e comp_op);
|
||||
|
||||
template <typename T1, typename T2>
|
||||
MAPNIK_DECL void composite(T1 & dst, T2 & src,
|
||||
template <typename T>
|
||||
MAPNIK_DECL void composite(T & dst, T & src,
|
||||
composite_mode_e mode,
|
||||
float opacity=1,
|
||||
int dx=0,
|
||||
int dy=0,
|
||||
bool premultiply_src=false);
|
||||
|
||||
extern template MAPNIK_DECL void composite<mapnik::image_data_32,mapnik::image_data_32>(mapnik::image_data_32 & dst,
|
||||
mapnik::image_data_32 & src,
|
||||
composite_mode_e mode,
|
||||
float opacity,
|
||||
int dx,
|
||||
int dy,
|
||||
bool premultiply_src);
|
||||
|
||||
}
|
||||
#endif // MAPNIK_IMAGE_COMPOSITING_HPP
|
||||
|
|
|
@ -150,6 +150,14 @@ public:
|
|||
{
|
||||
return height_;
|
||||
}
|
||||
inline unsigned getSize() const
|
||||
{
|
||||
return height_ * width_ * pixel_size;
|
||||
}
|
||||
inline unsigned getRowSize() const
|
||||
{
|
||||
return width_ * pixel_size;
|
||||
}
|
||||
inline void set(pixel_type const& t)
|
||||
{
|
||||
std::fill(pData_, pData_ + width_ * height_, t);
|
||||
|
@ -180,11 +188,21 @@ public:
|
|||
return pData_ + row * width_;
|
||||
}
|
||||
|
||||
inline const pixel_type* getRow(unsigned row, std::size_t x0) const
|
||||
{
|
||||
return pData_ + row * width_ + x0;
|
||||
}
|
||||
|
||||
inline pixel_type* getRow(unsigned row)
|
||||
{
|
||||
return pData_ + row * width_;
|
||||
}
|
||||
|
||||
inline pixel_type* getRow(unsigned row, std::size_t x0)
|
||||
{
|
||||
return pData_ + row * width_ + x0;
|
||||
}
|
||||
|
||||
inline void setRow(std::size_t row, pixel_type const* buf, std::size_t size)
|
||||
{
|
||||
assert(row < height_);
|
||||
|
@ -204,8 +222,10 @@ private:
|
|||
pixel_type *pData_;
|
||||
};
|
||||
|
||||
using image_data_32 = image_data<std::uint32_t>;
|
||||
using image_data_8 = image_data<byte> ;
|
||||
using image_data_rgba8 = image_data<std::uint32_t>;
|
||||
using image_data_gray8 = image_data<std::uint8_t> ;
|
||||
using image_data_gray16 = image_data<std::int16_t>;
|
||||
using image_data_gray32f = image_data<float>;
|
||||
}
|
||||
|
||||
#endif // MAPNIK_IMAGE_DATA_HPP
|
||||
|
|
112
include/mapnik/image_data_any.hpp
Normal file
112
include/mapnik/image_data_any.hpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2014 Artem Pavlenko
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef MAPNIK_IMAGE_DATA_ANY_HPP
|
||||
#define MAPNIK_IMAGE_DATA_ANY_HPP
|
||||
|
||||
#include <mapnik/image_data.hpp>
|
||||
#include <mapnik/util/variant.hpp>
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
struct image_data_null
|
||||
{
|
||||
unsigned char const* getBytes() const { return nullptr; }
|
||||
unsigned char* getBytes() { return nullptr;}
|
||||
std::size_t width() const { return 0; }
|
||||
std::size_t height() const { return 0; }
|
||||
};
|
||||
|
||||
using image_data_base = util::variant<image_data_null, image_data_rgba8, image_data_gray8, image_data_gray16, image_data_gray32f>;
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct get_bytes_visitor : util::static_visitor<unsigned char*>
|
||||
{
|
||||
template <typename T>
|
||||
unsigned char* operator()(T & data)
|
||||
{
|
||||
return data.getBytes();
|
||||
}
|
||||
};
|
||||
|
||||
struct get_bytes_visitor_const : util::static_visitor<unsigned char const*>
|
||||
{
|
||||
template <typename T>
|
||||
unsigned char const* operator()(T const& data) const
|
||||
{
|
||||
return data.getBytes();
|
||||
}
|
||||
};
|
||||
|
||||
struct get_width_visitor : util::static_visitor<std::size_t>
|
||||
{
|
||||
template <typename T>
|
||||
std::size_t operator()(T const& data) const
|
||||
{
|
||||
return data.width();
|
||||
}
|
||||
};
|
||||
|
||||
struct get_height_visitor : util::static_visitor<std::size_t>
|
||||
{
|
||||
template <typename T>
|
||||
std::size_t operator()(T const& data) const
|
||||
{
|
||||
return data.height();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
struct image_data_any : image_data_base
|
||||
{
|
||||
image_data_any() = default;
|
||||
|
||||
template <typename T>
|
||||
image_data_any(T && data) noexcept
|
||||
: image_data_base(std::move(data)) {}
|
||||
|
||||
unsigned char const* getBytes() const
|
||||
{
|
||||
return util::apply_visitor(detail::get_bytes_visitor_const(),*this);
|
||||
}
|
||||
|
||||
unsigned char* getBytes()
|
||||
{
|
||||
return util::apply_visitor(detail::get_bytes_visitor(),*this);
|
||||
}
|
||||
|
||||
std::size_t width() const
|
||||
{
|
||||
return util::apply_visitor(detail::get_width_visitor(),*this);
|
||||
}
|
||||
|
||||
std::size_t height() const
|
||||
{
|
||||
return util::apply_visitor(detail::get_height_visitor(),*this);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MAPNIK_IMAGE_DATA_ANY_HPP
|
|
@ -24,10 +24,11 @@
|
|||
#define MAPNIK_IMAGE_READER_HPP
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/image_data.hpp>
|
||||
#include <mapnik/image_data_any.hpp>
|
||||
#include <mapnik/config.hpp>
|
||||
#include <mapnik/noncopyable.hpp>
|
||||
#include <mapnik/factory.hpp>
|
||||
#include <mapnik/box2d.hpp>
|
||||
// boost
|
||||
#include <boost/optional.hpp>
|
||||
// stl
|
||||
|
@ -55,11 +56,13 @@ public:
|
|||
|
||||
struct MAPNIK_DECL image_reader : private mapnik::noncopyable
|
||||
{
|
||||
virtual unsigned width() const=0;
|
||||
virtual unsigned height() const=0;
|
||||
virtual bool has_alpha() const=0;
|
||||
virtual bool premultiplied_alpha() const=0;
|
||||
virtual void read(unsigned x,unsigned y,image_data_32& image)=0;
|
||||
virtual unsigned width() const = 0;
|
||||
virtual unsigned height() const = 0;
|
||||
virtual bool has_alpha() const = 0;
|
||||
virtual bool premultiplied_alpha() const = 0;
|
||||
virtual boost::optional<box2d<double> > bounding_box() const = 0;
|
||||
virtual void read(unsigned x,unsigned y,image_data_rgba8& image) = 0;
|
||||
virtual image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) = 0;
|
||||
virtual ~image_reader() {}
|
||||
};
|
||||
|
||||
|
@ -69,7 +72,7 @@ bool register_image_reader(std::string const& type, image_reader* (* fun)(Args..
|
|||
return factory<image_reader,std::string, Args...>::instance().register_product(type, fun);
|
||||
}
|
||||
|
||||
MAPNIK_DECL image_reader* get_image_reader(std::string const& file,std::string const& type);
|
||||
MAPNIK_DECL image_reader* get_image_reader(std::string const& file, std::string const& type);
|
||||
MAPNIK_DECL image_reader* get_image_reader(std::string const& file);
|
||||
MAPNIK_DECL image_reader* get_image_reader(char const* data, size_t size);
|
||||
|
||||
|
|
|
@ -60,25 +60,14 @@ enum scaling_method_e
|
|||
MAPNIK_DECL boost::optional<scaling_method_e> scaling_method_from_string(std::string const& name);
|
||||
MAPNIK_DECL boost::optional<std::string> scaling_method_to_string(scaling_method_e scaling_method);
|
||||
|
||||
template <typename Image>
|
||||
MAPNIK_DECL void scale_image_agg(Image & target,
|
||||
Image const& source,
|
||||
template <typename T>
|
||||
MAPNIK_DECL void scale_image_agg(T & target, T const& source,
|
||||
scaling_method_e scaling_method,
|
||||
double image_ratio_x,
|
||||
double image_ratio_y,
|
||||
double x_off_f,
|
||||
double y_off_f,
|
||||
double filter_factor);
|
||||
|
||||
extern template MAPNIK_DECL void scale_image_agg<mapnik::image_data_32>(
|
||||
mapnik::image_data_32 & target,
|
||||
mapnik::image_data_32 const& source,
|
||||
scaling_method_e scaling_method,
|
||||
double image_ratio_x,
|
||||
double image_ratio_y,
|
||||
double x_off_f,
|
||||
double y_off_f,
|
||||
double filter_radius);
|
||||
|
||||
}
|
||||
|
||||
#endif // MAPNIK_IMAGE_SCALING_HPP
|
||||
|
|
132
include/mapnik/image_scaling_traits.hpp
Normal file
132
include/mapnik/image_scaling_traits.hpp
Normal file
|
@ -0,0 +1,132 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2014 Artem Pavlenko
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef MAPNIK_IMAGE_SCALING_TRAITS_HPP
|
||||
#define MAPNIK_IMAGE_SCALING_TRAITS_HPP
|
||||
|
||||
// agg
|
||||
#include "agg_image_accessors.h"
|
||||
#include "agg_pixfmt_rgba.h"
|
||||
#include "agg_pixfmt_gray.h"
|
||||
#include "agg_span_allocator.h"
|
||||
#include "agg_span_image_filter_gray.h"
|
||||
#include "agg_span_image_filter_rgba.h"
|
||||
#include "agg_span_interpolator_linear.h"
|
||||
|
||||
namespace mapnik { namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct agg_scaling_traits {};
|
||||
|
||||
template <>
|
||||
struct agg_scaling_traits<image_data_rgba8>
|
||||
{
|
||||
using pixfmt_pre = agg::pixfmt_rgba32_pre;
|
||||
using color_type = agg::rgba8;
|
||||
using interpolator_type = agg::span_interpolator_linear<>;
|
||||
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
|
||||
using span_image_filter = agg::span_image_filter_rgba_nn<img_src_type,interpolator_type>;
|
||||
using span_image_resample_affine = agg::span_image_resample_rgba_affine<img_src_type>;
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
struct agg_scaling_traits<image_data_gray8>
|
||||
{
|
||||
using pixfmt_pre = agg::pixfmt_gray8_pre;
|
||||
using color_type = agg::gray8;
|
||||
using interpolator_type = agg::span_interpolator_linear<>;
|
||||
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
|
||||
using span_image_filter = agg::span_image_filter_gray_nn<img_src_type,interpolator_type>;
|
||||
using span_image_resample_affine = agg::span_image_resample_gray_affine<img_src_type>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct agg_scaling_traits<image_data_gray16>
|
||||
{
|
||||
using pixfmt_pre = agg::pixfmt_gray16_pre;
|
||||
using color_type = agg::gray16;
|
||||
using interpolator_type = agg::span_interpolator_linear<>;
|
||||
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
|
||||
using span_image_filter = agg::span_image_filter_gray_nn<img_src_type,interpolator_type>;
|
||||
using span_image_resample_affine = agg::span_image_resample_gray_affine<img_src_type>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct agg_scaling_traits<image_data_gray32f>
|
||||
{
|
||||
using pixfmt_pre = agg::pixfmt_gray32_pre;
|
||||
using color_type = agg::gray32;
|
||||
using interpolator_type = agg::span_interpolator_linear<>;
|
||||
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
|
||||
using span_image_filter = agg::span_image_filter_gray_nn<img_src_type,interpolator_type>;
|
||||
using span_image_resample_affine = agg::span_image_resample_gray_affine<img_src_type>;
|
||||
};
|
||||
|
||||
template <typename Filter>
|
||||
void set_scaling_method(Filter & filter, scaling_method_e scaling_method, double filter_factor)
|
||||
{
|
||||
switch(scaling_method)
|
||||
{
|
||||
case SCALING_BILINEAR:
|
||||
filter.calculate(agg::image_filter_bilinear(), true); break;
|
||||
case SCALING_BICUBIC:
|
||||
filter.calculate(agg::image_filter_bicubic(), true); break;
|
||||
case SCALING_SPLINE16:
|
||||
filter.calculate(agg::image_filter_spline16(), true); break;
|
||||
case SCALING_SPLINE36:
|
||||
filter.calculate(agg::image_filter_spline36(), true); break;
|
||||
case SCALING_HANNING:
|
||||
filter.calculate(agg::image_filter_hanning(), true); break;
|
||||
case SCALING_HAMMING:
|
||||
filter.calculate(agg::image_filter_hamming(), true); break;
|
||||
case SCALING_HERMITE:
|
||||
filter.calculate(agg::image_filter_hermite(), true); break;
|
||||
case SCALING_KAISER:
|
||||
filter.calculate(agg::image_filter_kaiser(), true); break;
|
||||
case SCALING_QUADRIC:
|
||||
filter.calculate(agg::image_filter_quadric(), true); break;
|
||||
case SCALING_CATROM:
|
||||
filter.calculate(agg::image_filter_catrom(), true); break;
|
||||
case SCALING_GAUSSIAN:
|
||||
filter.calculate(agg::image_filter_gaussian(), true); break;
|
||||
case SCALING_BESSEL:
|
||||
filter.calculate(agg::image_filter_bessel(), true); break;
|
||||
case SCALING_MITCHELL:
|
||||
filter.calculate(agg::image_filter_mitchell(), true); break;
|
||||
case SCALING_SINC:
|
||||
filter.calculate(agg::image_filter_sinc(filter_factor), true); break;
|
||||
case SCALING_LANCZOS:
|
||||
filter.calculate(agg::image_filter_lanczos(filter_factor), true); break;
|
||||
case SCALING_BLACKMAN:
|
||||
filter.calculate(agg::image_filter_blackman(filter_factor), true); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} //
|
||||
|
||||
|
||||
#endif // MAPNIK_IMAGE_SCALING_TRAITS_HPP
|
|
@ -249,76 +249,76 @@ MAPNIK_DECL void save_to_stream(image_32 const& image,
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern template MAPNIK_DECL void save_to_file<image_data_32>(image_data_32 const&,
|
||||
extern template MAPNIK_DECL void save_to_file<image_data_rgba8>(image_data_rgba8 const&,
|
||||
std::string const&,
|
||||
std::string const&,
|
||||
rgba_palette const&);
|
||||
|
||||
extern template MAPNIK_DECL void save_to_file<image_data_32>(image_data_32 const&,
|
||||
extern template MAPNIK_DECL void save_to_file<image_data_rgba8>(image_data_rgba8 const&,
|
||||
std::string const&,
|
||||
std::string const&);
|
||||
|
||||
extern template MAPNIK_DECL void save_to_file<image_data_32>(image_data_32 const&,
|
||||
extern template MAPNIK_DECL void save_to_file<image_data_rgba8>(image_data_rgba8 const&,
|
||||
std::string const&,
|
||||
rgba_palette const&);
|
||||
|
||||
extern template MAPNIK_DECL void save_to_file<image_data_32>(image_data_32 const&,
|
||||
extern template MAPNIK_DECL void save_to_file<image_data_rgba8>(image_data_rgba8 const&,
|
||||
std::string const&);
|
||||
|
||||
|
||||
extern template MAPNIK_DECL void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
|
||||
extern template MAPNIK_DECL void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
|
||||
std::string const&,
|
||||
std::string const&,
|
||||
rgba_palette const&);
|
||||
|
||||
extern template MAPNIK_DECL void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
|
||||
extern template MAPNIK_DECL void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
|
||||
std::string const&,
|
||||
std::string const&);
|
||||
|
||||
extern template MAPNIK_DECL void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
|
||||
extern template MAPNIK_DECL void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
|
||||
std::string const&,
|
||||
rgba_palette const&);
|
||||
|
||||
extern template MAPNIK_DECL void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
|
||||
extern template MAPNIK_DECL void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
|
||||
std::string const&);
|
||||
|
||||
extern template MAPNIK_DECL std::string save_to_string<image_data_32>(image_data_32 const&,
|
||||
extern template MAPNIK_DECL std::string save_to_string<image_data_rgba8>(image_data_rgba8 const&,
|
||||
std::string const&);
|
||||
|
||||
extern template MAPNIK_DECL std::string save_to_string<image_data_32>(image_data_32 const&,
|
||||
extern template MAPNIK_DECL std::string save_to_string<image_data_rgba8>(image_data_rgba8 const&,
|
||||
std::string const&,
|
||||
rgba_palette const&);
|
||||
|
||||
extern template MAPNIK_DECL std::string save_to_string<image_view<image_data_32> > (image_view<image_data_32> const&,
|
||||
extern template MAPNIK_DECL std::string save_to_string<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
|
||||
std::string const&);
|
||||
|
||||
extern template MAPNIK_DECL std::string save_to_string<image_view<image_data_32> > (image_view<image_data_32> const&,
|
||||
extern template MAPNIK_DECL std::string save_to_string<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
|
||||
std::string const&,
|
||||
rgba_palette const&);
|
||||
#ifdef _MSC_VER
|
||||
|
||||
template MAPNIK_DECL void save_to_stream<image_data_32>(
|
||||
image_data_32 const& image,
|
||||
template MAPNIK_DECL void save_to_stream<image_data_rgba8>(
|
||||
image_data_rgba8 const& image,
|
||||
std::ostream & stream,
|
||||
std::string const& type,
|
||||
rgba_palette const& palette
|
||||
);
|
||||
|
||||
template MAPNIK_DECL void save_to_stream<image_data_32>(
|
||||
image_data_32 const& image,
|
||||
template MAPNIK_DECL void save_to_stream<image_data_rgba8>(
|
||||
image_data_rgba8 const& image,
|
||||
std::ostream & stream,
|
||||
std::string const& type
|
||||
);
|
||||
|
||||
template MAPNIK_DECL void save_to_stream<image_view<image_data_32> > (
|
||||
image_view<image_data_32> const& image,
|
||||
template MAPNIK_DECL void save_to_stream<image_view<image_data_rgba8> > (
|
||||
image_view<image_data_rgba8> const& image,
|
||||
std::ostream & stream,
|
||||
std::string const& type,
|
||||
rgba_palette const& palette
|
||||
);
|
||||
|
||||
template MAPNIK_DECL void save_to_stream<image_view<image_data_32> > (
|
||||
image_view<image_data_32> const& image,
|
||||
template MAPNIK_DECL void save_to_stream<image_view<image_data_rgba8> > (
|
||||
image_view<image_data_rgba8> const& image,
|
||||
std::ostream & stream,
|
||||
std::string const& type
|
||||
);
|
||||
|
|
|
@ -30,6 +30,7 @@ class image_view
|
|||
{
|
||||
public:
|
||||
using pixel_type = typename T::pixel_type;
|
||||
static constexpr std::size_t pixel_size = sizeof(pixel_type);
|
||||
|
||||
image_view(unsigned x, unsigned y, unsigned width, unsigned height, T const& data)
|
||||
: x_(x),
|
||||
|
@ -84,11 +85,26 @@ public:
|
|||
return height_;
|
||||
}
|
||||
|
||||
inline unsigned getSize() const
|
||||
{
|
||||
return height_ * width_ * pixel_size;
|
||||
}
|
||||
|
||||
inline unsigned getRowSize() const
|
||||
{
|
||||
return width_ * pixel_size;
|
||||
}
|
||||
|
||||
inline const pixel_type* getRow(unsigned row) const
|
||||
{
|
||||
return data_.getRow(row + y_) + x_;
|
||||
}
|
||||
|
||||
inline const pixel_type* getRow(unsigned row, std::size_t x0) const
|
||||
{
|
||||
return data_.getRow(row + y_, x0) + x_;
|
||||
}
|
||||
|
||||
inline const unsigned char* getBytes() const
|
||||
{
|
||||
return data_.getBytes();
|
||||
|
@ -101,6 +117,15 @@ public:
|
|||
{
|
||||
return data_;
|
||||
}
|
||||
inline pixel_type* getData()
|
||||
{
|
||||
return data_.getData();
|
||||
}
|
||||
inline const pixel_type* getData() const
|
||||
{
|
||||
return data_.getData();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
unsigned x_;
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace mapnik
|
|||
using attr_storage = agg::pod_bvector<mapnik::svg::path_attributes>;
|
||||
using svg_storage_type = mapnik::svg::svg_storage<mapnik::svg::svg_path_storage,attr_storage>;
|
||||
using svg_path_ptr = std::shared_ptr<svg_storage_type>;
|
||||
using image_ptr = std::shared_ptr<image_data_32>;
|
||||
using image_ptr = std::shared_ptr<image_data_rgba8>;
|
||||
/**
|
||||
* A class to hold either vector or bitmap marker data. This allows these to be treated equally
|
||||
* in the image caches and most of the render paths.
|
||||
|
@ -56,7 +56,7 @@ public:
|
|||
marker()
|
||||
{
|
||||
// create default OGC 4x4 black pixel
|
||||
bitmap_data_ = boost::optional<mapnik::image_ptr>(std::make_shared<image_data_32>(4,4));
|
||||
bitmap_data_ = boost::optional<mapnik::image_ptr>(std::make_shared<image_data_rgba8>(4,4));
|
||||
(*bitmap_data_)->set(0xff000000);
|
||||
}
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ struct raster_markers_rasterizer_dispatch : mapnik::noncopyable
|
|||
using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba<blender_type, BufferType>;
|
||||
using renderer_base = agg::renderer_base<pixfmt_comp_type>;
|
||||
|
||||
raster_markers_rasterizer_dispatch(image_data_32 const& src,
|
||||
raster_markers_rasterizer_dispatch(image_data_rgba8 const& src,
|
||||
agg::trans_affine const& marker_trans,
|
||||
symbolizer_base const& sym,
|
||||
Detector & detector,
|
||||
|
@ -300,7 +300,7 @@ private:
|
|||
pixfmt_comp_type pixf_;
|
||||
renderer_base renb_;
|
||||
RasterizerType & ras_;
|
||||
image_data_32 const& src_;
|
||||
image_data_rgba8 const& src_;
|
||||
agg::trans_affine const& marker_trans_;
|
||||
symbolizer_base const& sym_;
|
||||
Detector & detector_;
|
||||
|
|
|
@ -83,12 +83,12 @@ private:
|
|||
static const unsigned char IEND_tpl[];
|
||||
};
|
||||
|
||||
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_data_8>(image_data_8 const& image);
|
||||
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_view<image_data_8> >(image_view<image_data_8> const& image);
|
||||
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_data_32>(image_data_32 const& image);
|
||||
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_view<image_data_32> >(image_view<image_data_32> const& image);
|
||||
extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha<image_data_32>(image_data_32 const& image);
|
||||
extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha<image_view<image_data_32> >(image_view<image_data_32> const& image);
|
||||
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_data_gray8>(image_data_gray8 const& image);
|
||||
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_view<image_data_gray8> >(image_view<image_data_gray8> const& image);
|
||||
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_data_rgba8>(image_data_rgba8 const& image);
|
||||
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_view<image_data_rgba8> >(image_view<image_data_rgba8> const& image);
|
||||
extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha<image_data_rgba8>(image_data_rgba8 const& image);
|
||||
extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha<image_view<image_data_rgba8> >(image_view<image_data_rgba8> const& image);
|
||||
|
||||
}}
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ void save_as_png(T1 & file,
|
|||
|
||||
template <typename T>
|
||||
void reduce_8(T const& in,
|
||||
image_data_8 & out,
|
||||
image_data_gray8 & out,
|
||||
octree<rgb> trees[],
|
||||
unsigned limits[],
|
||||
unsigned levels,
|
||||
|
@ -166,8 +166,8 @@ void reduce_8(T const& in,
|
|||
}
|
||||
for (unsigned y = 0; y < height; ++y)
|
||||
{
|
||||
mapnik::image_data_32::pixel_type const * row = in.getRow(y);
|
||||
mapnik::image_data_8::pixel_type * row_out = out.getRow(y);
|
||||
mapnik::image_data_rgba8::pixel_type const * row = in.getRow(y);
|
||||
mapnik::image_data_gray8::pixel_type * row_out = out.getRow(y);
|
||||
for (unsigned x = 0; x < width; ++x)
|
||||
{
|
||||
unsigned val = row[x];
|
||||
|
@ -200,7 +200,7 @@ void reduce_8(T const& in,
|
|||
|
||||
template <typename T>
|
||||
void reduce_4(T const& in,
|
||||
image_data_8 & out,
|
||||
image_data_gray8 & out,
|
||||
octree<rgb> trees[],
|
||||
unsigned limits[],
|
||||
unsigned levels,
|
||||
|
@ -217,8 +217,8 @@ void reduce_4(T const& in,
|
|||
}
|
||||
for (unsigned y = 0; y < height; ++y)
|
||||
{
|
||||
mapnik::image_data_32::pixel_type const * row = in.getRow(y);
|
||||
mapnik::image_data_8::pixel_type * row_out = out.getRow(y);
|
||||
mapnik::image_data_rgba8::pixel_type const * row = in.getRow(y);
|
||||
mapnik::image_data_gray8::pixel_type * row_out = out.getRow(y);
|
||||
for (unsigned x = 0; x < width; ++x)
|
||||
{
|
||||
unsigned val = row[x];
|
||||
|
@ -256,7 +256,7 @@ void reduce_4(T const& in,
|
|||
// 1-bit but only one color.
|
||||
template <typename T>
|
||||
void reduce_1(T const&,
|
||||
image_data_8 & out,
|
||||
image_data_gray8 & out,
|
||||
octree<rgb> /*trees*/[],
|
||||
unsigned /*limits*/[],
|
||||
std::vector<unsigned> & /*alpha*/)
|
||||
|
@ -266,7 +266,7 @@ void reduce_1(T const&,
|
|||
|
||||
template <typename T>
|
||||
void save_as_png(T & file, std::vector<mapnik::rgb> const& palette,
|
||||
mapnik::image_data_8 const& image,
|
||||
mapnik::image_data_gray8 const& image,
|
||||
unsigned width,
|
||||
unsigned height,
|
||||
unsigned color_depth,
|
||||
|
@ -556,7 +556,7 @@ void save_as_png8_oct(T1 & file,
|
|||
if (palette.size() > 16 )
|
||||
{
|
||||
// >16 && <=256 colors -> write 8-bit color depth
|
||||
image_data_8 reduced_image(width,height);
|
||||
image_data_gray8 reduced_image(width,height);
|
||||
reduce_8(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable);
|
||||
save_as_png(file,palette,reduced_image,width,height,8,alphaTable,opts);
|
||||
}
|
||||
|
@ -565,7 +565,7 @@ void save_as_png8_oct(T1 & file,
|
|||
// 1 color image -> write 1-bit color depth PNG
|
||||
unsigned image_width = ((width + 15) >> 3) & ~1U; // 1-bit image, round up to 16-bit boundary
|
||||
unsigned image_height = height;
|
||||
image_data_8 reduced_image(image_width,image_height);
|
||||
image_data_gray8 reduced_image(image_width,image_height);
|
||||
reduce_1(image,reduced_image,trees, limits, alphaTable);
|
||||
if (meanAlpha<255 && cols[0]==0)
|
||||
{
|
||||
|
@ -579,7 +579,7 @@ void save_as_png8_oct(T1 & file,
|
|||
// <=16 colors -> write 4-bit color depth PNG
|
||||
unsigned image_width = ((width + 7) >> 1) & ~3U; // 4-bit image, round up to 32-bit boundary
|
||||
unsigned image_height = height;
|
||||
image_data_8 reduced_image(image_width,image_height);
|
||||
image_data_gray8 reduced_image(image_width,image_height);
|
||||
reduce_4(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable);
|
||||
save_as_png(file,palette,reduced_image,width,height,4,alphaTable,opts);
|
||||
}
|
||||
|
@ -600,11 +600,11 @@ void save_as_png8(T1 & file,
|
|||
if (palette.size() > 16 )
|
||||
{
|
||||
// >16 && <=256 colors -> write 8-bit color depth
|
||||
image_data_8 reduced_image(width, height);
|
||||
image_data_gray8 reduced_image(width, height);
|
||||
for (unsigned y = 0; y < height; ++y)
|
||||
{
|
||||
mapnik::image_data_32::pixel_type const * row = image.getRow(y);
|
||||
mapnik::image_data_8::pixel_type * row_out = reduced_image.getRow(y);
|
||||
mapnik::image_data_rgba8::pixel_type const * row = image.getRow(y);
|
||||
mapnik::image_data_gray8::pixel_type * row_out = reduced_image.getRow(y);
|
||||
for (unsigned x = 0; x < width; ++x)
|
||||
{
|
||||
row_out[x] = tree.quantize(row[x]);
|
||||
|
@ -617,7 +617,7 @@ void save_as_png8(T1 & file,
|
|||
// 1 color image -> write 1-bit color depth PNG
|
||||
unsigned image_width = ((width + 15) >> 3) & ~1U; // 1-bit image, round up to 16-bit boundary
|
||||
unsigned image_height = height;
|
||||
image_data_8 reduced_image(image_width, image_height);
|
||||
image_data_gray8 reduced_image(image_width, image_height);
|
||||
reduced_image.set(0);
|
||||
save_as_png(file, palette, reduced_image, width, height, 1, alphaTable, opts);
|
||||
}
|
||||
|
@ -626,11 +626,11 @@ void save_as_png8(T1 & file,
|
|||
// <=16 colors -> write 4-bit color depth PNG
|
||||
unsigned image_width = ((width + 7) >> 1) & ~3U; // 4-bit image, round up to 32-bit boundary
|
||||
unsigned image_height = height;
|
||||
image_data_8 reduced_image(image_width, image_height);
|
||||
image_data_gray8 reduced_image(image_width, image_height);
|
||||
for (unsigned y = 0; y < height; ++y)
|
||||
{
|
||||
mapnik::image_data_32::pixel_type const * row = image.getRow(y);
|
||||
mapnik::image_data_8::pixel_type * row_out = reduced_image.getRow(y);
|
||||
mapnik::image_data_rgba8::pixel_type const * row = image.getRow(y);
|
||||
mapnik::image_data_gray8::pixel_type * row_out = reduced_image.getRow(y);
|
||||
byte index = 0;
|
||||
for (unsigned x = 0; x < width; ++x)
|
||||
{
|
||||
|
|
|
@ -25,33 +25,28 @@
|
|||
|
||||
// mapnik
|
||||
#include <mapnik/box2d.hpp>
|
||||
#include <mapnik/image_data.hpp>
|
||||
#include <mapnik/image_data_any.hpp>
|
||||
#include <mapnik/noncopyable.hpp>
|
||||
|
||||
#include <mapnik/util/variant.hpp>
|
||||
// boost
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
class raster : private mapnik::noncopyable
|
||||
{
|
||||
public:
|
||||
box2d<double> ext_;
|
||||
image_data_32 data_;
|
||||
image_data_any data_;
|
||||
double filter_factor_;
|
||||
bool premultiplied_alpha_;
|
||||
boost::optional<double> nodata_;
|
||||
|
||||
template <typename ImageData>
|
||||
raster(box2d<double> const& ext,
|
||||
unsigned width,
|
||||
unsigned height,
|
||||
ImageData && data,
|
||||
double filter_factor,
|
||||
bool premultiplied_alpha = false)
|
||||
: ext_(ext),
|
||||
data_(width,height),
|
||||
filter_factor_(filter_factor),
|
||||
premultiplied_alpha_(premultiplied_alpha) {}
|
||||
|
||||
raster(box2d<double> const& ext, image_data_32 && data,
|
||||
double filter_factor, bool premultiplied_alpha = false)
|
||||
: ext_(ext),
|
||||
data_(std::move(data)),
|
||||
filter_factor_(filter_factor),
|
||||
|
|
|
@ -40,7 +40,9 @@
|
|||
#include <mapnik/config.hpp>
|
||||
#include <mapnik/color.hpp>
|
||||
#include <mapnik/enumeration.hpp>
|
||||
|
||||
#include <mapnik/image_data.hpp>
|
||||
// boost
|
||||
#include <boost/optional.hpp>
|
||||
// boost
|
||||
#include <memory>
|
||||
|
||||
|
@ -195,12 +197,8 @@ public:
|
|||
//! \return The list of stops
|
||||
colorizer_stops const& get_stops() const { return stops_; }
|
||||
|
||||
|
||||
//! \brief Colorize a raster
|
||||
//!
|
||||
//! \param[in, out] raster A raster stored in float32 single channel format, which gets colorized in place.
|
||||
void colorize(std::shared_ptr<raster> const& raster, feature_impl const& f) const;
|
||||
|
||||
template <typename T>
|
||||
void colorize(image_data_rgba8 & out, T const& in, boost::optional<double>const& nodata, feature_impl const& f) const;
|
||||
|
||||
//! \brief Perform the translation of input to output
|
||||
//!
|
||||
|
|
|
@ -34,24 +34,159 @@
|
|||
// agg
|
||||
#include "agg_rendering_buffer.h"
|
||||
#include "agg_pixfmt_rgba.h"
|
||||
#include "agg_pixfmt_gray.h"
|
||||
#include "agg_rasterizer_scanline_aa.h"
|
||||
#include "agg_scanline_u.h"
|
||||
#include "agg_renderer_scanline.h"
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename F>
|
||||
void render_raster_symbolizer(raster_symbolizer const &sym,
|
||||
mapnik::feature_impl &feature,
|
||||
proj_transform const &prj_trans,
|
||||
renderer_common &common,
|
||||
struct image_data_dispatcher : util::static_visitor<void>
|
||||
{
|
||||
using composite_function = F;
|
||||
image_data_dispatcher(int start_x, int start_y,
|
||||
int width, int height,
|
||||
double scale_x, double scale_y,
|
||||
scaling_method_e method, double filter_factor,
|
||||
double opacity, composite_mode_e comp_op,
|
||||
raster_symbolizer const& sym, feature_impl const& feature, F & composite, boost::optional<double> const& nodata)
|
||||
: start_x_(start_x),
|
||||
start_y_(start_y),
|
||||
width_(width),
|
||||
height_(height),
|
||||
scale_x_(scale_x),
|
||||
scale_y_(scale_y),
|
||||
method_(method),
|
||||
filter_factor_(filter_factor),
|
||||
opacity_(opacity),
|
||||
comp_op_(comp_op),
|
||||
sym_(sym),
|
||||
feature_(feature),
|
||||
composite_(composite),
|
||||
nodata_(nodata) {}
|
||||
|
||||
void operator() (image_data_null const& data_in) const {} //no-op
|
||||
void operator() (image_data_rgba8 const& data_in) const
|
||||
{
|
||||
image_data_rgba8 data_out(width_, height_);
|
||||
scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_);
|
||||
composite_(data_out, comp_op_, opacity_, start_x_, start_y_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void operator() (T const& data_in) const
|
||||
{
|
||||
using image_data_type = T;
|
||||
image_data_type data_out(width_, height_);
|
||||
scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_);
|
||||
image_data_rgba8 dst(width_, height_);
|
||||
raster_colorizer_ptr colorizer = get<raster_colorizer_ptr>(sym_, keys::colorizer);
|
||||
if (colorizer) colorizer->colorize(dst, data_out, nodata_, feature_);
|
||||
composite_(dst, comp_op_, opacity_, start_x_, start_y_);
|
||||
}
|
||||
private:
|
||||
int start_x_;
|
||||
int start_y_;
|
||||
int width_;
|
||||
int height_;
|
||||
double scale_x_;
|
||||
double scale_y_;
|
||||
scaling_method_e method_;
|
||||
double filter_factor_;
|
||||
double opacity_;
|
||||
composite_mode_e comp_op_;
|
||||
raster_symbolizer const& sym_;
|
||||
feature_impl const& feature_;
|
||||
composite_function & composite_;
|
||||
boost::optional<double> const& nodata_;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
struct image_data_warp_dispatcher : util::static_visitor<void>
|
||||
{
|
||||
using composite_function = F;
|
||||
image_data_warp_dispatcher(proj_transform const& prj_trans,
|
||||
int start_x, int start_y, int width, int height,
|
||||
box2d<double> const& target_ext, box2d<double> const& source_ext,
|
||||
double offset_x, double offset_y, unsigned mesh_size, scaling_method_e scaling_method,
|
||||
double filter_factor, double opacity, composite_mode_e comp_op,
|
||||
raster_symbolizer const& sym, feature_impl const& feature, F & composite, boost::optional<double> const& nodata)
|
||||
: prj_trans_(prj_trans),
|
||||
start_x_(start_x),
|
||||
start_y_(start_y),
|
||||
width_(width),
|
||||
height_(height),
|
||||
target_ext_(target_ext),
|
||||
source_ext_(source_ext),
|
||||
offset_x_(offset_x),
|
||||
offset_y_(offset_y),
|
||||
mesh_size_(mesh_size),
|
||||
scaling_method_(scaling_method),
|
||||
filter_factor_(filter_factor),
|
||||
opacity_(opacity),
|
||||
comp_op_(comp_op),
|
||||
sym_(sym),
|
||||
feature_(feature),
|
||||
composite_(composite),
|
||||
nodata_(nodata) {}
|
||||
|
||||
void operator() (image_data_null const& data_in) const {} //no-op
|
||||
|
||||
void operator() (image_data_rgba8 const& data_in) const
|
||||
{
|
||||
image_data_rgba8 data_out(width_, height_);
|
||||
warp_image(data_out, data_in, prj_trans_, target_ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_);
|
||||
composite_(data_out, comp_op_, opacity_, start_x_, start_y_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void operator() (T const& data_in) const
|
||||
{
|
||||
using image_data_type = T;
|
||||
image_data_type data_out(width_, height_);
|
||||
if (nodata_) data_out.set(*nodata_);
|
||||
warp_image(data_out, data_in, prj_trans_, target_ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_);
|
||||
image_data_rgba8 dst(width_, height_);
|
||||
raster_colorizer_ptr colorizer = get<raster_colorizer_ptr>(sym_, keys::colorizer);
|
||||
if (colorizer) colorizer->colorize(dst, data_out, nodata_, feature_);
|
||||
composite_(dst, comp_op_, opacity_, start_x_, start_y_);
|
||||
}
|
||||
private:
|
||||
proj_transform const& prj_trans_;
|
||||
int start_x_;
|
||||
int start_y_;
|
||||
int width_;
|
||||
int height_;
|
||||
box2d<double> const& target_ext_;
|
||||
box2d<double> const& source_ext_;
|
||||
double offset_x_;
|
||||
double offset_y_;
|
||||
unsigned mesh_size_;
|
||||
scaling_method_e scaling_method_;
|
||||
double filter_factor_;
|
||||
double opacity_;
|
||||
composite_mode_e comp_op_;
|
||||
raster_symbolizer const& sym_;
|
||||
feature_impl const& feature_;
|
||||
composite_function & composite_;
|
||||
boost::optional<double> const& nodata_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void render_raster_symbolizer(raster_symbolizer const& sym,
|
||||
mapnik::feature_impl& feature,
|
||||
proj_transform const& prj_trans,
|
||||
renderer_common& common,
|
||||
F composite)
|
||||
{
|
||||
raster_ptr const& source = feature.get_raster();
|
||||
if (source)
|
||||
{
|
||||
// If there's a colorizer defined, use it to color the raster in-place
|
||||
raster_colorizer_ptr colorizer = get<raster_colorizer_ptr>(sym, keys::colorizer);
|
||||
if (colorizer)
|
||||
colorizer->colorize(source,feature);
|
||||
|
||||
box2d<double> target_ext = box2d<double>(source->ext_);
|
||||
prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS);
|
||||
box2d<double> ext = common.t_.forward(target_ext);
|
||||
|
@ -66,6 +201,9 @@ void render_raster_symbolizer(raster_symbolizer const &sym,
|
|||
scaling_method_e scaling_method = get<scaling_method_e>(sym, keys::scaling, feature, common.vars_, SCALING_NEAR);
|
||||
composite_mode_e comp_op = get<composite_mode_e>(sym, keys::comp_op, feature, common.vars_, src_over);
|
||||
double opacity = get<double>(sym,keys::opacity,feature, common.vars_, 1.0);
|
||||
// only premultiply rgba8 images
|
||||
if (source->data_.is<image_data_rgba8>())
|
||||
{
|
||||
bool premultiply_source = !source->premultiplied_alpha_;
|
||||
auto is_premultiplied = get_optional<bool>(sym, keys::premultiplied, feature, common.vars_);
|
||||
if (is_premultiplied)
|
||||
|
@ -82,20 +220,18 @@ void render_raster_symbolizer(raster_symbolizer const &sym,
|
|||
agg::pixfmt_rgba32 pixf(buffer);
|
||||
pixf.premultiply();
|
||||
}
|
||||
}
|
||||
|
||||
if (!prj_trans.equal())
|
||||
{
|
||||
double offset_x = ext.minx() - start_x;
|
||||
double offset_y = ext.miny() - start_y;
|
||||
raster target(target_ext, raster_width, raster_height, source->get_filter_factor());
|
||||
unsigned mesh_size = static_cast<unsigned>(get<value_integer>(sym,keys::mesh_size,feature, common.vars_, 16));
|
||||
reproject_and_scale_raster(target,
|
||||
*source,
|
||||
prj_trans,
|
||||
offset_x,
|
||||
offset_y,
|
||||
mesh_size,
|
||||
scaling_method);
|
||||
composite(target.data_, comp_op, opacity, start_x, start_y);
|
||||
detail::image_data_warp_dispatcher<F> dispatcher(prj_trans, start_x, start_y, raster_width, raster_height,
|
||||
target_ext, source->ext_, offset_x, offset_y, mesh_size,
|
||||
scaling_method, source->get_filter_factor(),
|
||||
opacity, comp_op, sym, feature, composite, source->nodata());
|
||||
util::apply_visitor(dispatcher, source->data_);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -107,20 +243,18 @@ void render_raster_symbolizer(raster_symbolizer const &sym,
|
|||
(std::abs(start_x) <= eps) &&
|
||||
(std::abs(start_y) <= eps) )
|
||||
{
|
||||
composite(source->data_, comp_op, opacity, start_x, start_y);
|
||||
if (source->data_.is<image_data_rgba8>())
|
||||
{
|
||||
composite(util::get<image_data_rgba8>(source->data_), comp_op, opacity, start_x, start_y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
raster target(target_ext, raster_width, raster_height, source->get_filter_factor());
|
||||
scale_image_agg<image_data_32>(target.data_,
|
||||
source->data_,
|
||||
scaling_method,
|
||||
image_ratio_x,
|
||||
image_ratio_y,
|
||||
0.0,
|
||||
0.0,
|
||||
source->get_filter_factor());
|
||||
composite(target.data_, comp_op, opacity, start_x, start_y);
|
||||
detail::image_data_dispatcher<F> dispatcher(start_x, start_y, raster_width, raster_height,
|
||||
image_ratio_x, image_ratio_y,
|
||||
scaling_method, source->get_filter_factor(),
|
||||
opacity, comp_op, sym, feature, composite, source->nodata());
|
||||
util::apply_visitor(dispatcher, source->data_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace mapnik {
|
|||
struct rasterizer;
|
||||
class marker;
|
||||
|
||||
std::shared_ptr<image_data_32> render_pattern(rasterizer & ras,
|
||||
std::shared_ptr<image_data_rgba8> render_pattern(rasterizer & ras,
|
||||
marker const& marker,
|
||||
agg::trans_affine const& tr,
|
||||
double opacity);
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include <mapnik/global.hpp>
|
||||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/image_data_any.hpp>
|
||||
#include <mapnik/util/variant.hpp>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
@ -33,9 +35,15 @@ extern "C"
|
|||
#define RealTIFFClose TIFFClose
|
||||
}
|
||||
|
||||
#define TIFF_WRITE_SCANLINE 0
|
||||
#define TIFF_WRITE_STRIPPED 1
|
||||
#define TIFF_WRITE_TILED 2
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
static tsize_t tiff_write_proc(thandle_t fd, tdata_t buf, tsize_t size)
|
||||
static inline tsize_t tiff_write_proc(thandle_t fd, tdata_t buf, tsize_t size)
|
||||
{
|
||||
std::ostream* out = reinterpret_cast<std::ostream*>(fd);
|
||||
std::ios::pos_type pos = out->tellp();
|
||||
|
@ -54,7 +62,7 @@ static tsize_t tiff_write_proc(thandle_t fd, tdata_t buf, tsize_t size)
|
|||
}
|
||||
}
|
||||
|
||||
static toff_t tiff_seek_proc(thandle_t fd, toff_t off, int whence)
|
||||
static inline toff_t tiff_seek_proc(thandle_t fd, toff_t off, int whence)
|
||||
{
|
||||
std::ostream* out = reinterpret_cast<std::ostream*>(fd);
|
||||
|
||||
|
@ -123,14 +131,14 @@ static toff_t tiff_seek_proc(thandle_t fd, toff_t off, int whence)
|
|||
return static_cast<toff_t>(out->tellp());
|
||||
}
|
||||
|
||||
static int tiff_close_proc(thandle_t fd)
|
||||
static inline int tiff_close_proc(thandle_t fd)
|
||||
{
|
||||
std::ostream* out = (std::ostream*)fd;
|
||||
out->flush();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static toff_t tiff_size_proc(thandle_t fd)
|
||||
static inline toff_t tiff_size_proc(thandle_t fd)
|
||||
{
|
||||
std::ostream* out = reinterpret_cast<std::ostream*>(fd);
|
||||
std::ios::pos_type pos = out->tellp();
|
||||
|
@ -140,27 +148,146 @@ static toff_t tiff_size_proc(thandle_t fd)
|
|||
return static_cast<toff_t>(len);
|
||||
}
|
||||
|
||||
static tsize_t tiff_dummy_read_proc(thandle_t , tdata_t , tsize_t)
|
||||
static inline tsize_t tiff_dummy_read_proc(thandle_t , tdata_t , tsize_t)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tiff_dummy_unmap_proc(thandle_t , tdata_t , toff_t)
|
||||
{
|
||||
}
|
||||
static inline void tiff_dummy_unmap_proc(thandle_t , tdata_t , toff_t) {}
|
||||
|
||||
static int tiff_dummy_map_proc(thandle_t , tdata_t*, toff_t* )
|
||||
static inline int tiff_dummy_map_proc(thandle_t , tdata_t*, toff_t* )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct tiff_config
|
||||
{
|
||||
tiff_config()
|
||||
: compression(COMPRESSION_ADOBE_DEFLATE),
|
||||
zlevel(4),
|
||||
tile_width(0),
|
||||
tile_height(0),
|
||||
rows_per_strip(0),
|
||||
method(TIFF_WRITE_STRIPPED) {}
|
||||
|
||||
int compression;
|
||||
int zlevel;
|
||||
int tile_width; // Tile width of zero means tile the width of the image
|
||||
int tile_height; // Tile height of zero means tile the height of the image
|
||||
int rows_per_strip;
|
||||
int method; // The method to use to write the TIFF.
|
||||
|
||||
};
|
||||
|
||||
struct tag_setter : public mapnik::util::static_visitor<>
|
||||
{
|
||||
tag_setter(TIFF * output, tiff_config & config)
|
||||
: output_(output),
|
||||
config_(config) {}
|
||||
|
||||
template <typename T>
|
||||
void operator() (T const&) const
|
||||
{
|
||||
// Assume this would be null type
|
||||
throw ImageWriterException("Could not write TIFF - unknown image type provided");
|
||||
}
|
||||
|
||||
inline void operator() (image_data_rgba8 const&) const
|
||||
{
|
||||
TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
|
||||
TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
|
||||
TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 8);
|
||||
TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 4);
|
||||
//uint16 extras[] = { EXTRASAMPLE_UNASSALPHA };
|
||||
uint16 extras[] = { EXTRASAMPLE_ASSOCALPHA };
|
||||
TIFFSetField(output_, TIFFTAG_EXTRASAMPLES, 1, extras);
|
||||
if (config_.compression == COMPRESSION_DEFLATE
|
||||
|| config_.compression == COMPRESSION_ADOBE_DEFLATE
|
||||
|| config_.compression == COMPRESSION_LZW)
|
||||
{
|
||||
TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL);
|
||||
|
||||
}
|
||||
}
|
||||
inline void operator() (image_data_gray32f const&) const
|
||||
{
|
||||
TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
|
||||
TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
|
||||
TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 32);
|
||||
TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1);
|
||||
if (config_.compression == COMPRESSION_DEFLATE
|
||||
|| config_.compression == COMPRESSION_ADOBE_DEFLATE
|
||||
|| config_.compression == COMPRESSION_LZW)
|
||||
{
|
||||
TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_FLOATINGPOINT);
|
||||
}
|
||||
}
|
||||
inline void operator() (image_data_gray16 const&) const
|
||||
{
|
||||
TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
|
||||
TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
|
||||
TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 16);
|
||||
TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1);
|
||||
if (config_.compression == COMPRESSION_DEFLATE
|
||||
|| config_.compression == COMPRESSION_ADOBE_DEFLATE
|
||||
|| config_.compression == COMPRESSION_LZW)
|
||||
{
|
||||
TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL);
|
||||
|
||||
}
|
||||
}
|
||||
inline void operator() (image_data_gray8 const&) const
|
||||
{
|
||||
TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
|
||||
TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
|
||||
TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 8);
|
||||
TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1);
|
||||
if (config_.compression == COMPRESSION_DEFLATE
|
||||
|| config_.compression == COMPRESSION_ADOBE_DEFLATE
|
||||
|| config_.compression == COMPRESSION_LZW)
|
||||
{
|
||||
TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL);
|
||||
|
||||
}
|
||||
}
|
||||
inline void operator() (image_data_null const&) const
|
||||
{
|
||||
// Assume this would be null type
|
||||
throw ImageWriterException("Could not write TIFF - Null image provided");
|
||||
}
|
||||
|
||||
private:
|
||||
TIFF * output_;
|
||||
tiff_config config_;
|
||||
};
|
||||
|
||||
void set_tiff_config(TIFF* output, tiff_config & config)
|
||||
{
|
||||
// Set some constant tiff information that doesn't vary based on type of data
|
||||
// or image size
|
||||
TIFFSetField(output, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
||||
|
||||
// Set the compression for the TIFF
|
||||
TIFFSetField(output, TIFFTAG_COMPRESSION, config.compression);
|
||||
|
||||
if (COMPRESSION_ADOBE_DEFLATE == config.compression
|
||||
|| COMPRESSION_DEFLATE == config.compression
|
||||
|| COMPRESSION_LZW == config.compression)
|
||||
{
|
||||
// Set the zip level for the compression
|
||||
// http://en.wikipedia.org/wiki/DEFLATE#Encoder.2Fcompressor
|
||||
// Changes the time spent trying to compress
|
||||
TIFFSetField(output, TIFFTAG_ZIPQUALITY, config.zlevel);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void save_as_tiff(T1 & file, T2 const& image)
|
||||
void save_as_tiff(T1 & file, T2 const& image, tiff_config & config)
|
||||
{
|
||||
using pixel_type = typename T2::pixel_type;
|
||||
|
||||
const int width = image.width();
|
||||
const int height = image.height();
|
||||
const int scanline_size = sizeof(unsigned char) * width * 3;
|
||||
|
||||
|
||||
TIFF* output = RealTIFFOpen("mapnik_tiff_stream",
|
||||
"wm",
|
||||
|
@ -179,13 +306,107 @@ void save_as_tiff(T1 & file, T2 const& image)
|
|||
|
||||
TIFFSetField(output, TIFFTAG_IMAGEWIDTH, width);
|
||||
TIFFSetField(output, TIFFTAG_IMAGELENGTH, height);
|
||||
TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
|
||||
TIFFSetField(output, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
||||
TIFFSetField(output, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
|
||||
TIFFSetField(output, TIFFTAG_BITSPERSAMPLE, 8);
|
||||
TIFFSetField(output, TIFFTAG_SAMPLESPERPIXEL, 3);
|
||||
TIFFSetField(output, TIFFTAG_IMAGEDEPTH, 1);
|
||||
set_tiff_config(output, config);
|
||||
|
||||
// Set tags that vary based on the type of data being provided.
|
||||
tag_setter set(output, config);
|
||||
set(image);
|
||||
//util::apply_visitor(set, image);
|
||||
|
||||
// Use specific types of writing methods.
|
||||
if (TIFF_WRITE_SCANLINE == config.method)
|
||||
{
|
||||
// Process Scanline
|
||||
TIFFSetField(output, TIFFTAG_ROWSPERSTRIP, 1);
|
||||
|
||||
int next_scanline = 0;
|
||||
std::unique_ptr<pixel_type[]> row (new pixel_type[width]);
|
||||
while (next_scanline < height)
|
||||
{
|
||||
std::copy(image.getRow(next_scanline), image.getRow(next_scanline) + width, row.get());
|
||||
TIFFWriteScanline(output, row.get(), next_scanline, 0);
|
||||
++next_scanline;
|
||||
}
|
||||
}
|
||||
else if (TIFF_WRITE_STRIPPED == config.method)
|
||||
{
|
||||
std::size_t rows_per_strip = config.rows_per_strip;
|
||||
if (0 == rows_per_strip)
|
||||
{
|
||||
rows_per_strip = height;
|
||||
}
|
||||
TIFFSetField(output, TIFFTAG_ROWSPERSTRIP, rows_per_strip);
|
||||
std::size_t strip_size = width * rows_per_strip;
|
||||
std::unique_ptr<pixel_type[]> strip_buffer(new pixel_type[strip_size]);
|
||||
int end_y=(height/rows_per_strip+1)*rows_per_strip;
|
||||
|
||||
for (int y=0; y < end_y; y+=rows_per_strip)
|
||||
{
|
||||
int ty1 = std::min(height, static_cast<int>(y + rows_per_strip)) - y;
|
||||
int row = y;
|
||||
for (int ty = 0; ty < ty1; ++ty, ++row)
|
||||
{
|
||||
std::copy(image.getRow(row), image.getRow(row) + width, strip_buffer.get() + ty * width);
|
||||
}
|
||||
if (TIFFWriteEncodedStrip(output, TIFFComputeStrip(output, y, 0), strip_buffer.get(), strip_size * sizeof(pixel_type)) == -1)
|
||||
{
|
||||
throw ImageWriterException("Could not write TIFF - TIFF Tile Write failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (TIFF_WRITE_TILED == config.method)
|
||||
{
|
||||
int tile_width = config.tile_width;
|
||||
int tile_height = config.tile_height;
|
||||
|
||||
if (0 == tile_height)
|
||||
{
|
||||
tile_height = height;
|
||||
if (height % 16 > 0)
|
||||
{
|
||||
tile_height = height + 16 - (height % 16);
|
||||
}
|
||||
}
|
||||
if (0 == tile_width)
|
||||
{
|
||||
tile_width = width;
|
||||
if (width % 16 > 0)
|
||||
{
|
||||
tile_width = width + 16 - (width % 16);
|
||||
}
|
||||
}
|
||||
TIFFSetField(output, TIFFTAG_TILEWIDTH, tile_width);
|
||||
TIFFSetField(output, TIFFTAG_TILELENGTH, tile_height);
|
||||
TIFFSetField(output, TIFFTAG_TILEDEPTH, 1);
|
||||
std::size_t tile_size = tile_width * tile_height;
|
||||
std::unique_ptr<pixel_type[]> image_data_out (new pixel_type[tile_size]);
|
||||
int end_y = (height / tile_height + 1) * tile_height;
|
||||
int end_x = (width / tile_width + 1) * tile_width;
|
||||
end_y = std::min(end_y, height);
|
||||
end_x = std::min(end_x, width);
|
||||
|
||||
for (int y = 0; y < end_y; y += tile_height)
|
||||
{
|
||||
int ty1 = std::min(height, y + tile_height) - y;
|
||||
|
||||
for (int x = 0; x < end_x; x += tile_width)
|
||||
{
|
||||
// Prefill the entire array with zeros.
|
||||
std::fill(image_data_out.get(), image_data_out.get() + tile_size, 0);
|
||||
int tx1 = std::min(width, x + tile_width);
|
||||
int row = y;
|
||||
for (int ty = 0; ty < ty1; ++ty, ++row)
|
||||
{
|
||||
std::copy(image.getRow(row, x), image.getRow(row, tx1), image_data_out.get() + ty * tile_width);
|
||||
}
|
||||
if (TIFFWriteEncodedTile(output, TIFFComputeTile(output, x, y, 0, 0), image_data_out.get(), tile_size * sizeof(pixel_type)) == -1)
|
||||
{
|
||||
throw ImageWriterException("Could not write TIFF - TIFF Tile Write failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO - handle palette images
|
||||
// std::vector<mapnik::rgb> const& palette
|
||||
|
||||
|
@ -199,26 +420,6 @@ void save_as_tiff(T1 & file, T2 const& image)
|
|||
// TIFFSetField(output, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
|
||||
// TIFFSetField(output, TIFFTAG_COLORMAP, r, g, b);
|
||||
|
||||
int next_scanline = 0;
|
||||
unsigned char* row = reinterpret_cast<unsigned char*>(::operator new(scanline_size));
|
||||
|
||||
while (next_scanline < height)
|
||||
{
|
||||
const unsigned* imageRow = image.getRow(next_scanline);
|
||||
|
||||
for (int i = 0, index = 0; i < width; ++i)
|
||||
{
|
||||
row[index++] = (imageRow[i]) & 0xff;
|
||||
row[index++] = (imageRow[i] >> 8) & 0xff;
|
||||
row[index++] = (imageRow[i] >> 16) & 0xff;
|
||||
}
|
||||
|
||||
TIFFWriteScanline(output, row, next_scanline, 0);
|
||||
++next_scanline;
|
||||
}
|
||||
|
||||
::operator delete(row);
|
||||
|
||||
RealTIFFClose(output);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
// mapnik
|
||||
#include <mapnik/image_scaling.hpp>
|
||||
#include <mapnik/config.hpp>
|
||||
#include <mapnik/box2d.hpp>
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
|
@ -39,6 +40,11 @@ MAPNIK_DECL void reproject_and_scale_raster(raster & target,
|
|||
unsigned mesh_size,
|
||||
scaling_method_e scaling_method);
|
||||
|
||||
|
||||
template <typename T>
|
||||
MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const& prj_trans,
|
||||
box2d<double> const& target_ext, box2d<double> const& source_ext,
|
||||
double offset_x, double offset_y, unsigned mesh_size, scaling_method_e scaling_method, double filter_factor);
|
||||
}
|
||||
|
||||
#endif // MAPNIK_WARP_HPP
|
||||
|
|
|
@ -98,11 +98,11 @@ inline int import_image_data(T2 const& image,
|
|||
else
|
||||
{
|
||||
// need to copy: https://github.com/mapnik/mapnik/issues/2024
|
||||
image_data_32 im(image.width(),image.height());
|
||||
image_data_rgba8 im(image.width(),image.height());
|
||||
for (unsigned y = 0; y < image.height(); ++y)
|
||||
{
|
||||
typename T2::pixel_type const * row_from = image.getRow(y);
|
||||
image_data_32::pixel_type * row_to = im.getRow(y);
|
||||
image_data_rgba8::pixel_type * row_to = im.getRow(y);
|
||||
std::copy(row_from, row_from + stride, row_to);
|
||||
}
|
||||
if (alpha)
|
||||
|
@ -121,11 +121,11 @@ inline int import_image_data(T2 const& image,
|
|||
}
|
||||
|
||||
template <>
|
||||
inline int import_image_data(image_data_32 const& im,
|
||||
inline int import_image_data(image_data_rgba8 const& im,
|
||||
WebPPicture & pic,
|
||||
bool alpha)
|
||||
{
|
||||
int stride = sizeof(image_data_32::pixel_type) * im.width();
|
||||
int stride = sizeof(image_data_rgba8::pixel_type) * im.width();
|
||||
if (alpha)
|
||||
{
|
||||
return WebPPictureImportRGBA(&pic, im.getBytes(), stride);
|
||||
|
|
|
@ -109,7 +109,7 @@ gdal_datasource::gdal_datasource(parameters const& params)
|
|||
nbands_ = dataset->GetRasterCount();
|
||||
width_ = dataset->GetRasterXSize();
|
||||
height_ = dataset->GetRasterYSize();
|
||||
desc_.add_descriptor(mapnik::attribute_descriptor("nodata", mapnik::Integer));
|
||||
desc_.add_descriptor(mapnik::attribute_descriptor("nodata", mapnik::Double));
|
||||
|
||||
double tr[6];
|
||||
bool bbox_override = false;
|
||||
|
|
|
@ -199,34 +199,38 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
|
|||
|
||||
if (im_width > 0 && im_height > 0)
|
||||
{
|
||||
mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, im_width, im_height, filter_factor);
|
||||
feature->set_raster(raster);
|
||||
mapnik::image_data_32 & image = raster->data_;
|
||||
image.set(0xffffffff);
|
||||
|
||||
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Image Size=(" << im_width << "," << im_height << ")";
|
||||
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Reading band=" << band_;
|
||||
|
||||
if (band_ > 0) // we are querying a single band
|
||||
{
|
||||
mapnik::image_data_gray16 image(im_width, im_height);
|
||||
image.set(std::numeric_limits<std::int16_t>::max());
|
||||
if (band_ > nbands_)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "GDAL Plugin: " << band_ << " is an invalid band, dataset only has " << nbands_ << "bands";
|
||||
throw datasource_exception(s.str());
|
||||
}
|
||||
float* imageData = reinterpret_cast<float*>(image.getBytes());
|
||||
|
||||
GDALRasterBand * band = dataset_.GetRasterBand(band_);
|
||||
raster_nodata = band->GetNoDataValue(&raster_has_nodata);
|
||||
raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height,
|
||||
imageData, image.width(), image.height(),
|
||||
GDT_Float32, 0, 0);
|
||||
if (raster_io_error == CE_Failure) {
|
||||
image.getData(), image.width(), image.height(),
|
||||
GDT_Int16, 0, 0);
|
||||
if (raster_io_error == CE_Failure)
|
||||
{
|
||||
throw datasource_exception(CPLGetLastErrorMsg());
|
||||
}
|
||||
mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, image, filter_factor);
|
||||
// set nodata value to be used in raster colorizer
|
||||
if (nodata_value_) raster->set_nodata(*nodata_value_);
|
||||
else raster->set_nodata(raster_nodata);
|
||||
feature->set_raster(raster);
|
||||
}
|
||||
else // working with all bands
|
||||
{
|
||||
mapnik::image_data_rgba8 image(im_width, im_height);
|
||||
image.set(std::numeric_limits<std::uint32_t>::max());
|
||||
for (int i = 0; i < nbands_; ++i)
|
||||
{
|
||||
GDALRasterBand * band = dataset_.GetRasterBand(i + 1);
|
||||
|
@ -363,7 +367,8 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
|
|||
raster_io_error = grey->RasterIO(GF_Read, x_off, y_off, width, height,
|
||||
imageData, image.width(), image.height(),
|
||||
GDT_Float32, 0, 0);
|
||||
if (raster_io_error == CE_Failure) {
|
||||
if (raster_io_error == CE_Failure)
|
||||
{
|
||||
throw datasource_exception(CPLGetLastErrorMsg());
|
||||
}
|
||||
int len = image.width() * image.height();
|
||||
|
@ -379,19 +384,26 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
raster_io_error = grey->RasterIO(GF_Read, x_off, y_off, width, height, image.getBytes() + 0,
|
||||
image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
|
||||
if (raster_io_error == CE_Failure) {
|
||||
if (raster_io_error == CE_Failure)
|
||||
{
|
||||
throw datasource_exception(CPLGetLastErrorMsg());
|
||||
}
|
||||
|
||||
raster_io_error = grey->RasterIO(GF_Read,x_off, y_off, width, height, image.getBytes() + 1,
|
||||
image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
|
||||
if (raster_io_error == CE_Failure) {
|
||||
if (raster_io_error == CE_Failure)
|
||||
{
|
||||
throw datasource_exception(CPLGetLastErrorMsg());
|
||||
}
|
||||
|
||||
raster_io_error = grey->RasterIO(GF_Read,x_off, y_off, width, height, image.getBytes() + 2,
|
||||
image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
|
||||
if (raster_io_error == CE_Failure) {
|
||||
|
||||
if (raster_io_error == CE_Failure)
|
||||
{
|
||||
throw datasource_exception(CPLGetLastErrorMsg());
|
||||
}
|
||||
|
||||
|
@ -435,15 +447,11 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
|
|||
MAPNIK_LOG_WARN(gdal) << "warning: nodata value (" << raster_nodata << ") used to set transparency instead of alpha band";
|
||||
}
|
||||
}
|
||||
}
|
||||
mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, image, filter_factor);
|
||||
// set nodata value to be used in raster colorizer
|
||||
if (nodata_value_)
|
||||
{
|
||||
raster->set_nodata(*nodata_value_);
|
||||
}
|
||||
else
|
||||
{
|
||||
raster->set_nodata(raster_nodata);
|
||||
if (nodata_value_) raster->set_nodata(*nodata_value_);
|
||||
else raster->set_nodata(raster_nodata);
|
||||
feature->set_raster(raster);
|
||||
}
|
||||
// report actual/original source nodata in feature attributes
|
||||
if (raster_has_nodata)
|
||||
|
|
|
@ -178,25 +178,20 @@ typedef enum {
|
|||
|
||||
}
|
||||
|
||||
using mapnik::box2d;
|
||||
|
||||
template<typename T>
|
||||
void read_data_band(mapnik::raster_ptr raster,
|
||||
mapnik::raster_ptr read_data_band(mapnik::box2d<double> const& bbox,
|
||||
uint16_t width, uint16_t height,
|
||||
bool hasnodata, T reader)
|
||||
{
|
||||
mapnik::image_data_32 & image = raster->data_;
|
||||
|
||||
mapnik::image_data_gray32f image(width, height);
|
||||
//image.set(std::numeric_limits<float>::max());
|
||||
// Start with plain white (ABGR or RGBA depending on endiannes)
|
||||
// TODO: set to transparent instead?
|
||||
image.set(0xffffffff);
|
||||
|
||||
raster->premultiplied_alpha_ = true;
|
||||
|
||||
float* data = (float*)image.getBytes();
|
||||
float* data = image.getData();
|
||||
double val;
|
||||
val = reader(); // nodata value, need to read anyway
|
||||
if ( hasnodata ) raster->set_nodata(val);
|
||||
for (int y=0; y<height; ++y) {
|
||||
for (int x=0; x<width; ++x) {
|
||||
val = reader();
|
||||
|
@ -204,16 +199,14 @@ void read_data_band(mapnik::raster_ptr raster,
|
|||
data[off] = val;
|
||||
}
|
||||
}
|
||||
mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(bbox, image, 1.0, true);
|
||||
if ( hasnodata ) raster->set_nodata(val);
|
||||
return raster;
|
||||
}
|
||||
|
||||
void
|
||||
pgraster_wkb_reader::read_indexed(mapnik::raster_ptr raster)
|
||||
mapnik::raster_ptr pgraster_wkb_reader::read_indexed(mapnik::box2d<double> const& bbox,
|
||||
uint16_t width, uint16_t height)
|
||||
{
|
||||
mapnik::image_data_32 & image = raster->data_;
|
||||
|
||||
// Start with all zeroes
|
||||
image.set(0);
|
||||
|
||||
uint8_t type = read_uint8(&ptr_);
|
||||
|
||||
int pixtype = BANDTYPE_PIXTYPE(type);
|
||||
|
@ -227,7 +220,7 @@ pgraster_wkb_reader::read_indexed(mapnik::raster_ptr raster)
|
|||
if ( offline ) {
|
||||
MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: offline band "
|
||||
" unsupported";
|
||||
return;
|
||||
return mapnik::raster_ptr();
|
||||
}
|
||||
|
||||
MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: reading " << height_ << "x" << width_ << " pixels";
|
||||
|
@ -240,27 +233,27 @@ pgraster_wkb_reader::read_indexed(mapnik::raster_ptr raster)
|
|||
case PT_8BSI:
|
||||
// mapnik does not support signed anyway
|
||||
case PT_8BUI:
|
||||
read_data_band(raster, width_, height_, hasnodata,
|
||||
return read_data_band(bbox, width_, height_, hasnodata,
|
||||
boost::bind(read_uint8, &ptr_));
|
||||
break;
|
||||
case PT_16BSI:
|
||||
// mapnik does not support signed anyway
|
||||
case PT_16BUI:
|
||||
read_data_band(raster, width_, height_, hasnodata,
|
||||
return read_data_band(bbox, width_, height_, hasnodata,
|
||||
boost::bind(read_uint16, &ptr_, endian_));
|
||||
break;
|
||||
case PT_32BSI:
|
||||
// mapnik does not support signed anyway
|
||||
case PT_32BUI:
|
||||
read_data_band(raster, width_, height_, hasnodata,
|
||||
return read_data_band(bbox, width_, height_, hasnodata,
|
||||
boost::bind(read_uint32, &ptr_, endian_));
|
||||
break;
|
||||
case PT_32BF:
|
||||
read_data_band(raster, width_, height_, hasnodata,
|
||||
return read_data_band(bbox, width_, height_, hasnodata,
|
||||
boost::bind(read_float32, &ptr_, endian_));
|
||||
break;
|
||||
case PT_64BF:
|
||||
read_data_band(raster, width_, height_, hasnodata,
|
||||
return read_data_band(bbox, width_, height_, hasnodata,
|
||||
boost::bind(read_float64, &ptr_, endian_));
|
||||
break;
|
||||
default:
|
||||
|
@ -270,28 +263,25 @@ pgraster_wkb_reader::read_indexed(mapnik::raster_ptr raster)
|
|||
//MAPNIK_LOG_WARN(pgraster) << err.str();
|
||||
throw mapnik::datasource_exception(err.str());
|
||||
}
|
||||
|
||||
return mapnik::raster_ptr();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void read_grayscale_band(mapnik::raster_ptr raster,
|
||||
mapnik::raster_ptr read_grayscale_band(mapnik::box2d<double> const& bbox,
|
||||
uint16_t width, uint16_t height,
|
||||
bool hasnodata, T reader)
|
||||
{
|
||||
mapnik::image_data_32 & image = raster->data_;
|
||||
|
||||
mapnik::image_data_rgba8 image(width,height);
|
||||
// Start with plain white (ABGR or RGBA depending on endiannes)
|
||||
// TODO: set to transparent instead?
|
||||
image.set(0xffffffff);
|
||||
|
||||
raster->premultiplied_alpha_ = true;
|
||||
|
||||
int val;
|
||||
uint8_t * data = image.getBytes();
|
||||
int ps = 4; // sizeof(image_data::pixel_type)
|
||||
int off;
|
||||
val = reader(); // nodata value, need to read anyway
|
||||
if ( hasnodata ) raster->set_nodata(val);
|
||||
for (int y=0; y<height; ++y) {
|
||||
for (int x=0; x<width; ++x) {
|
||||
val = reader();
|
||||
|
@ -302,10 +292,13 @@ void read_grayscale_band(mapnik::raster_ptr raster,
|
|||
data[off+2] = val;
|
||||
}
|
||||
}
|
||||
mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(bbox, image, 1.0, true);
|
||||
if ( hasnodata ) raster->set_nodata(val);
|
||||
return raster;
|
||||
}
|
||||
|
||||
void
|
||||
pgraster_wkb_reader::read_grayscale(mapnik::raster_ptr raster)
|
||||
mapnik::raster_ptr pgraster_wkb_reader::read_grayscale(mapnik::box2d<double> const& bbox,
|
||||
uint16_t width, uint16_t height)
|
||||
{
|
||||
uint8_t type = read_uint8(&ptr_);
|
||||
|
||||
|
@ -320,7 +313,7 @@ pgraster_wkb_reader::read_grayscale(mapnik::raster_ptr raster)
|
|||
if ( offline ) {
|
||||
MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: offline band "
|
||||
" unsupported";
|
||||
return;
|
||||
return mapnik::raster_ptr();
|
||||
}
|
||||
|
||||
switch (pixtype) {
|
||||
|
@ -331,19 +324,19 @@ pgraster_wkb_reader::read_grayscale(mapnik::raster_ptr raster)
|
|||
case PT_8BSI:
|
||||
// mapnik does not support signed anyway
|
||||
case PT_8BUI:
|
||||
read_grayscale_band(raster, width_, height_, hasnodata,
|
||||
return read_grayscale_band(bbox, width_, height_, hasnodata,
|
||||
boost::bind(read_uint8, &ptr_));
|
||||
break;
|
||||
case PT_16BSI:
|
||||
// mapnik does not support signed anyway
|
||||
case PT_16BUI:
|
||||
read_grayscale_band(raster, width_, height_, hasnodata,
|
||||
return read_grayscale_band(bbox, width_, height_, hasnodata,
|
||||
boost::bind(read_uint16, &ptr_, endian_));
|
||||
break;
|
||||
case PT_32BSI:
|
||||
// mapnik does not support signed anyway
|
||||
case PT_32BUI:
|
||||
read_grayscale_band(raster, width_, height_, hasnodata,
|
||||
return read_grayscale_band(bbox, width_, height_, hasnodata,
|
||||
boost::bind(read_uint32, &ptr_, endian_));
|
||||
break;
|
||||
default:
|
||||
|
@ -353,19 +346,15 @@ pgraster_wkb_reader::read_grayscale(mapnik::raster_ptr raster)
|
|||
//MAPNIK_LOG_WARN(pgraster) << err.str();
|
||||
throw mapnik::datasource_exception(err.str());
|
||||
}
|
||||
|
||||
return mapnik::raster_ptr();
|
||||
}
|
||||
|
||||
void
|
||||
pgraster_wkb_reader::read_rgba(mapnik::raster_ptr raster)
|
||||
mapnik::raster_ptr pgraster_wkb_reader::read_rgba(mapnik::box2d<double> const& bbox,
|
||||
uint16_t width, uint16_t height)
|
||||
{
|
||||
mapnik::image_data_32 & image = raster->data_;
|
||||
|
||||
mapnik::image_data_rgba8 image(width, height);
|
||||
// Start with plain white (ABGR or RGBA depending on endiannes)
|
||||
image.set(0xffffffff);
|
||||
//raster->set_nodata(0xffffffff);
|
||||
|
||||
raster->premultiplied_alpha_ = true;
|
||||
|
||||
uint8_t nodataval;
|
||||
for (int bn=0; bn<numBands_; ++bn) {
|
||||
|
@ -411,6 +400,9 @@ pgraster_wkb_reader::read_rgba(mapnik::raster_ptr raster)
|
|||
}
|
||||
}
|
||||
}
|
||||
mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(bbox, image, 1.0, true);
|
||||
raster->set_nodata(0xffffffff);
|
||||
return raster;
|
||||
}
|
||||
|
||||
mapnik::raster_ptr
|
||||
|
@ -458,28 +450,30 @@ pgraster_wkb_reader::get_raster() {
|
|||
return mapnik::raster_ptr();
|
||||
}
|
||||
|
||||
box2d<double> ext(ipX,ipY,ipX+(width_*scaleX),ipY+(height_*scaleY));
|
||||
mapnik::box2d<double> ext(ipX,ipY,ipX+(width_*scaleX),ipY+(height_*scaleY));
|
||||
MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: Raster extent=" << ext;
|
||||
|
||||
mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(ext, width_, height_, 1.0);
|
||||
|
||||
if ( bandno_ ) {
|
||||
if ( bandno_ != 1 ) {
|
||||
if ( bandno_ )
|
||||
{
|
||||
if ( bandno_ != 1 )
|
||||
{
|
||||
MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: "
|
||||
"reading bands other than 1st as indexed is unsupported";
|
||||
return mapnik::raster_ptr();
|
||||
}
|
||||
MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: requested band " << bandno_;
|
||||
read_indexed(raster);
|
||||
return read_indexed(ext, width_, height_);
|
||||
}
|
||||
else {
|
||||
switch (numBands_) {
|
||||
else
|
||||
{
|
||||
switch (numBands_)
|
||||
{
|
||||
case 1:
|
||||
read_grayscale(raster);
|
||||
return read_grayscale(ext, width_, height_);
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
read_rgba(raster);
|
||||
return read_rgba(ext, width_, height_);
|
||||
break;
|
||||
default:
|
||||
std::ostringstream err;
|
||||
|
@ -491,7 +485,5 @@ pgraster_wkb_reader::get_raster() {
|
|||
return mapnik::raster_ptr();
|
||||
}
|
||||
}
|
||||
|
||||
return raster;
|
||||
|
||||
return mapnik::raster_ptr();
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
// mapnik
|
||||
#include <mapnik/feature.hpp> // for raster_ptr
|
||||
#include <mapnik/box2d.hpp>
|
||||
|
||||
enum pgraster_color_interp {
|
||||
// Automatic color interpretation:
|
||||
|
@ -65,9 +66,9 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
void read_indexed(mapnik::raster_ptr raster);
|
||||
void read_grayscale(mapnik::raster_ptr raster);
|
||||
void read_rgba(mapnik::raster_ptr raster);
|
||||
mapnik::raster_ptr read_indexed(mapnik::box2d<double> const& bbox, uint16_t width, uint16_t height);
|
||||
mapnik::raster_ptr read_grayscale(mapnik::box2d<double> const& bbox, uint16_t width, uint16_t height);
|
||||
mapnik::raster_ptr read_rgba(mapnik::box2d<double> const& bbox, uint16_t width, uint16_t height);
|
||||
|
||||
//int wkbsize_;
|
||||
//const uint8_t* wkb_;
|
||||
|
|
|
@ -84,6 +84,16 @@ raster_datasource::raster_datasource(parameters const& params)
|
|||
{
|
||||
extent_initialized_ = extent_.from_string(*ext);
|
||||
}
|
||||
else //bounding box from image_reader
|
||||
{
|
||||
std::unique_ptr<image_reader> reader(mapnik::get_image_reader(*file));
|
||||
auto bbox = reader->bounding_box();
|
||||
if (bbox)
|
||||
{
|
||||
extent_ = *bbox;
|
||||
extent_initialized_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (! extent_initialized_)
|
||||
{
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <mapnik/image_reader.hpp>
|
||||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/feature_factory.hpp>
|
||||
#include <mapnik/util/variant.hpp>
|
||||
|
||||
// boost
|
||||
#pragma GCC diagnostic push
|
||||
|
@ -42,7 +43,7 @@
|
|||
using mapnik::query;
|
||||
using mapnik::image_reader;
|
||||
using mapnik::feature_ptr;
|
||||
using mapnik::image_data_32;
|
||||
using mapnik::image_data_rgba8;
|
||||
using mapnik::raster;
|
||||
using mapnik::feature_factory;
|
||||
|
||||
|
@ -113,9 +114,8 @@ feature_ptr raster_featureset<LookupPolicy>::next()
|
|||
rem.maxx() + x_off + width,
|
||||
rem.maxy() + y_off + height);
|
||||
intersect = t.backward(feature_raster_extent);
|
||||
|
||||
mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, width, height, 1.0);
|
||||
reader->read(x_off, y_off, raster->data_);
|
||||
mapnik::image_data_any data = reader->read(x_off, y_off, width, height);
|
||||
mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, std::move(data), 1.0);
|
||||
raster->premultiplied_alpha_ = reader->premultiplied_alpha();
|
||||
feature->set_raster(raster);
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ feature_ptr rasterlite_featureset::get_feature(mapnik::query const& q)
|
|||
if (size > 0)
|
||||
{
|
||||
mapnik::raster_ptr rasterp = std::make_shared<mapnik::raster>(intersect, width, height, 1.0);
|
||||
mapnik::image_data_32 & image = rasterp->data_;
|
||||
mapnik::image_data_rgba8 & image = rasterp->data_;
|
||||
image.set(0xffffffff);
|
||||
|
||||
unsigned char* raster_data = static_cast<unsigned char*>(raster);
|
||||
|
|
11
run_tests
11
run_tests
|
@ -5,15 +5,20 @@ failures=0
|
|||
source ./localize.sh
|
||||
PYTHON=${PYTHON:-python}
|
||||
|
||||
echo "*** Running visual tests..."
|
||||
$PYTHON tests/visual_tests/test.py -q
|
||||
echo "*** Running Next Gen C++ tests..."
|
||||
./tests/cxx/run
|
||||
failures=$((failures+$?))
|
||||
echo
|
||||
|
||||
echo "*** Running C++ tests..."
|
||||
echo "*** Running Old C++ tests..."
|
||||
./tests/cpp_tests/run
|
||||
failures=$((failures+$?))
|
||||
echo
|
||||
|
||||
echo "*** Running visual tests..."
|
||||
$PYTHON tests/visual_tests/test.py -q
|
||||
failures=$((failures+$?))
|
||||
|
||||
echo "*** Running python tests..."
|
||||
$PYTHON tests/run_tests.py -q
|
||||
failures=$((failures+$?))
|
||||
|
|
|
@ -412,7 +412,7 @@ void agg_renderer<T0,T1>::render_marker(pixel_position const& pos,
|
|||
agg::image_filter_bilinear filter_kernel;
|
||||
agg::image_filter_lut filter(filter_kernel, false);
|
||||
|
||||
image_data_32 const& src = **marker.get_bitmap_data();
|
||||
image_data_rgba8 const& src = **marker.get_bitmap_data();
|
||||
agg::rendering_buffer marker_buf((unsigned char *)src.getBytes(),
|
||||
src.width(),
|
||||
src.height(),
|
||||
|
|
|
@ -52,7 +52,7 @@ void agg_renderer<T0,T1>::process(raster_symbolizer const& sym,
|
|||
{
|
||||
render_raster_symbolizer(
|
||||
sym, feature, prj_trans, common_,
|
||||
[&](image_data_32 & target, composite_mode_e comp_op, double opacity,
|
||||
[&](image_data_rgba8 & target, composite_mode_e comp_op, double opacity,
|
||||
int start_x, int start_y) {
|
||||
composite(current_buffer_->data(), target,
|
||||
comp_op, opacity, start_x, start_y, false);
|
||||
|
|
|
@ -337,7 +337,7 @@ void cairo_context::set_gradient(cairo_gradient const& pattern, const box2d<doub
|
|||
check_object_status_and_throw_exception(*this);
|
||||
}
|
||||
|
||||
void cairo_context::add_image(double x, double y, image_data_32 & data, double opacity)
|
||||
void cairo_context::add_image(double x, double y, image_data_rgba8 & data, double opacity)
|
||||
{
|
||||
cairo_pattern pattern(data);
|
||||
pattern.set_origin(x, y);
|
||||
|
@ -348,7 +348,7 @@ void cairo_context::add_image(double x, double y, image_data_32 & data, double o
|
|||
check_object_status_and_throw_exception(*this);
|
||||
}
|
||||
|
||||
void cairo_context::add_image(agg::trans_affine const& tr, image_data_32 & data, double opacity)
|
||||
void cairo_context::add_image(agg::trans_affine const& tr, image_data_rgba8 & data, double opacity)
|
||||
{
|
||||
cairo_pattern pattern(data);
|
||||
if (!tr.is_identity())
|
||||
|
|
|
@ -124,7 +124,7 @@ struct markers_dispatch : mapnik::noncopyable
|
|||
template <typename RendererContext, typename Detector>
|
||||
struct raster_markers_dispatch : mapnik::noncopyable
|
||||
{
|
||||
raster_markers_dispatch(mapnik::image_data_32 & src,
|
||||
raster_markers_dispatch(mapnik::image_data_rgba8 & src,
|
||||
agg::trans_affine const& marker_trans,
|
||||
markers_symbolizer const& sym,
|
||||
Detector & detector,
|
||||
|
@ -165,7 +165,7 @@ struct raster_markers_dispatch : mapnik::noncopyable
|
|||
}
|
||||
}
|
||||
|
||||
image_data_32 & src_;
|
||||
image_data_rgba8 & src_;
|
||||
Detector & detector_;
|
||||
markers_symbolizer const& sym_;
|
||||
agg::trans_affine const& marker_trans_;
|
||||
|
|
|
@ -43,7 +43,7 @@ void cairo_renderer<T>::process(raster_symbolizer const& sym,
|
|||
cairo_save_restore guard(context_);
|
||||
render_raster_symbolizer(
|
||||
sym, feature, prj_trans, common_,
|
||||
[&](image_data_32 &target, composite_mode_e comp_op, double opacity,
|
||||
[&](image_data_rgba8 &target, composite_mode_e comp_op, double opacity,
|
||||
int start_x, int start_y) {
|
||||
context_.set_operator(comp_op);
|
||||
context_.add_image(start_x, start_y, target, opacity);
|
||||
|
|
|
@ -165,7 +165,7 @@ void grid_renderer<T>::render_marker(mapnik::feature_impl const& feature, pixel_
|
|||
}
|
||||
else
|
||||
{
|
||||
image_data_32 const& data = **marker.get_bitmap_data();
|
||||
image_data_rgba8 const& data = **marker.get_bitmap_data();
|
||||
double width = data.width();
|
||||
double height = data.height();
|
||||
double cx = 0.5 * width;
|
||||
|
@ -179,8 +179,8 @@ void grid_renderer<T>::render_marker(mapnik::feature_impl const& feature, pixel_
|
|||
}
|
||||
else
|
||||
{
|
||||
image_data_32 target(data.width(), data.height());
|
||||
mapnik::scale_image_agg<image_data_32>(target,
|
||||
image_data_rgba8 target(data.width(), data.height());
|
||||
mapnik::scale_image_agg(target,
|
||||
data,
|
||||
SCALING_NEAR,
|
||||
1,
|
||||
|
|
|
@ -38,8 +38,10 @@
|
|||
#include "agg_scanline_u.h"
|
||||
#include "agg_renderer_scanline.h"
|
||||
#include "agg_pixfmt_rgba.h"
|
||||
#include "agg_pixfmt_gray.h"
|
||||
#include "agg_color_rgba.h"
|
||||
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
|
||||
|
@ -120,9 +122,8 @@ For example, if you generate some pattern with AGG (premultiplied) and would lik
|
|||
|
||||
*/
|
||||
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void composite(T1 & dst, T2 & src, composite_mode_e mode,
|
||||
template <>
|
||||
MAPNIK_DECL void composite(image_data_rgba8 & dst, image_data_rgba8 & src, composite_mode_e mode,
|
||||
float opacity,
|
||||
int dx,
|
||||
int dy,
|
||||
|
@ -146,12 +147,23 @@ void composite(T1 & dst, T2 & src, composite_mode_e mode,
|
|||
ren.blend_from(pixf_mask,0,dx,dy,unsigned(255*opacity));
|
||||
}
|
||||
|
||||
template void composite<mapnik::image_data_32,mapnik::image_data_32>(mapnik::image_data_32&,
|
||||
mapnik::image_data_32&,
|
||||
composite_mode_e,
|
||||
float,
|
||||
int,
|
||||
int,
|
||||
bool);
|
||||
template <>
|
||||
MAPNIK_DECL void composite(image_data_gray32f & dst, image_data_gray32f & src, composite_mode_e mode,
|
||||
float opacity,
|
||||
int dx,
|
||||
int dy,
|
||||
bool premultiply_src)
|
||||
{
|
||||
using pixfmt_type = agg::pixfmt_gray32;
|
||||
using renderer_type = agg::renderer_base<pixfmt_type>;
|
||||
|
||||
agg::rendering_buffer dst_buffer(dst.getBytes(),dst.width(),dst.height(),dst.width());
|
||||
agg::rendering_buffer src_buffer(src.getBytes(),src.width(),src.height(),src.width());
|
||||
pixfmt_type pixf(dst_buffer);
|
||||
|
||||
agg::pixfmt_gray32 pixf_mask(src_buffer);
|
||||
renderer_type ren(pixf);
|
||||
ren.copy_from(pixf_mask,0,dx,dy);;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
// mapnik
|
||||
#include <mapnik/image_data.hpp>
|
||||
#include <mapnik/image_scaling.hpp>
|
||||
#include <mapnik/image_scaling_traits.hpp>
|
||||
// does not handle alpha correctly
|
||||
//#include <mapnik/span_image_filter.hpp>
|
||||
|
||||
|
@ -37,12 +38,14 @@
|
|||
// agg
|
||||
#include "agg_image_accessors.h"
|
||||
#include "agg_pixfmt_rgba.h"
|
||||
#include "agg_pixfmt_gray.h"
|
||||
#include "agg_color_rgba.h"
|
||||
#include "agg_rasterizer_scanline_aa.h"
|
||||
#include "agg_renderer_scanline.h"
|
||||
#include "agg_rendering_buffer.h"
|
||||
#include "agg_scanline_u.h"
|
||||
#include "agg_span_allocator.h"
|
||||
#include "agg_span_image_filter_gray.h"
|
||||
#include "agg_span_image_filter_rgba.h"
|
||||
#include "agg_span_interpolator_linear.h"
|
||||
#include "agg_trans_affine.h"
|
||||
|
@ -94,37 +97,39 @@ boost::optional<std::string> scaling_method_to_string(scaling_method_e scaling_m
|
|||
return mode;
|
||||
}
|
||||
|
||||
template <typename Image>
|
||||
void scale_image_agg(Image & target,
|
||||
Image const& source,
|
||||
scaling_method_e scaling_method,
|
||||
double image_ratio_x,
|
||||
double image_ratio_y,
|
||||
double x_off_f,
|
||||
double y_off_f,
|
||||
|
||||
template <typename T>
|
||||
void scale_image_agg(T & target, T const& source, scaling_method_e scaling_method,
|
||||
double image_ratio_x, double image_ratio_y, double x_off_f, double y_off_f,
|
||||
double filter_factor)
|
||||
{
|
||||
// "the image filters should work namely in the premultiplied color space"
|
||||
// http://old.nabble.com/Re:--AGG--Basic-image-transformations-p1110665.html
|
||||
// "Yes, you need to use premultiplied images only. Only in this case the simple weighted averaging works correctly in the image fitering."
|
||||
// http://permalink.gmane.org/gmane.comp.graphics.agg/3443
|
||||
using pixfmt_pre = agg::pixfmt_rgba32_pre;
|
||||
using image_data_type = T;
|
||||
using pixel_type = typename image_data_type::pixel_type;
|
||||
using pixfmt_pre = typename detail::agg_scaling_traits<image_data_type>::pixfmt_pre;
|
||||
using color_type = typename detail::agg_scaling_traits<image_data_type>::color_type;
|
||||
using img_src_type = typename detail::agg_scaling_traits<image_data_type>::img_src_type;
|
||||
using interpolator_type = typename detail::agg_scaling_traits<image_data_type>::interpolator_type;
|
||||
using renderer_base_pre = agg::renderer_base<pixfmt_pre>;
|
||||
constexpr std::size_t pixel_size = sizeof(pixel_type);
|
||||
|
||||
// define some stuff we'll use soon
|
||||
agg::rasterizer_scanline_aa<> ras;
|
||||
agg::scanline_u8 sl;
|
||||
agg::span_allocator<agg::rgba8> sa;
|
||||
agg::image_filter_lut filter;
|
||||
agg::span_allocator<color_type> sa;
|
||||
|
||||
// initialize source AGG buffer
|
||||
agg::rendering_buffer rbuf_src((unsigned char*)source.getBytes(), source.width(), source.height(), source.width() * 4);
|
||||
agg::rendering_buffer rbuf_src(const_cast<unsigned char*>(source.getBytes()),
|
||||
source.width(), source.height(), source.width() * pixel_size);
|
||||
pixfmt_pre pixf_src(rbuf_src);
|
||||
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
|
||||
|
||||
img_src_type img_src(pixf_src);
|
||||
|
||||
// initialize destination AGG buffer (with transparency)
|
||||
agg::rendering_buffer rbuf_dst((unsigned char*)target.getBytes(), target.width(), target.height(), target.width() * 4);
|
||||
agg::rendering_buffer rbuf_dst(target.getBytes(), target.width(), target.height(), target.width() * pixel_size);
|
||||
pixfmt_pre pixf_dst(rbuf_dst);
|
||||
renderer_base_pre rb_dst_pre(pixf_dst);
|
||||
|
||||
|
@ -133,9 +138,7 @@ void scale_image_agg(Image & target,
|
|||
img_mtx /= agg::trans_affine_scaling(image_ratio_x, image_ratio_y);
|
||||
|
||||
// create a linear interpolator for our scaling matrix
|
||||
using interpolator_type = agg::span_interpolator_linear<>;
|
||||
interpolator_type interpolator(img_mtx);
|
||||
|
||||
// draw an anticlockwise polygon to render our image into
|
||||
double scaled_width = target.width();
|
||||
double scaled_height = target.height();
|
||||
|
@ -145,73 +148,33 @@ void scale_image_agg(Image & target,
|
|||
ras.line_to_d(x_off_f + scaled_width, y_off_f + scaled_height);
|
||||
ras.line_to_d(x_off_f, y_off_f + scaled_height);
|
||||
|
||||
switch(scaling_method)
|
||||
if (scaling_method == SCALING_NEAR)
|
||||
{
|
||||
case SCALING_NEAR:
|
||||
{
|
||||
using span_gen_type = agg::span_image_filter_rgba_nn<img_src_type, interpolator_type>;
|
||||
using span_gen_type = typename detail::agg_scaling_traits<image_data_type>::span_image_filter;
|
||||
span_gen_type sg(img_src, interpolator);
|
||||
agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg);
|
||||
return;
|
||||
}
|
||||
case SCALING_BILINEAR:
|
||||
filter.calculate(agg::image_filter_bilinear(), true); break;
|
||||
case SCALING_BICUBIC:
|
||||
filter.calculate(agg::image_filter_bicubic(), true); break;
|
||||
case SCALING_SPLINE16:
|
||||
filter.calculate(agg::image_filter_spline16(), true); break;
|
||||
case SCALING_SPLINE36:
|
||||
filter.calculate(agg::image_filter_spline36(), true); break;
|
||||
case SCALING_HANNING:
|
||||
filter.calculate(agg::image_filter_hanning(), true); break;
|
||||
case SCALING_HAMMING:
|
||||
filter.calculate(agg::image_filter_hamming(), true); break;
|
||||
case SCALING_HERMITE:
|
||||
filter.calculate(agg::image_filter_hermite(), true); break;
|
||||
case SCALING_KAISER:
|
||||
filter.calculate(agg::image_filter_kaiser(), true); break;
|
||||
case SCALING_QUADRIC:
|
||||
filter.calculate(agg::image_filter_quadric(), true); break;
|
||||
case SCALING_CATROM:
|
||||
filter.calculate(agg::image_filter_catrom(), true); break;
|
||||
case SCALING_GAUSSIAN:
|
||||
filter.calculate(agg::image_filter_gaussian(), true); break;
|
||||
case SCALING_BESSEL:
|
||||
filter.calculate(agg::image_filter_bessel(), true); break;
|
||||
case SCALING_MITCHELL:
|
||||
filter.calculate(agg::image_filter_mitchell(), true); break;
|
||||
case SCALING_SINC:
|
||||
filter.calculate(agg::image_filter_sinc(filter_factor), true); break;
|
||||
case SCALING_LANCZOS:
|
||||
filter.calculate(agg::image_filter_lanczos(filter_factor), true); break;
|
||||
case SCALING_BLACKMAN:
|
||||
filter.calculate(agg::image_filter_blackman(filter_factor), true); break;
|
||||
}
|
||||
// details on various resampling considerations
|
||||
// http://old.nabble.com/Re%3A-Newbie---texture-p5057255.html
|
||||
|
||||
// high quality resampler
|
||||
using span_gen_type = agg::span_image_resample_rgba_affine<img_src_type>;
|
||||
|
||||
// faster, lower quality
|
||||
//using span_gen_type = agg::span_image_filter_rgba<img_src_type,interpolator_type>;
|
||||
|
||||
// local, modified agg::span_image_resample_rgba_affine
|
||||
// dating back to when we were not handling alpha correctly
|
||||
// and this file helped work around symptoms
|
||||
// https://github.com/mapnik/mapnik/issues/1489
|
||||
//using span_gen_type = mapnik::span_image_resample_rgba_affine<img_src_type>;
|
||||
else
|
||||
{
|
||||
using span_gen_type = typename detail::agg_scaling_traits<image_data_type>::span_image_resample_affine;
|
||||
agg::image_filter_lut filter;
|
||||
detail::set_scaling_method(filter, scaling_method, filter_factor);
|
||||
span_gen_type sg(img_src, interpolator, filter);
|
||||
agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg);
|
||||
}
|
||||
|
||||
template void scale_image_agg<image_data_32>(image_data_32& target,
|
||||
const image_data_32& source,
|
||||
scaling_method_e scaling_method,
|
||||
double image_ratio_x,
|
||||
double image_ratio_y,
|
||||
double x_off_f,
|
||||
double y_off_f,
|
||||
double filter_factor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template MAPNIK_DECL void scale_image_agg(image_data_rgba8 &, image_data_rgba8 const&, scaling_method_e,
|
||||
double, double , double, double , double);
|
||||
|
||||
template MAPNIK_DECL void scale_image_agg(image_data_gray8 &, image_data_gray8 const&, scaling_method_e,
|
||||
double, double , double, double , double);
|
||||
|
||||
template MAPNIK_DECL void scale_image_agg(image_data_gray16 &, image_data_gray16 const&, scaling_method_e,
|
||||
double, double , double, double , double);
|
||||
|
||||
template MAPNIK_DECL void scale_image_agg(image_data_gray32f &, image_data_gray32f const&, scaling_method_e,
|
||||
double, double , double, double , double);
|
||||
|
||||
}
|
||||
|
|
|
@ -255,6 +255,127 @@ void handle_png_options(std::string const& type,
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_TIFF)
|
||||
void handle_tiff_options(std::string const& type,
|
||||
tiff_config & config)
|
||||
{
|
||||
if (type == "tiff")
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (type.length() > 4)
|
||||
{
|
||||
boost::char_separator<char> sep(":");
|
||||
boost::tokenizer< boost::char_separator<char> > tokens(type, sep);
|
||||
for (auto const& t : tokens)
|
||||
{
|
||||
if (t == "tiff")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (boost::algorithm::starts_with(t, "compression="))
|
||||
{
|
||||
std::string val = t.substr(12);
|
||||
if (!val.empty())
|
||||
{
|
||||
if (val == "deflate")
|
||||
{
|
||||
config.compression = COMPRESSION_DEFLATE;
|
||||
}
|
||||
else if (val == "adobedeflate")
|
||||
{
|
||||
config.compression = COMPRESSION_ADOBE_DEFLATE;
|
||||
}
|
||||
else if (val == "lzw")
|
||||
{
|
||||
config.compression = COMPRESSION_LZW;
|
||||
}
|
||||
else if (val == "none")
|
||||
{
|
||||
config.compression = COMPRESSION_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ImageWriterException("invalid tiff compression: '" + val + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (boost::algorithm::starts_with(t, "method="))
|
||||
{
|
||||
std::string val = t.substr(7);
|
||||
if (!val.empty())
|
||||
{
|
||||
if (val == "scanline")
|
||||
{
|
||||
config.method = TIFF_WRITE_SCANLINE;
|
||||
}
|
||||
else if (val == "strip" || val == "stripped")
|
||||
{
|
||||
config.method = TIFF_WRITE_STRIPPED;
|
||||
}
|
||||
else if (val == "tiled")
|
||||
{
|
||||
config.method = TIFF_WRITE_TILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ImageWriterException("invalid tiff method: '" + val + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (boost::algorithm::starts_with(t, "zlevel="))
|
||||
{
|
||||
std::string val = t.substr(7);
|
||||
if (!val.empty())
|
||||
{
|
||||
if (!mapnik::util::string2int(val,config.zlevel) || config.zlevel < 0 || config.zlevel > 9)
|
||||
{
|
||||
throw ImageWriterException("invalid tiff zlevel: '" + val + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (boost::algorithm::starts_with(t, "tile_height="))
|
||||
{
|
||||
std::string val = t.substr(12);
|
||||
if (!val.empty())
|
||||
{
|
||||
if (!mapnik::util::string2int(val,config.tile_height) || config.tile_height < 0 )
|
||||
{
|
||||
throw ImageWriterException("invalid tiff tile_height: '" + val + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (boost::algorithm::starts_with(t, "tile_width="))
|
||||
{
|
||||
std::string val = t.substr(11);
|
||||
if (!val.empty())
|
||||
{
|
||||
if (!mapnik::util::string2int(val,config.tile_width) || config.tile_width < 0 )
|
||||
{
|
||||
throw ImageWriterException("invalid tiff tile_width: '" + val + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (boost::algorithm::starts_with(t, "rows_per_strip="))
|
||||
{
|
||||
std::string val = t.substr(15);
|
||||
if (!val.empty())
|
||||
{
|
||||
if (!mapnik::util::string2int(val,config.rows_per_strip) || config.rows_per_strip < 0 )
|
||||
{
|
||||
throw ImageWriterException("invalid tiff rows_per_strip: '" + val + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ImageWriterException("unhandled tiff option: " + t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_WEBP)
|
||||
void handle_webp_options(std::string const& type,
|
||||
WebPConfig & config,
|
||||
|
@ -621,7 +742,9 @@ void save_to_stream(T const& image,
|
|||
else if (boost::algorithm::starts_with(t, "tif"))
|
||||
{
|
||||
#if defined(HAVE_TIFF)
|
||||
save_as_tiff(stream, image);
|
||||
tiff_config config;
|
||||
handle_tiff_options(t, config);
|
||||
save_as_tiff(stream, image, config);
|
||||
#else
|
||||
throw ImageWriterException("tiff output is not enabled in your build of Mapnik");
|
||||
#endif
|
||||
|
@ -769,62 +892,62 @@ void save_to_cairo_file(mapnik::Map const& map,
|
|||
|
||||
#endif
|
||||
|
||||
template void save_to_file<image_data_32>(image_data_32 const&,
|
||||
template void save_to_file<image_data_rgba8>(image_data_rgba8 const&,
|
||||
std::string const&,
|
||||
std::string const&);
|
||||
|
||||
template void save_to_file<image_data_32>(image_data_32 const&,
|
||||
template void save_to_file<image_data_rgba8>(image_data_rgba8 const&,
|
||||
std::string const&,
|
||||
std::string const&,
|
||||
rgba_palette const& palette);
|
||||
|
||||
template void save_to_file<image_data_32>(image_data_32 const&,
|
||||
template void save_to_file<image_data_rgba8>(image_data_rgba8 const&,
|
||||
std::string const&);
|
||||
|
||||
template void save_to_file<image_data_32>(image_data_32 const&,
|
||||
template void save_to_file<image_data_rgba8>(image_data_rgba8 const&,
|
||||
std::string const&,
|
||||
rgba_palette const& palette);
|
||||
|
||||
template std::string save_to_string<image_data_32>(image_data_32 const&,
|
||||
template std::string save_to_string<image_data_rgba8>(image_data_rgba8 const&,
|
||||
std::string const&);
|
||||
|
||||
template std::string save_to_string<image_data_32>(image_data_32 const&,
|
||||
template std::string save_to_string<image_data_rgba8>(image_data_rgba8 const&,
|
||||
std::string const&,
|
||||
rgba_palette const& palette);
|
||||
|
||||
template void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
|
||||
template void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
|
||||
std::string const&,
|
||||
std::string const&);
|
||||
|
||||
template void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
|
||||
template void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
|
||||
std::string const&,
|
||||
std::string const&,
|
||||
rgba_palette const& palette);
|
||||
|
||||
template void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
|
||||
template void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
|
||||
std::string const&);
|
||||
|
||||
template void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
|
||||
template void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
|
||||
std::string const&,
|
||||
rgba_palette const& palette);
|
||||
|
||||
template std::string save_to_string<image_view<image_data_32> > (image_view<image_data_32> const&,
|
||||
template std::string save_to_string<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
|
||||
std::string const&);
|
||||
|
||||
template std::string save_to_string<image_view<image_data_32> > (image_view<image_data_32> const&,
|
||||
template std::string save_to_string<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
|
||||
std::string const&,
|
||||
rgba_palette const& palette);
|
||||
|
||||
void save_to_file(image_32 const& image,std::string const& file)
|
||||
{
|
||||
save_to_file<image_data_32>(image.data(), file);
|
||||
save_to_file<image_data_rgba8>(image.data(), file);
|
||||
}
|
||||
|
||||
void save_to_file (image_32 const& image,
|
||||
std::string const& file,
|
||||
std::string const& type)
|
||||
{
|
||||
save_to_file<image_data_32>(image.data(), file, type);
|
||||
save_to_file<image_data_rgba8>(image.data(), file, type);
|
||||
}
|
||||
|
||||
void save_to_file (image_32 const& image,
|
||||
|
@ -832,20 +955,20 @@ void save_to_file (image_32 const& image,
|
|||
std::string const& type,
|
||||
rgba_palette const& palette)
|
||||
{
|
||||
save_to_file<image_data_32>(image.data(), file, type, palette);
|
||||
save_to_file<image_data_rgba8>(image.data(), file, type, palette);
|
||||
}
|
||||
|
||||
std::string save_to_string(image_32 const& image,
|
||||
std::string const& type)
|
||||
{
|
||||
return save_to_string<image_data_32>(image.data(), type);
|
||||
return save_to_string<image_data_rgba8>(image.data(), type);
|
||||
}
|
||||
|
||||
std::string save_to_string(image_32 const& image,
|
||||
std::string const& type,
|
||||
rgba_palette const& palette)
|
||||
{
|
||||
return save_to_string<image_data_32>(image.data(), type, palette);
|
||||
return save_to_string<image_data_rgba8>(image.data(), type, palette);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -81,11 +81,13 @@ public:
|
|||
explicit jpeg_reader(std::string const& file_name);
|
||||
explicit jpeg_reader(char const* data, size_t size);
|
||||
~jpeg_reader();
|
||||
unsigned width() const;
|
||||
unsigned height() const;
|
||||
inline bool has_alpha() const { return false; }
|
||||
inline bool premultiplied_alpha() const { return true; }
|
||||
void read(unsigned x,unsigned y,image_data_32& image);
|
||||
unsigned width() const final;
|
||||
unsigned height() const final;
|
||||
boost::optional<box2d<double> > bounding_box() const final;
|
||||
inline bool has_alpha() const final { return false; }
|
||||
inline bool premultiplied_alpha() const final { return true; }
|
||||
void read(unsigned x,unsigned y,image_data_rgba8& image) final;
|
||||
image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final;
|
||||
private:
|
||||
void init();
|
||||
static void on_error(j_common_ptr cinfo);
|
||||
|
@ -258,7 +260,13 @@ unsigned jpeg_reader<T>::height() const
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void jpeg_reader<T>::read(unsigned x0, unsigned y0, image_data_32& image)
|
||||
boost::optional<box2d<double> > jpeg_reader<T>::bounding_box() const
|
||||
{
|
||||
return boost::optional<box2d<double> >();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void jpeg_reader<T>::read(unsigned x0, unsigned y0, image_data_rgba8& image)
|
||||
{
|
||||
stream_.clear();
|
||||
stream_.seekg(0, std::ios_base::beg);
|
||||
|
@ -312,4 +320,12 @@ void jpeg_reader<T>::read(unsigned x0, unsigned y0, image_data_32& image)
|
|||
jpeg_finish_decompress(&cinfo);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
image_data_any jpeg_reader<T>::read(unsigned x, unsigned y, unsigned width, unsigned height)
|
||||
{
|
||||
image_data_rgba8 data(width,height);
|
||||
read(x, y, data);
|
||||
return image_data_any(std::move(data));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ marker_cache::marker_cache()
|
|||
"<svg width='100%' height='100%' version='1.1' xmlns='http://www.w3.org/2000/svg'>"
|
||||
"<path fill='#0000FF' stroke='black' stroke-width='.5' d='m 31.698405,7.5302648 -8.910967,-6.0263712 0.594993,4.8210971 -18.9822542,0 0,2.4105482 18.9822542,0 -0.594993,4.8210971 z'/>"
|
||||
"</svg>");
|
||||
boost::optional<mapnik::image_ptr> bitmap_data = boost::optional<mapnik::image_ptr>(std::make_shared<image_data_32>(4,4));
|
||||
boost::optional<mapnik::image_ptr> bitmap_data = boost::optional<mapnik::image_ptr>(std::make_shared<image_data_rgba8>(4,4));
|
||||
(*bitmap_data)->set(0xff000000);
|
||||
marker_ptr mark = std::make_shared<mapnik::marker>(bitmap_data);
|
||||
marker_cache_.emplace("image://square",mark);
|
||||
|
@ -210,7 +210,7 @@ boost::optional<marker_ptr> marker_cache::find(std::string const& uri,
|
|||
unsigned width = reader->width();
|
||||
unsigned height = reader->height();
|
||||
BOOST_ASSERT(width > 0 && height > 0);
|
||||
mapnik::image_ptr image(std::make_shared<mapnik::image_data_32>(width,height));
|
||||
mapnik::image_ptr image(std::make_shared<mapnik::image_data_rgba8>(width,height));
|
||||
reader->read(0,0,*image);
|
||||
if (!reader->premultiplied_alpha())
|
||||
{
|
||||
|
|
|
@ -361,11 +361,11 @@ const mz_uint8 PNGWriter::IEND_tpl[] = {
|
|||
'I', 'E', 'N', 'D' // "IEND"
|
||||
};
|
||||
|
||||
template void PNGWriter::writeIDAT<image_data_8>(image_data_8 const& image);
|
||||
template void PNGWriter::writeIDAT<image_view<image_data_8> >(image_view<image_data_8> const& image);
|
||||
template void PNGWriter::writeIDAT<image_data_32>(image_data_32 const& image);
|
||||
template void PNGWriter::writeIDAT<image_view<image_data_32> >(image_view<image_data_32> const& image);
|
||||
template void PNGWriter::writeIDATStripAlpha<image_data_32>(image_data_32 const& image);
|
||||
template void PNGWriter::writeIDATStripAlpha<image_view<image_data_32> >(image_view<image_data_32> const& image);
|
||||
template void PNGWriter::writeIDAT<image_data_gray8>(image_data_gray8 const& image);
|
||||
template void PNGWriter::writeIDAT<image_view<image_data_gray8> >(image_view<image_data_gray8> const& image);
|
||||
template void PNGWriter::writeIDAT<image_data_rgba8>(image_data_rgba8 const& image);
|
||||
template void PNGWriter::writeIDAT<image_view<image_data_rgba8> >(image_view<image_data_rgba8> const& image);
|
||||
template void PNGWriter::writeIDATStripAlpha<image_data_rgba8>(image_data_rgba8 const& image);
|
||||
template void PNGWriter::writeIDATStripAlpha<image_view<image_data_rgba8> >(image_view<image_data_rgba8> const& image);
|
||||
|
||||
}}
|
||||
|
|
|
@ -76,11 +76,13 @@ public:
|
|||
explicit png_reader(std::string const& file_name);
|
||||
png_reader(char const* data, std::size_t size);
|
||||
~png_reader();
|
||||
unsigned width() const;
|
||||
unsigned height() const;
|
||||
inline bool has_alpha() const { return has_alpha_; }
|
||||
bool premultiplied_alpha() const { return false; } //http://www.libpng.org/pub/png/spec/1.1/PNG-Rationale.html
|
||||
void read(unsigned x,unsigned y,image_data_32& image);
|
||||
unsigned width() const final;
|
||||
unsigned height() const final;
|
||||
boost::optional<box2d<double> > bounding_box() const final;
|
||||
inline bool has_alpha() const final { return has_alpha_; }
|
||||
bool premultiplied_alpha() const final { return false; } //http://www.libpng.org/pub/png/spec/1.1/PNG-Rationale.html
|
||||
void read(unsigned x,unsigned y,image_data_rgba8& image) final;
|
||||
image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final;
|
||||
private:
|
||||
void init();
|
||||
static void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length);
|
||||
|
@ -219,7 +221,13 @@ unsigned png_reader<T>::height() const
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void png_reader<T>::read(unsigned x0, unsigned y0,image_data_32& image)
|
||||
boost::optional<box2d<double> > png_reader<T>::bounding_box() const
|
||||
{
|
||||
return boost::optional<box2d<double> >();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void png_reader<T>::read(unsigned x0, unsigned y0,image_data_rgba8& image)
|
||||
{
|
||||
stream_.clear();
|
||||
stream_.seekg(0, std::ios_base::beg);
|
||||
|
@ -300,4 +308,14 @@ void png_reader<T>::read(unsigned x0, unsigned y0,image_data_32& image)
|
|||
}
|
||||
png_read_end(png_ptr,0);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
image_data_any png_reader<T>::read(unsigned x, unsigned y, unsigned width, unsigned height)
|
||||
{
|
||||
image_data_rgba8 data(width,height);
|
||||
read(x, y, data);
|
||||
return image_data_any(std::move(data));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -122,23 +122,27 @@ bool raster_colorizer::add_stop(colorizer_stop const& stop)
|
|||
return true;
|
||||
}
|
||||
|
||||
void raster_colorizer::colorize(raster_ptr const& raster, feature_impl const& f) const
|
||||
template <typename T>
|
||||
void raster_colorizer::colorize(image_data_rgba8 & out, T const& in,
|
||||
boost::optional<double> const& nodata,
|
||||
feature_impl const& f) const
|
||||
{
|
||||
unsigned *imageData = raster->data_.getData();
|
||||
|
||||
int len = raster->data_.width() * raster->data_.height();
|
||||
boost::optional<double> const& nodata = raster->nodata();
|
||||
using image_data_type = T;
|
||||
using pixel_type = typename image_data_type::pixel_type;
|
||||
// TODO: assuming in/out have the same width/height for now
|
||||
std::uint32_t * out_data = out.getData();
|
||||
pixel_type const* in_data = in.getData();
|
||||
int len = out.width() * out.height();
|
||||
for (int i=0; i<len; ++i)
|
||||
{
|
||||
// the GDAL plugin reads single bands as floats
|
||||
float value = *reinterpret_cast<float *> (&imageData[i]);
|
||||
pixel_type value = in_data[i];
|
||||
if (nodata && (std::fabs(value - *nodata) < epsilon_))
|
||||
{
|
||||
imageData[i] = 0;
|
||||
out_data[i] = 0; // rgba(0,0,0,0)
|
||||
}
|
||||
else
|
||||
{
|
||||
imageData[i] = get_color(value);
|
||||
out_data[i] = get_color(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,7 +157,7 @@ unsigned raster_colorizer::get_color(float value) const
|
|||
int stopCount = stops_.size();
|
||||
|
||||
//use default color if no stops
|
||||
if(stopCount == 0)
|
||||
if (stopCount == 0)
|
||||
{
|
||||
return default_color_.rgba();
|
||||
}
|
||||
|
@ -282,4 +286,14 @@ unsigned raster_colorizer::get_color(float value) const
|
|||
}
|
||||
|
||||
|
||||
template void raster_colorizer::colorize(image_data_rgba8 & out, image_data_gray8 const& in,
|
||||
boost::optional<double>const& nodata,
|
||||
feature_impl const& f) const;
|
||||
template void raster_colorizer::colorize(image_data_rgba8 & out, image_data_gray16 const& in,
|
||||
boost::optional<double>const& nodata,
|
||||
feature_impl const& f) const;
|
||||
template void raster_colorizer::colorize(image_data_rgba8 & out, image_data_gray32f const& in,
|
||||
boost::optional<double>const& nodata,
|
||||
feature_impl const& f) const;
|
||||
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
namespace mapnik {
|
||||
|
||||
std::shared_ptr<image_data_32> render_pattern(rasterizer & ras,
|
||||
std::shared_ptr<image_data_rgba8> render_pattern(rasterizer & ras,
|
||||
marker const& marker,
|
||||
agg::trans_affine const& tr,
|
||||
double opacity)
|
||||
|
@ -51,7 +51,7 @@ std::shared_ptr<image_data_32> render_pattern(rasterizer & ras,
|
|||
mtx.translate(0.5 * bbox.width(), 0.5 * bbox.height());
|
||||
mtx = tr * mtx;
|
||||
|
||||
std::shared_ptr<mapnik::image_data_32> image = std::make_shared<mapnik::image_data_32>(bbox.width(), bbox.height());
|
||||
std::shared_ptr<mapnik::image_data_rgba8> image = std::make_shared<mapnik::image_data_rgba8>(bbox.width(), bbox.height());
|
||||
agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->width() * 4);
|
||||
pixfmt pixf(buf);
|
||||
renderer_base renb(pixf);
|
||||
|
|
|
@ -42,9 +42,9 @@ extern "C"
|
|||
|
||||
namespace mapnik { namespace impl {
|
||||
|
||||
static toff_t tiff_seek_proc(thandle_t fd, toff_t off, int whence)
|
||||
static toff_t tiff_seek_proc(thandle_t handle, toff_t off, int whence)
|
||||
{
|
||||
std::istream* in = reinterpret_cast<std::istream*>(fd);
|
||||
std::istream* in = reinterpret_cast<std::istream*>(handle);
|
||||
|
||||
switch(whence)
|
||||
{
|
||||
|
@ -66,9 +66,9 @@ static int tiff_close_proc(thandle_t)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static toff_t tiff_size_proc(thandle_t fd)
|
||||
static toff_t tiff_size_proc(thandle_t handle)
|
||||
{
|
||||
std::istream* in = reinterpret_cast<std::istream*>(fd);
|
||||
std::istream* in = reinterpret_cast<std::istream*>(handle);
|
||||
std::ios::pos_type pos = in->tellg();
|
||||
in->seekg(0, std::ios::end);
|
||||
std::ios::pos_type len = in->tellg();
|
||||
|
@ -76,9 +76,9 @@ static toff_t tiff_size_proc(thandle_t fd)
|
|||
return static_cast<toff_t>(len);
|
||||
}
|
||||
|
||||
static tsize_t tiff_read_proc(thandle_t fd, tdata_t buf, tsize_t size)
|
||||
static tsize_t tiff_read_proc(thandle_t handle, tdata_t buf, tsize_t size)
|
||||
{
|
||||
std::istream * in = reinterpret_cast<std::istream*>(fd);
|
||||
std::istream * in = reinterpret_cast<std::istream*>(handle);
|
||||
std::streamsize request_size = size;
|
||||
if (static_cast<tsize_t>(request_size) != size)
|
||||
return static_cast<tsize_t>(-1);
|
||||
|
@ -123,15 +123,23 @@ class tiff_reader : public image_reader
|
|||
private:
|
||||
source_type source_;
|
||||
input_stream stream_;
|
||||
tiff_ptr tif_;
|
||||
int read_method_;
|
||||
std::size_t width_;
|
||||
std::size_t height_;
|
||||
int rows_per_strip_;
|
||||
int tile_width_;
|
||||
int tile_height_;
|
||||
tiff_ptr tif_;
|
||||
std::size_t width_;
|
||||
std::size_t height_;
|
||||
boost::optional<box2d<double> > bbox_;
|
||||
unsigned bps_;
|
||||
unsigned photometric_;
|
||||
unsigned bands_;
|
||||
unsigned planar_config_;
|
||||
unsigned compression_;
|
||||
bool premultiplied_alpha_;
|
||||
bool has_alpha_;
|
||||
bool is_tiled_;
|
||||
|
||||
public:
|
||||
enum TiffType {
|
||||
generic=1,
|
||||
|
@ -141,18 +149,35 @@ public:
|
|||
explicit tiff_reader(std::string const& file_name);
|
||||
tiff_reader(char const* data, std::size_t size);
|
||||
virtual ~tiff_reader();
|
||||
unsigned width() const;
|
||||
unsigned height() const;
|
||||
inline bool has_alpha() const { return has_alpha_; }
|
||||
bool premultiplied_alpha() const;
|
||||
void read(unsigned x,unsigned y,image_data_32& image);
|
||||
unsigned width() const final;
|
||||
unsigned height() const final;
|
||||
boost::optional<box2d<double> > bounding_box() const final;
|
||||
inline bool has_alpha() const final { return has_alpha_; }
|
||||
bool premultiplied_alpha() const final;
|
||||
void read(unsigned x,unsigned y,image_data_rgba8& image) final;
|
||||
image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final;
|
||||
// methods specific to tiff reader
|
||||
unsigned bits_per_sample() const { return bps_; }
|
||||
unsigned photometric() const { return photometric_; }
|
||||
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&);
|
||||
void init();
|
||||
void read_generic(unsigned x,unsigned y,image_data_32& image);
|
||||
void read_stripped(unsigned x,unsigned y,image_data_32& image);
|
||||
void read_tiled(unsigned x,unsigned y,image_data_32& image);
|
||||
void read_generic(unsigned x,unsigned y,image_data_rgba8& image);
|
||||
void read_stripped(unsigned x,unsigned y,image_data_rgba8& image);
|
||||
|
||||
template <typename ImageData>
|
||||
void read_tiled(unsigned x,unsigned y, ImageData & image);
|
||||
|
||||
template <typename ImageData>
|
||||
image_data_any read_any_gray(unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
|
||||
TIFF* open(std::istream & input);
|
||||
};
|
||||
|
||||
|
@ -178,14 +203,21 @@ template <typename T>
|
|||
tiff_reader<T>::tiff_reader(std::string const& file_name)
|
||||
: source_(file_name, std::ios_base::in | std::ios_base::binary),
|
||||
stream_(source_),
|
||||
tif_(nullptr),
|
||||
read_method_(generic),
|
||||
width_(0),
|
||||
height_(0),
|
||||
rows_per_strip_(0),
|
||||
tile_width_(0),
|
||||
tile_height_(0),
|
||||
width_(0),
|
||||
height_(0),
|
||||
bps_(0),
|
||||
photometric_(0),
|
||||
bands_(1),
|
||||
planar_config_(PLANARCONFIG_CONTIG),
|
||||
compression_(COMPRESSION_NONE),
|
||||
premultiplied_alpha_(false),
|
||||
has_alpha_(false)
|
||||
has_alpha_(false),
|
||||
is_tiled_(false)
|
||||
{
|
||||
if (!stream_) throw image_reader_exception("TIFF reader: cannot open file "+ file_name);
|
||||
init();
|
||||
|
@ -195,16 +227,24 @@ template <typename T>
|
|||
tiff_reader<T>::tiff_reader(char const* data, std::size_t size)
|
||||
: source_(data, size),
|
||||
stream_(source_),
|
||||
tif_(nullptr),
|
||||
read_method_(generic),
|
||||
width_(0),
|
||||
height_(0),
|
||||
rows_per_strip_(0),
|
||||
tile_width_(0),
|
||||
tile_height_(0),
|
||||
width_(0),
|
||||
height_(0),
|
||||
bps_(0),
|
||||
photometric_(0),
|
||||
bands_(1),
|
||||
planar_config_(PLANARCONFIG_CONTIG),
|
||||
compression_(COMPRESSION_NONE),
|
||||
premultiplied_alpha_(false),
|
||||
has_alpha_(false)
|
||||
has_alpha_(false),
|
||||
is_tiled_(false)
|
||||
{
|
||||
if (!stream_) throw image_reader_exception("TIFF reader: cannot open image stream ");
|
||||
stream_.rdbuf()->pubsetbuf(0, 0);
|
||||
stream_.seekg(0, std::ios::beg);
|
||||
init();
|
||||
}
|
||||
|
@ -220,21 +260,46 @@ void tiff_reader<T>::init()
|
|||
|
||||
if (!tif) throw image_reader_exception("Can't open tiff file");
|
||||
|
||||
char msg[1024];
|
||||
TIFFGetField(tif,TIFFTAG_BITSPERSAMPLE,&bps_);
|
||||
TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photometric_);
|
||||
TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &bands_);
|
||||
|
||||
MAPNIK_LOG_DEBUG(tiff_reader) << "bits per sample: " << bps_;
|
||||
MAPNIK_LOG_DEBUG(tiff_reader) << "photometric: " << photometric_;
|
||||
MAPNIK_LOG_DEBUG(tiff_reader) << "bands: " << bands_;
|
||||
|
||||
if (TIFFRGBAImageOK(tif,msg))
|
||||
{
|
||||
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width_);
|
||||
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height_);
|
||||
if (TIFFIsTiled(tif))
|
||||
|
||||
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)
|
||||
{
|
||||
orientation = 1;
|
||||
}
|
||||
MAPNIK_LOG_DEBUG(tiff_reader) << "orientation: " << orientation;
|
||||
|
||||
is_tiled_ = TIFFIsTiled(tif);
|
||||
|
||||
if (is_tiled_)
|
||||
{
|
||||
TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width_);
|
||||
TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height_);
|
||||
read_method_=tiled;
|
||||
MAPNIK_LOG_DEBUG(tiff_reader) << "tiff is tiled";
|
||||
read_method_ = tiled;
|
||||
}
|
||||
else if (TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rows_per_strip_)!=0)
|
||||
{
|
||||
read_method_=stripped;
|
||||
MAPNIK_LOG_DEBUG(tiff_reader) << "tiff is stripped";
|
||||
read_method_ = stripped;
|
||||
}
|
||||
//TIFFTAG_EXTRASAMPLES
|
||||
uint16 extrasamples = 0;
|
||||
|
@ -249,10 +314,43 @@ void tiff_reader<T>::init()
|
|||
premultiplied_alpha_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
// Try extracting bounding box from geoTIFF tags
|
||||
{
|
||||
throw image_reader_exception(msg);
|
||||
uint16 count = 0;
|
||||
double *pixelscale;
|
||||
double *tilepoint;
|
||||
if (TIFFGetField(tif, 33550, &count, &pixelscale) == 1 && count == 3
|
||||
&& TIFFGetField(tif, 33922 , &count, &tilepoint) == 1 && count == 6)
|
||||
{
|
||||
MAPNIK_LOG_DEBUG(tiff_reader) << "PixelScale:" << pixelscale[0] << "," << pixelscale[1] << "," << pixelscale[2];
|
||||
MAPNIK_LOG_DEBUG(tiff_reader) << "TilePoint:" << tilepoint[0] << "," << tilepoint[1] << "," << tilepoint[2];
|
||||
MAPNIK_LOG_DEBUG(tiff_reader) << " " << tilepoint[3] << "," << tilepoint[4] << "," << tilepoint[5];
|
||||
|
||||
// assuming upper-left
|
||||
double lox = tilepoint[3];
|
||||
double loy = tilepoint[4];
|
||||
double hix = lox + pixelscale[0] * width_;
|
||||
double hiy = loy - pixelscale[1] * height_;
|
||||
bbox_.reset(box2d<double>(lox, loy, hix, hiy));
|
||||
MAPNIK_LOG_DEBUG(tiff_reader) << "Bounding Box:" << *bbox_;
|
||||
}
|
||||
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,6 +371,12 @@ unsigned tiff_reader<T>::height() const
|
|||
return height_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
boost::optional<box2d<double> > tiff_reader<T>::bounding_box() const
|
||||
{
|
||||
return bbox_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool tiff_reader<T>::premultiplied_alpha() const
|
||||
{
|
||||
|
@ -280,7 +384,7 @@ bool tiff_reader<T>::premultiplied_alpha() const
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void tiff_reader<T>::read(unsigned x,unsigned y,image_data_32& image)
|
||||
void tiff_reader<T>::read(unsigned x,unsigned y,image_data_rgba8& image)
|
||||
{
|
||||
if (read_method_==stripped)
|
||||
{
|
||||
|
@ -297,96 +401,279 @@ void tiff_reader<T>::read(unsigned x,unsigned y,image_data_32& image)
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void tiff_reader<T>::read_generic(unsigned, unsigned, image_data_32&)
|
||||
template <typename ImageData>
|
||||
image_data_any tiff_reader<T>::read_any_gray(unsigned x0, unsigned y0, unsigned width, unsigned height)
|
||||
{
|
||||
using image_data_type = ImageData;
|
||||
using pixel_type = typename image_data_type::pixel_type;
|
||||
if (read_method_ == tiled)
|
||||
{
|
||||
image_data_type data(width,height);
|
||||
read_tiled<image_data_type>(x0, y0, data);
|
||||
return image_data_any(std::move(data));
|
||||
}
|
||||
else
|
||||
{
|
||||
TIFF* tif = open(stream_);
|
||||
if (tif)
|
||||
{
|
||||
image_data_type data(width, height);
|
||||
std::size_t block_size = rows_per_strip_ > 0 ? rows_per_strip_ : tile_height_ ;
|
||||
std::ptrdiff_t start_y = y0 - y0 % block_size;
|
||||
std::ptrdiff_t end_y = std::min(y0 + height, static_cast<unsigned>(height_));
|
||||
std::ptrdiff_t start_x = x0;
|
||||
std::ptrdiff_t end_x = std::min(x0 + width, static_cast<unsigned>(width_));
|
||||
std::size_t element_size = sizeof(pixel_type);
|
||||
std::size_t size_to_allocate = (TIFFScanlineSize(tif) + element_size - 1)/element_size;
|
||||
const std::unique_ptr<pixel_type[]> scanline(new pixel_type[size_to_allocate]);
|
||||
for (std::size_t y = start_y; y < end_y; ++y)
|
||||
{
|
||||
if (-1 != TIFFReadScanline(tif, scanline.get(), y) && (y >= y0))
|
||||
{
|
||||
pixel_type * row = data.getRow(y - y0);
|
||||
std::transform(scanline.get() + start_x, scanline.get() + end_x, row, [](pixel_type const& p) { return p;});
|
||||
}
|
||||
}
|
||||
return image_data_any(std::move(data));
|
||||
}
|
||||
}
|
||||
return image_data_any();
|
||||
}
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct rgb8
|
||||
{
|
||||
std::uint8_t r;
|
||||
std::uint8_t g;
|
||||
std::uint8_t b;
|
||||
};
|
||||
|
||||
struct rgb8_to_rgba8
|
||||
{
|
||||
std::uint32_t operator() (rgb8 const& in) const
|
||||
{
|
||||
return ((255 << 24) | (in.r) | (in.g << 8) | (in.b << 16));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct tiff_reader_traits
|
||||
{
|
||||
using image_data_type = T;
|
||||
using pixel_type = typename image_data_type::pixel_type;
|
||||
static bool read_tile(TIFF * tif, unsigned x, unsigned y, pixel_type* buf, std::size_t tile_width, std::size_t tile_height)
|
||||
{
|
||||
return (TIFFReadEncodedTile(tif, TIFFComputeTile(tif, x,y,0,0), buf, tile_width * tile_height * sizeof(pixel_type)) != -1);
|
||||
}
|
||||
};
|
||||
|
||||
// default specialization that expands into RGBA
|
||||
template <>
|
||||
struct tiff_reader_traits<image_data_rgba8>
|
||||
{
|
||||
using pixel_type = std::uint32_t;
|
||||
static bool read_tile(TIFF * tif, unsigned x0, unsigned y0, pixel_type* buf, std::size_t tile_width, std::size_t tile_height)
|
||||
{
|
||||
if (TIFFReadRGBATile(tif, x0, y0, buf) != -1)
|
||||
{
|
||||
for (unsigned y = 0; y < tile_height/2; ++y)
|
||||
{
|
||||
std::swap_ranges(buf + y * tile_width, buf + (y + 1) * tile_width, buf + (tile_height - y - 1) * tile_width);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
image_data_any tiff_reader<T>::read(unsigned x0, unsigned y0, unsigned width, unsigned height)
|
||||
{
|
||||
switch (photometric_)
|
||||
{
|
||||
case PHOTOMETRIC_MINISBLACK:
|
||||
case PHOTOMETRIC_MINISWHITE:
|
||||
{
|
||||
switch (bps_)
|
||||
{
|
||||
case 8:
|
||||
{
|
||||
return read_any_gray<image_data_gray8>(x0, y0, width, height);
|
||||
}
|
||||
case 16:
|
||||
{
|
||||
return read_any_gray<image_data_gray16>(x0, y0, width, height);
|
||||
}
|
||||
case 32:
|
||||
{
|
||||
return read_any_gray<image_data_gray32f>(x0, y0, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
// read PHOTOMETRIC_RGB expand using RGBA interface
|
||||
/*
|
||||
case PHOTOMETRIC_RGB:
|
||||
{
|
||||
switch (bps_)
|
||||
{
|
||||
case 8:
|
||||
{
|
||||
TIFF* tif = open(stream_);
|
||||
if (tif)
|
||||
{
|
||||
image_data_rgba8 data(width, height);
|
||||
std::size_t element_size = sizeof(detail::rgb8);
|
||||
std::size_t size_to_allocate = (TIFFScanlineSize(tif) + element_size - 1)/element_size;
|
||||
const std::unique_ptr<detail::rgb8[]> scanline(new detail::rgb8[size_to_allocate]);
|
||||
std::ptrdiff_t start_y = y0 - y0 % rows_per_strip_;
|
||||
std::ptrdiff_t end_y = std::min(y0 + height, static_cast<unsigned>(height_));
|
||||
std::ptrdiff_t start_x = x0;
|
||||
std::ptrdiff_t end_x = std::min(x0 + width, static_cast<unsigned>(width_));
|
||||
for (std::size_t y = start_y; y < end_y; ++y)
|
||||
{
|
||||
if (-1 != TIFFReadScanline(tif, scanline.get(), y))
|
||||
{
|
||||
if (y >= y0)
|
||||
{
|
||||
image_data_rgba8::pixel_type * row = data.getRow(y - y0);
|
||||
std::transform(scanline.get() + start_x, scanline.get() + end_x, row, detail::rgb8_to_rgba8());
|
||||
}
|
||||
}
|
||||
}
|
||||
return image_data_any(std::move(data));
|
||||
}
|
||||
return image_data_any();
|
||||
}
|
||||
case 16:
|
||||
{
|
||||
image_data_rgba8 data(width,height);
|
||||
read(x0, y0, data);
|
||||
return image_data_any(std::move(data));
|
||||
}
|
||||
case 32:
|
||||
{
|
||||
image_data_rgba8 data(width,height);
|
||||
read(x0, y0, data);
|
||||
return image_data_any(std::move(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
default:
|
||||
{
|
||||
//PHOTOMETRIC_PALETTE = 3;
|
||||
//PHOTOMETRIC_MASK = 4;
|
||||
//PHOTOMETRIC_SEPARATED = 5;
|
||||
//PHOTOMETRIC_YCBCR = 6;
|
||||
//PHOTOMETRIC_CIELAB = 8;
|
||||
//PHOTOMETRIC_ICCLAB = 9;
|
||||
//PHOTOMETRIC_ITULAB = 10;
|
||||
//PHOTOMETRIC_LOGL = 32844;
|
||||
//PHOTOMETRIC_LOGLUV = 32845;
|
||||
image_data_rgba8 data(width,height);
|
||||
read(x0, y0, data);
|
||||
return image_data_any(std::move(data));
|
||||
}
|
||||
}
|
||||
return image_data_any();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void tiff_reader<T>::read_generic(unsigned, unsigned, image_data_rgba8& image)
|
||||
{
|
||||
TIFF* tif = open(stream_);
|
||||
if (tif)
|
||||
{
|
||||
MAPNIK_LOG_DEBUG(tiff_reader) << "tiff_reader: TODO - tiff is not stripped or tiled";
|
||||
throw std::runtime_error("tiff_reader: TODO - tiff is not stripped or tiled");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void tiff_reader<T>::read_tiled(unsigned x0,unsigned y0,image_data_32& image)
|
||||
template <typename ImageData>
|
||||
void tiff_reader<T>::read_tiled(unsigned x0,unsigned y0, ImageData & image)
|
||||
{
|
||||
using pixel_type = typename detail::tiff_reader_traits<ImageData>::pixel_type;
|
||||
|
||||
TIFF* tif = open(stream_);
|
||||
if (tif)
|
||||
{
|
||||
uint32* buf = (uint32*)_TIFFmalloc(tile_width_*tile_height_*sizeof(uint32));
|
||||
int width=image.width();
|
||||
int height=image.height();
|
||||
std::unique_ptr<pixel_type[]> buf(new pixel_type[tile_width_*tile_height_]);
|
||||
int width = image.width();
|
||||
int height = image.height();
|
||||
int start_y = (y0 / tile_height_) * tile_height_;
|
||||
int end_y = ((y0 + height) / tile_height_ + 1) * tile_height_;
|
||||
int start_x = (x0 / tile_width_) * tile_width_;
|
||||
int end_x = ((x0 + width) / tile_width_ + 1) * tile_width_;
|
||||
end_y = std::min(end_y, int(height_));
|
||||
end_x = std::min(end_x, int(width_));
|
||||
|
||||
int start_y=(y0/tile_height_)*tile_height_;
|
||||
int end_y=((y0+height)/tile_height_+1)*tile_height_;
|
||||
|
||||
int start_x=(x0/tile_width_)*tile_width_;
|
||||
int end_x=((x0+width)/tile_width_+1)*tile_width_;
|
||||
int row,tx0,tx1,ty0,ty1;
|
||||
|
||||
for (int y=start_y;y<end_y;y+=tile_height_)
|
||||
for (int y = start_y; y < end_y; y += tile_height_)
|
||||
{
|
||||
ty0 = std::max(y0,(unsigned)y) - y;
|
||||
ty1 = std::min(height+y0,(unsigned)(y+tile_height_)) - y;
|
||||
int ty0 = std::max(y0, static_cast<unsigned>(y)) - y;
|
||||
int ty1 = std::min(height + y0, static_cast<unsigned>(y + tile_height_)) - y;
|
||||
|
||||
int n0=tile_height_-ty1;
|
||||
int n1=tile_height_-ty0-1;
|
||||
|
||||
for (int x=start_x;x<end_x;x+=tile_width_)
|
||||
for (int x = start_x; x < end_x; x += tile_width_)
|
||||
{
|
||||
|
||||
if (!TIFFReadRGBATile(tif,x,y,buf)) break;
|
||||
|
||||
tx0=std::max(x0,(unsigned)x);
|
||||
tx1=std::min(width+x0,(unsigned)(x+tile_width_));
|
||||
row=y+ty0-y0;
|
||||
for (int n=n1;n>=n0;--n)
|
||||
if (!detail::tiff_reader_traits<ImageData>::read_tile(tif, x, y, buf.get(), tile_width_, tile_height_))
|
||||
{
|
||||
image.setRow(row,tx0-x0,tx1-x0,(const unsigned*)&buf[n*tile_width_+tx0-x]);
|
||||
++row;
|
||||
std::clog << "read_tile(...) failed at " << x << "/" << y << " for " << width_ << "/" << height_ << "\n";
|
||||
break;
|
||||
}
|
||||
int tx0 = std::max(x0, static_cast<unsigned>(x));
|
||||
int tx1 = std::min(width + x0, static_cast<unsigned>(x + tile_width_));
|
||||
int row = y + ty0 - y0;
|
||||
for (int ty = ty0; ty < ty1; ++ty, ++row)
|
||||
{
|
||||
image.setRow(row, tx0 - x0, tx1 - x0, &buf[ty * tile_width_ + tx0 - x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
_TIFFfree(buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void tiff_reader<T>::read_stripped(unsigned x0,unsigned y0,image_data_32& image)
|
||||
void tiff_reader<T>::read_stripped(unsigned x0,unsigned y0,image_data_rgba8& image)
|
||||
{
|
||||
TIFF* tif = open(stream_);
|
||||
if (tif)
|
||||
{
|
||||
uint32* buf = (uint32*)_TIFFmalloc(width_*rows_per_strip_*sizeof(uint32));
|
||||
|
||||
image_data_rgba8 strip(width_,rows_per_strip_,false);
|
||||
int width=image.width();
|
||||
int height=image.height();
|
||||
|
||||
unsigned start_y=(y0/rows_per_strip_)*rows_per_strip_;
|
||||
unsigned end_y=((y0+height)/rows_per_strip_+1)*rows_per_strip_;
|
||||
bool laststrip=((unsigned)end_y > height_)?true:false;
|
||||
bool laststrip=(static_cast<unsigned>(end_y) > height_)?true:false;
|
||||
int row,tx0,tx1,ty0,ty1;
|
||||
|
||||
tx0=x0;
|
||||
tx1=std::min(width+x0,(unsigned)width_);
|
||||
tx1=std::min(width+x0,static_cast<unsigned>(width_));
|
||||
|
||||
for (unsigned y=start_y; y < end_y; y+=rows_per_strip_)
|
||||
{
|
||||
ty0 = std::max(y0,y)-y;
|
||||
ty1 = std::min(height+y0,y+rows_per_strip_)-y;
|
||||
|
||||
if (!TIFFReadRGBAStrip(tif,y,buf)) break;
|
||||
|
||||
if (!TIFFReadRGBAStrip(tif,y,strip.getData()))
|
||||
{
|
||||
std::clog << "TIFFReadRGBAStrip failed at " << y << " for " << width_ << "/" << height_ << "\n";
|
||||
break;
|
||||
}
|
||||
row=y+ty0-y0;
|
||||
|
||||
int n0=laststrip ? 0:(rows_per_strip_-ty1);
|
||||
int n1=laststrip ? (ty1-ty0-1):(rows_per_strip_-ty0-1);
|
||||
for (int n=n1;n>=n0;--n)
|
||||
{
|
||||
image.setRow(row,tx0-x0,tx1-x0,(const unsigned*)&buf[n*width_+tx0]);
|
||||
image.setRow(row,tx0-x0,tx1-x0,&strip.getData()[n*width_+tx0]);
|
||||
++row;
|
||||
}
|
||||
}
|
||||
_TIFFfree(buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -395,7 +682,7 @@ TIFF* tiff_reader<T>::open(std::istream & input)
|
|||
{
|
||||
if (!tif_)
|
||||
{
|
||||
tif_ = tiff_ptr(TIFFClientOpen("tiff_input_stream", "rm",
|
||||
tif_ = tiff_ptr(TIFFClientOpen("tiff_input_stream", "rcm",
|
||||
reinterpret_cast<thandle_t>(&input),
|
||||
impl::tiff_read_proc,
|
||||
impl::tiff_write_proc,
|
||||
|
|
194
src/warp.cpp
194
src/warp.cpp
|
@ -24,6 +24,7 @@
|
|||
#include <mapnik/warp.hpp>
|
||||
#include <mapnik/config.hpp>
|
||||
#include <mapnik/image_data.hpp>
|
||||
#include <mapnik/image_scaling_traits.hpp>
|
||||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/box2d.hpp>
|
||||
#include <mapnik/view_transform.hpp>
|
||||
|
@ -47,19 +48,27 @@
|
|||
|
||||
namespace mapnik {
|
||||
|
||||
void reproject_and_scale_raster(raster & target, raster const& source,
|
||||
proj_transform const& prj_trans,
|
||||
double offset_x, double offset_y,
|
||||
unsigned mesh_size,
|
||||
scaling_method_e scaling_method)
|
||||
template <typename T>
|
||||
MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const& prj_trans,
|
||||
box2d<double> const& target_ext, box2d<double> const& source_ext,
|
||||
double offset_x, double offset_y, unsigned mesh_size, scaling_method_e scaling_method, double filter_factor)
|
||||
{
|
||||
view_transform ts(source.data_.width(), source.data_.height(),
|
||||
source.ext_);
|
||||
view_transform tt(target.data_.width(), target.data_.height(),
|
||||
target.ext_, offset_x, offset_y);
|
||||
using image_data_type = T;
|
||||
using pixel_type = typename image_data_type::pixel_type;
|
||||
using pixfmt_pre = typename detail::agg_scaling_traits<image_data_type>::pixfmt_pre;
|
||||
using color_type = typename detail::agg_scaling_traits<image_data_type>::color_type;
|
||||
using renderer_base = agg::renderer_base<pixfmt_pre>;
|
||||
using interpolator_type = typename detail::agg_scaling_traits<image_data_type>::interpolator_type;
|
||||
|
||||
std::size_t mesh_nx = std::ceil(source.data_.width()/double(mesh_size) + 1);
|
||||
std::size_t mesh_ny = std::ceil(source.data_.height()/double(mesh_size) + 1);
|
||||
constexpr std::size_t pixel_size = sizeof(pixel_type);
|
||||
|
||||
view_transform ts(source.width(), source.height(),
|
||||
source_ext);
|
||||
view_transform tt(target.width(), target.height(),
|
||||
target_ext, offset_x, offset_y);
|
||||
|
||||
std::size_t mesh_nx = std::ceil(source.width()/double(mesh_size) + 1);
|
||||
std::size_t mesh_ny = std::ceil(source.height()/double(mesh_size) + 1);
|
||||
|
||||
image_data<double> xs(mesh_nx, mesh_ny);
|
||||
image_data<double> ys(mesh_nx, mesh_ny);
|
||||
|
@ -69,81 +78,36 @@ void reproject_and_scale_raster(raster & target, raster const& source,
|
|||
{
|
||||
for (std::size_t i=0; i<mesh_nx; ++i)
|
||||
{
|
||||
xs(i,j) = std::min(i*mesh_size,source.data_.width());
|
||||
ys(i,j) = std::min(j*mesh_size,source.data_.height());
|
||||
xs(i,j) = std::min(i*mesh_size,source.width());
|
||||
ys(i,j) = std::min(j*mesh_size,source.height());
|
||||
ts.backward(&xs(i,j), &ys(i,j));
|
||||
}
|
||||
}
|
||||
prj_trans.backward(xs.getData(), ys.getData(), nullptr, mesh_nx*mesh_ny);
|
||||
|
||||
// Initialize AGG objects
|
||||
using pixfmt = agg::pixfmt_rgba32_pre;
|
||||
using color_type = pixfmt::color_type;
|
||||
using renderer_base = agg::renderer_base<pixfmt>;
|
||||
|
||||
agg::rasterizer_scanline_aa<> rasterizer;
|
||||
agg::scanline_bin scanline;
|
||||
agg::rendering_buffer buf((unsigned char*)target.data_.getData(),
|
||||
target.data_.width(),
|
||||
target.data_.height(),
|
||||
target.data_.width()*4);
|
||||
pixfmt pixf(buf);
|
||||
agg::rendering_buffer buf(target.getBytes(),
|
||||
target.width(),
|
||||
target.height(),
|
||||
target.width() * pixel_size);
|
||||
pixfmt_pre pixf(buf);
|
||||
renderer_base rb(pixf);
|
||||
rasterizer.clip_box(0, 0, target.data_.width(), target.data_.height());
|
||||
rasterizer.clip_box(0, 0, target.width(), target.height());
|
||||
agg::rendering_buffer buf_tile(
|
||||
(unsigned char*)source.data_.getData(),
|
||||
source.data_.width(),
|
||||
source.data_.height(),
|
||||
source.data_.width() * 4);
|
||||
const_cast<unsigned char*>(source.getBytes()),
|
||||
source.width(),
|
||||
source.height(),
|
||||
source.width() * pixel_size);
|
||||
|
||||
pixfmt pixf_tile(buf_tile);
|
||||
pixfmt_pre pixf_tile(buf_tile);
|
||||
|
||||
using img_accessor_type = agg::image_accessor_clone<pixfmt>;
|
||||
using img_accessor_type = agg::image_accessor_clone<pixfmt_pre>;
|
||||
img_accessor_type ia(pixf_tile);
|
||||
|
||||
agg::span_allocator<color_type> sa;
|
||||
|
||||
// Initialize filter
|
||||
agg::image_filter_lut filter;
|
||||
switch(scaling_method)
|
||||
{
|
||||
case SCALING_NEAR: break;
|
||||
case SCALING_BILINEAR:
|
||||
filter.calculate(agg::image_filter_bilinear(), true); break;
|
||||
case SCALING_BICUBIC:
|
||||
filter.calculate(agg::image_filter_bicubic(), true); break;
|
||||
case SCALING_SPLINE16:
|
||||
filter.calculate(agg::image_filter_spline16(), true); break;
|
||||
case SCALING_SPLINE36:
|
||||
filter.calculate(agg::image_filter_spline36(), true); break;
|
||||
case SCALING_HANNING:
|
||||
filter.calculate(agg::image_filter_hanning(), true); break;
|
||||
case SCALING_HAMMING:
|
||||
filter.calculate(agg::image_filter_hamming(), true); break;
|
||||
case SCALING_HERMITE:
|
||||
filter.calculate(agg::image_filter_hermite(), true); break;
|
||||
case SCALING_KAISER:
|
||||
filter.calculate(agg::image_filter_kaiser(), true); break;
|
||||
case SCALING_QUADRIC:
|
||||
filter.calculate(agg::image_filter_quadric(), true); break;
|
||||
case SCALING_CATROM:
|
||||
filter.calculate(agg::image_filter_catrom(), true); break;
|
||||
case SCALING_GAUSSIAN:
|
||||
filter.calculate(agg::image_filter_gaussian(), true); break;
|
||||
case SCALING_BESSEL:
|
||||
filter.calculate(agg::image_filter_bessel(), true); break;
|
||||
case SCALING_MITCHELL:
|
||||
filter.calculate(agg::image_filter_mitchell(), true); break;
|
||||
case SCALING_SINC:
|
||||
filter.calculate(agg::image_filter_sinc(source.get_filter_factor()), true); break;
|
||||
case SCALING_LANCZOS:
|
||||
filter.calculate(agg::image_filter_lanczos(source.get_filter_factor()), true); break;
|
||||
case SCALING_BLACKMAN:
|
||||
filter.calculate(agg::image_filter_blackman(source.get_filter_factor()), true); break;
|
||||
}
|
||||
|
||||
// Project mesh cells into target interpolating raster inside each one
|
||||
for(std::size_t j = 0; j < mesh_ny - 1; ++j)
|
||||
for (std::size_t j = 0; j < mesh_ny - 1; ++j)
|
||||
{
|
||||
for (std::size_t i = 0; i < mesh_nx - 1; ++i)
|
||||
{
|
||||
|
@ -166,33 +130,97 @@ void reproject_and_scale_raster(raster & target, raster const& source,
|
|||
std::size_t y0 = j * mesh_size;
|
||||
std::size_t x1 = (i+1) * mesh_size;
|
||||
std::size_t y1 = (j+1) * mesh_size;
|
||||
x1 = std::min(x1, source.data_.width());
|
||||
y1 = std::min(y1, source.data_.height());
|
||||
x1 = std::min(x1, source.width());
|
||||
y1 = std::min(y1, source.height());
|
||||
agg::trans_affine tr(polygon, x0, y0, x1, y1);
|
||||
if (tr.is_valid())
|
||||
{
|
||||
using interpolator_type = agg::span_interpolator_linear<agg::trans_affine>;
|
||||
interpolator_type interpolator(tr);
|
||||
|
||||
if (scaling_method == SCALING_NEAR)
|
||||
{
|
||||
using span_gen_type = agg::span_image_filter_rgba_nn
|
||||
<img_accessor_type, interpolator_type>;
|
||||
using span_gen_type = typename detail::agg_scaling_traits<image_data_type>::span_image_filter;
|
||||
span_gen_type sg(ia, interpolator);
|
||||
agg::render_scanlines_bin(rasterizer, scanline, rb,
|
||||
sa, sg);
|
||||
agg::render_scanlines_bin(rasterizer, scanline, rb, sa, sg);
|
||||
}
|
||||
else
|
||||
{
|
||||
using span_gen_type = agg::span_image_resample_rgba_affine
|
||||
<img_accessor_type>;
|
||||
using span_gen_type = typename detail::agg_scaling_traits<image_data_type>::span_image_resample_affine;
|
||||
agg::image_filter_lut filter;
|
||||
detail::set_scaling_method(filter, scaling_method, filter_factor);
|
||||
span_gen_type sg(ia, interpolator, filter);
|
||||
agg::render_scanlines_bin(rasterizer, scanline, rb,
|
||||
sa, sg);
|
||||
agg::render_scanlines_bin(rasterizer, scanline, rb, sa, sg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct warp_image_visitor : util::static_visitor<void>
|
||||
{
|
||||
warp_image_visitor (raster & target_raster, proj_transform const& prj_trans, box2d<double> const& source_ext,
|
||||
double offset_x, double offset_y, unsigned mesh_size,
|
||||
scaling_method_e scaling_method, double filter_factor)
|
||||
: target_raster_(target_raster),
|
||||
prj_trans_(prj_trans),
|
||||
source_ext_(source_ext),
|
||||
offset_x_(offset_x),
|
||||
offset_y_(offset_y),
|
||||
mesh_size_(mesh_size),
|
||||
scaling_method_(scaling_method),
|
||||
filter_factor_(filter_factor) {}
|
||||
|
||||
void operator() (image_data_null const&) {}
|
||||
|
||||
template <typename T>
|
||||
void operator() (T const& source)
|
||||
{
|
||||
using image_data_type = T;
|
||||
//source and target image data types must match
|
||||
if (target_raster_.data_.template is<image_data_type>())
|
||||
{
|
||||
image_data_type & target = util::get<image_data_type>(target_raster_.data_);
|
||||
warp_image (target, source, prj_trans_, target_raster_.ext_, source_ext_,
|
||||
offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_);
|
||||
}
|
||||
}
|
||||
|
||||
raster & target_raster_;
|
||||
proj_transform const& prj_trans_;
|
||||
box2d<double> const& source_ext_;
|
||||
double offset_x_;
|
||||
double offset_y_;
|
||||
unsigned mesh_size_;
|
||||
scaling_method_e scaling_method_;
|
||||
double filter_factor_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void reproject_and_scale_raster(raster & target, raster const& source,
|
||||
proj_transform const& prj_trans,
|
||||
double offset_x, double offset_y,
|
||||
unsigned mesh_size,
|
||||
scaling_method_e scaling_method)
|
||||
{
|
||||
detail::warp_image_visitor warper(target, prj_trans, source.ext_, offset_x, offset_y, mesh_size,
|
||||
scaling_method, source.get_filter_factor());
|
||||
util::apply_visitor(warper, source.data_);
|
||||
}
|
||||
|
||||
template MAPNIK_DECL void warp_image (image_data_rgba8&, image_data_rgba8 const&, proj_transform const&,
|
||||
box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double);
|
||||
|
||||
template MAPNIK_DECL void warp_image (image_data_gray8&, image_data_gray8 const&, proj_transform const&,
|
||||
box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double);
|
||||
|
||||
template MAPNIK_DECL void warp_image (image_data_gray16&, image_data_gray16 const&, proj_transform const&,
|
||||
box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double);
|
||||
|
||||
template MAPNIK_DECL void warp_image (image_data_gray32f&, image_data_gray32f const&, proj_transform const&,
|
||||
box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double);
|
||||
|
||||
|
||||
}// namespace mapnik
|
||||
|
|
|
@ -120,11 +120,13 @@ public:
|
|||
explicit webp_reader(char const* data, std::size_t size);
|
||||
explicit webp_reader(std::string const& filename);
|
||||
~webp_reader();
|
||||
unsigned width() const;
|
||||
unsigned height() const;
|
||||
inline bool has_alpha() const { return has_alpha_; }
|
||||
bool premultiplied_alpha() const { return false; }
|
||||
void read(unsigned x,unsigned y,image_data_32& image);
|
||||
unsigned width() const final;
|
||||
unsigned height() const final;
|
||||
boost::optional<box2d<double> > bounding_box() const final;
|
||||
inline bool has_alpha() const final { return has_alpha_; }
|
||||
bool premultiplied_alpha() const final { return false; }
|
||||
void read(unsigned x,unsigned y,image_data_rgba8& image) final;
|
||||
image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final;
|
||||
private:
|
||||
void init();
|
||||
};
|
||||
|
@ -229,7 +231,13 @@ unsigned webp_reader<T>::height() const
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void webp_reader<T>::read(unsigned x0, unsigned y0,image_data_32& image)
|
||||
boost::optional<box2d<double> > webp_reader<T>::bounding_box() const
|
||||
{
|
||||
return boost::optional<box2d<double> >();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void webp_reader<T>::read(unsigned x0, unsigned y0,image_data_rgba8& image)
|
||||
{
|
||||
WebPDecoderConfig config;
|
||||
config_guard guard(config);
|
||||
|
@ -260,4 +268,12 @@ void webp_reader<T>::read(unsigned x0, unsigned y0,image_data_32& image)
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
image_data_any webp_reader<T>::read(unsigned x, unsigned y, unsigned width, unsigned height)
|
||||
{
|
||||
image_data_rgba8 data(width,height);
|
||||
read(x, y, data);
|
||||
return image_data_any(std::move(data));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -153,11 +153,10 @@ int main(int argc, char** argv)
|
|||
BOOST_TEST_EQ( to_string(blend<source_over>(white,black)), to_string(white) );
|
||||
BOOST_TEST_EQ( to_string(blend<source_over>(black,white)), to_string(black) );
|
||||
|
||||
// https://github.com/mapnik/mapnik/issues/1452#issuecomment-8154646
|
||||
color near_white(254,254,254,254); // Source
|
||||
color near_trans(1,1,1,1); // Dest
|
||||
color expected_color(252,252,252,255); // expected result
|
||||
BOOST_TEST_EQ( to_string(blend<source_over_old_agg>(near_white,near_trans)), to_string(color(252,252,252,254)) );
|
||||
color expected_color(253,253,253,255); // expected result
|
||||
BOOST_TEST_EQ( to_string(blend<source_over_old_agg>(near_white,near_trans)), to_string(color(253,253,253,254)) );
|
||||
BOOST_TEST_EQ( to_string(blend<source_over>(near_white,near_trans)), to_string(expected_color) );
|
||||
BOOST_TEST_EQ( to_string(normal_blend(near_white,near_trans)), to_string(expected_color) );
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <iostream>
|
||||
#include <mapnik/graphics.hpp>
|
||||
#include <mapnik/image_data.hpp>
|
||||
#include <mapnik/image_reader.hpp>
|
||||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/util/fs.hpp>
|
||||
|
@ -38,6 +40,26 @@ int main(int argc, char** argv)
|
|||
}
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
mapnik::image_32 im(-10,-10); // should throw rather than overflow
|
||||
BOOST_TEST( im.width() < 10 ); // should not get here, but if we did this test should fail
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
BOOST_TEST( true ); // should hit bad alloc here
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
mapnik::image_data_rgba8 im(-10,-10); // should throw rather than overflow
|
||||
BOOST_TEST( im.width() < 10 ); // should not get here, but if we did this test should fail
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
BOOST_TEST( true ); // should hit bad alloc here
|
||||
}
|
||||
|
||||
#if defined(HAVE_PNG)
|
||||
should_throw = "./tests/cpp_tests/data/blank.png";
|
||||
BOOST_TEST( mapnik::util::exists( should_throw ) );
|
||||
|
|
|
@ -39,8 +39,8 @@ bool compare_images(std::string const& src_fn,std::string const& dest_fn)
|
|||
std::shared_ptr<image_32> image_ptr2 = std::make_shared<image_32>(reader2->width(),reader2->height());
|
||||
reader2->read(0,0,image_ptr2->data());
|
||||
|
||||
image_data_32 const& dest = image_ptr1->data();
|
||||
image_data_32 const& src = image_ptr2->data();
|
||||
image_data_rgba8 const& dest = image_ptr1->data();
|
||||
image_data_rgba8 const& src = image_ptr2->data();
|
||||
|
||||
unsigned int width = src.width();
|
||||
unsigned int height = src.height();
|
||||
|
|
11
tests/cxx/README.md
Normal file
11
tests/cxx/README.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
Catch C++ tests
|
||||
|
||||
### Building
|
||||
|
||||
python scons/scons.py tests/cxx/run
|
||||
|
||||
|
||||
### Running
|
||||
|
||||
./tests/cxx/run
|
32
tests/cxx/build.py
Normal file
32
tests/cxx/build.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
import os
|
||||
import glob
|
||||
from copy import copy
|
||||
|
||||
Import ('env')
|
||||
|
||||
test_env = env.Clone()
|
||||
|
||||
if not env['CPP_TESTS']:
|
||||
for cpp_test_bin in glob.glob('*-bin'):
|
||||
os.unlink(cpp_test_bin)
|
||||
else:
|
||||
test_env['LIBS'] = [env['MAPNIK_NAME']]
|
||||
test_env.AppendUnique(LIBS=copy(env['LIBMAPNIK_LIBS']))
|
||||
test_env.AppendUnique(LIBS='mapnik-wkt')
|
||||
test_env.AppendUnique(LIBS='mapnik-json')
|
||||
if env['RUNTIME_LINK'] == 'static' and env['PLATFORM'] == 'Linux':
|
||||
test_env.AppendUnique(LIBS='dl')
|
||||
test_env.AppendUnique(CXXFLAGS='-g')
|
||||
test_env['CXXFLAGS'] = copy(test_env['LIBMAPNIK_CXXFLAGS'])
|
||||
test_env.Append(CPPDEFINES = env['LIBMAPNIK_DEFINES'])
|
||||
if test_env['HAS_CAIRO']:
|
||||
test_env.PrependUnique(CPPPATH=test_env['CAIRO_CPPPATHS'])
|
||||
test_env.Append(CPPDEFINES = '-DHAVE_CAIRO')
|
||||
test_env_local = test_env.Clone()
|
||||
test_program = test_env_local.Program("run", source=glob.glob('*.cpp'))
|
||||
Depends(test_program, env.subst('../../src/%s' % env['MAPNIK_LIB_NAME']))
|
||||
Depends(test_program, env.subst('../../src/json/libmapnik-json${LIBSUFFIX}'))
|
||||
Depends(test_program, env.subst('../../src/wkt/libmapnik-wkt${LIBSUFFIX}'))
|
||||
# build locally if installing
|
||||
if 'install' in COMMAND_LINE_TARGETS:
|
||||
env.Alias('install',test_program)
|
8997
tests/cxx/catch.hpp
Normal file
8997
tests/cxx/catch.hpp
Normal file
File diff suppressed because it is too large
Load diff
2
tests/cxx/test_main.cpp
Normal file
2
tests/cxx/test_main.cpp
Normal file
|
@ -0,0 +1,2 @@
|
|||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
276
tests/cxx/tiff_io.cpp
Normal file
276
tests/cxx/tiff_io.cpp
Normal file
|
@ -0,0 +1,276 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <mapnik/image_reader.hpp>
|
||||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/util/file_io.hpp>
|
||||
#include <mapnik/tiff_io.hpp>
|
||||
#include "../../src/tiff_reader.cpp"
|
||||
|
||||
#define TIFF_ASSERT(filename) \
|
||||
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 ); \
|
||||
mapnik::util::file file(filename); \
|
||||
mapnik::tiff_reader<boost::iostreams::array_source> tiff_reader2(file.data().get(),file.size()); \
|
||||
REQUIRE( tiff_reader2.width() == 256 ); \
|
||||
REQUIRE( tiff_reader2.height() == 256 ); \
|
||||
std::unique_ptr<mapnik::image_reader> reader2(mapnik::get_image_reader(file.data().get(),file.size())); \
|
||||
REQUIRE( reader2->width() == 256 ); \
|
||||
REQUIRE( reader2->height() == 256 ); \
|
||||
|
||||
#define TIFF_ASSERT_ALPHA \
|
||||
REQUIRE( tiff_reader.has_alpha() == true ); \
|
||||
REQUIRE( tiff_reader.premultiplied_alpha() == false ); \
|
||||
REQUIRE( reader->has_alpha() == true ); \
|
||||
REQUIRE( reader->premultiplied_alpha() == false ); \
|
||||
REQUIRE( tiff_reader2.has_alpha() == true ); \
|
||||
REQUIRE( tiff_reader2.premultiplied_alpha() == false ); \
|
||||
REQUIRE( reader2->has_alpha() == true ); \
|
||||
REQUIRE( reader2->premultiplied_alpha() == false ); \
|
||||
|
||||
#define TIFF_ASSERT_NO_ALPHA \
|
||||
REQUIRE( tiff_reader.has_alpha() == false ); \
|
||||
REQUIRE( tiff_reader.premultiplied_alpha() == false ); \
|
||||
REQUIRE( reader->has_alpha() == false ); \
|
||||
REQUIRE( reader->premultiplied_alpha() == false ); \
|
||||
REQUIRE( tiff_reader2.has_alpha() == false ); \
|
||||
REQUIRE( tiff_reader2.premultiplied_alpha() == false ); \
|
||||
REQUIRE( reader2->has_alpha() == false ); \
|
||||
REQUIRE( reader2->premultiplied_alpha() == false ); \
|
||||
|
||||
#define TIFF_ASSERT_SIZE( data,reader ) \
|
||||
REQUIRE( data.width() == reader->width() ); \
|
||||
REQUIRE( data.height() == reader->height() ); \
|
||||
|
||||
#define TIFF_READ_ONE_PIXEL \
|
||||
mapnik::image_data_any subimage = reader->read(1, 1, 1, 1); \
|
||||
REQUIRE( subimage.width() == 1 ); \
|
||||
REQUIRE( subimage.height() == 1 ); \
|
||||
|
||||
TEST_CASE("tiff io") {
|
||||
|
||||
SECTION("scan rgb8 striped") {
|
||||
std::string filename("./tests/data/tiff/scan_512x512_rgb8_striped.tif");
|
||||
mapnik::tiff_reader<boost::iostreams::file_source> tiff_reader(filename);
|
||||
REQUIRE( tiff_reader.width() == 512 );
|
||||
REQUIRE( tiff_reader.height() == 512 );
|
||||
REQUIRE( tiff_reader.planar_config() == PLANARCONFIG_CONTIG );
|
||||
REQUIRE( tiff_reader.rows_per_strip() == 16 );
|
||||
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_PALETTE );
|
||||
REQUIRE( tiff_reader.compression() == COMPRESSION_NONE );
|
||||
std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(filename,"tiff"));
|
||||
REQUIRE( reader->width() == 512 );
|
||||
REQUIRE( reader->height() == 512 );
|
||||
mapnik::util::file file(filename);
|
||||
mapnik::tiff_reader<boost::iostreams::array_source> tiff_reader2(file.data().get(),file.size());
|
||||
REQUIRE( tiff_reader2.width() == 512 );
|
||||
REQUIRE( tiff_reader2.height() == 512 );
|
||||
std::unique_ptr<mapnik::image_reader> reader2(mapnik::get_image_reader(file.data().get(),file.size()));
|
||||
REQUIRE( reader2->width() == 512 );
|
||||
REQUIRE( reader2->height() == 512 );
|
||||
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 );
|
||||
TIFF_ASSERT_NO_ALPHA
|
||||
TIFF_READ_ONE_PIXEL
|
||||
}
|
||||
|
||||
SECTION("scan rgb8 tiled") {
|
||||
std::string filename("./tests/data/tiff/scan_512x512_rgb8_tiled.tif");
|
||||
mapnik::tiff_reader<boost::iostreams::file_source> tiff_reader(filename);
|
||||
REQUIRE( tiff_reader.width() == 512 );
|
||||
REQUIRE( tiff_reader.height() == 512 );
|
||||
REQUIRE( tiff_reader.planar_config() == PLANARCONFIG_CONTIG );
|
||||
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_PALETTE );
|
||||
REQUIRE( tiff_reader.compression() == COMPRESSION_LZW );
|
||||
std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(filename,"tiff"));
|
||||
REQUIRE( reader->width() == 512 );
|
||||
REQUIRE( reader->height() == 512 );
|
||||
mapnik::util::file file(filename);
|
||||
mapnik::tiff_reader<boost::iostreams::array_source> tiff_reader2(file.data().get(),file.size());
|
||||
REQUIRE( tiff_reader2.width() == 512 );
|
||||
REQUIRE( tiff_reader2.height() == 512 );
|
||||
std::unique_ptr<mapnik::image_reader> reader2(mapnik::get_image_reader(file.data().get(),file.size()));
|
||||
REQUIRE( reader2->width() == 512 );
|
||||
REQUIRE( reader2->height() == 512 );
|
||||
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 );
|
||||
TIFF_ASSERT_NO_ALPHA
|
||||
TIFF_READ_ONE_PIXEL
|
||||
}
|
||||
|
||||
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 );
|
||||
TIFF_ASSERT_ALPHA
|
||||
TIFF_READ_ONE_PIXEL
|
||||
}
|
||||
|
||||
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 );
|
||||
TIFF_ASSERT_ALPHA
|
||||
TIFF_READ_ONE_PIXEL
|
||||
}
|
||||
|
||||
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 );
|
||||
TIFF_ASSERT_NO_ALPHA
|
||||
TIFF_READ_ONE_PIXEL
|
||||
}
|
||||
|
||||
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 );
|
||||
TIFF_ASSERT_NO_ALPHA
|
||||
TIFF_READ_ONE_PIXEL
|
||||
}
|
||||
|
||||
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 );
|
||||
TIFF_ASSERT_NO_ALPHA
|
||||
TIFF_READ_ONE_PIXEL
|
||||
}
|
||||
|
||||
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 );
|
||||
TIFF_ASSERT_NO_ALPHA
|
||||
TIFF_READ_ONE_PIXEL
|
||||
}
|
||||
|
||||
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 );
|
||||
TIFF_ASSERT_NO_ALPHA
|
||||
TIFF_READ_ONE_PIXEL
|
||||
}
|
||||
|
||||
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 );
|
||||
TIFF_ASSERT_NO_ALPHA
|
||||
TIFF_READ_ONE_PIXEL
|
||||
}
|
||||
|
||||
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 );
|
||||
TIFF_ASSERT_NO_ALPHA
|
||||
TIFF_READ_ONE_PIXEL
|
||||
}
|
||||
|
||||
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 );
|
||||
TIFF_ASSERT_NO_ALPHA
|
||||
TIFF_READ_ONE_PIXEL
|
||||
}
|
||||
|
||||
}
|
31
tests/cxx/valgrind.supp
Normal file
31
tests/cxx/valgrind.supp
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
dl_error1
|
||||
Memcheck:Cond
|
||||
fun:index
|
||||
fun:expand_dynamic_string_token
|
||||
fun:fillin_rpath
|
||||
fun:_dl_init_paths
|
||||
fun:dl_main
|
||||
fun:_dl_sysdep_start
|
||||
fun:_dl_start
|
||||
}
|
||||
{
|
||||
dl_error2
|
||||
Memcheck:Cond
|
||||
fun:index
|
||||
fun:expand_dynamic_string_token
|
||||
fun:_dl_map_object
|
||||
fun:map_doit
|
||||
fun:_dl_catch_error
|
||||
fun:do_preload
|
||||
fun:dl_main
|
||||
fun:_dl_sysdep_start
|
||||
fun:_dl_start
|
||||
}
|
||||
{
|
||||
tmpfile
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
fun:fdopen@@GLIBC_*
|
||||
fun:tmpfile@@GLIBC_*
|
||||
}
|
4
tests/data/tiff/README.md
Normal file
4
tests/data/tiff/README.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
striped images created with rio
|
||||
tiled images created with:
|
||||
|
||||
tiffcp -t -w256 -l256 -c lzw input.tiff output.tif
|
BIN
tests/data/tiff/ndvi_256x256_gray16_striped.tif
Normal file
BIN
tests/data/tiff/ndvi_256x256_gray16_striped.tif
Normal file
Binary file not shown.
BIN
tests/data/tiff/ndvi_256x256_gray16_tiled.tif
Normal file
BIN
tests/data/tiff/ndvi_256x256_gray16_tiled.tif
Normal file
Binary file not shown.
BIN
tests/data/tiff/ndvi_256x256_gray32f_striped.tif
Normal file
BIN
tests/data/tiff/ndvi_256x256_gray32f_striped.tif
Normal file
Binary file not shown.
BIN
tests/data/tiff/ndvi_256x256_gray32f_tiled.tif
Normal file
BIN
tests/data/tiff/ndvi_256x256_gray32f_tiled.tif
Normal file
Binary file not shown.
BIN
tests/data/tiff/ndvi_256x256_gray8_striped.tif
Normal file
BIN
tests/data/tiff/ndvi_256x256_gray8_striped.tif
Normal file
Binary file not shown.
BIN
tests/data/tiff/ndvi_256x256_gray8_tiled.tif
Normal file
BIN
tests/data/tiff/ndvi_256x256_gray8_tiled.tif
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue