Merge pull request #2608 from mapnik/image_data_any

Image data any
This commit is contained in:
Dane Springmeyer 2014-12-18 20:21:29 -08:00
commit b0f94bff44
242 changed files with 15111 additions and 1999 deletions

View file

@ -1988,6 +1988,7 @@ if not HELP_REQUESTED:
# build C++ tests # build C++ tests
SConscript('tests/cpp_tests/build.py') SConscript('tests/cpp_tests/build.py')
SConscript('tests/cxx/build.py')
if env['BENCHMARK']: if env['BENCHMARK']:
SConscript('benchmark/build.py') SConscript('benchmark/build.py')

View file

@ -37,7 +37,7 @@ public:
return iterations_; return iterations_;
} }
virtual bool validate() const = 0; virtual bool validate() const = 0;
virtual void operator()() const = 0; virtual bool operator()() const = 0;
virtual ~test_case() {} virtual ~test_case() {}
}; };
@ -85,35 +85,40 @@ int run(T const& test_runner, std::string const& name)
std::clog << "test did not validate: " << name << "\n"; std::clog << "test did not validate: " << name << "\n";
return -1; return -1;
} }
std::chrono::high_resolution_clock::time_point start; // run test once before timing
std::chrono::high_resolution_clock::duration elapsed; // if it returns false then we'll abort timing
std::stringstream s; if (test_runner())
s << name << ":"
<< std::setw(45 - (int)s.tellp()) << std::right
<< " t:" << test_runner.threads()
<< " i:" << test_runner.iterations();
if (test_runner.threads() > 0)
{ {
using thread_group = std::vector<std::unique_ptr<std::thread> >; std::chrono::high_resolution_clock::time_point start;
using value_type = thread_group::value_type; std::chrono::high_resolution_clock::duration elapsed;
thread_group tg; std::stringstream s;
for (std::size_t i=0;i<test_runner.threads();++i) s << name << ":"
<< std::setw(45 - (int)s.tellp()) << std::right
<< " t:" << test_runner.threads()
<< " i:" << test_runner.iterations();
if (test_runner.threads() > 0)
{ {
tg.emplace_back(new std::thread(test_runner)); using thread_group = std::vector<std::unique_ptr<std::thread> >;
using value_type = thread_group::value_type;
thread_group tg;
for (std::size_t i=0;i<test_runner.threads();++i)
{
tg.emplace_back(new std::thread(test_runner));
}
start = std::chrono::high_resolution_clock::now();
std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
elapsed = std::chrono::high_resolution_clock::now() - start;
} }
start = std::chrono::high_resolution_clock::now(); else
std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();}); {
elapsed = std::chrono::high_resolution_clock::now() - start; start = std::chrono::high_resolution_clock::now();
test_runner();
elapsed = std::chrono::high_resolution_clock::now() - start;
}
s << std::setw(65 - (int)s.tellp()) << std::right
<< std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count() << " milliseconds\n";
std::clog << s.str();
} }
else
{
start = std::chrono::high_resolution_clock::now();
test_runner();
elapsed = std::chrono::high_resolution_clock::now() - start;
}
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; return 0;
} }
catch (std::exception const& ex) catch (std::exception const& ex)

View file

@ -1,5 +1,5 @@
#ifndef __MAPNIK_COMPARE_IMAGES_HPP__ #ifndef __MAPNIK_COMPARE_IMAGES_HPP__
#define __MAPNIK_COMPARE_IMAGES_HPP__ #define __MAPNIK_COMPARE_IMAGES_HPP__
#include <mapnik/graphics.hpp> #include <mapnik/graphics.hpp>
#include <mapnik/image_data.hpp> #include <mapnik/image_data.hpp>
@ -28,8 +28,8 @@ namespace benchmark {
std::shared_ptr<image_32> image_ptr2 = std::make_shared<image_32>(reader2->width(),reader2->height()); std::shared_ptr<image_32> image_ptr2 = std::make_shared<image_32>(reader2->width(),reader2->height());
reader2->read(0,0,image_ptr2->data()); reader2->read(0,0,image_ptr2->data());
image_data_32 const& dest = image_ptr1->data(); image_data_rgba8 const& dest = image_ptr1->data();
image_data_32 const& src = image_ptr2->data(); image_data_rgba8 const& src = image_ptr2->data();
unsigned int width = src.width(); unsigned int width = src.width();
unsigned int height = src.height(); unsigned int height = src.height();
@ -48,4 +48,4 @@ namespace benchmark {
} }
#endif // __MAPNIK_COMPARE_IMAGES_HPP__ #endif // __MAPNIK_COMPARE_IMAGES_HPP__

View 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>

View 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>

Binary file not shown.

View file

@ -29,4 +29,22 @@ run test_font_registration 10 1000
--width 600 \ --width 600 \
--height 600 \ --height 600 \
--iterations 20 \ --iterations 20 \
--threads 10 --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

View file

@ -41,7 +41,7 @@ public:
{ {
return true; return true;
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
// NOTE: sizeof(uint8_t) == 1 // NOTE: sizeof(uint8_t) == 1
@ -50,6 +50,7 @@ public:
ensure_zero(data,size_); ensure_zero(data,size_);
free(data); free(data);
} }
return true;
} }
}; };
@ -66,7 +67,7 @@ public:
{ {
return true; return true;
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
// NOTE: sizeof(uint8_t) == 1 // NOTE: sizeof(uint8_t) == 1
@ -75,6 +76,7 @@ public:
ensure_zero(data,size_); ensure_zero(data,size_);
free(data); free(data);
} }
return true;
} }
}; };
@ -91,7 +93,7 @@ public:
{ {
return true; return true;
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
uint8_t *data = static_cast<uint8_t *>(::operator new(sizeof(uint8_t) * size_)); uint8_t *data = static_cast<uint8_t *>(::operator new(sizeof(uint8_t) * size_));
@ -99,6 +101,7 @@ public:
ensure_zero(data,size_); ensure_zero(data,size_);
::operator delete(data); ::operator delete(data);
} }
return true;
} }
}; };
@ -116,7 +119,7 @@ public:
{ {
return true; return true;
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
uint8_t * data = static_cast<uint8_t*>(::operator new(sizeof(uint8_t)*size_)); uint8_t * data = static_cast<uint8_t*>(::operator new(sizeof(uint8_t)*size_));
@ -124,6 +127,7 @@ public:
ensure_zero(data,size_); ensure_zero(data,size_);
::operator delete(data),data=0; ::operator delete(data),data=0;
} }
return true;
} }
}; };
@ -140,12 +144,13 @@ public:
{ {
return true; return true;
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
std::vector<uint8_t> data(size_); std::vector<uint8_t> data(size_);
ensure_zero(&data[0],data.size()); ensure_zero(&data[0],data.size());
} }
return true;
} }
}; };
@ -163,13 +168,14 @@ public:
{ {
return true; return true;
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
std::vector<uint8_t> data(0); std::vector<uint8_t> data(0);
data.resize(size_,0); data.resize(size_,0);
ensure_zero(&data[0],data.size()); ensure_zero(&data[0],data.size());
} }
return true;
} }
}; };
@ -187,13 +193,41 @@ public:
{ {
return true; return true;
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
std::vector<uint8_t> data(0); std::vector<uint8_t> data(0);
data.assign(size_,0); data.assign(size_,0);
ensure_zero(&data[0],data.size()); 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; return true;
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
uint8_t *data = (uint8_t *)calloc(size_,sizeof(uint8_t)); uint8_t *data = (uint8_t *)calloc(size_,sizeof(uint8_t));
ensure_zero(data,size_); ensure_zero(data,size_);
free(data); free(data);
} }
return true;
} }
}; };
@ -260,12 +295,13 @@ public:
{ {
return true; return true;
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
std::string data(array_.begin(),array_.end()); std::string data(array_.begin(),array_.end());
ensure_zero((uint8_t *)&data[0],size_); ensure_zero((uint8_t *)&data[0],size_);
} }
return true;
} }
}; };
@ -282,12 +318,13 @@ public:
{ {
return true; return true;
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
std::string data(&array_[0],array_.size()); std::string data(&array_[0],array_.size());
ensure_zero((uint8_t *)&data[0],size_); ensure_zero((uint8_t *)&data[0],size_);
} }
return true;
} }
}; };
@ -309,12 +346,13 @@ public:
{ {
return true; return true;
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
std::valarray<uint8_t> data(static_cast<uint8_t>(0),static_cast<size_t>(size_)); std::valarray<uint8_t> data(static_cast<uint8_t>(0),static_cast<size_t>(size_));
ensure_zero(&data[0],size_); ensure_zero(&data[0],size_);
} }
return true;
} }
}; };
@ -335,12 +373,13 @@ public:
{ {
return true; return true;
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
boost::container::static_vector<uint8_t,256*256> data(size_,0); boost::container::static_vector<uint8_t,256*256> data(size_,0);
ensure_zero(&data[0],size_); ensure_zero(&data[0],size_);
} }
return true;
} }
}; };
#endif #endif

View file

@ -22,11 +22,12 @@ public:
} }
return ret; return ret;
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
mapnik::expression_ptr expr = mapnik::parse_expression(expr_); mapnik::expression_ptr expr = mapnik::parse_expression(expr_);
} }
return true;
} }
}; };

View file

@ -26,7 +26,7 @@ public:
} }
return count == expected_count; return count == expected_count;
} }
void operator()() const bool operator()() const
{ {
std::size_t expected_count = mapnik::freetype_engine::face_names().size(); std::size_t expected_count = mapnik::freetype_engine::face_names().size();
for (unsigned i=0;i<iterations_;++i) for (unsigned i=0;i<iterations_;++i)
@ -49,6 +49,7 @@ public:
std::clog << "warning: face creation not working as expected\n"; std::clog << "warning: face creation not working as expected\n";
} }
} }
return true;
} }
}; };

View file

@ -12,7 +12,7 @@ public:
{ {
return mapnik::freetype_engine::register_fonts("./fonts", true); return mapnik::freetype_engine::register_fonts("./fonts", true);
} }
void operator()() const bool operator()() const
{ {
unsigned long count = 0; unsigned long count = 0;
for (unsigned i=0;i<iterations_;++i) for (unsigned i=0;i<iterations_;++i)
@ -20,6 +20,7 @@ public:
mapnik::freetype_engine::register_fonts("./fonts", true); mapnik::freetype_engine::register_fonts("./fonts", true);
count++; count++;
} }
return true;
} }
}; };

View file

@ -4,7 +4,7 @@
class test : public benchmark::test_case class test : public benchmark::test_case
{ {
mapnik::image_data_32 im_; mapnik::image_data_rgba8 im_;
public: public:
test(mapnik::parameters const& params) test(mapnik::parameters const& params)
: test_case(params), : test_case(params),
@ -13,7 +13,7 @@ public:
{ {
return true; return true;
} }
void operator()() const bool operator()() const
{ {
std::string out; std::string out;
for (std::size_t i=0;i<iterations_;++i) { 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"); out = mapnik::save_to_string(im_,"png8:m=h:z=1");
} }
} }
return true;
}; };
BENCHMARK(test,"encoding blank png") BENCHMARK(test,"encoding blank png")

View file

@ -23,7 +23,7 @@ public:
mapnik::save_to_file(im_->data(),actual, "png8:m=h:z=1"); mapnik::save_to_file(im_->data(),actual, "png8:m=h:z=1");
return benchmark::compare_images(actual,expected); return benchmark::compare_images(actual,expected);
} }
void operator()() const bool operator()() const
{ {
std::string out; std::string out;
for (std::size_t i=0;i<iterations_;++i) { 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"); out = mapnik::save_to_string(im_->data(),"png8:m=h:z=1");
} }
} }
return true;
}; };
BENCHMARK(test,"encoding multicolor png") BENCHMARK(test,"encoding multicolor png")

View file

@ -108,7 +108,7 @@ public:
render(geom2,geom.envelope(),actual); render(geom2,geom.envelope(),actual);
return benchmark::compare_images(actual,expect); return benchmark::compare_images(actual,expect);
} }
void operator()() const bool operator()() const
{ {
boost::ptr_vector<mapnik::geometry_type> paths; boost::ptr_vector<mapnik::geometry_type> paths;
if (!mapnik::from_wkt(wkt_in_, paths)) if (!mapnik::from_wkt(wkt_in_, paths))
@ -130,6 +130,7 @@ public:
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {} while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {}
} }
} }
return true;
} }
}; };
@ -189,7 +190,7 @@ public:
render(geom2,geom.envelope(),actual); render(geom2,geom.envelope(),actual);
return benchmark::compare_images(actual,expect); return benchmark::compare_images(actual,expect);
} }
void operator()() const bool operator()() const
{ {
boost::ptr_vector<mapnik::geometry_type> paths; boost::ptr_vector<mapnik::geometry_type> paths;
if (!mapnik::from_wkt(wkt_in_, paths)) if (!mapnik::from_wkt(wkt_in_, paths))
@ -217,6 +218,7 @@ public:
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {} while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {}
} }
} }
return true;
} }
}; };
@ -265,7 +267,7 @@ public:
render(geom2,geom.envelope(),actual); render(geom2,geom.envelope(),actual);
return benchmark::compare_images(actual,expect); return benchmark::compare_images(actual,expect);
} }
void operator()() const bool operator()() const
{ {
boost::ptr_vector<mapnik::geometry_type> paths; boost::ptr_vector<mapnik::geometry_type> paths;
if (!mapnik::from_wkt(wkt_in_, paths)) if (!mapnik::from_wkt(wkt_in_, paths))
@ -282,6 +284,7 @@ public:
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {} while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {}
} }
} }
return true;
} }
}; };

View file

@ -28,7 +28,7 @@ public:
//mapnik::save_to_file(im,"test.png"); //mapnik::save_to_file(im,"test.png");
return true; return true;
} }
void operator()() const bool operator()() const
{ {
mapnik::Map m(256,256); mapnik::Map m(256,256);
mapnik::load_map(m,xml_); mapnik::load_map(m,xml_);
@ -39,6 +39,7 @@ public:
mapnik::agg_renderer<mapnik::image_32> ren(m,im); mapnik::agg_renderer<mapnik::image_32> ren(m,im);
ren.apply(); ren.apply();
} }
return true;
} }
}; };

View file

@ -36,7 +36,7 @@ public:
(std::fabs(bbox.maxy() - to_.maxy()) < .5) (std::fabs(bbox.maxy() - to_.maxy()) < .5)
); );
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
for (int i=-180;i<180;i=i+5) for (int i=-180;i<180;i=i+5)
@ -51,6 +51,7 @@ public:
} }
} }
} }
return true;
} }
}; };

View file

@ -58,11 +58,17 @@ public:
mapnik::image_32 im(m.width(),m.height()); mapnik::image_32 im(m.width(),m.height());
mapnik::agg_renderer<mapnik::image_32> ren(m,im,scale_factor_); mapnik::agg_renderer<mapnik::image_32> ren(m,im,scale_factor_);
ren.apply(); 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; return true;
} }
void operator()() const bool operator()() const
{ {
if (!preview_.empty()) {
return false;
}
mapnik::Map m(width_,height_); mapnik::Map m(width_,height_);
mapnik::load_map(m,xml_); mapnik::load_map(m,xml_);
if (extent_.valid()) { if (extent_.valid()) {
@ -76,6 +82,7 @@ public:
mapnik::agg_renderer<mapnik::image_32> ren(m,im,scale_factor_); mapnik::agg_renderer<mapnik::image_32> ren(m,im,scale_factor_);
ren.apply(); ren.apply();
} }
return true;
} }
}; };

View file

@ -26,13 +26,7 @@ template <typename Renderer> void process_layers(Renderer & ren,
if (lyr.visible(scale_denom)) if (lyr.visible(scale_denom))
{ {
std::set<std::string> names; 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); mapnik::layer l(lyr);
l.set_datasource(ds);
l.add_style("labels");
ren.apply_to_layer(l, ren.apply_to_layer(l,
ren, ren,
map_proj, map_proj,
@ -56,6 +50,7 @@ class test : public benchmark::test_case
std::shared_ptr<mapnik::Map> m_; std::shared_ptr<mapnik::Map> m_;
double scale_factor_; double scale_factor_;
std::string preview_; std::string preview_;
mutable mapnik::image_32 im_;
public: public:
test(mapnik::parameters const& params) test(mapnik::parameters const& params)
: test_case(params), : test_case(params),
@ -65,7 +60,8 @@ public:
height_(*params.get<mapnik::value_integer>("height",256)), height_(*params.get<mapnik::value_integer>("height",256)),
m_(new mapnik::Map(width_,height_)), m_(new mapnik::Map(width_,height_)),
scale_factor_(*params.get<mapnik::value_double>("scale_factor",2.0)), 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"); boost::optional<std::string> map = params.get<std::string>("map");
if (!map) if (!map)
@ -75,6 +71,7 @@ public:
xml_ = *map; xml_ = *map;
boost::optional<std::string> ext = params.get<std::string>("extent"); boost::optional<std::string> ext = params.get<std::string>("extent");
mapnik::load_map(*m_,xml_,true);
if (ext && !ext->empty()) if (ext && !ext->empty())
{ {
if (!extent_.from_string(*ext)) if (!extent_.from_string(*ext))
@ -82,51 +79,67 @@ public:
} }
else 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 bool validate() const
{ {
mapnik::request m_req(width_,height_,extent_); mapnik::request m_req(width_,height_,extent_);
mapnik::image_32 im(m_->width(),m_->height());
mapnik::attributes variables; mapnik::attributes variables;
m_req.set_buffer_size(m_->buffer_size()); m_req.set_buffer_size(m_->buffer_size());
mapnik::projection map_proj(m_->srs(),true); mapnik::projection map_proj(m_->srs(),true);
double scale_denom = mapnik::scale_denominator(m_req.scale(),map_proj.is_geographic()); double scale_denom = mapnik::scale_denominator(m_req.scale(),map_proj.is_geographic());
scale_denom *= scale_factor_; 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_); ren.start_map_processing(*m_);
std::vector<mapnik::layer> const& layers = m_->layers(); std::vector<mapnik::layer> const& layers = m_->layers();
process_layers(ren,m_req,map_proj,layers,scale_denom); process_layers(ren,m_req,map_proj,layers,scale_denom);
ren.end_map_processing(*m_); ren.end_map_processing(*m_);
if (!preview_.empty()) { if (!preview_.empty()) {
std::clog << "preview available at " << preview_ << "\n"; std::clog << "preview available at " << preview_ << "\n";
mapnik::save_to_file(im,preview_); mapnik::save_to_file(im_,preview_);
} }
return true; return true;
} }
void operator()() const bool operator()() const
{ {
if (preview_.empty()) { if (!preview_.empty()) {
for (unsigned i=0;i<iterations_;++i) return false;
{
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_);
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_);
}
} }
for (unsigned i=0;i<iterations_;++i)
{
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_);
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_);
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;
} }
}; };

View file

@ -16,13 +16,14 @@ public:
mapnik::util::string2bool(value_,result); mapnik::util::string2bool(value_,result);
return (result == true); return (result == true);
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
bool result = false; bool result = false;
mapnik::util::string2bool(value_,result); mapnik::util::string2bool(value_,result);
mapnik::util::string2bool(value_.data(),value_.data()+value_.size(),result); mapnik::util::string2bool(value_.data(),value_.data()+value_.size(),result);
} }
return true;
} }
}; };

View file

@ -18,13 +18,14 @@ public:
if (result != 1.23456789) return false; if (result != 1.23456789) return false;
return true; return true;
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
double result = 0; double result = 0;
mapnik::util::string2double(value_,result); mapnik::util::string2double(value_,result);
mapnik::util::string2double(value_.data(),value_.data()+value_.size(),result); mapnik::util::string2double(value_.data(),value_.data()+value_.size(),result);
} }
return true;
} }
}; };

View file

@ -18,13 +18,14 @@ public:
if (result != 123456789) return false; if (result != 123456789) return false;
return true; return true;
} }
void operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
mapnik::value_integer result = 0; mapnik::value_integer result = 0;
mapnik::util::string2int(value_,result); mapnik::util::string2int(value_,result);
mapnik::util::string2int(value_.data(),value_.data()+value_.size(),result); mapnik::util::string2int(value_.data(),value_.data()+value_.size(),result);
} }
return true;
} }
}; };

View file

@ -14,13 +14,14 @@ public:
mapnik::util::to_string(s,value_); mapnik::util::to_string(s,value_);
return (s == "-0.1234"); return (s == "-0.1234");
} }
void operator()() const bool operator()() const
{ {
std::string out; std::string out;
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
out.clear(); out.clear();
mapnik::util::to_string(out,value_); mapnik::util::to_string(out,value_);
} }
return true;
} }
}; };

View file

@ -14,7 +14,7 @@ public:
s << value_; s << value_;
return (s.str() == "-0.1234"); return (s.str() == "-0.1234");
} }
void operator()() const bool operator()() const
{ {
std::string out; std::string out;
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
@ -22,6 +22,7 @@ public:
s << value_; s << value_;
out = s.str(); out = s.str();
} }
return true;
} }
}; };

View file

@ -23,13 +23,14 @@ public:
utf32[3] != 0x5dd) return false; utf32[3] != 0x5dd) return false;
return true; return true;
} }
void operator()() const bool operator()() const
{ {
std::u32string utf32; std::u32string utf32;
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> utf32conv; std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> utf32conv;
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
utf32 = utf32conv.from_bytes(utf8_); utf32 = utf32conv.from_bytes(utf8_);
} }
return true;
} }
}; };
@ -52,12 +53,13 @@ public:
utf32[3] != 0x5dd) return false; utf32[3] != 0x5dd) return false;
return true; return true;
} }
void operator()() const bool operator()() const
{ {
std::u32string utf32; std::u32string utf32;
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
utf32 = boost::locale::conv::utf_to_utf<char32_t>(utf8_); utf32 = boost::locale::conv::utf_to_utf<char32_t>(utf8_);
} }
return true;
} }
}; };
@ -80,13 +82,14 @@ public:
utf32[3] != 0x5dd) return false; utf32[3] != 0x5dd) return false;
return true; return true;
} }
void operator()() const bool operator()() const
{ {
mapnik::transcoder tr_("utf-8"); mapnik::transcoder tr_("utf-8");
mapnik::value_unicode_string utf32; mapnik::value_unicode_string utf32;
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
utf32 = tr_.transcode(utf8_.data(),utf8_.size()); utf32 = tr_.transcode(utf8_.data(),utf8_.size());
} }
return true;
} }
}; };

View file

@ -120,12 +120,12 @@ bool is_solid(mapnik::image_32 const& im)
{ {
if (im.width() > 0 && im.height() > 0) if (im.width() > 0 && im.height() > 0)
{ {
mapnik::image_data_32 const & data = im.data(); mapnik::image_data_rgba8 const & data = im.data();
mapnik::image_data_32::pixel_type const* first_row = data.getRow(0); mapnik::image_data_rgba8::pixel_type const* first_row = data.getRow(0);
mapnik::image_data_32::pixel_type const first_pixel = first_row[0]; mapnik::image_data_rgba8::pixel_type const first_pixel = first_row[0];
for (unsigned y = 0; y < im.height(); ++y) 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) for (unsigned x = 0; x < im.width(); ++x)
{ {
if (first_pixel != row[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())) 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); return data(x,y);
} }
PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions");

View file

@ -42,18 +42,18 @@
#include <mapnik/image_view.hpp> #include <mapnik/image_view.hpp>
#include <sstream> #include <sstream>
using mapnik::image_data_32; using mapnik::image_data_rgba8;
using mapnik::image_view; using mapnik::image_view;
using mapnik::save_to_file; using mapnik::save_to_file;
// output 'raw' pixels // 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); std::ostringstream ss(std::ios::out|std::ios::binary);
for (unsigned i=0;i<view.height();i++) for (unsigned i=0;i<view.height();i++)
{ {
ss.write(reinterpret_cast<const char*>(view.getRow(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 return
#if PY_VERSION_HEX >= 0x03000000 #if PY_VERSION_HEX >= 0x03000000
@ -65,7 +65,7 @@ PyObject* view_tostring1(image_view<image_data_32> const& view)
} }
// encode (png,jpeg) // 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); std::string s = save_to_string(view, format);
return return
@ -77,7 +77,7 @@ PyObject* view_tostring2(image_view<image_data_32> const & view, std::string con
(s.data(),s.size()); (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); std::string s = save_to_string(view, format, pal);
return return
@ -89,15 +89,15 @@ PyObject* view_tostring3(image_view<image_data_32> const & view, std::string con
(s.data(),s.size()); (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) 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_rgba8>::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_pixel = first_row[0];
for (unsigned y = 0; y < view.height(); ++y) 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) for (unsigned x = 0; x < view.width(); ++x)
{ {
if (first_pixel != row[x]) if (first_pixel != row[x])
@ -110,20 +110,20 @@ bool is_solid(image_view<image_data_32> const& view)
return true; 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) std::string const& filename)
{ {
save_to_file(view,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& filename,
std::string const& type) std::string const& type)
{ {
save_to_file(view,filename,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& filename,
std::string const& type, std::string const& type,
mapnik::rgba_palette const& pal) mapnik::rgba_palette const& pal)
@ -135,9 +135,9 @@ void save_view3(image_view<image_data_32> const& view,
void export_image_view() void export_image_view()
{ {
using namespace boost::python; using namespace boost::python;
class_<image_view<image_data_32> >("ImageView","A view into an image.",no_init) class_<image_view<image_data_rgba8> >("ImageView","A view into an image.",no_init)
.def("width",&image_view<image_data_32>::width) .def("width",&image_view<image_data_rgba8>::width)
.def("height",&image_view<image_data_32>::height) .def("height",&image_view<image_data_rgba8>::height)
.def("is_solid",&is_solid) .def("is_solid",&is_solid)
.def("tostring",&view_tostring1) .def("tostring",&view_tostring1)
.def("tostring",&view_tostring2) .def("tostring",&view_tostring2)

View file

@ -201,7 +201,7 @@ struct symbolizer_icon : public mapnik::util::static_visitor<QIcon>
{ {
// FIXME! // 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) if (symbol)
{ {
QImage image(symbol->getBytes(), QImage image(symbol->getBytes(),

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -120,6 +120,15 @@ namespace agg
double m_mul; 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 #endif

View file

@ -2,8 +2,8 @@
// Anti-Grain Geometry - Version 2.4 // Anti-Grain Geometry - Version 2.4
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
// //
// Permission to copy, use, modify, sell and distribute this software // Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies. // is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied // This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose. // warranty, and with no claim as to its suitability for any purpose.
// //
@ -18,12 +18,13 @@
#include <cmath> #include <cmath>
#include "agg_basics.h" #include "agg_basics.h"
#include "agg_gamma_functions.h"
namespace agg namespace agg
{ {
template<class LoResT=int8u, template<class LoResT=int8u,
class HiResT=int8u, class HiResT=int8u,
unsigned GammaShift=8, unsigned GammaShift=8,
unsigned HiResShift=8> class gamma_lut unsigned HiResShift=8> class gamma_lut
{ {
public: public:
@ -49,8 +50,8 @@ namespace agg
pod_allocator<HiResT>::deallocate(m_dir_gamma, gamma_size); pod_allocator<HiResT>::deallocate(m_dir_gamma, gamma_size);
} }
gamma_lut() : gamma_lut() :
m_gamma(1.0), m_gamma(1.0),
m_dir_gamma(pod_allocator<HiResT>::allocate(gamma_size)), m_dir_gamma(pod_allocator<HiResT>::allocate(gamma_size)),
m_inv_gamma(pod_allocator<LoResT>::allocate(hi_res_size)) m_inv_gamma(pod_allocator<LoResT>::allocate(hi_res_size))
{ {
@ -67,14 +68,14 @@ namespace agg
} }
gamma_lut(double g) : gamma_lut(double g) :
m_gamma(1.0), m_gamma(1.0),
m_dir_gamma(pod_allocator<HiResT>::allocate(gamma_size)), m_dir_gamma(pod_allocator<HiResT>::allocate(gamma_size)),
m_inv_gamma(pod_allocator<LoResT>::allocate(hi_res_size)) m_inv_gamma(pod_allocator<LoResT>::allocate(hi_res_size))
{ {
gamma(g); gamma(g);
} }
void gamma(double g) void gamma(double g)
{ {
m_gamma = g; m_gamma = g;
@ -98,13 +99,13 @@ namespace agg
return m_gamma; return m_gamma;
} }
HiResT dir(LoResT v) const HiResT dir(LoResT v) const
{ {
return m_dir_gamma[unsigned(v)]; return m_dir_gamma[unsigned(v)];
} }
LoResT inv(HiResT v) const LoResT inv(HiResT v) const
{ {
return m_inv_gamma[unsigned(v)]; return m_inv_gamma[unsigned(v)];
} }
@ -116,6 +117,189 @@ namespace agg
HiResT* m_dir_gamma; HiResT* m_dir_gamma;
LoResT* m_inv_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 #endif

97
deps/agg/include/agg_pixfmt_base.h vendored Normal file
View 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

View file

@ -2,8 +2,8 @@
// Anti-Grain Geometry - Version 2.4 // Anti-Grain Geometry - Version 2.4
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
// //
// Permission to copy, use, modify, sell and distribute this software // Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies. // is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied // This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose. // warranty, and with no claim as to its suitability for any purpose.
// //
@ -13,37 +13,46 @@
// http://www.antigrain.com // http://www.antigrain.com
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// //
// Adaptation for high precision colors has been sponsored by // Adaptation for high precision colors has been sponsored by
// Liberty Technology Systems, Inc., visit http://lib-sys.com // Liberty Technology Systems, Inc., visit http://lib-sys.com
// //
// Liberty Technology Systems, Inc. is the provider of // Liberty Technology Systems, Inc. is the provider of
// PostScript and PDF technology for software developers. // PostScript and PDF technology for software developers.
// //
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
#ifndef AGG_PIXFMT_GRAY_INCLUDED #ifndef AGG_PIXFMT_GRAY_INCLUDED
#define AGG_PIXFMT_GRAY_INCLUDED #define AGG_PIXFMT_GRAY_INCLUDED
#include <cstring> #include <cstring>
#include "agg_basics.h" #include "agg_pixfmt_base.h"
#include "agg_color_gray.h"
#include "agg_rendering_buffer.h" #include "agg_rendering_buffer.h"
namespace agg namespace agg
{ {
//============================================================blender_gray //============================================================blender_gray
template<class ColorT> struct blender_gray template<class ColorT> struct blender_gray
{ {
typedef ColorT color_type; typedef ColorT color_type;
typedef typename color_type::value_type value_type; typedef typename color_type::value_type value_type;
typedef typename color_type::calc_type calc_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, // Blend pixels using the non-premultiplied form of Alvy-Ray Smith's
unsigned alpha, unsigned cover=0) // 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,23 +63,24 @@ namespace agg
typedef ColorT color_type; typedef ColorT color_type;
typedef typename color_type::value_type value_type; typedef typename color_type::value_type value_type;
typedef typename color_type::calc_type calc_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, // Blend pixels using the premultiplied form of Alvy-Ray Smith's
unsigned alpha, unsigned cover) // 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; blend_pix(p, color_type::mult_cover(cv, cover), color_type::mult_cover(alpha, cover));
cover = (cover + 1) << (base_shift - 8);
*p = (value_type)((*p * alpha + cv * cover) >> base_shift);
} }
static AGG_INLINE void blend_pix(value_type* p, unsigned cv, static AGG_INLINE void blend_pix(value_type* p,
unsigned alpha) 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);
} }
}; };
//=====================================================apply_gamma_dir_gray //=====================================================apply_gamma_dir_gray
@ -112,10 +122,11 @@ namespace agg
//=================================================pixfmt_alpha_blend_gray //=================================================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 class pixfmt_alpha_blend_gray
{ {
public: public:
typedef pixfmt_gray_tag pixfmt_category;
typedef RenBuf rbuf_type; typedef RenBuf rbuf_type;
typedef typename rbuf_type::row_data row_data; typedef typename rbuf_type::row_data row_data;
typedef Blender blender_type; typedef Blender blender_type;
@ -123,54 +134,117 @@ namespace agg
typedef int order_type; // A fake one typedef int order_type; // A fake one
typedef typename color_type::value_type value_type; typedef typename color_type::value_type value_type;
typedef typename color_type::calc_type calc_type; typedef typename color_type::calc_type calc_type;
enum base_scale_e enum
{ {
base_shift = color_type::base_shift, num_components = 1,
base_scale = color_type::base_scale, pix_width = sizeof(value_type) * Step,
base_mask = color_type::base_mask, pix_step = Step,
pix_width = sizeof(value_type), pix_offset = Offset,
pix_step = Step, };
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: private:
//-------------------------------------------------------------------- //--------------------------------------------------------------------
static AGG_INLINE void copy_or_blend_pix(value_type* p, AGG_INLINE void blend_pix(pixel_type* p,
const color_type& c, value_type v, value_type a,
unsigned cover) 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)
{
blender_type::blend_pix(p->c, v, a);
}
//--------------------------------------------------------------------
AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover)
{
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())
{ {
calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; if (c.is_opaque() && cover == cover_mask)
if(alpha == base_mask)
{ {
*p = c.v; p->set(c);
} }
else 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, AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c)
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 else
{ {
Blender::blend_pix(p, c.v, c.a); blend_pix(p, c);
} }
} }
} }
public: public:
//-------------------------------------------------------------------- //--------------------------------------------------------------------
explicit pixfmt_alpha_blend_gray(rbuf_type& rb) : explicit pixfmt_alpha_blend_gray(rbuf_type& rb) :
@ -183,10 +257,10 @@ namespace agg
bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2)
{ {
rect_i r(x1, y1, x2, 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(); int stride = pixf.stride();
m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1),
(r.x2 - r.x1) + 1, (r.x2 - r.x1) + 1,
(r.y2 - r.y1) + 1, (r.y2 - r.y1) + 1,
stride); stride);
@ -201,61 +275,98 @@ namespace agg
AGG_INLINE int stride() const { return m_rbuf->stride(); } AGG_INLINE int stride() const { return m_rbuf->stride(); }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); }
const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); }
row_data row(int y) const { return m_rbuf->row(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) 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 AGG_INLINE color_type pixel(int x, int y) const
{ {
value_type* p = (value_type*)m_rbuf->row_ptr(y) + x * Step + Offset; if (const pixel_type* p = pix_value_ptr(x, y))
return color_type(*p); {
return p->get();
}
return color_type::no_color();
} }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
AGG_INLINE void copy_pixel(int x, int y, const color_type& c) 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) AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover)
{ {
copy_or_blend_pix((value_type*) copy_or_blend_pix(pix_value_ptr(x, y, 1), c, cover);
m_rbuf->row_ptr(x, y, 1) + x * Step + Offset,
c,
cover);
} }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
AGG_INLINE void copy_hline(int x, int y, AGG_INLINE void copy_hline(int x, int y,
unsigned len, unsigned len,
const color_type& c) const color_type& c)
{ {
value_type* p = (value_type*) pixel_type* p = pix_value_ptr(x, y, len);
m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
do do
{ {
*p = c.v; p->set(c);
p += Step; p = p->next();
} }
while(--len); while(--len);
} }
@ -263,49 +374,44 @@ namespace agg
//-------------------------------------------------------------------- //--------------------------------------------------------------------
AGG_INLINE void copy_vline(int x, int y, AGG_INLINE void copy_vline(int x, int y,
unsigned len, unsigned len,
const color_type& c) const color_type& c)
{ {
do do
{ {
value_type* p = (value_type*) pix_value_ptr(x, y++, 1)->set(c);
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
*p = c.v;
} }
while(--len); while (--len);
} }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
void blend_hline(int x, int y, void blend_hline(int x, int y,
unsigned len, unsigned len,
const color_type& c, const color_type& c,
int8u cover) int8u cover)
{ {
if (c.a) if (!c.is_transparent())
{ {
value_type* p = (value_type*) pixel_type* p = pix_value_ptr(x, y, len);
m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; if (c.is_opaque() && cover == cover_mask)
if(alpha == base_mask)
{ {
do do
{ {
*p = c.v; p->set(c);
p += Step; p = p->next();
} }
while(--len); while (--len);
} }
else else
{ {
do do
{ {
Blender::blend_pix(p, c.v, alpha, cover); blend_pix(p, c, cover);
p += Step; p = p->next();
} }
while(--len); while (--len);
} }
} }
} }
@ -313,35 +419,27 @@ namespace agg
//-------------------------------------------------------------------- //--------------------------------------------------------------------
void blend_vline(int x, int y, void blend_vline(int x, int y,
unsigned len, unsigned len,
const color_type& c, const color_type& c,
int8u cover) int8u cover)
{ {
if (c.a) if (!c.is_transparent())
{ {
value_type* p; if (c.is_opaque() && cover == cover_mask)
calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8;
if(alpha == base_mask)
{ {
do do
{ {
p = (value_type*) pix_value_ptr(x, y++, 1)->set(c);
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
*p = c.v;
} }
while(--len); while (--len);
} }
else else
{ {
do do
{ {
p = (value_type*) blend_pix(pix_value_ptr(x, y++, 1), c, cover);
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
Blender::blend_pix(p, c.v, alpha, cover);
} }
while(--len); while (--len);
} }
} }
} }
@ -349,200 +447,162 @@ namespace agg
//-------------------------------------------------------------------- //--------------------------------------------------------------------
void blend_solid_hspan(int x, int y, void blend_solid_hspan(int x, int y,
unsigned len, unsigned len,
const color_type& c, const color_type& c,
const int8u* covers) const int8u* covers)
{ {
if (c.a) if (!c.is_transparent())
{ {
value_type* p = (value_type*) pixel_type* p = pix_value_ptr(x, y, len);
m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
do do
{ {
calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; if (c.is_opaque() && *covers == cover_mask)
if(alpha == base_mask)
{ {
*p = c.v; p->set(c);
} }
else else
{ {
Blender::blend_pix(p, c.v, alpha, *covers); blend_pix(p, c, *covers);
} }
p += Step; p = p->next();
++covers; ++covers;
} }
while(--len); while (--len);
} }
} }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
void blend_solid_vspan(int x, int y, void blend_solid_vspan(int x, int y,
unsigned len, unsigned len,
const color_type& c, const color_type& c,
const int8u* covers) const int8u* covers)
{ {
if (c.a) if (!c.is_transparent())
{ {
do 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*) if (c.is_opaque() && *covers == cover_mask)
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
if(alpha == base_mask)
{ {
*p = c.v; p->set(c);
} }
else else
{ {
Blender::blend_pix(p, c.v, alpha, *covers); blend_pix(p, c, *covers);
} }
++covers; ++covers;
} }
while(--len); while (--len);
} }
} }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
void copy_color_hspan(int x, int y, void copy_color_hspan(int x, int y,
unsigned len, unsigned len,
const color_type* colors) const color_type* colors)
{ {
value_type* p = (value_type*) pixel_type* p = pix_value_ptr(x, y, len);
m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
do do
{ {
*p = colors->v; p->set(*colors++);
p += Step; p = p->next();
++colors;
} }
while(--len); while (--len);
} }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
void copy_color_vspan(int x, int y, void copy_color_vspan(int x, int y,
unsigned len, unsigned len,
const color_type* colors) const color_type* colors)
{ {
do do
{ {
value_type* p = (value_type*) pix_value_ptr(x, y++, 1)->set(*colors++);
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
*p = colors->v;
++colors;
} }
while(--len); while (--len);
} }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
void blend_color_hspan(int x, int y, void blend_color_hspan(int x, int y,
unsigned len, unsigned len,
const color_type* colors, const color_type* colors,
const int8u* covers, const int8u* covers,
int8u cover) int8u cover)
{ {
value_type* p = (value_type*) pixel_type* p = pix_value_ptr(x, y, len);
m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
if(covers) if (covers)
{ {
do do
{ {
copy_or_blend_pix(p, *colors++, *covers++); copy_or_blend_pix(p, *colors++, *covers++);
p += Step; p = p->next();
} }
while(--len); while (--len);
} }
else else
{ {
if(cover == 255) if (cover == cover_mask)
{ {
do do
{ {
if(colors->a == base_mask) copy_or_blend_pix(p, *colors++);
{ p = p->next();
*p = colors->v;
}
else
{
copy_or_blend_pix(p, *colors);
}
p += Step;
++colors;
} }
while(--len); while (--len);
} }
else else
{ {
do do
{ {
copy_or_blend_pix(p, *colors++, cover); copy_or_blend_pix(p, *colors++, cover);
p += Step; p = p->next();
} }
while(--len); while (--len);
} }
} }
} }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
void blend_color_vspan(int x, int y, void blend_color_vspan(int x, int y,
unsigned len, unsigned len,
const color_type* colors, const color_type* colors,
const int8u* covers, const int8u* covers,
int8u cover) int8u cover)
{ {
value_type* p; if (covers)
if(covers)
{ {
do do
{ {
p = (value_type*) copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++);
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
copy_or_blend_pix(p, *colors++, *covers++);
} }
while(--len); while (--len);
} }
else else
{ {
if(cover == 255) if (cover == cover_mask)
{ {
do do
{ {
p = (value_type*) copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++);
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
if(colors->a == base_mask)
{
*p = colors->v;
}
else
{
copy_or_blend_pix(p, *colors);
}
++colors;
} }
while(--len); while (--len);
} }
else else
{ {
do do
{ {
p = (value_type*) copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover);
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
copy_or_blend_pix(p, *colors++, cover);
} }
while(--len); while (--len);
} }
} }
} }
@ -551,22 +611,19 @@ namespace agg
template<class Function> void for_each_pixel(Function f) template<class Function> void for_each_pixel(Function f)
{ {
unsigned y; unsigned y;
for(y = 0; y < height(); ++y) for (y = 0; y < height(); ++y)
{ {
row_data r = m_rbuf->row(y); row_data r = m_rbuf->row(y);
if(r.ptr) if (r.ptr)
{ {
unsigned len = r.x2 - r.x1 + 1; unsigned len = r.x2 - r.x1 + 1;
pixel_type* p = pix_value_ptr(r.x1, y, len);
value_type* p = (value_type*)
m_rbuf->row_ptr(r.x1, y, len) + r.x1 * Step + Offset;
do do
{ {
f(p); f(p->c);
p += Step; p = p->next();
} }
while(--len); while (--len);
} }
} }
} }
@ -585,69 +642,70 @@ namespace agg
//-------------------------------------------------------------------- //--------------------------------------------------------------------
template<class RenBuf2> template<class RenBuf2>
void copy_from(const RenBuf2& from, void copy_from(const RenBuf2& from,
int xdst, int ydst, int xdst, int ydst,
int xsrc, int ysrc, int xsrc, int ysrc,
unsigned len) unsigned len)
{ {
const int8u* p = from.row_ptr(ysrc); if (const int8u* p = from.row_ptr(ysrc))
if(p)
{ {
memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width,
p + xsrc * pix_width, p + xsrc * pix_width,
len * pix_width); len * pix_width);
} }
} }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
// Blend from single color, using grayscale surface as alpha channel.
template<class SrcPixelFormatRenderer> template<class SrcPixelFormatRenderer>
void blend_from_color(const SrcPixelFormatRenderer& from, void blend_from_color(const SrcPixelFormatRenderer& from,
const color_type& color, const color_type& color,
int xdst, int ydst, int xdst, int ydst,
int xsrc, int ysrc, int xsrc, int ysrc,
unsigned len, unsigned len,
int8u cover) int8u cover)
{ {
typedef typename SrcPixelFormatRenderer::value_type src_value_type; typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); typedef typename SrcPixelFormatRenderer::color_type src_color_type;
if(psrc)
if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
{ {
value_type* pdst = pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
(value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst;
do do
{ {
copy_or_blend_pix(pdst, copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0]));
color, psrc = psrc->next();
(*psrc * cover + base_mask) >> base_shift); pdst = pdst->next();
++psrc;
++pdst;
} }
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> template<class SrcPixelFormatRenderer>
void blend_from_lut(const SrcPixelFormatRenderer& from, void blend_from_lut(const SrcPixelFormatRenderer& from,
const color_type* color_lut, const color_type* color_lut,
int xdst, int ydst, int xdst, int ydst,
int xsrc, int ysrc, int xsrc, int ysrc,
unsigned len, unsigned len,
int8u cover) int8u cover)
{ {
typedef typename SrcPixelFormatRenderer::value_type src_value_type; typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc);
if(psrc) if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
{ {
value_type* pdst = pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
(value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst;
do do
{ {
copy_or_blend_pix(pdst, color_lut[*psrc], cover); copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover);
++psrc; psrc = psrc->next();
++pdst; pdst = pdst->next();
} }
while(--len); while (--len);
} }
} }
@ -655,16 +713,25 @@ namespace agg
rbuf_type* m_rbuf; rbuf_type* m_rbuf;
}; };
typedef blender_gray<gray8> blender_gray8; 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<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 blender_gray_pre<gray8> blender_gray8_pre;
typedef pixfmt_alpha_blend_gray<blender_gray8_pre, rendering_buffer> pixfmt_gray8_pre; //----pixfmt_gray8_pre typedef blender_gray_pre<sgray8> blender_sgray8_pre;
typedef pixfmt_alpha_blend_gray<blender_gray16, rendering_buffer> pixfmt_gray16; //----pixfmt_gray16 typedef blender_gray_pre<gray16> blender_gray16_pre;
typedef pixfmt_alpha_blend_gray<blender_gray16_pre, rendering_buffer> pixfmt_gray16_pre; //----pixfmt_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 #endif

View file

@ -133,6 +133,9 @@ which triggers locks
void my_function(std::string const& val); // if std::string or user type, pass by const& 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 #### When to use shared_ptr and unique_ptr

View file

@ -36,7 +36,7 @@ namespace mapnik
class pattern_source : private mapnik::noncopyable class pattern_source : private mapnik::noncopyable
{ {
public: 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), : pattern_(pattern),
opacity_(opacity) {} opacity_(opacity) {}
@ -57,7 +57,7 @@ public:
static_cast<unsigned>(((c >> 24) & 0xff) * opacity_)); static_cast<unsigned>(((c >> 24) & 0xff) * opacity_));
} }
private: private:
image_data_32 const& pattern_; image_data_rgba8 const& pattern_;
double opacity_; double opacity_;
}; };
} }

View file

@ -121,7 +121,7 @@ private:
class cairo_pattern : private mapnik::noncopyable class cairo_pattern : private mapnik::noncopyable
{ {
public: 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(); int pixels = data.width() * data.height();
const unsigned int *in_ptr = data.getData(); const unsigned int *in_ptr = data.getData();
@ -308,8 +308,8 @@ public:
void paint(); void paint();
void set_pattern(cairo_pattern const& pattern); void set_pattern(cairo_pattern const& pattern);
void set_gradient(cairo_gradient const& pattern, box2d<double> const& bbox); 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(double x, double y, image_data_rgba8 & data, double opacity = 1.0);
void add_image(agg::trans_affine const& tr, image_data_32 & 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_face(cairo_face_manager & manager, face_ptr face);
void set_font_matrix(cairo_matrix_t const& matrix); void set_font_matrix(cairo_matrix_t const& matrix);
void set_matrix(cairo_matrix_t const& matrix); void set_matrix(cairo_matrix_t const& matrix);

View file

@ -53,7 +53,7 @@ private:
unsigned width_; unsigned width_;
unsigned height_; unsigned height_;
boost::optional<color> background_; boost::optional<color> background_;
image_data_32 data_; image_data_rgba8 data_;
bool painted_; bool painted_;
bool premultiplied_; bool premultiplied_;
public: public:
@ -98,12 +98,12 @@ public:
void set_alpha(float opacity); void set_alpha(float opacity);
inline const image_data_32& data() const inline const image_data_rgba8& data() const
{ {
return data_; return data_;
} }
inline image_data_32& data() inline image_data_rgba8& data()
{ {
return data_; return data_;
} }
@ -118,9 +118,9 @@ public:
return data_.getBytes(); 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: private:
@ -151,7 +151,7 @@ public:
return height_; 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> ext0(0,0,width_,height_);
box2d<int> ext1(x0,y0,x0+data.width(),y0+data.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> ext0(0,0,width_,height_);
box2d<int> ext1(x0,y0,x0 + data.width(),y0 + data.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> ext0(0,0,width_,height_);
box2d<int> ext1(x0,y0,x0 + data.width(),y0 + data.height()); box2d<int> ext1(x0,y0,x0 + data.width(),y0 + data.height());
@ -267,7 +267,7 @@ public:
} }
template <typename MergeMethod> 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> ext0(0,0,width_,height_);
box2d<int> ext1(x0,y0,x0 + data.width(),y0 + data.height()); box2d<int> ext1(x0,y0,x0 + data.width(),y0 + data.height());

View file

@ -195,7 +195,7 @@ public:
return height_; 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> ext0(0,0,width_,height_);
box2d<int> ext1(x0,y0,x0+data.width(),y0+data.height()); box2d<int> ext1(x0,y0,x0+data.width(),y0+data.height());

View file

@ -51,7 +51,7 @@ struct raster_markers_rasterizer_dispatch_grid : mapnik::noncopyable
using RasterizerType = typename std::tuple_element<1,RendererContext>::type; using RasterizerType = typename std::tuple_element<1,RendererContext>::type;
using PixMapType = typename std::tuple_element<2,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, agg::trans_affine const& marker_trans,
markers_symbolizer const& sym, markers_symbolizer const& sym,
Detector & detector, Detector & detector,
@ -130,7 +130,7 @@ private:
pixfmt_type pixf_; pixfmt_type pixf_;
RendererBase renb_; RendererBase renb_;
RasterizerType & ras_; RasterizerType & ras_;
image_data_32 const& src_; image_data_rgba8 const& src_;
agg::trans_affine const& marker_trans_; agg::trans_affine const& marker_trans_;
markers_symbolizer const& sym_; markers_symbolizer const& sym_;
Detector & detector_; Detector & detector_;

View file

@ -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<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); MAPNIK_DECL boost::optional<std::string> comp_op_to_string(composite_mode_e comp_op);
template <typename T1, typename T2> template <typename T>
MAPNIK_DECL void composite(T1 & dst, T2 & src, MAPNIK_DECL void composite(T & dst, T & src,
composite_mode_e mode, composite_mode_e mode,
float opacity=1, float opacity=1,
int dx=0, int dx=0,
int dy=0, int dy=0,
bool premultiply_src=false); 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 #endif // MAPNIK_IMAGE_COMPOSITING_HPP

View file

@ -150,6 +150,14 @@ public:
{ {
return height_; 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) inline void set(pixel_type const& t)
{ {
std::fill(pData_, pData_ + width_ * height_, t); std::fill(pData_, pData_ + width_ * height_, t);
@ -180,11 +188,21 @@ public:
return pData_ + row * width_; 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) inline pixel_type* getRow(unsigned row)
{ {
return pData_ + row * width_; 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) inline void setRow(std::size_t row, pixel_type const* buf, std::size_t size)
{ {
assert(row < height_); assert(row < height_);
@ -204,8 +222,10 @@ private:
pixel_type *pData_; pixel_type *pData_;
}; };
using image_data_32 = image_data<std::uint32_t>; using image_data_rgba8 = image_data<std::uint32_t>;
using image_data_8 = image_data<byte> ; 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 #endif // MAPNIK_IMAGE_DATA_HPP

View 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

View file

@ -24,10 +24,11 @@
#define MAPNIK_IMAGE_READER_HPP #define MAPNIK_IMAGE_READER_HPP
// mapnik // mapnik
#include <mapnik/image_data.hpp> #include <mapnik/image_data_any.hpp>
#include <mapnik/config.hpp> #include <mapnik/config.hpp>
#include <mapnik/noncopyable.hpp> #include <mapnik/noncopyable.hpp>
#include <mapnik/factory.hpp> #include <mapnik/factory.hpp>
#include <mapnik/box2d.hpp>
// boost // boost
#include <boost/optional.hpp> #include <boost/optional.hpp>
// stl // stl
@ -55,11 +56,13 @@ public:
struct MAPNIK_DECL image_reader : private mapnik::noncopyable struct MAPNIK_DECL image_reader : private mapnik::noncopyable
{ {
virtual unsigned width() const=0; virtual unsigned width() const = 0;
virtual unsigned height() const=0; virtual unsigned height() const = 0;
virtual bool has_alpha() const=0; virtual bool has_alpha() const = 0;
virtual bool premultiplied_alpha() const=0; virtual bool premultiplied_alpha() const = 0;
virtual void read(unsigned x,unsigned y,image_data_32& image)=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() {} 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); 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(std::string const& file);
MAPNIK_DECL image_reader* get_image_reader(char const* data, size_t size); MAPNIK_DECL image_reader* get_image_reader(char const* data, size_t size);

View file

@ -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<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); MAPNIK_DECL boost::optional<std::string> scaling_method_to_string(scaling_method_e scaling_method);
template <typename Image> template <typename T>
MAPNIK_DECL void scale_image_agg(Image & target, MAPNIK_DECL void scale_image_agg(T & target, T const& source,
Image const& source, scaling_method_e scaling_method,
scaling_method_e scaling_method, double image_ratio_x,
double image_ratio_x, double image_ratio_y,
double image_ratio_y, double x_off_f,
double x_off_f, double y_off_f,
double y_off_f, double filter_factor);
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 #endif // MAPNIK_IMAGE_SCALING_HPP

View 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

View file

@ -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&,
std::string const&, std::string const&,
rgba_palette 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&,
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&, std::string const&,
rgba_palette 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_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&,
std::string const&, std::string const&,
rgba_palette 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&,
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&, std::string const&,
rgba_palette 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 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&); 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&, std::string const&,
rgba_palette 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&); 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&, std::string const&,
rgba_palette const&); rgba_palette const&);
#ifdef _MSC_VER #ifdef _MSC_VER
template MAPNIK_DECL void save_to_stream<image_data_32>( template MAPNIK_DECL void save_to_stream<image_data_rgba8>(
image_data_32 const& image, image_data_rgba8 const& image,
std::ostream & stream, std::ostream & stream,
std::string const& type, std::string const& type,
rgba_palette const& palette rgba_palette const& palette
); );
template MAPNIK_DECL void save_to_stream<image_data_32>( template MAPNIK_DECL void save_to_stream<image_data_rgba8>(
image_data_32 const& image, image_data_rgba8 const& image,
std::ostream & stream, std::ostream & stream,
std::string const& type std::string const& type
); );
template MAPNIK_DECL void save_to_stream<image_view<image_data_32> > ( template MAPNIK_DECL void save_to_stream<image_view<image_data_rgba8> > (
image_view<image_data_32> const& image, image_view<image_data_rgba8> const& image,
std::ostream & stream, std::ostream & stream,
std::string const& type, std::string const& type,
rgba_palette const& palette rgba_palette const& palette
); );
template MAPNIK_DECL void save_to_stream<image_view<image_data_32> > ( template MAPNIK_DECL void save_to_stream<image_view<image_data_rgba8> > (
image_view<image_data_32> const& image, image_view<image_data_rgba8> const& image,
std::ostream & stream, std::ostream & stream,
std::string const& type std::string const& type
); );

View file

@ -30,7 +30,8 @@ class image_view
{ {
public: public:
using pixel_type = typename T::pixel_type; 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) image_view(unsigned x, unsigned y, unsigned width, unsigned height, T const& data)
: x_(x), : x_(x),
y_(y), y_(y),
@ -84,10 +85,25 @@ public:
return height_; 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 inline const pixel_type* getRow(unsigned row) const
{ {
return data_.getRow(row + y_) + x_; 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 inline const unsigned char* getBytes() const
{ {
@ -101,6 +117,15 @@ public:
{ {
return data_; return data_;
} }
inline pixel_type* getData()
{
return data_.getData();
}
inline const pixel_type* getData() const
{
return data_.getData();
}
private: private:
unsigned x_; unsigned x_;

View file

@ -45,7 +45,7 @@ namespace mapnik
using attr_storage = agg::pod_bvector<mapnik::svg::path_attributes>; 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_storage_type = mapnik::svg::svg_storage<mapnik::svg::svg_path_storage,attr_storage>;
using svg_path_ptr = std::shared_ptr<svg_storage_type>; 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 * 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. * in the image caches and most of the render paths.
@ -56,7 +56,7 @@ public:
marker() marker()
{ {
// create default OGC 4x4 black pixel // 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); (*bitmap_data_)->set(0xff000000);
} }

View file

@ -169,7 +169,7 @@ struct raster_markers_rasterizer_dispatch : mapnik::noncopyable
using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba<blender_type, BufferType>; using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba<blender_type, BufferType>;
using renderer_base = agg::renderer_base<pixfmt_comp_type>; 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, agg::trans_affine const& marker_trans,
symbolizer_base const& sym, symbolizer_base const& sym,
Detector & detector, Detector & detector,
@ -300,7 +300,7 @@ private:
pixfmt_comp_type pixf_; pixfmt_comp_type pixf_;
renderer_base renb_; renderer_base renb_;
RasterizerType & ras_; RasterizerType & ras_;
image_data_32 const& src_; image_data_rgba8 const& src_;
agg::trans_affine const& marker_trans_; agg::trans_affine const& marker_trans_;
symbolizer_base const& sym_; symbolizer_base const& sym_;
Detector & detector_; Detector & detector_;

View file

@ -83,12 +83,12 @@ private:
static const unsigned char IEND_tpl[]; 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_data_gray8>(image_data_gray8 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_view<image_data_gray8> >(image_view<image_data_gray8> 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_data_rgba8>(image_data_rgba8 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::writeIDAT<image_view<image_data_rgba8> >(image_view<image_data_rgba8> 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_data_rgba8>(image_data_rgba8 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::writeIDATStripAlpha<image_view<image_data_rgba8> >(image_view<image_data_rgba8> const& image);
}} }}

View file

@ -149,7 +149,7 @@ void save_as_png(T1 & file,
template <typename T> template <typename T>
void reduce_8(T const& in, void reduce_8(T const& in,
image_data_8 & out, image_data_gray8 & out,
octree<rgb> trees[], octree<rgb> trees[],
unsigned limits[], unsigned limits[],
unsigned levels, unsigned levels,
@ -166,8 +166,8 @@ void reduce_8(T const& in,
} }
for (unsigned y = 0; y < height; ++y) for (unsigned y = 0; y < height; ++y)
{ {
mapnik::image_data_32::pixel_type const * row = in.getRow(y); mapnik::image_data_rgba8::pixel_type const * row = in.getRow(y);
mapnik::image_data_8::pixel_type * row_out = out.getRow(y); mapnik::image_data_gray8::pixel_type * row_out = out.getRow(y);
for (unsigned x = 0; x < width; ++x) for (unsigned x = 0; x < width; ++x)
{ {
unsigned val = row[x]; unsigned val = row[x];
@ -200,7 +200,7 @@ void reduce_8(T const& in,
template <typename T> template <typename T>
void reduce_4(T const& in, void reduce_4(T const& in,
image_data_8 & out, image_data_gray8 & out,
octree<rgb> trees[], octree<rgb> trees[],
unsigned limits[], unsigned limits[],
unsigned levels, unsigned levels,
@ -217,8 +217,8 @@ void reduce_4(T const& in,
} }
for (unsigned y = 0; y < height; ++y) for (unsigned y = 0; y < height; ++y)
{ {
mapnik::image_data_32::pixel_type const * row = in.getRow(y); mapnik::image_data_rgba8::pixel_type const * row = in.getRow(y);
mapnik::image_data_8::pixel_type * row_out = out.getRow(y); mapnik::image_data_gray8::pixel_type * row_out = out.getRow(y);
for (unsigned x = 0; x < width; ++x) for (unsigned x = 0; x < width; ++x)
{ {
unsigned val = row[x]; unsigned val = row[x];
@ -256,7 +256,7 @@ void reduce_4(T const& in,
// 1-bit but only one color. // 1-bit but only one color.
template <typename T> template <typename T>
void reduce_1(T const&, void reduce_1(T const&,
image_data_8 & out, image_data_gray8 & out,
octree<rgb> /*trees*/[], octree<rgb> /*trees*/[],
unsigned /*limits*/[], unsigned /*limits*/[],
std::vector<unsigned> & /*alpha*/) std::vector<unsigned> & /*alpha*/)
@ -266,7 +266,7 @@ void reduce_1(T const&,
template <typename T> template <typename T>
void save_as_png(T & file, std::vector<mapnik::rgb> const& palette, 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 width,
unsigned height, unsigned height,
unsigned color_depth, unsigned color_depth,
@ -556,7 +556,7 @@ void save_as_png8_oct(T1 & file,
if (palette.size() > 16 ) if (palette.size() > 16 )
{ {
// >16 && <=256 colors -> write 8-bit color depth // >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); reduce_8(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable);
save_as_png(file,palette,reduced_image,width,height,8,alphaTable,opts); 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 // 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_width = ((width + 15) >> 3) & ~1U; // 1-bit image, round up to 16-bit boundary
unsigned image_height = height; 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); reduce_1(image,reduced_image,trees, limits, alphaTable);
if (meanAlpha<255 && cols[0]==0) 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 // <=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_width = ((width + 7) >> 1) & ~3U; // 4-bit image, round up to 32-bit boundary
unsigned image_height = height; 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); reduce_4(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable);
save_as_png(file,palette,reduced_image,width,height,4,alphaTable,opts); 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 ) if (palette.size() > 16 )
{ {
// >16 && <=256 colors -> write 8-bit color depth // >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) for (unsigned y = 0; y < height; ++y)
{ {
mapnik::image_data_32::pixel_type const * row = image.getRow(y); mapnik::image_data_rgba8::pixel_type const * row = image.getRow(y);
mapnik::image_data_8::pixel_type * row_out = reduced_image.getRow(y); mapnik::image_data_gray8::pixel_type * row_out = reduced_image.getRow(y);
for (unsigned x = 0; x < width; ++x) for (unsigned x = 0; x < width; ++x)
{ {
row_out[x] = tree.quantize(row[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 // 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_width = ((width + 15) >> 3) & ~1U; // 1-bit image, round up to 16-bit boundary
unsigned image_height = height; 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); reduced_image.set(0);
save_as_png(file, palette, reduced_image, width, height, 1, alphaTable, opts); 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 // <=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_width = ((width + 7) >> 1) & ~3U; // 4-bit image, round up to 32-bit boundary
unsigned image_height = height; 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) for (unsigned y = 0; y < height; ++y)
{ {
mapnik::image_data_32::pixel_type const * row = image.getRow(y); mapnik::image_data_rgba8::pixel_type const * row = image.getRow(y);
mapnik::image_data_8::pixel_type * row_out = reduced_image.getRow(y); mapnik::image_data_gray8::pixel_type * row_out = reduced_image.getRow(y);
byte index = 0; byte index = 0;
for (unsigned x = 0; x < width; ++x) for (unsigned x = 0; x < width; ++x)
{ {

View file

@ -25,33 +25,28 @@
// mapnik // mapnik
#include <mapnik/box2d.hpp> #include <mapnik/box2d.hpp>
#include <mapnik/image_data.hpp> #include <mapnik/image_data_any.hpp>
#include <mapnik/noncopyable.hpp> #include <mapnik/noncopyable.hpp>
#include <mapnik/util/variant.hpp>
// boost // boost
#include <boost/optional.hpp> #include <boost/optional.hpp>
namespace mapnik { namespace mapnik {
class raster : private mapnik::noncopyable class raster : private mapnik::noncopyable
{ {
public: public:
box2d<double> ext_; box2d<double> ext_;
image_data_32 data_; image_data_any data_;
double filter_factor_; double filter_factor_;
bool premultiplied_alpha_; bool premultiplied_alpha_;
boost::optional<double> nodata_; boost::optional<double> nodata_;
template <typename ImageData>
raster(box2d<double> const& ext, raster(box2d<double> const& ext,
unsigned width, ImageData && data,
unsigned height,
double filter_factor, double filter_factor,
bool premultiplied_alpha = false) 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), : ext_(ext),
data_(std::move(data)), data_(std::move(data)),
filter_factor_(filter_factor), filter_factor_(filter_factor),

View file

@ -40,7 +40,9 @@
#include <mapnik/config.hpp> #include <mapnik/config.hpp>
#include <mapnik/color.hpp> #include <mapnik/color.hpp>
#include <mapnik/enumeration.hpp> #include <mapnik/enumeration.hpp>
#include <mapnik/image_data.hpp>
// boost
#include <boost/optional.hpp>
// boost // boost
#include <memory> #include <memory>
@ -195,12 +197,8 @@ public:
//! \return The list of stops //! \return The list of stops
colorizer_stops const& get_stops() const { return stops_; } colorizer_stops const& get_stops() const { return stops_; }
template <typename T>
//! \brief Colorize a raster void colorize(image_data_rgba8 & out, T const& in, boost::optional<double>const& nodata, feature_impl const& f) const;
//!
//! \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;
//! \brief Perform the translation of input to output //! \brief Perform the translation of input to output
//! //!

View file

@ -34,24 +34,159 @@
// agg // agg
#include "agg_rendering_buffer.h" #include "agg_rendering_buffer.h"
#include "agg_pixfmt_rgba.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 mapnik {
namespace detail {
template <typename F> template <typename F>
void render_raster_symbolizer(raster_symbolizer const &sym, struct image_data_dispatcher : util::static_visitor<void>
mapnik::feature_impl &feature, {
proj_transform const &prj_trans, using composite_function = F;
renderer_common &common, 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) F composite)
{ {
raster_ptr const& source = feature.get_raster(); raster_ptr const& source = feature.get_raster();
if (source) 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_); box2d<double> target_ext = box2d<double>(source->ext_);
prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS); prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS);
box2d<double> ext = common.t_.forward(target_ext); box2d<double> ext = common.t_.forward(target_ext);
@ -66,36 +201,37 @@ 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); 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); 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); double opacity = get<double>(sym,keys::opacity,feature, common.vars_, 1.0);
bool premultiply_source = !source->premultiplied_alpha_; // only premultiply rgba8 images
auto is_premultiplied = get_optional<bool>(sym, keys::premultiplied, feature, common.vars_); if (source->data_.is<image_data_rgba8>())
if (is_premultiplied)
{ {
if (*is_premultiplied) premultiply_source = false; bool premultiply_source = !source->premultiplied_alpha_;
else premultiply_source = true; auto is_premultiplied = get_optional<bool>(sym, keys::premultiplied, feature, common.vars_);
} if (is_premultiplied)
if (premultiply_source) {
{ if (*is_premultiplied) premultiply_source = false;
agg::rendering_buffer buffer(source->data_.getBytes(), else premultiply_source = true;
source->data_.width(), }
source->data_.height(), if (premultiply_source)
source->data_.width() * 4); {
agg::pixfmt_rgba32 pixf(buffer); agg::rendering_buffer buffer(source->data_.getBytes(),
pixf.premultiply(); source->data_.width(),
source->data_.height(),
source->data_.width() * 4);
agg::pixfmt_rgba32 pixf(buffer);
pixf.premultiply();
}
} }
if (!prj_trans.equal()) if (!prj_trans.equal())
{ {
double offset_x = ext.minx() - start_x; double offset_x = ext.minx() - start_x;
double offset_y = ext.miny() - start_y; 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)); unsigned mesh_size = static_cast<unsigned>(get<value_integer>(sym,keys::mesh_size,feature, common.vars_, 16));
reproject_and_scale_raster(target, detail::image_data_warp_dispatcher<F> dispatcher(prj_trans, start_x, start_y, raster_width, raster_height,
*source, target_ext, source->ext_, offset_x, offset_y, mesh_size,
prj_trans, scaling_method, source->get_filter_factor(),
offset_x, opacity, comp_op, sym, feature, composite, source->nodata());
offset_y, util::apply_visitor(dispatcher, source->data_);
mesh_size,
scaling_method);
composite(target.data_, comp_op, opacity, start_x, start_y);
} }
else else
{ {
@ -107,20 +243,18 @@ void render_raster_symbolizer(raster_symbolizer const &sym,
(std::abs(start_x) <= eps) && (std::abs(start_x) <= eps) &&
(std::abs(start_y) <= 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 else
{ {
raster target(target_ext, raster_width, raster_height, source->get_filter_factor()); detail::image_data_dispatcher<F> dispatcher(start_x, start_y, raster_width, raster_height,
scale_image_agg<image_data_32>(target.data_, image_ratio_x, image_ratio_y,
source->data_, scaling_method, source->get_filter_factor(),
scaling_method, opacity, comp_op, sym, feature, composite, source->nodata());
image_ratio_x, util::apply_visitor(dispatcher, source->data_);
image_ratio_y,
0.0,
0.0,
source->get_filter_factor());
composite(target.data_, comp_op, opacity, start_x, start_y);
} }
} }
} }

View file

@ -37,7 +37,7 @@ namespace mapnik {
struct rasterizer; struct rasterizer;
class marker; 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, marker const& marker,
agg::trans_affine const& tr, agg::trans_affine const& tr,
double opacity); double opacity);

View file

@ -25,6 +25,8 @@
#include <mapnik/global.hpp> #include <mapnik/global.hpp>
#include <mapnik/image_util.hpp> #include <mapnik/image_util.hpp>
#include <mapnik/image_data_any.hpp>
#include <mapnik/util/variant.hpp>
extern "C" extern "C"
{ {
@ -33,9 +35,15 @@ extern "C"
#define RealTIFFClose TIFFClose #define RealTIFFClose TIFFClose
} }
#define TIFF_WRITE_SCANLINE 0
#define TIFF_WRITE_STRIPPED 1
#define TIFF_WRITE_TILED 2
#include <iostream>
namespace mapnik { 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::ostream* out = reinterpret_cast<std::ostream*>(fd);
std::ios::pos_type pos = out->tellp(); 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); 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()); 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; std::ostream* out = (std::ostream*)fd;
out->flush(); out->flush();
return 0; 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::ostream* out = reinterpret_cast<std::ostream*>(fd);
std::ios::pos_type pos = out->tellp(); 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); 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; 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; 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> 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 width = image.width();
const int height = image.height(); const int height = image.height();
const int scanline_size = sizeof(unsigned char) * width * 3;
TIFF* output = RealTIFFOpen("mapnik_tiff_stream", TIFF* output = RealTIFFOpen("mapnik_tiff_stream",
"wm", "wm",
@ -179,13 +306,107 @@ void save_as_tiff(T1 & file, T2 const& image)
TIFFSetField(output, TIFFTAG_IMAGEWIDTH, width); TIFFSetField(output, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(output, TIFFTAG_IMAGELENGTH, height); TIFFSetField(output, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); TIFFSetField(output, TIFFTAG_IMAGEDEPTH, 1);
TIFFSetField(output, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); set_tiff_config(output, config);
TIFFSetField(output, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField(output, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(output, TIFFTAG_SAMPLESPERPIXEL, 3);
TIFFSetField(output, TIFFTAG_ROWSPERSTRIP, 1);
// 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 // TODO - handle palette images
// std::vector<mapnik::rgb> const& palette // 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_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
// TIFFSetField(output, TIFFTAG_COLORMAP, r, g, b); // 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); RealTIFFClose(output);
} }

View file

@ -26,6 +26,7 @@
// mapnik // mapnik
#include <mapnik/image_scaling.hpp> #include <mapnik/image_scaling.hpp>
#include <mapnik/config.hpp> #include <mapnik/config.hpp>
#include <mapnik/box2d.hpp>
namespace mapnik { namespace mapnik {
@ -33,12 +34,17 @@ class raster;
class proj_transform; class proj_transform;
MAPNIK_DECL void reproject_and_scale_raster(raster & target, MAPNIK_DECL void reproject_and_scale_raster(raster & target,
raster const& source, raster const& source,
proj_transform const& prj_trans, proj_transform const& prj_trans,
double offset_x, double offset_y, double offset_x, double offset_y,
unsigned mesh_size, unsigned mesh_size,
scaling_method_e scaling_method); 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 #endif // MAPNIK_WARP_HPP

View file

@ -98,11 +98,11 @@ inline int import_image_data(T2 const& image,
else else
{ {
// need to copy: https://github.com/mapnik/mapnik/issues/2024 // 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) for (unsigned y = 0; y < image.height(); ++y)
{ {
typename T2::pixel_type const * row_from = image.getRow(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); std::copy(row_from, row_from + stride, row_to);
} }
if (alpha) if (alpha)
@ -121,11 +121,11 @@ inline int import_image_data(T2 const& image,
} }
template <> template <>
inline int import_image_data(image_data_32 const& im, inline int import_image_data(image_data_rgba8 const& im,
WebPPicture & pic, WebPPicture & pic,
bool alpha) bool alpha)
{ {
int stride = sizeof(image_data_32::pixel_type) * im.width(); int stride = sizeof(image_data_rgba8::pixel_type) * im.width();
if (alpha) if (alpha)
{ {
return WebPPictureImportRGBA(&pic, im.getBytes(), stride); return WebPPictureImportRGBA(&pic, im.getBytes(), stride);

View file

@ -109,7 +109,7 @@ gdal_datasource::gdal_datasource(parameters const& params)
nbands_ = dataset->GetRasterCount(); nbands_ = dataset->GetRasterCount();
width_ = dataset->GetRasterXSize(); width_ = dataset->GetRasterXSize();
height_ = dataset->GetRasterYSize(); height_ = dataset->GetRasterYSize();
desc_.add_descriptor(mapnik::attribute_descriptor("nodata", mapnik::Integer)); desc_.add_descriptor(mapnik::attribute_descriptor("nodata", mapnik::Double));
double tr[6]; double tr[6];
bool bbox_override = false; bool bbox_override = false;

View file

@ -199,34 +199,38 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
if (im_width > 0 && im_height > 0) 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: Image Size=(" << im_width << "," << im_height << ")";
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Reading band=" << band_; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Reading band=" << band_;
if (band_ > 0) // we are querying a single 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_) if (band_ > nbands_)
{ {
std::ostringstream s; std::ostringstream s;
s << "GDAL Plugin: " << band_ << " is an invalid band, dataset only has " << nbands_ << "bands"; s << "GDAL Plugin: " << band_ << " is an invalid band, dataset only has " << nbands_ << "bands";
throw datasource_exception(s.str()); throw datasource_exception(s.str());
} }
float* imageData = reinterpret_cast<float*>(image.getBytes());
GDALRasterBand * band = dataset_.GetRasterBand(band_); GDALRasterBand * band = dataset_.GetRasterBand(band_);
raster_nodata = band->GetNoDataValue(&raster_has_nodata); raster_nodata = band->GetNoDataValue(&raster_has_nodata);
raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height,
imageData, image.width(), image.height(), image.getData(), image.width(), image.height(),
GDT_Float32, 0, 0); GDT_Int16, 0, 0);
if (raster_io_error == CE_Failure) { if (raster_io_error == CE_Failure)
{
throw datasource_exception(CPLGetLastErrorMsg()); 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 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) for (int i = 0; i < nbands_; ++i)
{ {
GDALRasterBand * band = dataset_.GetRasterBand(i + 1); 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, raster_io_error = grey->RasterIO(GF_Read, x_off, y_off, width, height,
imageData, image.width(), image.height(), imageData, image.width(), image.height(),
GDT_Float32, 0, 0); GDT_Float32, 0, 0);
if (raster_io_error == CE_Failure) { if (raster_io_error == CE_Failure)
{
throw datasource_exception(CPLGetLastErrorMsg()); throw datasource_exception(CPLGetLastErrorMsg());
} }
int len = image.width() * image.height(); 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, 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()); 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()); throw datasource_exception(CPLGetLastErrorMsg());
} }
raster_io_error = grey->RasterIO(GF_Read,x_off, y_off, width, height, image.getBytes() + 1, 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()); 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()); throw datasource_exception(CPLGetLastErrorMsg());
} }
raster_io_error = grey->RasterIO(GF_Read,x_off, y_off, width, height, image.getBytes() + 2, 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()); 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()); 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_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 // set nodata value to be used in raster colorizer
if (nodata_value_) if (nodata_value_) raster->set_nodata(*nodata_value_);
{ else raster->set_nodata(raster_nodata);
raster->set_nodata(*nodata_value_); feature->set_raster(raster);
}
else
{
raster->set_nodata(raster_nodata);
} }
// report actual/original source nodata in feature attributes // report actual/original source nodata in feature attributes
if (raster_has_nodata) if (raster_has_nodata)

View file

@ -178,25 +178,20 @@ typedef enum {
} }
using mapnik::box2d;
template<typename T> 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, uint16_t width, uint16_t height,
bool hasnodata, T reader) 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) // Start with plain white (ABGR or RGBA depending on endiannes)
// TODO: set to transparent instead? // TODO: set to transparent instead?
image.set(0xffffffff); image.set(0xffffffff);
raster->premultiplied_alpha_ = true; float* data = image.getData();
float* data = (float*)image.getBytes();
double val; double val;
val = reader(); // nodata value, need to read anyway val = reader(); // nodata value, need to read anyway
if ( hasnodata ) raster->set_nodata(val);
for (int y=0; y<height; ++y) { for (int y=0; y<height; ++y) {
for (int x=0; x<width; ++x) { for (int x=0; x<width; ++x) {
val = reader(); val = reader();
@ -204,16 +199,14 @@ void read_data_band(mapnik::raster_ptr raster,
data[off] = val; 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 mapnik::raster_ptr pgraster_wkb_reader::read_indexed(mapnik::box2d<double> const& bbox,
pgraster_wkb_reader::read_indexed(mapnik::raster_ptr raster) 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_); uint8_t type = read_uint8(&ptr_);
int pixtype = BANDTYPE_PIXTYPE(type); int pixtype = BANDTYPE_PIXTYPE(type);
@ -227,7 +220,7 @@ pgraster_wkb_reader::read_indexed(mapnik::raster_ptr raster)
if ( offline ) { if ( offline ) {
MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: offline band " MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: offline band "
" unsupported"; " unsupported";
return; return mapnik::raster_ptr();
} }
MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: reading " << height_ << "x" << width_ << " pixels"; 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: case PT_8BSI:
// mapnik does not support signed anyway // mapnik does not support signed anyway
case PT_8BUI: case PT_8BUI:
read_data_band(raster, width_, height_, hasnodata, return read_data_band(bbox, width_, height_, hasnodata,
boost::bind(read_uint8, &ptr_)); boost::bind(read_uint8, &ptr_));
break; break;
case PT_16BSI: case PT_16BSI:
// mapnik does not support signed anyway // mapnik does not support signed anyway
case PT_16BUI: case PT_16BUI:
read_data_band(raster, width_, height_, hasnodata, return read_data_band(bbox, width_, height_, hasnodata,
boost::bind(read_uint16, &ptr_, endian_)); boost::bind(read_uint16, &ptr_, endian_));
break; break;
case PT_32BSI: case PT_32BSI:
// mapnik does not support signed anyway // mapnik does not support signed anyway
case PT_32BUI: case PT_32BUI:
read_data_band(raster, width_, height_, hasnodata, return read_data_band(bbox, width_, height_, hasnodata,
boost::bind(read_uint32, &ptr_, endian_)); boost::bind(read_uint32, &ptr_, endian_));
break; break;
case PT_32BF: case PT_32BF:
read_data_band(raster, width_, height_, hasnodata, return read_data_band(bbox, width_, height_, hasnodata,
boost::bind(read_float32, &ptr_, endian_)); boost::bind(read_float32, &ptr_, endian_));
break; break;
case PT_64BF: case PT_64BF:
read_data_band(raster, width_, height_, hasnodata, return read_data_band(bbox, width_, height_, hasnodata,
boost::bind(read_float64, &ptr_, endian_)); boost::bind(read_float64, &ptr_, endian_));
break; break;
default: default:
@ -270,28 +263,25 @@ pgraster_wkb_reader::read_indexed(mapnik::raster_ptr raster)
//MAPNIK_LOG_WARN(pgraster) << err.str(); //MAPNIK_LOG_WARN(pgraster) << err.str();
throw mapnik::datasource_exception(err.str()); throw mapnik::datasource_exception(err.str());
} }
return mapnik::raster_ptr();
} }
template<typename T> 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, uint16_t width, uint16_t height,
bool hasnodata, T reader) 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) // Start with plain white (ABGR or RGBA depending on endiannes)
// TODO: set to transparent instead? // TODO: set to transparent instead?
image.set(0xffffffff); image.set(0xffffffff);
raster->premultiplied_alpha_ = true;
int val; int val;
uint8_t * data = image.getBytes(); uint8_t * data = image.getBytes();
int ps = 4; // sizeof(image_data::pixel_type) int ps = 4; // sizeof(image_data::pixel_type)
int off; int off;
val = reader(); // nodata value, need to read anyway val = reader(); // nodata value, need to read anyway
if ( hasnodata ) raster->set_nodata(val);
for (int y=0; y<height; ++y) { for (int y=0; y<height; ++y) {
for (int x=0; x<width; ++x) { for (int x=0; x<width; ++x) {
val = reader(); val = reader();
@ -302,10 +292,13 @@ void read_grayscale_band(mapnik::raster_ptr raster,
data[off+2] = val; 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 mapnik::raster_ptr pgraster_wkb_reader::read_grayscale(mapnik::box2d<double> const& bbox,
pgraster_wkb_reader::read_grayscale(mapnik::raster_ptr raster) uint16_t width, uint16_t height)
{ {
uint8_t type = read_uint8(&ptr_); uint8_t type = read_uint8(&ptr_);
@ -320,7 +313,7 @@ pgraster_wkb_reader::read_grayscale(mapnik::raster_ptr raster)
if ( offline ) { if ( offline ) {
MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: offline band " MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: offline band "
" unsupported"; " unsupported";
return; return mapnik::raster_ptr();
} }
switch (pixtype) { switch (pixtype) {
@ -331,19 +324,19 @@ pgraster_wkb_reader::read_grayscale(mapnik::raster_ptr raster)
case PT_8BSI: case PT_8BSI:
// mapnik does not support signed anyway // mapnik does not support signed anyway
case PT_8BUI: case PT_8BUI:
read_grayscale_band(raster, width_, height_, hasnodata, return read_grayscale_band(bbox, width_, height_, hasnodata,
boost::bind(read_uint8, &ptr_)); boost::bind(read_uint8, &ptr_));
break; break;
case PT_16BSI: case PT_16BSI:
// mapnik does not support signed anyway // mapnik does not support signed anyway
case PT_16BUI: case PT_16BUI:
read_grayscale_band(raster, width_, height_, hasnodata, return read_grayscale_band(bbox, width_, height_, hasnodata,
boost::bind(read_uint16, &ptr_, endian_)); boost::bind(read_uint16, &ptr_, endian_));
break; break;
case PT_32BSI: case PT_32BSI:
// mapnik does not support signed anyway // mapnik does not support signed anyway
case PT_32BUI: case PT_32BUI:
read_grayscale_band(raster, width_, height_, hasnodata, return read_grayscale_band(bbox, width_, height_, hasnodata,
boost::bind(read_uint32, &ptr_, endian_)); boost::bind(read_uint32, &ptr_, endian_));
break; break;
default: default:
@ -353,19 +346,15 @@ pgraster_wkb_reader::read_grayscale(mapnik::raster_ptr raster)
//MAPNIK_LOG_WARN(pgraster) << err.str(); //MAPNIK_LOG_WARN(pgraster) << err.str();
throw mapnik::datasource_exception(err.str()); throw mapnik::datasource_exception(err.str());
} }
return mapnik::raster_ptr();
} }
void mapnik::raster_ptr pgraster_wkb_reader::read_rgba(mapnik::box2d<double> const& bbox,
pgraster_wkb_reader::read_rgba(mapnik::raster_ptr raster) 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) // Start with plain white (ABGR or RGBA depending on endiannes)
image.set(0xffffffff); image.set(0xffffffff);
//raster->set_nodata(0xffffffff);
raster->premultiplied_alpha_ = true;
uint8_t nodataval; uint8_t nodataval;
for (int bn=0; bn<numBands_; ++bn) { 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 mapnik::raster_ptr
@ -458,28 +450,30 @@ pgraster_wkb_reader::get_raster() {
return mapnik::raster_ptr(); 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_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_ ) { if ( bandno_ != 1 )
if ( bandno_ != 1 ) { {
MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: " MAPNIK_LOG_WARN(pgraster) << "pgraster_wkb_reader: "
"reading bands other than 1st as indexed is unsupported"; "reading bands other than 1st as indexed is unsupported";
return mapnik::raster_ptr(); return mapnik::raster_ptr();
} }
MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: requested band " << bandno_; MAPNIK_LOG_DEBUG(pgraster) << "pgraster_wkb_reader: requested band " << bandno_;
read_indexed(raster); return read_indexed(ext, width_, height_);
} }
else { else
switch (numBands_) { {
switch (numBands_)
{
case 1: case 1:
read_grayscale(raster); return read_grayscale(ext, width_, height_);
break; break;
case 3: case 3:
case 4: case 4:
read_rgba(raster); return read_rgba(ext, width_, height_);
break; break;
default: default:
std::ostringstream err; std::ostringstream err;
@ -491,7 +485,5 @@ pgraster_wkb_reader::get_raster() {
return mapnik::raster_ptr(); return mapnik::raster_ptr();
} }
} }
return mapnik::raster_ptr();
return raster;
} }

View file

@ -29,6 +29,7 @@
// mapnik // mapnik
#include <mapnik/feature.hpp> // for raster_ptr #include <mapnik/feature.hpp> // for raster_ptr
#include <mapnik/box2d.hpp>
enum pgraster_color_interp { enum pgraster_color_interp {
// Automatic color interpretation: // Automatic color interpretation:
@ -65,9 +66,9 @@ public:
} }
private: private:
void read_indexed(mapnik::raster_ptr raster); mapnik::raster_ptr read_indexed(mapnik::box2d<double> const& bbox, uint16_t width, uint16_t height);
void read_grayscale(mapnik::raster_ptr raster); mapnik::raster_ptr read_grayscale(mapnik::box2d<double> const& bbox, uint16_t width, uint16_t height);
void read_rgba(mapnik::raster_ptr raster); mapnik::raster_ptr read_rgba(mapnik::box2d<double> const& bbox, uint16_t width, uint16_t height);
//int wkbsize_; //int wkbsize_;
//const uint8_t* wkb_; //const uint8_t* wkb_;

View file

@ -84,6 +84,16 @@ raster_datasource::raster_datasource(parameters const& params)
{ {
extent_initialized_ = extent_.from_string(*ext); 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_) if (! extent_initialized_)
{ {

View file

@ -28,6 +28,7 @@
#include <mapnik/image_reader.hpp> #include <mapnik/image_reader.hpp>
#include <mapnik/image_util.hpp> #include <mapnik/image_util.hpp>
#include <mapnik/feature_factory.hpp> #include <mapnik/feature_factory.hpp>
#include <mapnik/util/variant.hpp>
// boost // boost
#pragma GCC diagnostic push #pragma GCC diagnostic push
@ -42,7 +43,7 @@
using mapnik::query; using mapnik::query;
using mapnik::image_reader; using mapnik::image_reader;
using mapnik::feature_ptr; using mapnik::feature_ptr;
using mapnik::image_data_32; using mapnik::image_data_rgba8;
using mapnik::raster; using mapnik::raster;
using mapnik::feature_factory; using mapnik::feature_factory;
@ -113,9 +114,8 @@ feature_ptr raster_featureset<LookupPolicy>::next()
rem.maxx() + x_off + width, rem.maxx() + x_off + width,
rem.maxy() + y_off + height); rem.maxy() + y_off + height);
intersect = t.backward(feature_raster_extent); intersect = t.backward(feature_raster_extent);
mapnik::image_data_any data = reader->read(x_off, y_off, width, height);
mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, width, height, 1.0); mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, std::move(data), 1.0);
reader->read(x_off, y_off, raster->data_);
raster->premultiplied_alpha_ = reader->premultiplied_alpha(); raster->premultiplied_alpha_ = reader->premultiplied_alpha();
feature->set_raster(raster); feature->set_raster(raster);
} }

View file

@ -115,7 +115,7 @@ feature_ptr rasterlite_featureset::get_feature(mapnik::query const& q)
if (size > 0) if (size > 0)
{ {
mapnik::raster_ptr rasterp = std::make_shared<mapnik::raster>(intersect, width, height, 1.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); image.set(0xffffffff);
unsigned char* raster_data = static_cast<unsigned char*>(raster); unsigned char* raster_data = static_cast<unsigned char*>(raster);

View file

@ -5,15 +5,20 @@ failures=0
source ./localize.sh source ./localize.sh
PYTHON=${PYTHON:-python} PYTHON=${PYTHON:-python}
echo "*** Running visual tests..." echo "*** Running Next Gen C++ tests..."
$PYTHON tests/visual_tests/test.py -q ./tests/cxx/run
failures=$((failures+$?)) failures=$((failures+$?))
echo
echo "*** Running C++ tests..." echo "*** Running Old C++ tests..."
./tests/cpp_tests/run ./tests/cpp_tests/run
failures=$((failures+$?)) failures=$((failures+$?))
echo echo
echo "*** Running visual tests..."
$PYTHON tests/visual_tests/test.py -q
failures=$((failures+$?))
echo "*** Running python tests..." echo "*** Running python tests..."
$PYTHON tests/run_tests.py -q $PYTHON tests/run_tests.py -q
failures=$((failures+$?)) failures=$((failures+$?))

View file

@ -412,7 +412,7 @@ void agg_renderer<T0,T1>::render_marker(pixel_position const& pos,
agg::image_filter_bilinear filter_kernel; agg::image_filter_bilinear filter_kernel;
agg::image_filter_lut filter(filter_kernel, false); 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(), agg::rendering_buffer marker_buf((unsigned char *)src.getBytes(),
src.width(), src.width(),
src.height(), src.height(),

View file

@ -52,7 +52,7 @@ void agg_renderer<T0,T1>::process(raster_symbolizer const& sym,
{ {
render_raster_symbolizer( render_raster_symbolizer(
sym, feature, prj_trans, common_, 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) { int start_x, int start_y) {
composite(current_buffer_->data(), target, composite(current_buffer_->data(), target,
comp_op, opacity, start_x, start_y, false); comp_op, opacity, start_x, start_y, false);

View file

@ -337,7 +337,7 @@ void cairo_context::set_gradient(cairo_gradient const& pattern, const box2d<doub
check_object_status_and_throw_exception(*this); 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); cairo_pattern pattern(data);
pattern.set_origin(x, y); 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); 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); cairo_pattern pattern(data);
if (!tr.is_identity()) if (!tr.is_identity())

View file

@ -124,7 +124,7 @@ struct markers_dispatch : mapnik::noncopyable
template <typename RendererContext, typename Detector> template <typename RendererContext, typename Detector>
struct raster_markers_dispatch : mapnik::noncopyable 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, agg::trans_affine const& marker_trans,
markers_symbolizer const& sym, markers_symbolizer const& sym,
Detector & detector, Detector & detector,
@ -165,7 +165,7 @@ struct raster_markers_dispatch : mapnik::noncopyable
} }
} }
image_data_32 & src_; image_data_rgba8 & src_;
Detector & detector_; Detector & detector_;
markers_symbolizer const& sym_; markers_symbolizer const& sym_;
agg::trans_affine const& marker_trans_; agg::trans_affine const& marker_trans_;

View file

@ -43,7 +43,7 @@ void cairo_renderer<T>::process(raster_symbolizer const& sym,
cairo_save_restore guard(context_); cairo_save_restore guard(context_);
render_raster_symbolizer( render_raster_symbolizer(
sym, feature, prj_trans, common_, 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) { int start_x, int start_y) {
context_.set_operator(comp_op); context_.set_operator(comp_op);
context_.add_image(start_x, start_y, target, opacity); context_.add_image(start_x, start_y, target, opacity);

View file

@ -165,7 +165,7 @@ void grid_renderer<T>::render_marker(mapnik::feature_impl const& feature, pixel_
} }
else else
{ {
image_data_32 const& data = **marker.get_bitmap_data(); image_data_rgba8 const& data = **marker.get_bitmap_data();
double width = data.width(); double width = data.width();
double height = data.height(); double height = data.height();
double cx = 0.5 * width; double cx = 0.5 * width;
@ -179,13 +179,13 @@ void grid_renderer<T>::render_marker(mapnik::feature_impl const& feature, pixel_
} }
else else
{ {
image_data_32 target(data.width(), data.height()); image_data_rgba8 target(data.width(), data.height());
mapnik::scale_image_agg<image_data_32>(target, mapnik::scale_image_agg(target,
data, data,
SCALING_NEAR, SCALING_NEAR,
1, 1,
1, 1,
0.0, 0.0, 1.0); // TODO: is 1.0 a valid default here, and do we even care in grid_renderer what the image looks like? 0.0, 0.0, 1.0); // TODO: is 1.0 a valid default here, and do we even care in grid_renderer what the image looks like?
pixmap_.set_rectangle(feature.id(), target, pixmap_.set_rectangle(feature.id(), target,
boost::math::iround(pos.x - cx), boost::math::iround(pos.x - cx),
boost::math::iround(pos.y - cy)); boost::math::iround(pos.y - cy));

View file

@ -38,8 +38,10 @@
#include "agg_scanline_u.h" #include "agg_scanline_u.h"
#include "agg_renderer_scanline.h" #include "agg_renderer_scanline.h"
#include "agg_pixfmt_rgba.h" #include "agg_pixfmt_rgba.h"
#include "agg_pixfmt_gray.h"
#include "agg_color_rgba.h" #include "agg_color_rgba.h"
namespace mapnik namespace mapnik
{ {
@ -120,9 +122,8 @@ For example, if you generate some pattern with AGG (premultiplied) and would lik
*/ */
template <>
template <typename T1, typename T2> MAPNIK_DECL void composite(image_data_rgba8 & dst, image_data_rgba8 & src, composite_mode_e mode,
void composite(T1 & dst, T2 & src, composite_mode_e mode,
float opacity, float opacity,
int dx, int dx,
int dy, 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)); 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&, template <>
mapnik::image_data_32&, MAPNIK_DECL void composite(image_data_gray32f & dst, image_data_gray32f & src, composite_mode_e mode,
composite_mode_e, float opacity,
float, int dx,
int, int dy,
int, bool premultiply_src)
bool); {
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);;
}
} }

View file

@ -23,6 +23,7 @@
// mapnik // mapnik
#include <mapnik/image_data.hpp> #include <mapnik/image_data.hpp>
#include <mapnik/image_scaling.hpp> #include <mapnik/image_scaling.hpp>
#include <mapnik/image_scaling_traits.hpp>
// does not handle alpha correctly // does not handle alpha correctly
//#include <mapnik/span_image_filter.hpp> //#include <mapnik/span_image_filter.hpp>
@ -37,12 +38,14 @@
// agg // agg
#include "agg_image_accessors.h" #include "agg_image_accessors.h"
#include "agg_pixfmt_rgba.h" #include "agg_pixfmt_rgba.h"
#include "agg_pixfmt_gray.h"
#include "agg_color_rgba.h" #include "agg_color_rgba.h"
#include "agg_rasterizer_scanline_aa.h" #include "agg_rasterizer_scanline_aa.h"
#include "agg_renderer_scanline.h" #include "agg_renderer_scanline.h"
#include "agg_rendering_buffer.h" #include "agg_rendering_buffer.h"
#include "agg_scanline_u.h" #include "agg_scanline_u.h"
#include "agg_span_allocator.h" #include "agg_span_allocator.h"
#include "agg_span_image_filter_gray.h"
#include "agg_span_image_filter_rgba.h" #include "agg_span_image_filter_rgba.h"
#include "agg_span_interpolator_linear.h" #include "agg_span_interpolator_linear.h"
#include "agg_trans_affine.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; return mode;
} }
template <typename Image>
void scale_image_agg(Image & target, template <typename T>
Image const& source, void scale_image_agg(T & target, T const& source, scaling_method_e scaling_method,
scaling_method_e scaling_method, double image_ratio_x, double image_ratio_y, double x_off_f, double y_off_f,
double image_ratio_x,
double image_ratio_y,
double x_off_f,
double y_off_f,
double filter_factor) double filter_factor)
{ {
// "the image filters should work namely in the premultiplied color space" // "the image filters should work namely in the premultiplied color space"
// http://old.nabble.com/Re:--AGG--Basic-image-transformations-p1110665.html // 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." // "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 // 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>; 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 // define some stuff we'll use soon
agg::rasterizer_scanline_aa<> ras; agg::rasterizer_scanline_aa<> ras;
agg::scanline_u8 sl; agg::scanline_u8 sl;
agg::span_allocator<agg::rgba8> sa; agg::span_allocator<color_type> sa;
agg::image_filter_lut filter;
// initialize source AGG buffer // 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); pixfmt_pre pixf_src(rbuf_src);
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
img_src_type img_src(pixf_src); img_src_type img_src(pixf_src);
// initialize destination AGG buffer (with transparency) // 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); pixfmt_pre pixf_dst(rbuf_dst);
renderer_base_pre rb_dst_pre(pixf_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); img_mtx /= agg::trans_affine_scaling(image_ratio_x, image_ratio_y);
// create a linear interpolator for our scaling matrix // create a linear interpolator for our scaling matrix
using interpolator_type = agg::span_interpolator_linear<>;
interpolator_type interpolator(img_mtx); interpolator_type interpolator(img_mtx);
// draw an anticlockwise polygon to render our image into // draw an anticlockwise polygon to render our image into
double scaled_width = target.width(); double scaled_width = target.width();
double scaled_height = target.height(); 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 + scaled_width, y_off_f + scaled_height);
ras.line_to_d(x_off_f, 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 = typename detail::agg_scaling_traits<image_data_type>::span_image_filter;
{
using span_gen_type = agg::span_image_filter_rgba_nn<img_src_type, interpolator_type>;
span_gen_type sg(img_src, interpolator); span_gen_type sg(img_src, interpolator);
agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg); agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg);
return;
} }
case SCALING_BILINEAR: else
filter.calculate(agg::image_filter_bilinear(), true); break; {
case SCALING_BICUBIC: using span_gen_type = typename detail::agg_scaling_traits<image_data_type>::span_image_resample_affine;
filter.calculate(agg::image_filter_bicubic(), true); break; agg::image_filter_lut filter;
case SCALING_SPLINE16: detail::set_scaling_method(filter, scaling_method, filter_factor);
filter.calculate(agg::image_filter_spline16(), true); break; span_gen_type sg(img_src, interpolator, filter);
case SCALING_SPLINE36: agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg);
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>;
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, template MAPNIK_DECL void scale_image_agg(image_data_rgba8 &, image_data_rgba8 const&, scaling_method_e,
const image_data_32& source, double, double , double, double , double);
scaling_method_e scaling_method,
double image_ratio_x, template MAPNIK_DECL void scale_image_agg(image_data_gray8 &, image_data_gray8 const&, scaling_method_e,
double image_ratio_y, double, double , double, double , double);
double x_off_f,
double y_off_f, template MAPNIK_DECL void scale_image_agg(image_data_gray16 &, image_data_gray16 const&, scaling_method_e,
double filter_factor); 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);
} }

View file

@ -255,6 +255,127 @@ void handle_png_options(std::string const& type,
} }
#endif #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) #if defined(HAVE_WEBP)
void handle_webp_options(std::string const& type, void handle_webp_options(std::string const& type,
WebPConfig & config, WebPConfig & config,
@ -621,7 +742,9 @@ void save_to_stream(T const& image,
else if (boost::algorithm::starts_with(t, "tif")) else if (boost::algorithm::starts_with(t, "tif"))
{ {
#if defined(HAVE_TIFF) #if defined(HAVE_TIFF)
save_as_tiff(stream, image); tiff_config config;
handle_tiff_options(t, config);
save_as_tiff(stream, image, config);
#else #else
throw ImageWriterException("tiff output is not enabled in your build of Mapnik"); throw ImageWriterException("tiff output is not enabled in your build of Mapnik");
#endif #endif
@ -769,62 +892,62 @@ void save_to_cairo_file(mapnik::Map const& map,
#endif #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&,
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&,
std::string const&, std::string const&,
rgba_palette const& palette); 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&); 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); 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&); 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&, std::string const&,
rgba_palette const& palette); 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&,
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&,
std::string const&, std::string const&,
rgba_palette const& palette); 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); 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&); 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&, std::string const&,
rgba_palette const& palette); rgba_palette const& palette);
void save_to_file(image_32 const& image,std::string const& file) 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, void save_to_file (image_32 const& image,
std::string const& file, std::string const& file,
std::string const& type) 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, void save_to_file (image_32 const& image,
@ -832,20 +955,20 @@ void save_to_file (image_32 const& image,
std::string const& type, std::string const& type,
rgba_palette const& palette) 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 save_to_string(image_32 const& image,
std::string const& type) 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 save_to_string(image_32 const& image,
std::string const& type, std::string const& type,
rgba_palette const& palette) 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);
} }
} }

View file

@ -81,11 +81,13 @@ public:
explicit jpeg_reader(std::string const& file_name); explicit jpeg_reader(std::string const& file_name);
explicit jpeg_reader(char const* data, size_t size); explicit jpeg_reader(char const* data, size_t size);
~jpeg_reader(); ~jpeg_reader();
unsigned width() const; unsigned width() const final;
unsigned height() const; unsigned height() const final;
inline bool has_alpha() const { return false; } boost::optional<box2d<double> > bounding_box() const final;
inline bool premultiplied_alpha() const { return true; } inline bool has_alpha() const final { return false; }
void read(unsigned x,unsigned y,image_data_32& image); 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: private:
void init(); void init();
static void on_error(j_common_ptr cinfo); static void on_error(j_common_ptr cinfo);
@ -258,7 +260,13 @@ unsigned jpeg_reader<T>::height() const
} }
template <typename T> 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_.clear();
stream_.seekg(0, std::ios_base::beg); 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); 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));
}
} }

View file

@ -62,7 +62,7 @@ marker_cache::marker_cache()
"<svg width='100%' height='100%' version='1.1' xmlns='http://www.w3.org/2000/svg'>" "<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'/>" "<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>"); "</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); (*bitmap_data)->set(0xff000000);
marker_ptr mark = std::make_shared<mapnik::marker>(bitmap_data); marker_ptr mark = std::make_shared<mapnik::marker>(bitmap_data);
marker_cache_.emplace("image://square",mark); 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 width = reader->width();
unsigned height = reader->height(); unsigned height = reader->height();
BOOST_ASSERT(width > 0 && height > 0); 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); reader->read(0,0,*image);
if (!reader->premultiplied_alpha()) if (!reader->premultiplied_alpha())
{ {

View file

@ -361,11 +361,11 @@ const mz_uint8 PNGWriter::IEND_tpl[] = {
'I', 'E', 'N', 'D' // "IEND" 'I', 'E', 'N', 'D' // "IEND"
}; };
template void PNGWriter::writeIDAT<image_data_8>(image_data_8 const& image); template void PNGWriter::writeIDAT<image_data_gray8>(image_data_gray8 const& image);
template void PNGWriter::writeIDAT<image_view<image_data_8> >(image_view<image_data_8> const& image); template void PNGWriter::writeIDAT<image_view<image_data_gray8> >(image_view<image_data_gray8> const& image);
template void PNGWriter::writeIDAT<image_data_32>(image_data_32 const& image); template void PNGWriter::writeIDAT<image_data_rgba8>(image_data_rgba8 const& image);
template void PNGWriter::writeIDAT<image_view<image_data_32> >(image_view<image_data_32> const& image); template void PNGWriter::writeIDAT<image_view<image_data_rgba8> >(image_view<image_data_rgba8> const& image);
template void PNGWriter::writeIDATStripAlpha<image_data_32>(image_data_32 const& image); template void PNGWriter::writeIDATStripAlpha<image_data_rgba8>(image_data_rgba8 const& image);
template void PNGWriter::writeIDATStripAlpha<image_view<image_data_32> >(image_view<image_data_32> const& image); template void PNGWriter::writeIDATStripAlpha<image_view<image_data_rgba8> >(image_view<image_data_rgba8> const& image);
}} }}

View file

@ -76,11 +76,13 @@ public:
explicit png_reader(std::string const& file_name); explicit png_reader(std::string const& file_name);
png_reader(char const* data, std::size_t size); png_reader(char const* data, std::size_t size);
~png_reader(); ~png_reader();
unsigned width() const; unsigned width() const final;
unsigned height() const; unsigned height() const final;
inline bool has_alpha() const { return has_alpha_; } boost::optional<box2d<double> > bounding_box() const final;
bool premultiplied_alpha() const { return false; } //http://www.libpng.org/pub/png/spec/1.1/PNG-Rationale.html inline bool has_alpha() const final { return has_alpha_; }
void read(unsigned x,unsigned y,image_data_32& image); 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: private:
void init(); void init();
static void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length); 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> 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_.clear();
stream_.seekg(0, std::ios_base::beg); 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); 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));
}
} }

View file

@ -122,23 +122,27 @@ bool raster_colorizer::add_stop(colorizer_stop const& stop)
return true; 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(); using image_data_type = T;
using pixel_type = typename image_data_type::pixel_type;
int len = raster->data_.width() * raster->data_.height(); // TODO: assuming in/out have the same width/height for now
boost::optional<double> const& nodata = raster->nodata(); 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) for (int i=0; i<len; ++i)
{ {
// the GDAL plugin reads single bands as floats pixel_type value = in_data[i];
float value = *reinterpret_cast<float *> (&imageData[i]);
if (nodata && (std::fabs(value - *nodata) < epsilon_)) if (nodata && (std::fabs(value - *nodata) < epsilon_))
{ {
imageData[i] = 0; out_data[i] = 0; // rgba(0,0,0,0)
} }
else 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(); int stopCount = stops_.size();
//use default color if no stops //use default color if no stops
if(stopCount == 0) if (stopCount == 0)
{ {
return default_color_.rgba(); 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;
} }

View file

@ -35,7 +35,7 @@
namespace mapnik { 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, marker const& marker,
agg::trans_affine const& tr, agg::trans_affine const& tr,
double opacity) 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.translate(0.5 * bbox.width(), 0.5 * bbox.height());
mtx = tr * mtx; 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); agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->width() * 4);
pixfmt pixf(buf); pixfmt pixf(buf);
renderer_base renb(pixf); renderer_base renb(pixf);

View file

@ -42,9 +42,9 @@ extern "C"
namespace mapnik { namespace impl { 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) switch(whence)
{ {
@ -66,9 +66,9 @@ static int tiff_close_proc(thandle_t)
return 0; 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(); std::ios::pos_type pos = in->tellg();
in->seekg(0, std::ios::end); in->seekg(0, std::ios::end);
std::ios::pos_type len = in->tellg(); 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); 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; std::streamsize request_size = size;
if (static_cast<tsize_t>(request_size) != size) if (static_cast<tsize_t>(request_size) != size)
return static_cast<tsize_t>(-1); return static_cast<tsize_t>(-1);
@ -123,15 +123,23 @@ class tiff_reader : public image_reader
private: private:
source_type source_; source_type source_;
input_stream stream_; input_stream stream_;
tiff_ptr tif_;
int read_method_; int read_method_;
std::size_t width_;
std::size_t height_;
int rows_per_strip_; int rows_per_strip_;
int tile_width_; int tile_width_;
int tile_height_; 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 premultiplied_alpha_;
bool has_alpha_; bool has_alpha_;
bool is_tiled_;
public: public:
enum TiffType { enum TiffType {
generic=1, generic=1,
@ -141,18 +149,35 @@ public:
explicit tiff_reader(std::string const& file_name); explicit tiff_reader(std::string const& file_name);
tiff_reader(char const* data, std::size_t size); tiff_reader(char const* data, std::size_t size);
virtual ~tiff_reader(); virtual ~tiff_reader();
unsigned width() const; unsigned width() const final;
unsigned height() const; unsigned height() const final;
inline bool has_alpha() const { return has_alpha_; } boost::optional<box2d<double> > bounding_box() const final;
bool premultiplied_alpha() const; inline bool has_alpha() const final { return has_alpha_; }
void read(unsigned x,unsigned y,image_data_32& image); 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: private:
tiff_reader(const tiff_reader&); tiff_reader(const tiff_reader&);
tiff_reader& operator=(const tiff_reader&); tiff_reader& operator=(const tiff_reader&);
void init(); void init();
void read_generic(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_32& image); void read_stripped(unsigned x,unsigned y,image_data_rgba8& image);
void read_tiled(unsigned x,unsigned y,image_data_32& 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); TIFF* open(std::istream & input);
}; };
@ -178,14 +203,21 @@ template <typename T>
tiff_reader<T>::tiff_reader(std::string const& file_name) tiff_reader<T>::tiff_reader(std::string const& file_name)
: source_(file_name, std::ios_base::in | std::ios_base::binary), : source_(file_name, std::ios_base::in | std::ios_base::binary),
stream_(source_), stream_(source_),
tif_(nullptr),
read_method_(generic), read_method_(generic),
width_(0),
height_(0),
rows_per_strip_(0), rows_per_strip_(0),
tile_width_(0), tile_width_(0),
tile_height_(0), tile_height_(0),
width_(0),
height_(0),
bps_(0),
photometric_(0),
bands_(1),
planar_config_(PLANARCONFIG_CONTIG),
compression_(COMPRESSION_NONE),
premultiplied_alpha_(false), 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); if (!stream_) throw image_reader_exception("TIFF reader: cannot open file "+ file_name);
init(); init();
@ -195,16 +227,24 @@ template <typename T>
tiff_reader<T>::tiff_reader(char const* data, std::size_t size) tiff_reader<T>::tiff_reader(char const* data, std::size_t size)
: source_(data, size), : source_(data, size),
stream_(source_), stream_(source_),
tif_(nullptr),
read_method_(generic), read_method_(generic),
width_(0),
height_(0),
rows_per_strip_(0), rows_per_strip_(0),
tile_width_(0), tile_width_(0),
tile_height_(0), tile_height_(0),
width_(0),
height_(0),
bps_(0),
photometric_(0),
bands_(1),
planar_config_(PLANARCONFIG_CONTIG),
compression_(COMPRESSION_NONE),
premultiplied_alpha_(false), premultiplied_alpha_(false),
has_alpha_(false) has_alpha_(false),
is_tiled_(false)
{ {
if (!stream_) throw image_reader_exception("TIFF reader: cannot open image stream "); if (!stream_) throw image_reader_exception("TIFF reader: cannot open image stream ");
stream_.rdbuf()->pubsetbuf(0, 0);
stream_.seekg(0, std::ios::beg); stream_.seekg(0, std::ios::beg);
init(); init();
} }
@ -220,39 +260,97 @@ void tiff_reader<T>::init()
if (!tif) throw image_reader_exception("Can't open tiff file"); 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_);
if (TIFFRGBAImageOK(tif,msg)) MAPNIK_LOG_DEBUG(tiff_reader) << "bits per sample: " << bps_;
MAPNIK_LOG_DEBUG(tiff_reader) << "photometric: " << photometric_;
MAPNIK_LOG_DEBUG(tiff_reader) << "bands: " << bands_;
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width_);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height_);
if (width_ > 10000 || height_ > 10000)
{ {
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width_); throw image_reader_exception("Can't allocate tiff > 10000x10000");
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height_); }
if (TIFFIsTiled(tif))
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_);
MAPNIK_LOG_DEBUG(tiff_reader) << "tiff is tiled";
read_method_ = tiled;
}
else if (TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rows_per_strip_)!=0)
{
MAPNIK_LOG_DEBUG(tiff_reader) << "tiff is stripped";
read_method_ = stripped;
}
//TIFFTAG_EXTRASAMPLES
uint16 extrasamples = 0;
uint16* sampleinfo = nullptr;
if (TIFFGetField(tif, TIFFTAG_EXTRASAMPLES,
&extrasamples, &sampleinfo))
{
has_alpha_ = true;
if (extrasamples == 1 &&
sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA)
{ {
TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width_); premultiplied_alpha_ = true;
TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height_);
read_method_=tiled;
}
else if (TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rows_per_strip_)!=0)
{
read_method_=stripped;
}
//TIFFTAG_EXTRASAMPLES
uint16 extrasamples = 0;
uint16* sampleinfo = nullptr;
if (TIFFGetField(tif, TIFFTAG_EXTRASAMPLES,
&extrasamples, &sampleinfo))
{
has_alpha_ = true;
if (extrasamples == 1 &&
sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA)
{
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_; return height_;
} }
template <typename T>
boost::optional<box2d<double> > tiff_reader<T>::bounding_box() const
{
return bbox_;
}
template <typename T> template <typename T>
bool tiff_reader<T>::premultiplied_alpha() const bool tiff_reader<T>::premultiplied_alpha() const
{ {
@ -280,7 +384,7 @@ bool tiff_reader<T>::premultiplied_alpha() const
} }
template <typename T> 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) if (read_method_==stripped)
{ {
@ -297,96 +401,279 @@ void tiff_reader<T>::read(unsigned x,unsigned y,image_data_32& image)
} }
template <typename T> 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_); TIFF* tif = open(stream_);
if (tif) 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> 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_); TIFF* tif = open(stream_);
if (tif) if (tif)
{ {
uint32* buf = (uint32*)_TIFFmalloc(tile_width_*tile_height_*sizeof(uint32)); std::unique_ptr<pixel_type[]> buf(new pixel_type[tile_width_*tile_height_]);
int width=image.width(); int width = image.width();
int height=image.height(); 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_; for (int y = start_y; y < end_y; y += 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_)
{ {
ty0 = std::max(y0,(unsigned)y) - y; int ty0 = std::max(y0, static_cast<unsigned>(y)) - y;
ty1 = std::min(height+y0,(unsigned)(y+tile_height_)) - y; int ty1 = std::min(height + y0, static_cast<unsigned>(y + tile_height_)) - y;
int n0=tile_height_-ty1; for (int x = start_x; x < end_x; x += tile_width_)
int n1=tile_height_-ty0-1;
for (int x=start_x;x<end_x;x+=tile_width_)
{ {
if (!detail::tiff_reader_traits<ImageData>::read_tile(tif, x, y, buf.get(), tile_width_, tile_height_))
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)
{ {
image.setRow(row,tx0-x0,tx1-x0,(const unsigned*)&buf[n*tile_width_+tx0-x]); std::clog << "read_tile(...) failed at " << x << "/" << y << " for " << width_ << "/" << height_ << "\n";
++row; 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> 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_); TIFF* tif = open(stream_);
if (tif) 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 width=image.width();
int height=image.height(); int height=image.height();
unsigned start_y=(y0/rows_per_strip_)*rows_per_strip_; unsigned start_y=(y0/rows_per_strip_)*rows_per_strip_;
unsigned end_y=((y0+height)/rows_per_strip_+1)*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; int row,tx0,tx1,ty0,ty1;
tx0=x0; 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_) for (unsigned y=start_y; y < end_y; y+=rows_per_strip_)
{ {
ty0 = std::max(y0,y)-y; ty0 = std::max(y0,y)-y;
ty1 = std::min(height+y0,y+rows_per_strip_)-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; row=y+ty0-y0;
int n0=laststrip ? 0:(rows_per_strip_-ty1); int n0=laststrip ? 0:(rows_per_strip_-ty1);
int n1=laststrip ? (ty1-ty0-1):(rows_per_strip_-ty0-1); int n1=laststrip ? (ty1-ty0-1):(rows_per_strip_-ty0-1);
for (int n=n1;n>=n0;--n) 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; ++row;
} }
} }
_TIFFfree(buf);
} }
} }
@ -395,7 +682,7 @@ TIFF* tiff_reader<T>::open(std::istream & input)
{ {
if (!tif_) if (!tif_)
{ {
tif_ = tiff_ptr(TIFFClientOpen("tiff_input_stream", "rm", tif_ = tiff_ptr(TIFFClientOpen("tiff_input_stream", "rcm",
reinterpret_cast<thandle_t>(&input), reinterpret_cast<thandle_t>(&input),
impl::tiff_read_proc, impl::tiff_read_proc,
impl::tiff_write_proc, impl::tiff_write_proc,

View file

@ -24,6 +24,7 @@
#include <mapnik/warp.hpp> #include <mapnik/warp.hpp>
#include <mapnik/config.hpp> #include <mapnik/config.hpp>
#include <mapnik/image_data.hpp> #include <mapnik/image_data.hpp>
#include <mapnik/image_scaling_traits.hpp>
#include <mapnik/image_util.hpp> #include <mapnik/image_util.hpp>
#include <mapnik/box2d.hpp> #include <mapnik/box2d.hpp>
#include <mapnik/view_transform.hpp> #include <mapnik/view_transform.hpp>
@ -47,19 +48,27 @@
namespace mapnik { namespace mapnik {
void reproject_and_scale_raster(raster & target, raster const& source, template <typename T>
proj_transform const& prj_trans, MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const& prj_trans,
double offset_x, double offset_y, box2d<double> const& target_ext, box2d<double> const& source_ext,
unsigned mesh_size, double offset_x, double offset_y, unsigned mesh_size, scaling_method_e scaling_method, double filter_factor)
scaling_method_e scaling_method)
{ {
view_transform ts(source.data_.width(), source.data_.height(), using image_data_type = T;
source.ext_); using pixel_type = typename image_data_type::pixel_type;
view_transform tt(target.data_.width(), target.data_.height(), using pixfmt_pre = typename detail::agg_scaling_traits<image_data_type>::pixfmt_pre;
target.ext_, offset_x, offset_y); 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); constexpr std::size_t pixel_size = sizeof(pixel_type);
std::size_t mesh_ny = std::ceil(source.data_.height()/double(mesh_size) + 1);
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> xs(mesh_nx, mesh_ny);
image_data<double> ys(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) for (std::size_t i=0; i<mesh_nx; ++i)
{ {
xs(i,j) = std::min(i*mesh_size,source.data_.width()); xs(i,j) = std::min(i*mesh_size,source.width());
ys(i,j) = std::min(j*mesh_size,source.data_.height()); ys(i,j) = std::min(j*mesh_size,source.height());
ts.backward(&xs(i,j), &ys(i,j)); ts.backward(&xs(i,j), &ys(i,j));
} }
} }
prj_trans.backward(xs.getData(), ys.getData(), nullptr, mesh_nx*mesh_ny); 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::rasterizer_scanline_aa<> rasterizer;
agg::scanline_bin scanline; agg::scanline_bin scanline;
agg::rendering_buffer buf((unsigned char*)target.data_.getData(), agg::rendering_buffer buf(target.getBytes(),
target.data_.width(), target.width(),
target.data_.height(), target.height(),
target.data_.width()*4); target.width() * pixel_size);
pixfmt pixf(buf); pixfmt_pre pixf(buf);
renderer_base rb(pixf); 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( agg::rendering_buffer buf_tile(
(unsigned char*)source.data_.getData(), const_cast<unsigned char*>(source.getBytes()),
source.data_.width(), source.width(),
source.data_.height(), source.height(),
source.data_.width() * 4); 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); img_accessor_type ia(pixf_tile);
agg::span_allocator<color_type> sa; 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 // 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) 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 y0 = j * mesh_size;
std::size_t x1 = (i+1) * mesh_size; std::size_t x1 = (i+1) * mesh_size;
std::size_t y1 = (j+1) * mesh_size; std::size_t y1 = (j+1) * mesh_size;
x1 = std::min(x1, source.data_.width()); x1 = std::min(x1, source.width());
y1 = std::min(y1, source.data_.height()); y1 = std::min(y1, source.height());
agg::trans_affine tr(polygon, x0, y0, x1, y1); agg::trans_affine tr(polygon, x0, y0, x1, y1);
if (tr.is_valid()) if (tr.is_valid())
{ {
using interpolator_type = agg::span_interpolator_linear<agg::trans_affine>;
interpolator_type interpolator(tr); interpolator_type interpolator(tr);
if (scaling_method == SCALING_NEAR) if (scaling_method == SCALING_NEAR)
{ {
using span_gen_type = agg::span_image_filter_rgba_nn using span_gen_type = typename detail::agg_scaling_traits<image_data_type>::span_image_filter;
<img_accessor_type, interpolator_type>;
span_gen_type sg(ia, interpolator); span_gen_type sg(ia, interpolator);
agg::render_scanlines_bin(rasterizer, scanline, rb, agg::render_scanlines_bin(rasterizer, scanline, rb, sa, sg);
sa, sg);
} }
else else
{ {
using span_gen_type = agg::span_image_resample_rgba_affine using span_gen_type = typename detail::agg_scaling_traits<image_data_type>::span_image_resample_affine;
<img_accessor_type>; agg::image_filter_lut filter;
detail::set_scaling_method(filter, scaling_method, filter_factor);
span_gen_type sg(ia, interpolator, filter); span_gen_type sg(ia, interpolator, filter);
agg::render_scanlines_bin(rasterizer, scanline, rb, agg::render_scanlines_bin(rasterizer, scanline, rb, sa, sg);
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 }// namespace mapnik

View file

@ -120,11 +120,13 @@ public:
explicit webp_reader(char const* data, std::size_t size); explicit webp_reader(char const* data, std::size_t size);
explicit webp_reader(std::string const& filename); explicit webp_reader(std::string const& filename);
~webp_reader(); ~webp_reader();
unsigned width() const; unsigned width() const final;
unsigned height() const; unsigned height() const final;
inline bool has_alpha() const { return has_alpha_; } boost::optional<box2d<double> > bounding_box() const final;
bool premultiplied_alpha() const { return false; } inline bool has_alpha() const final { return has_alpha_; }
void read(unsigned x,unsigned y,image_data_32& image); 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: private:
void init(); void init();
}; };
@ -229,7 +231,13 @@ unsigned webp_reader<T>::height() const
} }
template <typename T> 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; WebPDecoderConfig config;
config_guard guard(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));
}
} }

View file

@ -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>(white,black)), to_string(white) );
BOOST_TEST_EQ( to_string(blend<source_over>(black,white)), to_string(black) ); 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_white(254,254,254,254); // Source
color near_trans(1,1,1,1); // Dest color near_trans(1,1,1,1); // Dest
color expected_color(252,252,252,255); // expected result 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(252,252,252,254)) ); 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(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) ); BOOST_TEST_EQ( to_string(normal_blend(near_white,near_trans)), to_string(expected_color) );

View file

@ -1,5 +1,7 @@
#include <boost/detail/lightweight_test.hpp> #include <boost/detail/lightweight_test.hpp>
#include <iostream> #include <iostream>
#include <mapnik/graphics.hpp>
#include <mapnik/image_data.hpp>
#include <mapnik/image_reader.hpp> #include <mapnik/image_reader.hpp>
#include <mapnik/image_util.hpp> #include <mapnik/image_util.hpp>
#include <mapnik/util/fs.hpp> #include <mapnik/util/fs.hpp>
@ -38,6 +40,26 @@ int main(int argc, char** argv)
} }
#endif #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) #if defined(HAVE_PNG)
should_throw = "./tests/cpp_tests/data/blank.png"; should_throw = "./tests/cpp_tests/data/blank.png";
BOOST_TEST( mapnik::util::exists( should_throw ) ); BOOST_TEST( mapnik::util::exists( should_throw ) );

View file

@ -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()); std::shared_ptr<image_32> image_ptr2 = std::make_shared<image_32>(reader2->width(),reader2->height());
reader2->read(0,0,image_ptr2->data()); reader2->read(0,0,image_ptr2->data());
image_data_32 const& dest = image_ptr1->data(); image_data_rgba8 const& dest = image_ptr1->data();
image_data_32 const& src = image_ptr2->data(); image_data_rgba8 const& src = image_ptr2->data();
unsigned int width = src.width(); unsigned int width = src.width();
unsigned int height = src.height(); unsigned int height = src.height();

11
tests/cxx/README.md Normal file
View 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
View 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

File diff suppressed because it is too large Load diff

2
tests/cxx/test_main.cpp Normal file
View file

@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

276
tests/cxx/tiff_io.cpp Normal file
View 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
View 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_*
}

View file

@ -0,0 +1,4 @@
striped images created with rio
tiled images created with:
tiffcp -t -w256 -l256 -c lzw input.tiff output.tif

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show more