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
SConscript('tests/cpp_tests/build.py')
SConscript('tests/cxx/build.py')
if env['BENCHMARK']:
SConscript('benchmark/build.py')

View file

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

View file

@ -1,5 +1,5 @@
#ifndef __MAPNIK_COMPARE_IMAGES_HPP__
#define __MAPNIK_COMPARE_IMAGES_HPP__
#define __MAPNIK_COMPARE_IMAGES_HPP__
#include <mapnik/graphics.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());
reader2->read(0,0,image_ptr2->data());
image_data_32 const& dest = image_ptr1->data();
image_data_32 const& src = image_ptr2->data();
image_data_rgba8 const& dest = image_ptr1->data();
image_data_rgba8 const& src = image_ptr2->data();
unsigned int width = src.width();
unsigned int height = src.height();
@ -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 \
--height 600 \
--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;
}
void operator()() const
bool operator()() const
{
for (std::size_t i=0;i<iterations_;++i) {
// NOTE: sizeof(uint8_t) == 1
@ -50,6 +50,7 @@ public:
ensure_zero(data,size_);
free(data);
}
return true;
}
};
@ -66,7 +67,7 @@ public:
{
return true;
}
void operator()() const
bool operator()() const
{
for (std::size_t i=0;i<iterations_;++i) {
// NOTE: sizeof(uint8_t) == 1
@ -75,6 +76,7 @@ public:
ensure_zero(data,size_);
free(data);
}
return true;
}
};
@ -91,7 +93,7 @@ public:
{
return true;
}
void operator()() const
bool operator()() const
{
for (std::size_t i=0;i<iterations_;++i) {
uint8_t *data = static_cast<uint8_t *>(::operator new(sizeof(uint8_t) * size_));
@ -99,6 +101,7 @@ public:
ensure_zero(data,size_);
::operator delete(data);
}
return true;
}
};
@ -116,7 +119,7 @@ public:
{
return true;
}
void operator()() const
bool operator()() const
{
for (std::size_t i=0;i<iterations_;++i) {
uint8_t * data = static_cast<uint8_t*>(::operator new(sizeof(uint8_t)*size_));
@ -124,6 +127,7 @@ public:
ensure_zero(data,size_);
::operator delete(data),data=0;
}
return true;
}
};
@ -140,12 +144,13 @@ public:
{
return true;
}
void operator()() const
bool operator()() const
{
for (std::size_t i=0;i<iterations_;++i) {
std::vector<uint8_t> data(size_);
ensure_zero(&data[0],data.size());
}
return true;
}
};
@ -163,13 +168,14 @@ public:
{
return true;
}
void operator()() const
bool operator()() const
{
for (std::size_t i=0;i<iterations_;++i) {
std::vector<uint8_t> data(0);
data.resize(size_,0);
ensure_zero(&data[0],data.size());
}
return true;
}
};
@ -187,13 +193,41 @@ public:
{
return true;
}
void operator()() const
bool operator()() const
{
for (std::size_t i=0;i<iterations_;++i) {
std::vector<uint8_t> data(0);
data.assign(size_,0);
ensure_zero(&data[0],data.size());
}
return true;
}
};
class test3d : public benchmark::test_case
{
public:
uint32_t size_;
std::vector<uint8_t> array_;
test3d(mapnik::parameters const& params)
: test_case(params),
size_(*params.get<mapnik::value_integer>("size",256*256)),
array_(size_,0) { }
bool validate() const
{
return true;
}
bool operator()() const
{
for (std::size_t i=0;i<iterations_;++i) {
std::deque<uint8_t> data(size_);
for (std::size_t i=0;i<size_;++i) {
if (data[i] != 0) {
throw std::runtime_error("found non zero value");
}
}
}
return true;
}
};
@ -237,13 +271,14 @@ public:
{
return true;
}
void operator()() const
bool operator()() const
{
for (std::size_t i=0;i<iterations_;++i) {
uint8_t *data = (uint8_t *)calloc(size_,sizeof(uint8_t));
ensure_zero(data,size_);
free(data);
}
return true;
}
};
@ -260,12 +295,13 @@ public:
{
return true;
}
void operator()() const
bool operator()() const
{
for (std::size_t i=0;i<iterations_;++i) {
std::string data(array_.begin(),array_.end());
ensure_zero((uint8_t *)&data[0],size_);
}
return true;
}
};
@ -282,12 +318,13 @@ public:
{
return true;
}
void operator()() const
bool operator()() const
{
for (std::size_t i=0;i<iterations_;++i) {
std::string data(&array_[0],array_.size());
ensure_zero((uint8_t *)&data[0],size_);
}
return true;
}
};
@ -309,12 +346,13 @@ public:
{
return true;
}
void operator()() const
bool operator()() const
{
for (std::size_t i=0;i<iterations_;++i) {
std::valarray<uint8_t> data(static_cast<uint8_t>(0),static_cast<size_t>(size_));
ensure_zero(&data[0],size_);
}
return true;
}
};
@ -335,12 +373,13 @@ public:
{
return true;
}
void operator()() const
bool operator()() const
{
for (std::size_t i=0;i<iterations_;++i) {
boost::container::static_vector<uint8_t,256*256> data(size_,0);
ensure_zero(&data[0],size_);
}
return true;
}
};
#endif

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -58,11 +58,17 @@ public:
mapnik::image_32 im(m.width(),m.height());
mapnik::agg_renderer<mapnik::image_32> ren(m,im,scale_factor_);
ren.apply();
if (!preview_.empty()) mapnik::save_to_file(im,preview_);
if (!preview_.empty()) {
std::clog << "preview available at " << preview_ << "\n";
mapnik::save_to_file(im,preview_);
}
return true;
}
void operator()() const
bool operator()() const
{
if (!preview_.empty()) {
return false;
}
mapnik::Map m(width_,height_);
mapnik::load_map(m,xml_);
if (extent_.valid()) {
@ -76,6 +82,7 @@ public:
mapnik::agg_renderer<mapnik::image_32> ren(m,im,scale_factor_);
ren.apply();
}
return true;
}
};

View file

@ -26,13 +26,7 @@ template <typename Renderer> void process_layers(Renderer & ren,
if (lyr.visible(scale_denom))
{
std::set<std::string> names;
mapnik::parameters p;
p["type"]="csv";
p["file"]="benchmark/data/roads.csv";
mapnik::datasource_ptr ds = mapnik::datasource_cache::instance().create(p);
mapnik::layer l(lyr);
l.set_datasource(ds);
l.add_style("labels");
ren.apply_to_layer(l,
ren,
map_proj,
@ -56,6 +50,7 @@ class test : public benchmark::test_case
std::shared_ptr<mapnik::Map> m_;
double scale_factor_;
std::string preview_;
mutable mapnik::image_32 im_;
public:
test(mapnik::parameters const& params)
: test_case(params),
@ -65,7 +60,8 @@ public:
height_(*params.get<mapnik::value_integer>("height",256)),
m_(new mapnik::Map(width_,height_)),
scale_factor_(*params.get<mapnik::value_double>("scale_factor",2.0)),
preview_(*params.get<std::string>("preview",""))
preview_(*params.get<std::string>("preview","")),
im_(m_->width(),m_->height())
{
boost::optional<std::string> map = params.get<std::string>("map");
if (!map)
@ -75,6 +71,7 @@ public:
xml_ = *map;
boost::optional<std::string> ext = params.get<std::string>("extent");
mapnik::load_map(*m_,xml_,true);
if (ext && !ext->empty())
{
if (!extent_.from_string(*ext))
@ -82,51 +79,67 @@ public:
}
else
{
throw std::runtime_error("please provide a --extent=<minx,miny,maxx,maxy> arg");
m_->zoom_all();
extent_ = m_->get_current_extent();
std::clog << "Defaulting to max extent " << extent_ << "\n";
std::clog << " (pass --extent=<minx,miny,maxx,maxy> to restrict bounds)\n";
}
mapnik::load_map(*m_,xml_,true);
}
bool validate() const
{
mapnik::request m_req(width_,height_,extent_);
mapnik::image_32 im(m_->width(),m_->height());
mapnik::attributes variables;
m_req.set_buffer_size(m_->buffer_size());
mapnik::projection map_proj(m_->srs(),true);
double scale_denom = mapnik::scale_denominator(m_req.scale(),map_proj.is_geographic());
scale_denom *= scale_factor_;
mapnik::agg_renderer<mapnik::image_32> ren(*m_,m_req,variables,im,scale_factor_);
mapnik::agg_renderer<mapnik::image_32> ren(*m_,m_req,variables,im_,scale_factor_);
ren.start_map_processing(*m_);
std::vector<mapnik::layer> const& layers = m_->layers();
process_layers(ren,m_req,map_proj,layers,scale_denom);
ren.end_map_processing(*m_);
if (!preview_.empty()) {
std::clog << "preview available at " << preview_ << "\n";
mapnik::save_to_file(im,preview_);
mapnik::save_to_file(im_,preview_);
}
return true;
}
void operator()() const
bool operator()() const
{
if (preview_.empty()) {
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_);
}
if (!preview_.empty()) {
return false;
}
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);
return (result == true);
}
void operator()() const
bool operator()() const
{
for (std::size_t i=0;i<iterations_;++i) {
bool result = false;
mapnik::util::string2bool(value_,result);
mapnik::util::string2bool(value_.data(),value_.data()+value_.size(),result);
}
return true;
}
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -201,7 +201,7 @@ struct symbolizer_icon : public mapnik::util::static_visitor<QIcon>
{
// FIXME!
/*
std::shared_ptr<mapnik::image_data_32> symbol = sym.get_image();
std::shared_ptr<mapnik::image_data_rgba8> symbol = sym.get_image();
if (symbol)
{
QImage image(symbol->getBytes(),

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;
};
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

View file

@ -2,8 +2,8 @@
// 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.
// 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.
//
@ -18,12 +18,13 @@
#include <cmath>
#include "agg_basics.h"
#include "agg_gamma_functions.h"
namespace agg
{
template<class LoResT=int8u,
class HiResT=int8u,
unsigned GammaShift=8,
template<class LoResT=int8u,
class HiResT=int8u,
unsigned GammaShift=8,
unsigned HiResShift=8> class gamma_lut
{
public:
@ -49,8 +50,8 @@ namespace agg
pod_allocator<HiResT>::deallocate(m_dir_gamma, gamma_size);
}
gamma_lut() :
m_gamma(1.0),
gamma_lut() :
m_gamma(1.0),
m_dir_gamma(pod_allocator<HiResT>::allocate(gamma_size)),
m_inv_gamma(pod_allocator<LoResT>::allocate(hi_res_size))
{
@ -67,14 +68,14 @@ namespace agg
}
gamma_lut(double g) :
m_gamma(1.0),
m_gamma(1.0),
m_dir_gamma(pod_allocator<HiResT>::allocate(gamma_size)),
m_inv_gamma(pod_allocator<LoResT>::allocate(hi_res_size))
{
gamma(g);
}
void gamma(double g)
void gamma(double g)
{
m_gamma = g;
@ -98,13 +99,13 @@ namespace agg
return m_gamma;
}
HiResT dir(LoResT v) const
{
return m_dir_gamma[unsigned(v)];
HiResT dir(LoResT v) const
{
return m_dir_gamma[unsigned(v)];
}
LoResT inv(HiResT v) const
{
LoResT inv(HiResT v) const
{
return m_inv_gamma[unsigned(v)];
}
@ -116,6 +117,189 @@ namespace agg
HiResT* m_dir_gamma;
LoResT* m_inv_gamma;
};
//
// sRGB support classes
//
// Optimized sRGB lookup table. The direct conversion (sRGB to linear)
// is a straightforward lookup. The inverse conversion (linear to sRGB)
// is implemented using binary search.
template<class LinearType>
class sRGB_lut_base
{
public:
LinearType dir(int8u v) const
{
return m_dir_table[v];
}
int8u inv(LinearType v) const
{
// Unrolled binary search.
int8u x = 0;
if (v > m_inv_table[128]) x = 128;
if (v > m_inv_table[x + 64]) x += 64;
if (v > m_inv_table[x + 32]) x += 32;
if (v > m_inv_table[x + 16]) x += 16;
if (v > m_inv_table[x + 8]) x += 8;
if (v > m_inv_table[x + 4]) x += 4;
if (v > m_inv_table[x + 2]) x += 2;
if (v > m_inv_table[x + 1]) x += 1;
return x;
}
protected:
LinearType m_dir_table[256];
LinearType m_inv_table[256];
// Only derived classes may instantiate.
sRGB_lut_base()
{
}
};
// sRGB_lut - implements sRGB conversion for the various types.
// Base template is undefined, specializations are provided below.
template<class LinearType>
class sRGB_lut;
template<>
class sRGB_lut<float> : public sRGB_lut_base<float>
{
public:
sRGB_lut()
{
// Generate lookup tables.
m_dir_table[0] = 0;
m_inv_table[0] = 0;
for (unsigned i = 1; i <= 255; ++i)
{
// Floating-point RGB is in range [0,1].
m_dir_table[i] = float(sRGB_to_linear(i / 255.0));
m_inv_table[i] = float(sRGB_to_linear((i - 0.5) / 255.0));
}
}
};
template<>
class sRGB_lut<int16u> : public sRGB_lut_base<int16u>
{
public:
sRGB_lut()
{
// Generate lookup tables.
m_dir_table[0] = 0;
m_inv_table[0] = 0;
for (unsigned i = 1; i <= 255; ++i)
{
// 16-bit RGB is in range [0,65535].
m_dir_table[i] = uround(65535.0 * sRGB_to_linear(i / 255.0));
m_inv_table[i] = uround(65535.0 * sRGB_to_linear((i - 0.5) / 255.0));
}
}
};
template<>
class sRGB_lut<int8u> : public sRGB_lut_base<int8u>
{
public:
sRGB_lut()
{
// Generate lookup tables.
m_dir_table[0] = 0;
m_inv_table[0] = 0;
for (unsigned i = 1; i <= 255; ++i)
{
// 8-bit RGB is handled with simple bidirectional lookup tables.
m_dir_table[i] = uround(255.0 * sRGB_to_linear(i / 255.0));
m_inv_table[i] = uround(255.0 * linear_to_sRGB(i / 255.0));
}
}
int8u inv(int8u v) const
{
// In this case, the inverse transform is a simple lookup.
return m_inv_table[v];
}
};
// Common base class for sRGB_conv objects. Defines an internal
// sRGB_lut object so that users don't have to.
template<class T>
class sRGB_conv_base
{
public:
static T rgb_from_sRGB(int8u x)
{
return lut.dir(x);
}
static int8u rgb_to_sRGB(T x)
{
return lut.inv(x);
}
private:
static sRGB_lut<T> lut;
};
// Definition of sRGB_conv_base::lut. Due to the fact that this a template,
// we don't need to place the definition in a cpp file. Hurrah.
template<class T>
sRGB_lut<T> sRGB_conv_base<T>::lut;
// Wrapper for sRGB-linear conversion.
// Base template is undefined, specializations are provided below.
template<class T>
class sRGB_conv;
template<>
class sRGB_conv<float> : public sRGB_conv_base<float>
{
public:
static float alpha_from_sRGB(int8u x)
{
return float(x / 255.0);
}
static int8u alpha_to_sRGB(float x)
{
if (x <= 0) return 0;
else if (x >= 1) return 255;
else return int8u(0.5 + x * 255);
}
};
template<>
class sRGB_conv<int16u> : public sRGB_conv_base<int16u>
{
public:
static int16u alpha_from_sRGB(int8u x)
{
return (x << 8) | x;
}
static int8u alpha_to_sRGB(int16u x)
{
return x >> 8;
}
};
template<>
class sRGB_conv<int8u> : public sRGB_conv_base<int8u>
{
public:
static int8u alpha_from_sRGB(int8u x)
{
return x;
}
static int8u alpha_to_sRGB(int8u x)
{
return x;
}
};
}
#endif

97
deps/agg/include/agg_pixfmt_base.h vendored Normal file
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
// 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.
// 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.
//
@ -13,37 +13,46 @@
// 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. is the provider of
// PostScript and PDF technology for software developers.
//
//
//----------------------------------------------------------------------------
#ifndef AGG_PIXFMT_GRAY_INCLUDED
#define AGG_PIXFMT_GRAY_INCLUDED
#include <cstring>
#include "agg_basics.h"
#include "agg_color_gray.h"
#include "agg_pixfmt_base.h"
#include "agg_rendering_buffer.h"
namespace agg
{
//============================================================blender_gray
template<class ColorT> struct blender_gray
{
typedef ColorT color_type;
typedef typename color_type::value_type value_type;
typedef typename color_type::calc_type calc_type;
enum base_scale_e { base_shift = color_type::base_shift };
typedef typename color_type::long_type long_type;
static AGG_INLINE void blend_pix(value_type* p, unsigned cv,
unsigned alpha, unsigned cover=0)
// Blend pixels using the non-premultiplied form of Alvy-Ray Smith's
// compositing function. Since the render buffer is opaque we skip the
// initial premultiply and final demultiply.
static AGG_INLINE void blend_pix(value_type* p,
value_type cv, value_type alpha, cover_type cover)
{
*p = (value_type)((((cv - calc_type(*p)) * alpha) + (calc_type(*p) << base_shift)) >> base_shift);
blend_pix(p, cv, color_type::mult_cover(alpha, cover));
}
static AGG_INLINE void blend_pix(value_type* p,
value_type cv, value_type alpha)
{
*p = color_type::lerp(*p, cv, alpha);
}
};
@ -54,23 +63,24 @@ namespace agg
typedef ColorT color_type;
typedef typename color_type::value_type value_type;
typedef typename color_type::calc_type calc_type;
enum base_scale_e { base_shift = color_type::base_shift };
typedef typename color_type::long_type long_type;
static AGG_INLINE void blend_pix(value_type* p, unsigned cv,
unsigned alpha, unsigned cover)
// Blend pixels using the premultiplied form of Alvy-Ray Smith's
// compositing function.
static AGG_INLINE void blend_pix(value_type* p,
value_type cv, value_type alpha, cover_type cover)
{
alpha = color_type::base_mask - alpha;
cover = (cover + 1) << (base_shift - 8);
*p = (value_type)((*p * alpha + cv * cover) >> base_shift);
blend_pix(p, color_type::mult_cover(cv, cover), color_type::mult_cover(alpha, cover));
}
static AGG_INLINE void blend_pix(value_type* p, unsigned cv,
unsigned alpha)
static AGG_INLINE void blend_pix(value_type* p,
value_type cv, value_type alpha)
{
*p = (value_type)(((*p * (color_type::base_mask - alpha)) >> base_shift) + cv);
*p = color_type::prelerp(*p, cv, alpha);
}
};
//=====================================================apply_gamma_dir_gray
@ -112,10 +122,11 @@ namespace agg
//=================================================pixfmt_alpha_blend_gray
template<class Blender, class RenBuf, unsigned Step=1, unsigned Offset=0>
template<class Blender, class RenBuf, unsigned Step = 1, unsigned Offset = 0>
class pixfmt_alpha_blend_gray
{
public:
typedef pixfmt_gray_tag pixfmt_category;
typedef RenBuf rbuf_type;
typedef typename rbuf_type::row_data row_data;
typedef Blender blender_type;
@ -123,54 +134,117 @@ namespace agg
typedef int order_type; // A fake one
typedef typename color_type::value_type value_type;
typedef typename color_type::calc_type calc_type;
enum base_scale_e
enum
{
base_shift = color_type::base_shift,
base_scale = color_type::base_scale,
base_mask = color_type::base_mask,
pix_width = sizeof(value_type),
pix_step = Step,
pix_offset = Offset
num_components = 1,
pix_width = sizeof(value_type) * Step,
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:
//--------------------------------------------------------------------
static AGG_INLINE void copy_or_blend_pix(value_type* p,
const color_type& c,
unsigned cover)
AGG_INLINE void blend_pix(pixel_type* p,
value_type v, value_type a,
unsigned cover)
{
if (c.a)
blender_type::blend_pix(p->c, v, a, cover);
}
//--------------------------------------------------------------------
AGG_INLINE void blend_pix(pixel_type* p, value_type v, value_type a)
{
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(alpha == base_mask)
if (c.is_opaque() && cover == cover_mask)
{
*p = c.v;
p->set(c);
}
else
{
Blender::blend_pix(p, c.v, alpha, cover);
blend_pix(p, c, cover);
}
}
}
static AGG_INLINE void copy_or_blend_pix(value_type* p,
const color_type& c)
//--------------------------------------------------------------------
AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c)
{
if (c.a)
if (!c.is_transparent())
{
if(c.a == base_mask)
if (c.is_opaque())
{
*p = c.v;
p->set(c);
}
else
{
Blender::blend_pix(p, c.v, c.a);
blend_pix(p, c);
}
}
}
public:
//--------------------------------------------------------------------
explicit pixfmt_alpha_blend_gray(rbuf_type& rb) :
@ -183,10 +257,10 @@ namespace agg
bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2)
{
rect_i r(x1, y1, x2, y2);
if(r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1)))
if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1)))
{
int stride = pixf.stride();
m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1),
m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1),
(r.x2 - r.x1) + 1,
(r.y2 - r.y1) + 1,
stride);
@ -201,61 +275,98 @@ namespace agg
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); }
row_data row(int y) const { return m_rbuf->row(y); }
const int8u* pix_ptr(int x, int y) const
//--------------------------------------------------------------------
AGG_INLINE int8u* pix_ptr(int x, int y)
{
return m_rbuf->row_ptr(y) + x * Step + Offset;
return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset);
}
int8u* pix_ptr(int x, int y)
AGG_INLINE const int8u* pix_ptr(int x, int y) const
{
return m_rbuf->row_ptr(y) + x * Step + Offset;
return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset);
}
// Return pointer to pixel value, forcing row to be allocated.
AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len)
{
return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step + pix_offset));
}
// Return pointer to pixel value, or null if row not allocated.
AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const
{
int8u* p = m_rbuf->row_ptr(y);
return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step + pix_offset)) : 0;
}
// Get pixel pointer from raw buffer pointer.
AGG_INLINE static pixel_type* pix_value_ptr(void* p)
{
return (pixel_type*)((value_type*)p + pix_offset);
}
// Get pixel pointer from raw buffer pointer.
AGG_INLINE static const pixel_type* pix_value_ptr(const void* p)
{
return (const pixel_type*)((const value_type*)p + pix_offset);
}
//--------------------------------------------------------------------
AGG_INLINE static void write_plain_color(void* p, color_type c)
{
// Grayscale formats are implicitly premultiplied.
c.premultiply();
pix_value_ptr(p)->set(c);
}
//--------------------------------------------------------------------
AGG_INLINE static color_type read_plain_color(const void* p)
{
return pix_value_ptr(p)->get();
}
//--------------------------------------------------------------------
AGG_INLINE static void make_pix(int8u* p, const color_type& c)
{
*(value_type*)p = c.v;
((pixel_type*)p)->set(c);
}
//--------------------------------------------------------------------
AGG_INLINE color_type pixel(int x, int y) const
{
value_type* p = (value_type*)m_rbuf->row_ptr(y) + x * Step + Offset;
return color_type(*p);
if (const pixel_type* p = pix_value_ptr(x, y))
{
return p->get();
}
return color_type::no_color();
}
//--------------------------------------------------------------------
AGG_INLINE void copy_pixel(int x, int y, const color_type& c)
{
*((value_type*)m_rbuf->row_ptr(x, y, 1) + x * Step + Offset) = c.v;
pix_value_ptr(x, y, 1)->set(c);
}
//--------------------------------------------------------------------
AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover)
{
copy_or_blend_pix((value_type*)
m_rbuf->row_ptr(x, y, 1) + x * Step + Offset,
c,
cover);
copy_or_blend_pix(pix_value_ptr(x, y, 1), c, cover);
}
//--------------------------------------------------------------------
AGG_INLINE void copy_hline(int x, int y,
unsigned len,
AGG_INLINE void copy_hline(int x, int y,
unsigned len,
const color_type& c)
{
value_type* p = (value_type*)
m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
pixel_type* p = pix_value_ptr(x, y, len);
do
{
*p = c.v;
p += Step;
p->set(c);
p = p->next();
}
while(--len);
}
@ -263,49 +374,44 @@ namespace agg
//--------------------------------------------------------------------
AGG_INLINE void copy_vline(int x, int y,
unsigned len,
unsigned len,
const color_type& c)
{
do
{
value_type* p = (value_type*)
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
*p = c.v;
pix_value_ptr(x, y++, 1)->set(c);
}
while(--len);
while (--len);
}
//--------------------------------------------------------------------
void blend_hline(int x, int y,
unsigned len,
unsigned len,
const color_type& c,
int8u cover)
{
if (c.a)
if (!c.is_transparent())
{
value_type* p = (value_type*)
m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
pixel_type* p = pix_value_ptr(x, y, len);
calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8;
if(alpha == base_mask)
if (c.is_opaque() && cover == cover_mask)
{
do
{
*p = c.v;
p += Step;
p->set(c);
p = p->next();
}
while(--len);
while (--len);
}
else
{
do
{
Blender::blend_pix(p, c.v, alpha, cover);
p += Step;
blend_pix(p, c, cover);
p = p->next();
}
while(--len);
while (--len);
}
}
}
@ -313,35 +419,27 @@ namespace agg
//--------------------------------------------------------------------
void blend_vline(int x, int y,
unsigned len,
unsigned len,
const color_type& c,
int8u cover)
{
if (c.a)
if (!c.is_transparent())
{
value_type* p;
calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8;
if(alpha == base_mask)
if (c.is_opaque() && cover == cover_mask)
{
do
{
p = (value_type*)
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
*p = c.v;
pix_value_ptr(x, y++, 1)->set(c);
}
while(--len);
while (--len);
}
else
{
do
{
p = (value_type*)
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
Blender::blend_pix(p, c.v, alpha, cover);
blend_pix(pix_value_ptr(x, y++, 1), c, cover);
}
while(--len);
while (--len);
}
}
}
@ -349,200 +447,162 @@ namespace agg
//--------------------------------------------------------------------
void blend_solid_hspan(int x, int y,
unsigned len,
unsigned len,
const color_type& c,
const int8u* covers)
{
if (c.a)
if (!c.is_transparent())
{
value_type* p = (value_type*)
m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
pixel_type* p = pix_value_ptr(x, y, len);
do
do
{
calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8;
if(alpha == base_mask)
if (c.is_opaque() && *covers == cover_mask)
{
*p = c.v;
p->set(c);
}
else
{
Blender::blend_pix(p, c.v, alpha, *covers);
blend_pix(p, c, *covers);
}
p += Step;
p = p->next();
++covers;
}
while(--len);
while (--len);
}
}
//--------------------------------------------------------------------
void blend_solid_vspan(int x, int y,
unsigned len,
unsigned len,
const color_type& c,
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*)
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
if(alpha == base_mask)
if (c.is_opaque() && *covers == cover_mask)
{
*p = c.v;
p->set(c);
}
else
{
Blender::blend_pix(p, c.v, alpha, *covers);
blend_pix(p, c, *covers);
}
++covers;
}
while(--len);
while (--len);
}
}
//--------------------------------------------------------------------
void copy_color_hspan(int x, int y,
unsigned len,
unsigned len,
const color_type* colors)
{
value_type* p = (value_type*)
m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
pixel_type* p = pix_value_ptr(x, y, len);
do
do
{
*p = colors->v;
p += Step;
++colors;
p->set(*colors++);
p = p->next();
}
while(--len);
while (--len);
}
//--------------------------------------------------------------------
void copy_color_vspan(int x, int y,
unsigned len,
unsigned len,
const color_type* colors)
{
do
do
{
value_type* p = (value_type*)
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
*p = colors->v;
++colors;
pix_value_ptr(x, y++, 1)->set(*colors++);
}
while(--len);
while (--len);
}
//--------------------------------------------------------------------
void blend_color_hspan(int x, int y,
unsigned len,
unsigned len,
const color_type* colors,
const int8u* covers,
int8u cover)
{
value_type* p = (value_type*)
m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
pixel_type* p = pix_value_ptr(x, y, len);
if(covers)
if (covers)
{
do
do
{
copy_or_blend_pix(p, *colors++, *covers++);
p += Step;
p = p->next();
}
while(--len);
while (--len);
}
else
{
if(cover == 255)
if (cover == cover_mask)
{
do
do
{
if(colors->a == base_mask)
{
*p = colors->v;
}
else
{
copy_or_blend_pix(p, *colors);
}
p += Step;
++colors;
copy_or_blend_pix(p, *colors++);
p = p->next();
}
while(--len);
while (--len);
}
else
{
do
do
{
copy_or_blend_pix(p, *colors++, cover);
p += Step;
p = p->next();
}
while(--len);
while (--len);
}
}
}
//--------------------------------------------------------------------
void blend_color_vspan(int x, int y,
unsigned len,
unsigned len,
const color_type* colors,
const int8u* covers,
int8u cover)
{
value_type* p;
if(covers)
if (covers)
{
do
do
{
p = (value_type*)
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
copy_or_blend_pix(p, *colors++, *covers++);
copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++);
}
while(--len);
while (--len);
}
else
{
if(cover == 255)
if (cover == cover_mask)
{
do
do
{
p = (value_type*)
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;
copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++);
}
while(--len);
while (--len);
}
else
{
do
do
{
p = (value_type*)
m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
copy_or_blend_pix(p, *colors++, cover);
copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover);
}
while(--len);
while (--len);
}
}
}
@ -551,22 +611,19 @@ namespace agg
template<class Function> void for_each_pixel(Function f)
{
unsigned y;
for(y = 0; y < height(); ++y)
for (y = 0; y < height(); ++y)
{
row_data r = m_rbuf->row(y);
if(r.ptr)
if (r.ptr)
{
unsigned len = r.x2 - r.x1 + 1;
value_type* p = (value_type*)
m_rbuf->row_ptr(r.x1, y, len) + r.x1 * Step + Offset;
pixel_type* p = pix_value_ptr(r.x1, y, len);
do
{
f(p);
p += Step;
f(p->c);
p = p->next();
}
while(--len);
while (--len);
}
}
}
@ -585,69 +642,70 @@ namespace agg
//--------------------------------------------------------------------
template<class RenBuf2>
void copy_from(const RenBuf2& from,
void copy_from(const RenBuf2& from,
int xdst, int ydst,
int xsrc, int ysrc,
unsigned len)
{
const int8u* p = from.row_ptr(ysrc);
if(p)
if (const int8u* p = from.row_ptr(ysrc))
{
memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width,
p + xsrc * pix_width,
memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width,
p + xsrc * pix_width,
len * pix_width);
}
}
//--------------------------------------------------------------------
// Blend from single color, using grayscale surface as alpha channel.
template<class SrcPixelFormatRenderer>
void blend_from_color(const SrcPixelFormatRenderer& from,
void blend_from_color(const SrcPixelFormatRenderer& from,
const color_type& color,
int xdst, int ydst,
int xsrc, int ysrc,
unsigned len,
int8u cover)
{
typedef typename SrcPixelFormatRenderer::value_type src_value_type;
const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc);
if(psrc)
typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
typedef typename SrcPixelFormatRenderer::color_type src_color_type;
if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
{
value_type* pdst =
(value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst;
do
pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
do
{
copy_or_blend_pix(pdst,
color,
(*psrc * cover + base_mask) >> base_shift);
++psrc;
++pdst;
copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0]));
psrc = psrc->next();
pdst = pdst->next();
}
while(--len);
while (--len);
}
}
//--------------------------------------------------------------------
// Blend from color table, using grayscale surface as indexes into table.
// Obviously, this only works for integer value types.
template<class SrcPixelFormatRenderer>
void blend_from_lut(const SrcPixelFormatRenderer& from,
void blend_from_lut(const SrcPixelFormatRenderer& from,
const color_type* color_lut,
int xdst, int ydst,
int xsrc, int ysrc,
unsigned len,
int8u cover)
{
typedef typename SrcPixelFormatRenderer::value_type src_value_type;
const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc);
if(psrc)
typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
{
value_type* pdst =
(value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst;
do
pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
do
{
copy_or_blend_pix(pdst, color_lut[*psrc], cover);
++psrc;
++pdst;
copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover);
psrc = psrc->next();
pdst = pdst->next();
}
while(--len);
while (--len);
}
}
@ -655,16 +713,25 @@ namespace agg
rbuf_type* m_rbuf;
};
typedef blender_gray<gray8> blender_gray8;
typedef blender_gray_pre<gray8> blender_gray8_pre;
typedef blender_gray<gray16> blender_gray16;
typedef blender_gray_pre<gray16> blender_gray16_pre;
typedef blender_gray<gray8> blender_gray8;
typedef blender_gray<sgray8> blender_sgray8;
typedef blender_gray<gray16> blender_gray16;
typedef blender_gray<gray32> blender_gray32;
typedef pixfmt_alpha_blend_gray<blender_gray8, rendering_buffer> pixfmt_gray8; //----pixfmt_gray8
typedef pixfmt_alpha_blend_gray<blender_gray8_pre, rendering_buffer> pixfmt_gray8_pre; //----pixfmt_gray8_pre
typedef pixfmt_alpha_blend_gray<blender_gray16, rendering_buffer> pixfmt_gray16; //----pixfmt_gray16
typedef pixfmt_alpha_blend_gray<blender_gray16_pre, rendering_buffer> pixfmt_gray16_pre; //----pixfmt_gray16_pre
typedef blender_gray_pre<gray8> blender_gray8_pre;
typedef blender_gray_pre<sgray8> blender_sgray8_pre;
typedef blender_gray_pre<gray16> blender_gray16_pre;
typedef blender_gray_pre<gray32> blender_gray32_pre;
typedef pixfmt_alpha_blend_gray<blender_gray8, rendering_buffer> pixfmt_gray8;
typedef pixfmt_alpha_blend_gray<blender_sgray8, rendering_buffer> pixfmt_sgray8;
typedef pixfmt_alpha_blend_gray<blender_gray16, rendering_buffer> pixfmt_gray16;
typedef pixfmt_alpha_blend_gray<blender_gray32, rendering_buffer> pixfmt_gray32;
typedef pixfmt_alpha_blend_gray<blender_gray8_pre, rendering_buffer> pixfmt_gray8_pre;
typedef pixfmt_alpha_blend_gray<blender_sgray8_pre, rendering_buffer> pixfmt_sgray8_pre;
typedef pixfmt_alpha_blend_gray<blender_gray16_pre, rendering_buffer> pixfmt_gray16_pre;
typedef pixfmt_alpha_blend_gray<blender_gray32_pre, rendering_buffer> pixfmt_gray32_pre;
}
#endif

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&
#### Use unique_ptr instead of new/delete
#### Use std::copy instead of memcpy
#### When to use shared_ptr and unique_ptr

View file

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

View file

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

View file

@ -53,7 +53,7 @@ private:
unsigned width_;
unsigned height_;
boost::optional<color> background_;
image_data_32 data_;
image_data_rgba8 data_;
bool painted_;
bool premultiplied_;
public:
@ -98,12 +98,12 @@ public:
void set_alpha(float opacity);
inline const image_data_32& data() const
inline const image_data_rgba8& data() const
{
return data_;
}
inline image_data_32& data()
inline image_data_rgba8& data()
{
return data_;
}
@ -118,9 +118,9 @@ public:
return data_.getBytes();
}
inline image_view<image_data_32> get_view(unsigned x,unsigned y, unsigned w,unsigned h)
inline image_view<image_data_rgba8> get_view(unsigned x,unsigned y, unsigned w,unsigned h)
{
return image_view<image_data_32>(x,y,w,h,data_);
return image_view<image_data_rgba8>(x,y,w,h,data_);
}
private:
@ -151,7 +151,7 @@ public:
return height_;
}
inline void set_rectangle(int x0,int y0,image_data_32 const& data)
inline void set_rectangle(int x0,int y0,image_data_rgba8 const& data)
{
box2d<int> ext0(0,0,width_,height_);
box2d<int> ext1(x0,y0,x0+data.width(),y0+data.height());
@ -175,7 +175,7 @@ public:
}
}
inline void set_rectangle_alpha(int x0,int y0,const image_data_32& data)
inline void set_rectangle_alpha(int x0,int y0,const image_data_rgba8& data)
{
box2d<int> ext0(0,0,width_,height_);
box2d<int> ext1(x0,y0,x0 + data.width(),y0 + data.height());
@ -219,7 +219,7 @@ public:
}
}
inline void set_rectangle_alpha2(image_data_32 const& data, unsigned x0, unsigned y0, float opacity)
inline void set_rectangle_alpha2(image_data_rgba8 const& data, unsigned x0, unsigned y0, float opacity)
{
box2d<int> ext0(0,0,width_,height_);
box2d<int> ext1(x0,y0,x0 + data.width(),y0 + data.height());
@ -267,7 +267,7 @@ public:
}
template <typename MergeMethod>
inline void merge_rectangle(image_data_32 const& data, unsigned x0, unsigned y0, float opacity)
inline void merge_rectangle(image_data_rgba8 const& data, unsigned x0, unsigned y0, float opacity)
{
box2d<int> ext0(0,0,width_,height_);
box2d<int> ext1(x0,y0,x0 + data.width(),y0 + data.height());

View file

@ -195,7 +195,7 @@ public:
return height_;
}
inline void set_rectangle(value_type id,image_data_32 const& data,int x0,int y0)
inline void set_rectangle(value_type id,image_data_rgba8 const& data,int x0,int y0)
{
box2d<int> ext0(0,0,width_,height_);
box2d<int> ext1(x0,y0,x0+data.width(),y0+data.height());

View file

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

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

View file

@ -150,6 +150,14 @@ public:
{
return height_;
}
inline unsigned getSize() const
{
return height_ * width_ * pixel_size;
}
inline unsigned getRowSize() const
{
return width_ * pixel_size;
}
inline void set(pixel_type const& t)
{
std::fill(pData_, pData_ + width_ * height_, t);
@ -180,11 +188,21 @@ public:
return pData_ + row * width_;
}
inline const pixel_type* getRow(unsigned row, std::size_t x0) const
{
return pData_ + row * width_ + x0;
}
inline pixel_type* getRow(unsigned row)
{
return pData_ + row * width_;
}
inline pixel_type* getRow(unsigned row, std::size_t x0)
{
return pData_ + row * width_ + x0;
}
inline void setRow(std::size_t row, pixel_type const* buf, std::size_t size)
{
assert(row < height_);
@ -204,8 +222,10 @@ private:
pixel_type *pData_;
};
using image_data_32 = image_data<std::uint32_t>;
using image_data_8 = image_data<byte> ;
using image_data_rgba8 = image_data<std::uint32_t>;
using image_data_gray8 = image_data<std::uint8_t> ;
using image_data_gray16 = image_data<std::int16_t>;
using image_data_gray32f = image_data<float>;
}
#endif // MAPNIK_IMAGE_DATA_HPP

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
// mapnik
#include <mapnik/image_data.hpp>
#include <mapnik/image_data_any.hpp>
#include <mapnik/config.hpp>
#include <mapnik/noncopyable.hpp>
#include <mapnik/factory.hpp>
#include <mapnik/box2d.hpp>
// boost
#include <boost/optional.hpp>
// stl
@ -55,11 +56,13 @@ public:
struct MAPNIK_DECL image_reader : private mapnik::noncopyable
{
virtual unsigned width() const=0;
virtual unsigned height() const=0;
virtual bool has_alpha() const=0;
virtual bool premultiplied_alpha() const=0;
virtual void read(unsigned x,unsigned y,image_data_32& image)=0;
virtual unsigned width() const = 0;
virtual unsigned height() const = 0;
virtual bool has_alpha() const = 0;
virtual bool premultiplied_alpha() const = 0;
virtual boost::optional<box2d<double> > bounding_box() const = 0;
virtual void read(unsigned x,unsigned y,image_data_rgba8& image) = 0;
virtual image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) = 0;
virtual ~image_reader() {}
};
@ -69,7 +72,7 @@ bool register_image_reader(std::string const& type, image_reader* (* fun)(Args..
return factory<image_reader,std::string, Args...>::instance().register_product(type, fun);
}
MAPNIK_DECL image_reader* get_image_reader(std::string const& file,std::string const& type);
MAPNIK_DECL image_reader* get_image_reader(std::string const& file, std::string const& type);
MAPNIK_DECL image_reader* get_image_reader(std::string const& file);
MAPNIK_DECL image_reader* get_image_reader(char const* data, size_t size);

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<std::string> scaling_method_to_string(scaling_method_e scaling_method);
template <typename Image>
MAPNIK_DECL void scale_image_agg(Image & target,
Image const& source,
scaling_method_e scaling_method,
double image_ratio_x,
double image_ratio_y,
double x_off_f,
double y_off_f,
double filter_factor);
extern template MAPNIK_DECL void scale_image_agg<mapnik::image_data_32>(
mapnik::image_data_32 & target,
mapnik::image_data_32 const& source,
scaling_method_e scaling_method,
double image_ratio_x,
double image_ratio_y,
double x_off_f,
double y_off_f,
double filter_radius);
template <typename T>
MAPNIK_DECL void scale_image_agg(T & target, T const& source,
scaling_method_e scaling_method,
double image_ratio_x,
double image_ratio_y,
double x_off_f,
double y_off_f,
double filter_factor);
}
#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&,
rgba_palette const&);
extern template MAPNIK_DECL void save_to_file<image_data_32>(image_data_32 const&,
extern template MAPNIK_DECL void save_to_file<image_data_rgba8>(image_data_rgba8 const&,
std::string const&,
std::string const&);
extern template MAPNIK_DECL void save_to_file<image_data_32>(image_data_32 const&,
extern template MAPNIK_DECL void save_to_file<image_data_rgba8>(image_data_rgba8 const&,
std::string const&,
rgba_palette const&);
extern template MAPNIK_DECL void save_to_file<image_data_32>(image_data_32 const&,
extern template MAPNIK_DECL void save_to_file<image_data_rgba8>(image_data_rgba8 const&,
std::string const&);
extern template MAPNIK_DECL void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
extern template MAPNIK_DECL void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
std::string const&,
std::string const&,
rgba_palette const&);
extern template MAPNIK_DECL void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
extern template MAPNIK_DECL void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
std::string const&,
std::string const&);
extern template MAPNIK_DECL void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
extern template MAPNIK_DECL void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
std::string const&,
rgba_palette const&);
extern template MAPNIK_DECL void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
extern template MAPNIK_DECL void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
std::string const&);
extern template MAPNIK_DECL std::string save_to_string<image_data_32>(image_data_32 const&,
extern template MAPNIK_DECL std::string save_to_string<image_data_rgba8>(image_data_rgba8 const&,
std::string const&);
extern template MAPNIK_DECL std::string save_to_string<image_data_32>(image_data_32 const&,
extern template MAPNIK_DECL std::string save_to_string<image_data_rgba8>(image_data_rgba8 const&,
std::string const&,
rgba_palette const&);
extern template MAPNIK_DECL std::string save_to_string<image_view<image_data_32> > (image_view<image_data_32> const&,
extern template MAPNIK_DECL std::string save_to_string<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
std::string const&);
extern template MAPNIK_DECL std::string save_to_string<image_view<image_data_32> > (image_view<image_data_32> const&,
extern template MAPNIK_DECL std::string save_to_string<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
std::string const&,
rgba_palette const&);
#ifdef _MSC_VER
template MAPNIK_DECL void save_to_stream<image_data_32>(
image_data_32 const& image,
template MAPNIK_DECL void save_to_stream<image_data_rgba8>(
image_data_rgba8 const& image,
std::ostream & stream,
std::string const& type,
rgba_palette const& palette
);
template MAPNIK_DECL void save_to_stream<image_data_32>(
image_data_32 const& image,
template MAPNIK_DECL void save_to_stream<image_data_rgba8>(
image_data_rgba8 const& image,
std::ostream & stream,
std::string const& type
);
template MAPNIK_DECL void save_to_stream<image_view<image_data_32> > (
image_view<image_data_32> const& image,
template MAPNIK_DECL void save_to_stream<image_view<image_data_rgba8> > (
image_view<image_data_rgba8> const& image,
std::ostream & stream,
std::string const& type,
rgba_palette const& palette
);
template MAPNIK_DECL void save_to_stream<image_view<image_data_32> > (
image_view<image_data_32> const& image,
template MAPNIK_DECL void save_to_stream<image_view<image_data_rgba8> > (
image_view<image_data_rgba8> const& image,
std::ostream & stream,
std::string const& type
);

View file

@ -30,7 +30,8 @@ class image_view
{
public:
using pixel_type = typename T::pixel_type;
static constexpr std::size_t pixel_size = sizeof(pixel_type);
image_view(unsigned x, unsigned y, unsigned width, unsigned height, T const& data)
: x_(x),
y_(y),
@ -84,10 +85,25 @@ public:
return height_;
}
inline unsigned getSize() const
{
return height_ * width_ * pixel_size;
}
inline unsigned getRowSize() const
{
return width_ * pixel_size;
}
inline const pixel_type* getRow(unsigned row) const
{
return data_.getRow(row + y_) + x_;
}
inline const pixel_type* getRow(unsigned row, std::size_t x0) const
{
return data_.getRow(row + y_, x0) + x_;
}
inline const unsigned char* getBytes() const
{
@ -101,6 +117,15 @@ public:
{
return data_;
}
inline pixel_type* getData()
{
return data_.getData();
}
inline const pixel_type* getData() const
{
return data_.getData();
}
private:
unsigned x_;

View file

@ -45,7 +45,7 @@ namespace mapnik
using attr_storage = agg::pod_bvector<mapnik::svg::path_attributes>;
using svg_storage_type = mapnik::svg::svg_storage<mapnik::svg::svg_path_storage,attr_storage>;
using svg_path_ptr = std::shared_ptr<svg_storage_type>;
using image_ptr = std::shared_ptr<image_data_32>;
using image_ptr = std::shared_ptr<image_data_rgba8>;
/**
* A class to hold either vector or bitmap marker data. This allows these to be treated equally
* in the image caches and most of the render paths.
@ -56,7 +56,7 @@ public:
marker()
{
// create default OGC 4x4 black pixel
bitmap_data_ = boost::optional<mapnik::image_ptr>(std::make_shared<image_data_32>(4,4));
bitmap_data_ = boost::optional<mapnik::image_ptr>(std::make_shared<image_data_rgba8>(4,4));
(*bitmap_data_)->set(0xff000000);
}

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 renderer_base = agg::renderer_base<pixfmt_comp_type>;
raster_markers_rasterizer_dispatch(image_data_32 const& src,
raster_markers_rasterizer_dispatch(image_data_rgba8 const& src,
agg::trans_affine const& marker_trans,
symbolizer_base const& sym,
Detector & detector,
@ -300,7 +300,7 @@ private:
pixfmt_comp_type pixf_;
renderer_base renb_;
RasterizerType & ras_;
image_data_32 const& src_;
image_data_rgba8 const& src_;
agg::trans_affine const& marker_trans_;
symbolizer_base const& sym_;
Detector & detector_;

View file

@ -83,12 +83,12 @@ private:
static const unsigned char IEND_tpl[];
};
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_data_8>(image_data_8 const& image);
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_view<image_data_8> >(image_view<image_data_8> const& image);
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_data_32>(image_data_32 const& image);
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_view<image_data_32> >(image_view<image_data_32> const& image);
extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha<image_data_32>(image_data_32 const& image);
extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha<image_view<image_data_32> >(image_view<image_data_32> const& image);
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_data_gray8>(image_data_gray8 const& image);
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_view<image_data_gray8> >(image_view<image_data_gray8> const& image);
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_data_rgba8>(image_data_rgba8 const& image);
extern template MAPNIK_DECL void PNGWriter::writeIDAT<image_view<image_data_rgba8> >(image_view<image_data_rgba8> const& image);
extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha<image_data_rgba8>(image_data_rgba8 const& image);
extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha<image_view<image_data_rgba8> >(image_view<image_data_rgba8> const& image);
}}

View file

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

View file

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

View file

@ -40,7 +40,9 @@
#include <mapnik/config.hpp>
#include <mapnik/color.hpp>
#include <mapnik/enumeration.hpp>
#include <mapnik/image_data.hpp>
// boost
#include <boost/optional.hpp>
// boost
#include <memory>
@ -195,12 +197,8 @@ public:
//! \return The list of stops
colorizer_stops const& get_stops() const { return stops_; }
//! \brief Colorize a raster
//!
//! \param[in, out] raster A raster stored in float32 single channel format, which gets colorized in place.
void colorize(std::shared_ptr<raster> const& raster, feature_impl const& f) const;
template <typename T>
void colorize(image_data_rgba8 & out, T const& in, boost::optional<double>const& nodata, feature_impl const& f) const;
//! \brief Perform the translation of input to output
//!

View file

@ -34,24 +34,159 @@
// agg
#include "agg_rendering_buffer.h"
#include "agg_pixfmt_rgba.h"
#include "agg_pixfmt_gray.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_scanline_u.h"
#include "agg_renderer_scanline.h"
namespace mapnik {
namespace detail {
template <typename F>
void render_raster_symbolizer(raster_symbolizer const &sym,
mapnik::feature_impl &feature,
proj_transform const &prj_trans,
renderer_common &common,
struct image_data_dispatcher : util::static_visitor<void>
{
using composite_function = F;
image_data_dispatcher(int start_x, int start_y,
int width, int height,
double scale_x, double scale_y,
scaling_method_e method, double filter_factor,
double opacity, composite_mode_e comp_op,
raster_symbolizer const& sym, feature_impl const& feature, F & composite, boost::optional<double> const& nodata)
: start_x_(start_x),
start_y_(start_y),
width_(width),
height_(height),
scale_x_(scale_x),
scale_y_(scale_y),
method_(method),
filter_factor_(filter_factor),
opacity_(opacity),
comp_op_(comp_op),
sym_(sym),
feature_(feature),
composite_(composite),
nodata_(nodata) {}
void operator() (image_data_null const& data_in) const {} //no-op
void operator() (image_data_rgba8 const& data_in) const
{
image_data_rgba8 data_out(width_, height_);
scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_);
composite_(data_out, comp_op_, opacity_, start_x_, start_y_);
}
template <typename T>
void operator() (T const& data_in) const
{
using image_data_type = T;
image_data_type data_out(width_, height_);
scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_);
image_data_rgba8 dst(width_, height_);
raster_colorizer_ptr colorizer = get<raster_colorizer_ptr>(sym_, keys::colorizer);
if (colorizer) colorizer->colorize(dst, data_out, nodata_, feature_);
composite_(dst, comp_op_, opacity_, start_x_, start_y_);
}
private:
int start_x_;
int start_y_;
int width_;
int height_;
double scale_x_;
double scale_y_;
scaling_method_e method_;
double filter_factor_;
double opacity_;
composite_mode_e comp_op_;
raster_symbolizer const& sym_;
feature_impl const& feature_;
composite_function & composite_;
boost::optional<double> const& nodata_;
};
template <typename F>
struct image_data_warp_dispatcher : util::static_visitor<void>
{
using composite_function = F;
image_data_warp_dispatcher(proj_transform const& prj_trans,
int start_x, int start_y, int width, int height,
box2d<double> const& target_ext, box2d<double> const& source_ext,
double offset_x, double offset_y, unsigned mesh_size, scaling_method_e scaling_method,
double filter_factor, double opacity, composite_mode_e comp_op,
raster_symbolizer const& sym, feature_impl const& feature, F & composite, boost::optional<double> const& nodata)
: prj_trans_(prj_trans),
start_x_(start_x),
start_y_(start_y),
width_(width),
height_(height),
target_ext_(target_ext),
source_ext_(source_ext),
offset_x_(offset_x),
offset_y_(offset_y),
mesh_size_(mesh_size),
scaling_method_(scaling_method),
filter_factor_(filter_factor),
opacity_(opacity),
comp_op_(comp_op),
sym_(sym),
feature_(feature),
composite_(composite),
nodata_(nodata) {}
void operator() (image_data_null const& data_in) const {} //no-op
void operator() (image_data_rgba8 const& data_in) const
{
image_data_rgba8 data_out(width_, height_);
warp_image(data_out, data_in, prj_trans_, target_ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_);
composite_(data_out, comp_op_, opacity_, start_x_, start_y_);
}
template <typename T>
void operator() (T const& data_in) const
{
using image_data_type = T;
image_data_type data_out(width_, height_);
if (nodata_) data_out.set(*nodata_);
warp_image(data_out, data_in, prj_trans_, target_ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_);
image_data_rgba8 dst(width_, height_);
raster_colorizer_ptr colorizer = get<raster_colorizer_ptr>(sym_, keys::colorizer);
if (colorizer) colorizer->colorize(dst, data_out, nodata_, feature_);
composite_(dst, comp_op_, opacity_, start_x_, start_y_);
}
private:
proj_transform const& prj_trans_;
int start_x_;
int start_y_;
int width_;
int height_;
box2d<double> const& target_ext_;
box2d<double> const& source_ext_;
double offset_x_;
double offset_y_;
unsigned mesh_size_;
scaling_method_e scaling_method_;
double filter_factor_;
double opacity_;
composite_mode_e comp_op_;
raster_symbolizer const& sym_;
feature_impl const& feature_;
composite_function & composite_;
boost::optional<double> const& nodata_;
};
}
template <typename F>
void render_raster_symbolizer(raster_symbolizer const& sym,
mapnik::feature_impl& feature,
proj_transform const& prj_trans,
renderer_common& common,
F composite)
{
raster_ptr const& source = feature.get_raster();
if (source)
{
// If there's a colorizer defined, use it to color the raster in-place
raster_colorizer_ptr colorizer = get<raster_colorizer_ptr>(sym, keys::colorizer);
if (colorizer)
colorizer->colorize(source,feature);
box2d<double> target_ext = box2d<double>(source->ext_);
prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS);
box2d<double> ext = common.t_.forward(target_ext);
@ -66,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);
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);
bool premultiply_source = !source->premultiplied_alpha_;
auto is_premultiplied = get_optional<bool>(sym, keys::premultiplied, feature, common.vars_);
if (is_premultiplied)
// only premultiply rgba8 images
if (source->data_.is<image_data_rgba8>())
{
if (*is_premultiplied) premultiply_source = false;
else premultiply_source = true;
}
if (premultiply_source)
{
agg::rendering_buffer buffer(source->data_.getBytes(),
source->data_.width(),
source->data_.height(),
source->data_.width() * 4);
agg::pixfmt_rgba32 pixf(buffer);
pixf.premultiply();
bool premultiply_source = !source->premultiplied_alpha_;
auto is_premultiplied = get_optional<bool>(sym, keys::premultiplied, feature, common.vars_);
if (is_premultiplied)
{
if (*is_premultiplied) premultiply_source = false;
else premultiply_source = true;
}
if (premultiply_source)
{
agg::rendering_buffer buffer(source->data_.getBytes(),
source->data_.width(),
source->data_.height(),
source->data_.width() * 4);
agg::pixfmt_rgba32 pixf(buffer);
pixf.premultiply();
}
}
if (!prj_trans.equal())
{
double offset_x = ext.minx() - start_x;
double offset_y = ext.miny() - start_y;
raster target(target_ext, raster_width, raster_height, source->get_filter_factor());
unsigned mesh_size = static_cast<unsigned>(get<value_integer>(sym,keys::mesh_size,feature, common.vars_, 16));
reproject_and_scale_raster(target,
*source,
prj_trans,
offset_x,
offset_y,
mesh_size,
scaling_method);
composite(target.data_, comp_op, opacity, start_x, start_y);
detail::image_data_warp_dispatcher<F> dispatcher(prj_trans, start_x, start_y, raster_width, raster_height,
target_ext, source->ext_, offset_x, offset_y, mesh_size,
scaling_method, source->get_filter_factor(),
opacity, comp_op, sym, feature, composite, source->nodata());
util::apply_visitor(dispatcher, source->data_);
}
else
{
@ -107,20 +243,18 @@ void render_raster_symbolizer(raster_symbolizer const &sym,
(std::abs(start_x) <= eps) &&
(std::abs(start_y) <= eps) )
{
composite(source->data_, comp_op, opacity, start_x, start_y);
if (source->data_.is<image_data_rgba8>())
{
composite(util::get<image_data_rgba8>(source->data_), comp_op, opacity, start_x, start_y);
}
}
else
{
raster target(target_ext, raster_width, raster_height, source->get_filter_factor());
scale_image_agg<image_data_32>(target.data_,
source->data_,
scaling_method,
image_ratio_x,
image_ratio_y,
0.0,
0.0,
source->get_filter_factor());
composite(target.data_, comp_op, opacity, start_x, start_y);
detail::image_data_dispatcher<F> dispatcher(start_x, start_y, raster_width, raster_height,
image_ratio_x, image_ratio_y,
scaling_method, source->get_filter_factor(),
opacity, comp_op, sym, feature, composite, source->nodata());
util::apply_visitor(dispatcher, source->data_);
}
}
}

View file

@ -37,7 +37,7 @@ namespace mapnik {
struct rasterizer;
class marker;
std::shared_ptr<image_data_32> render_pattern(rasterizer & ras,
std::shared_ptr<image_data_rgba8> render_pattern(rasterizer & ras,
marker const& marker,
agg::trans_affine const& tr,
double opacity);

View file

@ -25,6 +25,8 @@
#include <mapnik/global.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/image_data_any.hpp>
#include <mapnik/util/variant.hpp>
extern "C"
{
@ -33,9 +35,15 @@ extern "C"
#define RealTIFFClose TIFFClose
}
#define TIFF_WRITE_SCANLINE 0
#define TIFF_WRITE_STRIPPED 1
#define TIFF_WRITE_TILED 2
#include <iostream>
namespace mapnik {
static tsize_t tiff_write_proc(thandle_t fd, tdata_t buf, tsize_t size)
static inline tsize_t tiff_write_proc(thandle_t fd, tdata_t buf, tsize_t size)
{
std::ostream* out = reinterpret_cast<std::ostream*>(fd);
std::ios::pos_type pos = out->tellp();
@ -54,7 +62,7 @@ static tsize_t tiff_write_proc(thandle_t fd, tdata_t buf, tsize_t size)
}
}
static toff_t tiff_seek_proc(thandle_t fd, toff_t off, int whence)
static inline toff_t tiff_seek_proc(thandle_t fd, toff_t off, int whence)
{
std::ostream* out = reinterpret_cast<std::ostream*>(fd);
@ -123,14 +131,14 @@ static toff_t tiff_seek_proc(thandle_t fd, toff_t off, int whence)
return static_cast<toff_t>(out->tellp());
}
static int tiff_close_proc(thandle_t fd)
static inline int tiff_close_proc(thandle_t fd)
{
std::ostream* out = (std::ostream*)fd;
out->flush();
return 0;
}
static toff_t tiff_size_proc(thandle_t fd)
static inline toff_t tiff_size_proc(thandle_t fd)
{
std::ostream* out = reinterpret_cast<std::ostream*>(fd);
std::ios::pos_type pos = out->tellp();
@ -140,27 +148,146 @@ static toff_t tiff_size_proc(thandle_t fd)
return static_cast<toff_t>(len);
}
static tsize_t tiff_dummy_read_proc(thandle_t , tdata_t , tsize_t)
static inline tsize_t tiff_dummy_read_proc(thandle_t , tdata_t , tsize_t)
{
return 0;
}
static void tiff_dummy_unmap_proc(thandle_t , tdata_t , toff_t)
{
}
static inline void tiff_dummy_unmap_proc(thandle_t , tdata_t , toff_t) {}
static int tiff_dummy_map_proc(thandle_t , tdata_t*, toff_t* )
static inline int tiff_dummy_map_proc(thandle_t , tdata_t*, toff_t* )
{
return 0;
}
struct tiff_config
{
tiff_config()
: compression(COMPRESSION_ADOBE_DEFLATE),
zlevel(4),
tile_width(0),
tile_height(0),
rows_per_strip(0),
method(TIFF_WRITE_STRIPPED) {}
int compression;
int zlevel;
int tile_width; // Tile width of zero means tile the width of the image
int tile_height; // Tile height of zero means tile the height of the image
int rows_per_strip;
int method; // The method to use to write the TIFF.
};
struct tag_setter : public mapnik::util::static_visitor<>
{
tag_setter(TIFF * output, tiff_config & config)
: output_(output),
config_(config) {}
template <typename T>
void operator() (T const&) const
{
// Assume this would be null type
throw ImageWriterException("Could not write TIFF - unknown image type provided");
}
inline void operator() (image_data_rgba8 const&) const
{
TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 4);
//uint16 extras[] = { EXTRASAMPLE_UNASSALPHA };
uint16 extras[] = { EXTRASAMPLE_ASSOCALPHA };
TIFFSetField(output_, TIFFTAG_EXTRASAMPLES, 1, extras);
if (config_.compression == COMPRESSION_DEFLATE
|| config_.compression == COMPRESSION_ADOBE_DEFLATE
|| config_.compression == COMPRESSION_LZW)
{
TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL);
}
}
inline void operator() (image_data_gray32f const&) const
{
TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 32);
TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1);
if (config_.compression == COMPRESSION_DEFLATE
|| config_.compression == COMPRESSION_ADOBE_DEFLATE
|| config_.compression == COMPRESSION_LZW)
{
TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_FLOATINGPOINT);
}
}
inline void operator() (image_data_gray16 const&) const
{
TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 16);
TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1);
if (config_.compression == COMPRESSION_DEFLATE
|| config_.compression == COMPRESSION_ADOBE_DEFLATE
|| config_.compression == COMPRESSION_LZW)
{
TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL);
}
}
inline void operator() (image_data_gray8 const&) const
{
TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1);
if (config_.compression == COMPRESSION_DEFLATE
|| config_.compression == COMPRESSION_ADOBE_DEFLATE
|| config_.compression == COMPRESSION_LZW)
{
TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL);
}
}
inline void operator() (image_data_null const&) const
{
// Assume this would be null type
throw ImageWriterException("Could not write TIFF - Null image provided");
}
private:
TIFF * output_;
tiff_config config_;
};
void set_tiff_config(TIFF* output, tiff_config & config)
{
// Set some constant tiff information that doesn't vary based on type of data
// or image size
TIFFSetField(output, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
// Set the compression for the TIFF
TIFFSetField(output, TIFFTAG_COMPRESSION, config.compression);
if (COMPRESSION_ADOBE_DEFLATE == config.compression
|| COMPRESSION_DEFLATE == config.compression
|| COMPRESSION_LZW == config.compression)
{
// Set the zip level for the compression
// http://en.wikipedia.org/wiki/DEFLATE#Encoder.2Fcompressor
// Changes the time spent trying to compress
TIFFSetField(output, TIFFTAG_ZIPQUALITY, config.zlevel);
}
}
template <typename T1, typename T2>
void save_as_tiff(T1 & file, T2 const& image)
void save_as_tiff(T1 & file, T2 const& image, tiff_config & config)
{
using pixel_type = typename T2::pixel_type;
const int width = image.width();
const int height = image.height();
const int scanline_size = sizeof(unsigned char) * width * 3;
TIFF* output = RealTIFFOpen("mapnik_tiff_stream",
"wm",
@ -179,13 +306,107 @@ void save_as_tiff(T1 & file, T2 const& image)
TIFFSetField(output, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(output, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
TIFFSetField(output, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(output, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField(output, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(output, TIFFTAG_SAMPLESPERPIXEL, 3);
TIFFSetField(output, TIFFTAG_ROWSPERSTRIP, 1);
TIFFSetField(output, TIFFTAG_IMAGEDEPTH, 1);
set_tiff_config(output, config);
// Set tags that vary based on the type of data being provided.
tag_setter set(output, config);
set(image);
//util::apply_visitor(set, image);
// Use specific types of writing methods.
if (TIFF_WRITE_SCANLINE == config.method)
{
// Process Scanline
TIFFSetField(output, TIFFTAG_ROWSPERSTRIP, 1);
int next_scanline = 0;
std::unique_ptr<pixel_type[]> row (new pixel_type[width]);
while (next_scanline < height)
{
std::copy(image.getRow(next_scanline), image.getRow(next_scanline) + width, row.get());
TIFFWriteScanline(output, row.get(), next_scanline, 0);
++next_scanline;
}
}
else if (TIFF_WRITE_STRIPPED == config.method)
{
std::size_t rows_per_strip = config.rows_per_strip;
if (0 == rows_per_strip)
{
rows_per_strip = height;
}
TIFFSetField(output, TIFFTAG_ROWSPERSTRIP, rows_per_strip);
std::size_t strip_size = width * rows_per_strip;
std::unique_ptr<pixel_type[]> strip_buffer(new pixel_type[strip_size]);
int end_y=(height/rows_per_strip+1)*rows_per_strip;
for (int y=0; y < end_y; y+=rows_per_strip)
{
int ty1 = std::min(height, static_cast<int>(y + rows_per_strip)) - y;
int row = y;
for (int ty = 0; ty < ty1; ++ty, ++row)
{
std::copy(image.getRow(row), image.getRow(row) + width, strip_buffer.get() + ty * width);
}
if (TIFFWriteEncodedStrip(output, TIFFComputeStrip(output, y, 0), strip_buffer.get(), strip_size * sizeof(pixel_type)) == -1)
{
throw ImageWriterException("Could not write TIFF - TIFF Tile Write failed");
}
}
}
else if (TIFF_WRITE_TILED == config.method)
{
int tile_width = config.tile_width;
int tile_height = config.tile_height;
if (0 == tile_height)
{
tile_height = height;
if (height % 16 > 0)
{
tile_height = height + 16 - (height % 16);
}
}
if (0 == tile_width)
{
tile_width = width;
if (width % 16 > 0)
{
tile_width = width + 16 - (width % 16);
}
}
TIFFSetField(output, TIFFTAG_TILEWIDTH, tile_width);
TIFFSetField(output, TIFFTAG_TILELENGTH, tile_height);
TIFFSetField(output, TIFFTAG_TILEDEPTH, 1);
std::size_t tile_size = tile_width * tile_height;
std::unique_ptr<pixel_type[]> image_data_out (new pixel_type[tile_size]);
int end_y = (height / tile_height + 1) * tile_height;
int end_x = (width / tile_width + 1) * tile_width;
end_y = std::min(end_y, height);
end_x = std::min(end_x, width);
for (int y = 0; y < end_y; y += tile_height)
{
int ty1 = std::min(height, y + tile_height) - y;
for (int x = 0; x < end_x; x += tile_width)
{
// Prefill the entire array with zeros.
std::fill(image_data_out.get(), image_data_out.get() + tile_size, 0);
int tx1 = std::min(width, x + tile_width);
int row = y;
for (int ty = 0; ty < ty1; ++ty, ++row)
{
std::copy(image.getRow(row, x), image.getRow(row, tx1), image_data_out.get() + ty * tile_width);
}
if (TIFFWriteEncodedTile(output, TIFFComputeTile(output, x, y, 0, 0), image_data_out.get(), tile_size * sizeof(pixel_type)) == -1)
{
throw ImageWriterException("Could not write TIFF - TIFF Tile Write failed");
}
}
}
}
// TODO - handle palette images
// std::vector<mapnik::rgb> const& palette
@ -199,26 +420,6 @@ void save_as_tiff(T1 & file, T2 const& image)
// TIFFSetField(output, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
// TIFFSetField(output, TIFFTAG_COLORMAP, r, g, b);
int next_scanline = 0;
unsigned char* row = reinterpret_cast<unsigned char*>(::operator new(scanline_size));
while (next_scanline < height)
{
const unsigned* imageRow = image.getRow(next_scanline);
for (int i = 0, index = 0; i < width; ++i)
{
row[index++] = (imageRow[i]) & 0xff;
row[index++] = (imageRow[i] >> 8) & 0xff;
row[index++] = (imageRow[i] >> 16) & 0xff;
}
TIFFWriteScanline(output, row, next_scanline, 0);
++next_scanline;
}
::operator delete(row);
RealTIFFClose(output);
}

View file

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

View file

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

View file

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

View file

@ -199,34 +199,38 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
if (im_width > 0 && im_height > 0)
{
mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, im_width, im_height, filter_factor);
feature->set_raster(raster);
mapnik::image_data_32 & image = raster->data_;
image.set(0xffffffff);
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Image Size=(" << im_width << "," << im_height << ")";
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Reading band=" << band_;
if (band_ > 0) // we are querying a single band
{
mapnik::image_data_gray16 image(im_width, im_height);
image.set(std::numeric_limits<std::int16_t>::max());
if (band_ > nbands_)
{
std::ostringstream s;
s << "GDAL Plugin: " << band_ << " is an invalid band, dataset only has " << nbands_ << "bands";
throw datasource_exception(s.str());
}
float* imageData = reinterpret_cast<float*>(image.getBytes());
GDALRasterBand * band = dataset_.GetRasterBand(band_);
raster_nodata = band->GetNoDataValue(&raster_has_nodata);
raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height,
imageData, image.width(), image.height(),
GDT_Float32, 0, 0);
if (raster_io_error == CE_Failure) {
image.getData(), image.width(), image.height(),
GDT_Int16, 0, 0);
if (raster_io_error == CE_Failure)
{
throw datasource_exception(CPLGetLastErrorMsg());
}
mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, image, filter_factor);
// set nodata value to be used in raster colorizer
if (nodata_value_) raster->set_nodata(*nodata_value_);
else raster->set_nodata(raster_nodata);
feature->set_raster(raster);
}
else // working with all bands
{
mapnik::image_data_rgba8 image(im_width, im_height);
image.set(std::numeric_limits<std::uint32_t>::max());
for (int i = 0; i < nbands_; ++i)
{
GDALRasterBand * band = dataset_.GetRasterBand(i + 1);
@ -363,7 +367,8 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
raster_io_error = grey->RasterIO(GF_Read, x_off, y_off, width, height,
imageData, image.width(), image.height(),
GDT_Float32, 0, 0);
if (raster_io_error == CE_Failure) {
if (raster_io_error == CE_Failure)
{
throw datasource_exception(CPLGetLastErrorMsg());
}
int len = image.width() * image.height();
@ -379,19 +384,26 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
}
}
}
raster_io_error = grey->RasterIO(GF_Read, x_off, y_off, width, height, image.getBytes() + 0,
image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
if (raster_io_error == CE_Failure) {
if (raster_io_error == CE_Failure)
{
throw datasource_exception(CPLGetLastErrorMsg());
}
raster_io_error = grey->RasterIO(GF_Read,x_off, y_off, width, height, image.getBytes() + 1,
image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
if (raster_io_error == CE_Failure) {
if (raster_io_error == CE_Failure)
{
throw datasource_exception(CPLGetLastErrorMsg());
}
raster_io_error = grey->RasterIO(GF_Read,x_off, y_off, width, height, image.getBytes() + 2,
image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
if (raster_io_error == CE_Failure) {
if (raster_io_error == CE_Failure)
{
throw datasource_exception(CPLGetLastErrorMsg());
}
@ -435,15 +447,11 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
MAPNIK_LOG_WARN(gdal) << "warning: nodata value (" << raster_nodata << ") used to set transparency instead of alpha band";
}
}
}
// set nodata value to be used in raster colorizer
if (nodata_value_)
{
raster->set_nodata(*nodata_value_);
}
else
{
raster->set_nodata(raster_nodata);
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);
}
// report actual/original source nodata in feature attributes
if (raster_has_nodata)

View file

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

View file

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

View file

@ -84,6 +84,16 @@ raster_datasource::raster_datasource(parameters const& params)
{
extent_initialized_ = extent_.from_string(*ext);
}
else //bounding box from image_reader
{
std::unique_ptr<image_reader> reader(mapnik::get_image_reader(*file));
auto bbox = reader->bounding_box();
if (bbox)
{
extent_ = *bbox;
extent_initialized_ = true;
}
}
if (! extent_initialized_)
{

View file

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

View file

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

View file

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

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_lut filter(filter_kernel, false);
image_data_32 const& src = **marker.get_bitmap_data();
image_data_rgba8 const& src = **marker.get_bitmap_data();
agg::rendering_buffer marker_buf((unsigned char *)src.getBytes(),
src.width(),
src.height(),

View file

@ -52,7 +52,7 @@ void agg_renderer<T0,T1>::process(raster_symbolizer const& sym,
{
render_raster_symbolizer(
sym, feature, prj_trans, common_,
[&](image_data_32 & target, composite_mode_e comp_op, double opacity,
[&](image_data_rgba8 & target, composite_mode_e comp_op, double opacity,
int start_x, int start_y) {
composite(current_buffer_->data(), target,
comp_op, opacity, start_x, start_y, false);

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);
}
void cairo_context::add_image(double x, double y, image_data_32 & data, double opacity)
void cairo_context::add_image(double x, double y, image_data_rgba8 & data, double opacity)
{
cairo_pattern pattern(data);
pattern.set_origin(x, y);
@ -348,7 +348,7 @@ void cairo_context::add_image(double x, double y, image_data_32 & data, double o
check_object_status_and_throw_exception(*this);
}
void cairo_context::add_image(agg::trans_affine const& tr, image_data_32 & data, double opacity)
void cairo_context::add_image(agg::trans_affine const& tr, image_data_rgba8 & data, double opacity)
{
cairo_pattern pattern(data);
if (!tr.is_identity())

View file

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

View file

@ -43,7 +43,7 @@ void cairo_renderer<T>::process(raster_symbolizer const& sym,
cairo_save_restore guard(context_);
render_raster_symbolizer(
sym, feature, prj_trans, common_,
[&](image_data_32 &target, composite_mode_e comp_op, double opacity,
[&](image_data_rgba8 &target, composite_mode_e comp_op, double opacity,
int start_x, int start_y) {
context_.set_operator(comp_op);
context_.add_image(start_x, start_y, target, opacity);

View file

@ -165,7 +165,7 @@ void grid_renderer<T>::render_marker(mapnik::feature_impl const& feature, pixel_
}
else
{
image_data_32 const& data = **marker.get_bitmap_data();
image_data_rgba8 const& data = **marker.get_bitmap_data();
double width = data.width();
double height = data.height();
double cx = 0.5 * width;
@ -179,13 +179,13 @@ void grid_renderer<T>::render_marker(mapnik::feature_impl const& feature, pixel_
}
else
{
image_data_32 target(data.width(), data.height());
mapnik::scale_image_agg<image_data_32>(target,
data,
SCALING_NEAR,
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?
image_data_rgba8 target(data.width(), data.height());
mapnik::scale_image_agg(target,
data,
SCALING_NEAR,
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?
pixmap_.set_rectangle(feature.id(), target,
boost::math::iround(pos.x - cx),
boost::math::iround(pos.y - cy));

View file

@ -38,8 +38,10 @@
#include "agg_scanline_u.h"
#include "agg_renderer_scanline.h"
#include "agg_pixfmt_rgba.h"
#include "agg_pixfmt_gray.h"
#include "agg_color_rgba.h"
namespace mapnik
{
@ -120,9 +122,8 @@ For example, if you generate some pattern with AGG (premultiplied) and would lik
*/
template <typename T1, typename T2>
void composite(T1 & dst, T2 & src, composite_mode_e mode,
template <>
MAPNIK_DECL void composite(image_data_rgba8 & dst, image_data_rgba8 & src, composite_mode_e mode,
float opacity,
int dx,
int dy,
@ -146,12 +147,23 @@ void composite(T1 & dst, T2 & src, composite_mode_e mode,
ren.blend_from(pixf_mask,0,dx,dy,unsigned(255*opacity));
}
template void composite<mapnik::image_data_32,mapnik::image_data_32>(mapnik::image_data_32&,
mapnik::image_data_32&,
composite_mode_e,
float,
int,
int,
bool);
template <>
MAPNIK_DECL void composite(image_data_gray32f & dst, image_data_gray32f & src, composite_mode_e mode,
float opacity,
int dx,
int dy,
bool premultiply_src)
{
using pixfmt_type = agg::pixfmt_gray32;
using renderer_type = agg::renderer_base<pixfmt_type>;
agg::rendering_buffer dst_buffer(dst.getBytes(),dst.width(),dst.height(),dst.width());
agg::rendering_buffer src_buffer(src.getBytes(),src.width(),src.height(),src.width());
pixfmt_type pixf(dst_buffer);
agg::pixfmt_gray32 pixf_mask(src_buffer);
renderer_type ren(pixf);
ren.copy_from(pixf_mask,0,dx,dy);;
}
}

View file

@ -23,6 +23,7 @@
// mapnik
#include <mapnik/image_data.hpp>
#include <mapnik/image_scaling.hpp>
#include <mapnik/image_scaling_traits.hpp>
// does not handle alpha correctly
//#include <mapnik/span_image_filter.hpp>
@ -37,12 +38,14 @@
// agg
#include "agg_image_accessors.h"
#include "agg_pixfmt_rgba.h"
#include "agg_pixfmt_gray.h"
#include "agg_color_rgba.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_renderer_scanline.h"
#include "agg_rendering_buffer.h"
#include "agg_scanline_u.h"
#include "agg_span_allocator.h"
#include "agg_span_image_filter_gray.h"
#include "agg_span_image_filter_rgba.h"
#include "agg_span_interpolator_linear.h"
#include "agg_trans_affine.h"
@ -94,37 +97,39 @@ boost::optional<std::string> scaling_method_to_string(scaling_method_e scaling_m
return mode;
}
template <typename Image>
void scale_image_agg(Image & target,
Image const& source,
scaling_method_e scaling_method,
double image_ratio_x,
double image_ratio_y,
double x_off_f,
double y_off_f,
template <typename T>
void scale_image_agg(T & target, T const& source, scaling_method_e scaling_method,
double image_ratio_x, double image_ratio_y, double x_off_f, double y_off_f,
double filter_factor)
{
// "the image filters should work namely in the premultiplied color space"
// http://old.nabble.com/Re:--AGG--Basic-image-transformations-p1110665.html
// "Yes, you need to use premultiplied images only. Only in this case the simple weighted averaging works correctly in the image fitering."
// http://permalink.gmane.org/gmane.comp.graphics.agg/3443
using pixfmt_pre = agg::pixfmt_rgba32_pre;
using image_data_type = T;
using pixel_type = typename image_data_type::pixel_type;
using pixfmt_pre = typename detail::agg_scaling_traits<image_data_type>::pixfmt_pre;
using color_type = typename detail::agg_scaling_traits<image_data_type>::color_type;
using img_src_type = typename detail::agg_scaling_traits<image_data_type>::img_src_type;
using interpolator_type = typename detail::agg_scaling_traits<image_data_type>::interpolator_type;
using renderer_base_pre = agg::renderer_base<pixfmt_pre>;
constexpr std::size_t pixel_size = sizeof(pixel_type);
// define some stuff we'll use soon
agg::rasterizer_scanline_aa<> ras;
agg::scanline_u8 sl;
agg::span_allocator<agg::rgba8> sa;
agg::image_filter_lut filter;
agg::span_allocator<color_type> sa;
// initialize source AGG buffer
agg::rendering_buffer rbuf_src((unsigned char*)source.getBytes(), source.width(), source.height(), source.width() * 4);
agg::rendering_buffer rbuf_src(const_cast<unsigned char*>(source.getBytes()),
source.width(), source.height(), source.width() * pixel_size);
pixfmt_pre pixf_src(rbuf_src);
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
img_src_type img_src(pixf_src);
// initialize destination AGG buffer (with transparency)
agg::rendering_buffer rbuf_dst((unsigned char*)target.getBytes(), target.width(), target.height(), target.width() * 4);
agg::rendering_buffer rbuf_dst(target.getBytes(), target.width(), target.height(), target.width() * pixel_size);
pixfmt_pre pixf_dst(rbuf_dst);
renderer_base_pre rb_dst_pre(pixf_dst);
@ -133,9 +138,7 @@ void scale_image_agg(Image & target,
img_mtx /= agg::trans_affine_scaling(image_ratio_x, image_ratio_y);
// create a linear interpolator for our scaling matrix
using interpolator_type = agg::span_interpolator_linear<>;
interpolator_type interpolator(img_mtx);
// draw an anticlockwise polygon to render our image into
double scaled_width = target.width();
double scaled_height = target.height();
@ -145,73 +148,33 @@ void scale_image_agg(Image & target,
ras.line_to_d(x_off_f + scaled_width, y_off_f + scaled_height);
ras.line_to_d(x_off_f, y_off_f + scaled_height);
switch(scaling_method)
if (scaling_method == SCALING_NEAR)
{
case SCALING_NEAR:
{
using span_gen_type = agg::span_image_filter_rgba_nn<img_src_type, interpolator_type>;
using span_gen_type = typename detail::agg_scaling_traits<image_data_type>::span_image_filter;
span_gen_type sg(img_src, interpolator);
agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg);
return;
}
case SCALING_BILINEAR:
filter.calculate(agg::image_filter_bilinear(), true); break;
case SCALING_BICUBIC:
filter.calculate(agg::image_filter_bicubic(), true); break;
case SCALING_SPLINE16:
filter.calculate(agg::image_filter_spline16(), true); break;
case SCALING_SPLINE36:
filter.calculate(agg::image_filter_spline36(), true); break;
case SCALING_HANNING:
filter.calculate(agg::image_filter_hanning(), true); break;
case SCALING_HAMMING:
filter.calculate(agg::image_filter_hamming(), true); break;
case SCALING_HERMITE:
filter.calculate(agg::image_filter_hermite(), true); break;
case SCALING_KAISER:
filter.calculate(agg::image_filter_kaiser(), true); break;
case SCALING_QUADRIC:
filter.calculate(agg::image_filter_quadric(), true); break;
case SCALING_CATROM:
filter.calculate(agg::image_filter_catrom(), true); break;
case SCALING_GAUSSIAN:
filter.calculate(agg::image_filter_gaussian(), true); break;
case SCALING_BESSEL:
filter.calculate(agg::image_filter_bessel(), true); break;
case SCALING_MITCHELL:
filter.calculate(agg::image_filter_mitchell(), true); break;
case SCALING_SINC:
filter.calculate(agg::image_filter_sinc(filter_factor), true); break;
case SCALING_LANCZOS:
filter.calculate(agg::image_filter_lanczos(filter_factor), true); break;
case SCALING_BLACKMAN:
filter.calculate(agg::image_filter_blackman(filter_factor), true); break;
else
{
using span_gen_type = typename detail::agg_scaling_traits<image_data_type>::span_image_resample_affine;
agg::image_filter_lut filter;
detail::set_scaling_method(filter, scaling_method, filter_factor);
span_gen_type sg(img_src, interpolator, filter);
agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg);
}
// 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,
const image_data_32& source,
scaling_method_e scaling_method,
double image_ratio_x,
double image_ratio_y,
double x_off_f,
double y_off_f,
double filter_factor);
template MAPNIK_DECL void scale_image_agg(image_data_rgba8 &, image_data_rgba8 const&, scaling_method_e,
double, double , double, double , double);
template MAPNIK_DECL void scale_image_agg(image_data_gray8 &, image_data_gray8 const&, scaling_method_e,
double, double , double, double , double);
template MAPNIK_DECL void scale_image_agg(image_data_gray16 &, image_data_gray16 const&, scaling_method_e,
double, double , double, double , double);
template MAPNIK_DECL void scale_image_agg(image_data_gray32f &, image_data_gray32f const&, scaling_method_e,
double, double , double, double , double);
}

View file

@ -255,6 +255,127 @@ void handle_png_options(std::string const& type,
}
#endif
#if defined(HAVE_TIFF)
void handle_tiff_options(std::string const& type,
tiff_config & config)
{
if (type == "tiff")
{
return;
}
if (type.length() > 4)
{
boost::char_separator<char> sep(":");
boost::tokenizer< boost::char_separator<char> > tokens(type, sep);
for (auto const& t : tokens)
{
if (t == "tiff")
{
continue;
}
else if (boost::algorithm::starts_with(t, "compression="))
{
std::string val = t.substr(12);
if (!val.empty())
{
if (val == "deflate")
{
config.compression = COMPRESSION_DEFLATE;
}
else if (val == "adobedeflate")
{
config.compression = COMPRESSION_ADOBE_DEFLATE;
}
else if (val == "lzw")
{
config.compression = COMPRESSION_LZW;
}
else if (val == "none")
{
config.compression = COMPRESSION_NONE;
}
else
{
throw ImageWriterException("invalid tiff compression: '" + val + "'");
}
}
}
else if (boost::algorithm::starts_with(t, "method="))
{
std::string val = t.substr(7);
if (!val.empty())
{
if (val == "scanline")
{
config.method = TIFF_WRITE_SCANLINE;
}
else if (val == "strip" || val == "stripped")
{
config.method = TIFF_WRITE_STRIPPED;
}
else if (val == "tiled")
{
config.method = TIFF_WRITE_TILED;
}
else
{
throw ImageWriterException("invalid tiff method: '" + val + "'");
}
}
}
else if (boost::algorithm::starts_with(t, "zlevel="))
{
std::string val = t.substr(7);
if (!val.empty())
{
if (!mapnik::util::string2int(val,config.zlevel) || config.zlevel < 0 || config.zlevel > 9)
{
throw ImageWriterException("invalid tiff zlevel: '" + val + "'");
}
}
}
else if (boost::algorithm::starts_with(t, "tile_height="))
{
std::string val = t.substr(12);
if (!val.empty())
{
if (!mapnik::util::string2int(val,config.tile_height) || config.tile_height < 0 )
{
throw ImageWriterException("invalid tiff tile_height: '" + val + "'");
}
}
}
else if (boost::algorithm::starts_with(t, "tile_width="))
{
std::string val = t.substr(11);
if (!val.empty())
{
if (!mapnik::util::string2int(val,config.tile_width) || config.tile_width < 0 )
{
throw ImageWriterException("invalid tiff tile_width: '" + val + "'");
}
}
}
else if (boost::algorithm::starts_with(t, "rows_per_strip="))
{
std::string val = t.substr(15);
if (!val.empty())
{
if (!mapnik::util::string2int(val,config.rows_per_strip) || config.rows_per_strip < 0 )
{
throw ImageWriterException("invalid tiff rows_per_strip: '" + val + "'");
}
}
}
else
{
throw ImageWriterException("unhandled tiff option: " + t);
}
}
}
}
#endif
#if defined(HAVE_WEBP)
void handle_webp_options(std::string const& type,
WebPConfig & config,
@ -621,7 +742,9 @@ void save_to_stream(T const& image,
else if (boost::algorithm::starts_with(t, "tif"))
{
#if defined(HAVE_TIFF)
save_as_tiff(stream, image);
tiff_config config;
handle_tiff_options(t, config);
save_as_tiff(stream, image, config);
#else
throw ImageWriterException("tiff output is not enabled in your build of Mapnik");
#endif
@ -769,62 +892,62 @@ void save_to_cairo_file(mapnik::Map const& map,
#endif
template void save_to_file<image_data_32>(image_data_32 const&,
template void save_to_file<image_data_rgba8>(image_data_rgba8 const&,
std::string const&,
std::string const&);
template void save_to_file<image_data_32>(image_data_32 const&,
template void save_to_file<image_data_rgba8>(image_data_rgba8 const&,
std::string const&,
std::string const&,
rgba_palette const& palette);
template void save_to_file<image_data_32>(image_data_32 const&,
template void save_to_file<image_data_rgba8>(image_data_rgba8 const&,
std::string const&);
template void save_to_file<image_data_32>(image_data_32 const&,
template void save_to_file<image_data_rgba8>(image_data_rgba8 const&,
std::string const&,
rgba_palette const& palette);
template std::string save_to_string<image_data_32>(image_data_32 const&,
template std::string save_to_string<image_data_rgba8>(image_data_rgba8 const&,
std::string const&);
template std::string save_to_string<image_data_32>(image_data_32 const&,
template std::string save_to_string<image_data_rgba8>(image_data_rgba8 const&,
std::string const&,
rgba_palette const& palette);
template void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
template void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
std::string const&,
std::string const&);
template void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
template void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
std::string const&,
std::string const&,
rgba_palette const& palette);
template void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
template void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
std::string const&);
template void save_to_file<image_view<image_data_32> > (image_view<image_data_32> const&,
template void save_to_file<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
std::string const&,
rgba_palette const& palette);
template std::string save_to_string<image_view<image_data_32> > (image_view<image_data_32> const&,
template std::string save_to_string<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
std::string const&);
template std::string save_to_string<image_view<image_data_32> > (image_view<image_data_32> const&,
template std::string save_to_string<image_view<image_data_rgba8> > (image_view<image_data_rgba8> const&,
std::string const&,
rgba_palette const& palette);
void save_to_file(image_32 const& image,std::string const& file)
{
save_to_file<image_data_32>(image.data(), file);
save_to_file<image_data_rgba8>(image.data(), file);
}
void save_to_file (image_32 const& image,
std::string const& file,
std::string const& type)
{
save_to_file<image_data_32>(image.data(), file, type);
save_to_file<image_data_rgba8>(image.data(), file, type);
}
void save_to_file (image_32 const& image,
@ -832,20 +955,20 @@ void save_to_file (image_32 const& image,
std::string const& type,
rgba_palette const& palette)
{
save_to_file<image_data_32>(image.data(), file, type, palette);
save_to_file<image_data_rgba8>(image.data(), file, type, palette);
}
std::string save_to_string(image_32 const& image,
std::string const& type)
{
return save_to_string<image_data_32>(image.data(), type);
return save_to_string<image_data_rgba8>(image.data(), type);
}
std::string save_to_string(image_32 const& image,
std::string const& type,
rgba_palette const& palette)
{
return save_to_string<image_data_32>(image.data(), type, palette);
return save_to_string<image_data_rgba8>(image.data(), type, palette);
}
}

View file

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

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'>"
"<path fill='#0000FF' stroke='black' stroke-width='.5' d='m 31.698405,7.5302648 -8.910967,-6.0263712 0.594993,4.8210971 -18.9822542,0 0,2.4105482 18.9822542,0 -0.594993,4.8210971 z'/>"
"</svg>");
boost::optional<mapnik::image_ptr> bitmap_data = boost::optional<mapnik::image_ptr>(std::make_shared<image_data_32>(4,4));
boost::optional<mapnik::image_ptr> bitmap_data = boost::optional<mapnik::image_ptr>(std::make_shared<image_data_rgba8>(4,4));
(*bitmap_data)->set(0xff000000);
marker_ptr mark = std::make_shared<mapnik::marker>(bitmap_data);
marker_cache_.emplace("image://square",mark);
@ -210,7 +210,7 @@ boost::optional<marker_ptr> marker_cache::find(std::string const& uri,
unsigned width = reader->width();
unsigned height = reader->height();
BOOST_ASSERT(width > 0 && height > 0);
mapnik::image_ptr image(std::make_shared<mapnik::image_data_32>(width,height));
mapnik::image_ptr image(std::make_shared<mapnik::image_data_rgba8>(width,height));
reader->read(0,0,*image);
if (!reader->premultiplied_alpha())
{

View file

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

View file

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

View file

@ -122,23 +122,27 @@ bool raster_colorizer::add_stop(colorizer_stop const& stop)
return true;
}
void raster_colorizer::colorize(raster_ptr const& raster, feature_impl const& f) const
template <typename T>
void raster_colorizer::colorize(image_data_rgba8 & out, T const& in,
boost::optional<double> const& nodata,
feature_impl const& f) const
{
unsigned *imageData = raster->data_.getData();
int len = raster->data_.width() * raster->data_.height();
boost::optional<double> const& nodata = raster->nodata();
using image_data_type = T;
using pixel_type = typename image_data_type::pixel_type;
// TODO: assuming in/out have the same width/height for now
std::uint32_t * out_data = out.getData();
pixel_type const* in_data = in.getData();
int len = out.width() * out.height();
for (int i=0; i<len; ++i)
{
// the GDAL plugin reads single bands as floats
float value = *reinterpret_cast<float *> (&imageData[i]);
pixel_type value = in_data[i];
if (nodata && (std::fabs(value - *nodata) < epsilon_))
{
imageData[i] = 0;
out_data[i] = 0; // rgba(0,0,0,0)
}
else
{
imageData[i] = get_color(value);
out_data[i] = get_color(value);
}
}
}
@ -153,7 +157,7 @@ unsigned raster_colorizer::get_color(float value) const
int stopCount = stops_.size();
//use default color if no stops
if(stopCount == 0)
if (stopCount == 0)
{
return default_color_.rgba();
}
@ -282,4 +286,14 @@ unsigned raster_colorizer::get_color(float value) const
}
template void raster_colorizer::colorize(image_data_rgba8 & out, image_data_gray8 const& in,
boost::optional<double>const& nodata,
feature_impl const& f) const;
template void raster_colorizer::colorize(image_data_rgba8 & out, image_data_gray16 const& in,
boost::optional<double>const& nodata,
feature_impl const& f) const;
template void raster_colorizer::colorize(image_data_rgba8 & out, image_data_gray32f const& in,
boost::optional<double>const& nodata,
feature_impl const& f) const;
}

View file

@ -35,7 +35,7 @@
namespace mapnik {
std::shared_ptr<image_data_32> render_pattern(rasterizer & ras,
std::shared_ptr<image_data_rgba8> render_pattern(rasterizer & ras,
marker const& marker,
agg::trans_affine const& tr,
double opacity)
@ -51,7 +51,7 @@ std::shared_ptr<image_data_32> render_pattern(rasterizer & ras,
mtx.translate(0.5 * bbox.width(), 0.5 * bbox.height());
mtx = tr * mtx;
std::shared_ptr<mapnik::image_data_32> image = std::make_shared<mapnik::image_data_32>(bbox.width(), bbox.height());
std::shared_ptr<mapnik::image_data_rgba8> image = std::make_shared<mapnik::image_data_rgba8>(bbox.width(), bbox.height());
agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->width() * 4);
pixfmt pixf(buf);
renderer_base renb(pixf);

View file

@ -42,9 +42,9 @@ extern "C"
namespace mapnik { namespace impl {
static toff_t tiff_seek_proc(thandle_t fd, toff_t off, int whence)
static toff_t tiff_seek_proc(thandle_t handle, toff_t off, int whence)
{
std::istream* in = reinterpret_cast<std::istream*>(fd);
std::istream* in = reinterpret_cast<std::istream*>(handle);
switch(whence)
{
@ -66,9 +66,9 @@ static int tiff_close_proc(thandle_t)
return 0;
}
static toff_t tiff_size_proc(thandle_t fd)
static toff_t tiff_size_proc(thandle_t handle)
{
std::istream* in = reinterpret_cast<std::istream*>(fd);
std::istream* in = reinterpret_cast<std::istream*>(handle);
std::ios::pos_type pos = in->tellg();
in->seekg(0, std::ios::end);
std::ios::pos_type len = in->tellg();
@ -76,9 +76,9 @@ static toff_t tiff_size_proc(thandle_t fd)
return static_cast<toff_t>(len);
}
static tsize_t tiff_read_proc(thandle_t fd, tdata_t buf, tsize_t size)
static tsize_t tiff_read_proc(thandle_t handle, tdata_t buf, tsize_t size)
{
std::istream * in = reinterpret_cast<std::istream*>(fd);
std::istream * in = reinterpret_cast<std::istream*>(handle);
std::streamsize request_size = size;
if (static_cast<tsize_t>(request_size) != size)
return static_cast<tsize_t>(-1);
@ -123,15 +123,23 @@ class tiff_reader : public image_reader
private:
source_type source_;
input_stream stream_;
tiff_ptr tif_;
int read_method_;
std::size_t width_;
std::size_t height_;
int rows_per_strip_;
int tile_width_;
int tile_height_;
tiff_ptr tif_;
std::size_t width_;
std::size_t height_;
boost::optional<box2d<double> > bbox_;
unsigned bps_;
unsigned photometric_;
unsigned bands_;
unsigned planar_config_;
unsigned compression_;
bool premultiplied_alpha_;
bool has_alpha_;
bool is_tiled_;
public:
enum TiffType {
generic=1,
@ -141,18 +149,35 @@ public:
explicit tiff_reader(std::string const& file_name);
tiff_reader(char const* data, std::size_t size);
virtual ~tiff_reader();
unsigned width() const;
unsigned height() const;
inline bool has_alpha() const { return has_alpha_; }
bool premultiplied_alpha() const;
void read(unsigned x,unsigned y,image_data_32& image);
unsigned width() const final;
unsigned height() const final;
boost::optional<box2d<double> > bounding_box() const final;
inline bool has_alpha() const final { return has_alpha_; }
bool premultiplied_alpha() const final;
void read(unsigned x,unsigned y,image_data_rgba8& image) final;
image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final;
// methods specific to tiff reader
unsigned bits_per_sample() const { return bps_; }
unsigned photometric() const { return photometric_; }
bool is_tiled() const { return is_tiled_; }
unsigned tile_width() const { return tile_width_; }
unsigned tile_height() const { return tile_height_; }
unsigned rows_per_strip() const { return rows_per_strip_; }
unsigned planar_config() const { return planar_config_; }
unsigned compression() const { return compression_; }
private:
tiff_reader(const tiff_reader&);
tiff_reader& operator=(const tiff_reader&);
void init();
void read_generic(unsigned x,unsigned y,image_data_32& image);
void read_stripped(unsigned x,unsigned y,image_data_32& image);
void read_tiled(unsigned x,unsigned y,image_data_32& image);
void read_generic(unsigned x,unsigned y,image_data_rgba8& image);
void read_stripped(unsigned x,unsigned y,image_data_rgba8& image);
template <typename ImageData>
void read_tiled(unsigned x,unsigned y, ImageData & image);
template <typename ImageData>
image_data_any read_any_gray(unsigned x, unsigned y, unsigned width, unsigned height);
TIFF* open(std::istream & input);
};
@ -178,14 +203,21 @@ template <typename T>
tiff_reader<T>::tiff_reader(std::string const& file_name)
: source_(file_name, std::ios_base::in | std::ios_base::binary),
stream_(source_),
tif_(nullptr),
read_method_(generic),
width_(0),
height_(0),
rows_per_strip_(0),
tile_width_(0),
tile_height_(0),
width_(0),
height_(0),
bps_(0),
photometric_(0),
bands_(1),
planar_config_(PLANARCONFIG_CONTIG),
compression_(COMPRESSION_NONE),
premultiplied_alpha_(false),
has_alpha_(false)
has_alpha_(false),
is_tiled_(false)
{
if (!stream_) throw image_reader_exception("TIFF reader: cannot open file "+ file_name);
init();
@ -195,16 +227,24 @@ template <typename T>
tiff_reader<T>::tiff_reader(char const* data, std::size_t size)
: source_(data, size),
stream_(source_),
tif_(nullptr),
read_method_(generic),
width_(0),
height_(0),
rows_per_strip_(0),
tile_width_(0),
tile_height_(0),
width_(0),
height_(0),
bps_(0),
photometric_(0),
bands_(1),
planar_config_(PLANARCONFIG_CONTIG),
compression_(COMPRESSION_NONE),
premultiplied_alpha_(false),
has_alpha_(false)
has_alpha_(false),
is_tiled_(false)
{
if (!stream_) throw image_reader_exception("TIFF reader: cannot open image stream ");
stream_.rdbuf()->pubsetbuf(0, 0);
stream_.seekg(0, std::ios::beg);
init();
}
@ -220,39 +260,97 @@ void tiff_reader<T>::init()
if (!tif) throw image_reader_exception("Can't open tiff file");
char msg[1024];
TIFFGetField(tif,TIFFTAG_BITSPERSAMPLE,&bps_);
TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photometric_);
TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &bands_);
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_);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height_);
if (TIFFIsTiled(tif))
throw image_reader_exception("Can't allocate tiff > 10000x10000");
}
TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planar_config_);
TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression_ );
TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rows_per_strip_);
std::uint16_t orientation;
if (TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation) == 0)
{
orientation = 1;
}
MAPNIK_LOG_DEBUG(tiff_reader) << "orientation: " << orientation;
is_tiled_ = TIFFIsTiled(tif);
if (is_tiled_)
{
TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width_);
TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height_);
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_);
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;
}
premultiplied_alpha_ = true;
}
}
else
// Try extracting bounding box from geoTIFF tags
{
throw image_reader_exception(msg);
uint16 count = 0;
double *pixelscale;
double *tilepoint;
if (TIFFGetField(tif, 33550, &count, &pixelscale) == 1 && count == 3
&& TIFFGetField(tif, 33922 , &count, &tilepoint) == 1 && count == 6)
{
MAPNIK_LOG_DEBUG(tiff_reader) << "PixelScale:" << pixelscale[0] << "," << pixelscale[1] << "," << pixelscale[2];
MAPNIK_LOG_DEBUG(tiff_reader) << "TilePoint:" << tilepoint[0] << "," << tilepoint[1] << "," << tilepoint[2];
MAPNIK_LOG_DEBUG(tiff_reader) << " " << tilepoint[3] << "," << tilepoint[4] << "," << tilepoint[5];
// assuming upper-left
double lox = tilepoint[3];
double loy = tilepoint[4];
double hix = lox + pixelscale[0] * width_;
double hiy = loy - pixelscale[1] * height_;
bbox_.reset(box2d<double>(lox, loy, hix, hiy));
MAPNIK_LOG_DEBUG(tiff_reader) << "Bounding Box:" << *bbox_;
}
}
if (!is_tiled_ &&
compression_ == COMPRESSION_NONE &&
planar_config_ == PLANARCONFIG_CONTIG)
{
if (height_ > 128 * 1024 * 1024)
{
std::size_t line_size = (bands_ * width_ * bps_ + 7) / 8;
std::size_t default_strip_height = 8192 / line_size;
if (default_strip_height == 0) default_strip_height = 1;
std::size_t num_strips = height_ / default_strip_height;
if (num_strips > 128 * 1024 * 1024)
{
throw image_reader_exception("Can't allocate tiff");
}
}
}
}
@ -273,6 +371,12 @@ unsigned tiff_reader<T>::height() const
return height_;
}
template <typename T>
boost::optional<box2d<double> > tiff_reader<T>::bounding_box() const
{
return bbox_;
}
template <typename T>
bool tiff_reader<T>::premultiplied_alpha() const
{
@ -280,7 +384,7 @@ bool tiff_reader<T>::premultiplied_alpha() const
}
template <typename T>
void tiff_reader<T>::read(unsigned x,unsigned y,image_data_32& image)
void tiff_reader<T>::read(unsigned x,unsigned y,image_data_rgba8& image)
{
if (read_method_==stripped)
{
@ -297,96 +401,279 @@ void tiff_reader<T>::read(unsigned x,unsigned y,image_data_32& image)
}
template <typename T>
void tiff_reader<T>::read_generic(unsigned, unsigned, image_data_32&)
template <typename ImageData>
image_data_any tiff_reader<T>::read_any_gray(unsigned x0, unsigned y0, unsigned width, unsigned height)
{
using image_data_type = ImageData;
using pixel_type = typename image_data_type::pixel_type;
if (read_method_ == tiled)
{
image_data_type data(width,height);
read_tiled<image_data_type>(x0, y0, data);
return image_data_any(std::move(data));
}
else
{
TIFF* tif = open(stream_);
if (tif)
{
image_data_type data(width, height);
std::size_t block_size = rows_per_strip_ > 0 ? rows_per_strip_ : tile_height_ ;
std::ptrdiff_t start_y = y0 - y0 % block_size;
std::ptrdiff_t end_y = std::min(y0 + height, static_cast<unsigned>(height_));
std::ptrdiff_t start_x = x0;
std::ptrdiff_t end_x = std::min(x0 + width, static_cast<unsigned>(width_));
std::size_t element_size = sizeof(pixel_type);
std::size_t size_to_allocate = (TIFFScanlineSize(tif) + element_size - 1)/element_size;
const std::unique_ptr<pixel_type[]> scanline(new pixel_type[size_to_allocate]);
for (std::size_t y = start_y; y < end_y; ++y)
{
if (-1 != TIFFReadScanline(tif, scanline.get(), y) && (y >= y0))
{
pixel_type * row = data.getRow(y - y0);
std::transform(scanline.get() + start_x, scanline.get() + end_x, row, [](pixel_type const& p) { return p;});
}
}
return image_data_any(std::move(data));
}
}
return image_data_any();
}
namespace detail {
struct rgb8
{
std::uint8_t r;
std::uint8_t g;
std::uint8_t b;
};
struct rgb8_to_rgba8
{
std::uint32_t operator() (rgb8 const& in) const
{
return ((255 << 24) | (in.r) | (in.g << 8) | (in.b << 16));
}
};
template <typename T>
struct tiff_reader_traits
{
using image_data_type = T;
using pixel_type = typename image_data_type::pixel_type;
static bool read_tile(TIFF * tif, unsigned x, unsigned y, pixel_type* buf, std::size_t tile_width, std::size_t tile_height)
{
return (TIFFReadEncodedTile(tif, TIFFComputeTile(tif, x,y,0,0), buf, tile_width * tile_height * sizeof(pixel_type)) != -1);
}
};
// default specialization that expands into RGBA
template <>
struct tiff_reader_traits<image_data_rgba8>
{
using pixel_type = std::uint32_t;
static bool read_tile(TIFF * tif, unsigned x0, unsigned y0, pixel_type* buf, std::size_t tile_width, std::size_t tile_height)
{
if (TIFFReadRGBATile(tif, x0, y0, buf) != -1)
{
for (unsigned y = 0; y < tile_height/2; ++y)
{
std::swap_ranges(buf + y * tile_width, buf + (y + 1) * tile_width, buf + (tile_height - y - 1) * tile_width);
}
return true;
}
return false;
}
};
}
template <typename T>
image_data_any tiff_reader<T>::read(unsigned x0, unsigned y0, unsigned width, unsigned height)
{
switch (photometric_)
{
case PHOTOMETRIC_MINISBLACK:
case PHOTOMETRIC_MINISWHITE:
{
switch (bps_)
{
case 8:
{
return read_any_gray<image_data_gray8>(x0, y0, width, height);
}
case 16:
{
return read_any_gray<image_data_gray16>(x0, y0, width, height);
}
case 32:
{
return read_any_gray<image_data_gray32f>(x0, y0, width, height);
}
}
}
// read PHOTOMETRIC_RGB expand using RGBA interface
/*
case PHOTOMETRIC_RGB:
{
switch (bps_)
{
case 8:
{
TIFF* tif = open(stream_);
if (tif)
{
image_data_rgba8 data(width, height);
std::size_t element_size = sizeof(detail::rgb8);
std::size_t size_to_allocate = (TIFFScanlineSize(tif) + element_size - 1)/element_size;
const std::unique_ptr<detail::rgb8[]> scanline(new detail::rgb8[size_to_allocate]);
std::ptrdiff_t start_y = y0 - y0 % rows_per_strip_;
std::ptrdiff_t end_y = std::min(y0 + height, static_cast<unsigned>(height_));
std::ptrdiff_t start_x = x0;
std::ptrdiff_t end_x = std::min(x0 + width, static_cast<unsigned>(width_));
for (std::size_t y = start_y; y < end_y; ++y)
{
if (-1 != TIFFReadScanline(tif, scanline.get(), y))
{
if (y >= y0)
{
image_data_rgba8::pixel_type * row = data.getRow(y - y0);
std::transform(scanline.get() + start_x, scanline.get() + end_x, row, detail::rgb8_to_rgba8());
}
}
}
return image_data_any(std::move(data));
}
return image_data_any();
}
case 16:
{
image_data_rgba8 data(width,height);
read(x0, y0, data);
return image_data_any(std::move(data));
}
case 32:
{
image_data_rgba8 data(width,height);
read(x0, y0, data);
return image_data_any(std::move(data));
}
}
}
*/
default:
{
//PHOTOMETRIC_PALETTE = 3;
//PHOTOMETRIC_MASK = 4;
//PHOTOMETRIC_SEPARATED = 5;
//PHOTOMETRIC_YCBCR = 6;
//PHOTOMETRIC_CIELAB = 8;
//PHOTOMETRIC_ICCLAB = 9;
//PHOTOMETRIC_ITULAB = 10;
//PHOTOMETRIC_LOGL = 32844;
//PHOTOMETRIC_LOGLUV = 32845;
image_data_rgba8 data(width,height);
read(x0, y0, data);
return image_data_any(std::move(data));
}
}
return image_data_any();
}
template <typename T>
void tiff_reader<T>::read_generic(unsigned, unsigned, image_data_rgba8& image)
{
TIFF* tif = open(stream_);
if (tif)
{
MAPNIK_LOG_DEBUG(tiff_reader) << "tiff_reader: TODO - tiff is not stripped or tiled";
throw std::runtime_error("tiff_reader: TODO - tiff is not stripped or tiled");
}
}
template <typename T>
void tiff_reader<T>::read_tiled(unsigned x0,unsigned y0,image_data_32& image)
template <typename ImageData>
void tiff_reader<T>::read_tiled(unsigned x0,unsigned y0, ImageData & image)
{
using pixel_type = typename detail::tiff_reader_traits<ImageData>::pixel_type;
TIFF* tif = open(stream_);
if (tif)
{
uint32* buf = (uint32*)_TIFFmalloc(tile_width_*tile_height_*sizeof(uint32));
int width=image.width();
int height=image.height();
std::unique_ptr<pixel_type[]> buf(new pixel_type[tile_width_*tile_height_]);
int width = image.width();
int height = image.height();
int start_y = (y0 / tile_height_) * tile_height_;
int end_y = ((y0 + height) / tile_height_ + 1) * tile_height_;
int start_x = (x0 / tile_width_) * tile_width_;
int end_x = ((x0 + width) / tile_width_ + 1) * tile_width_;
end_y = std::min(end_y, int(height_));
end_x = std::min(end_x, int(width_));
int start_y=(y0/tile_height_)*tile_height_;
int end_y=((y0+height)/tile_height_+1)*tile_height_;
int start_x=(x0/tile_width_)*tile_width_;
int end_x=((x0+width)/tile_width_+1)*tile_width_;
int row,tx0,tx1,ty0,ty1;
for (int y=start_y;y<end_y;y+=tile_height_)
for (int y = start_y; y < end_y; y += tile_height_)
{
ty0 = std::max(y0,(unsigned)y) - y;
ty1 = std::min(height+y0,(unsigned)(y+tile_height_)) - y;
int ty0 = std::max(y0, static_cast<unsigned>(y)) - y;
int ty1 = std::min(height + y0, static_cast<unsigned>(y + tile_height_)) - y;
int n0=tile_height_-ty1;
int n1=tile_height_-ty0-1;
for (int x=start_x;x<end_x;x+=tile_width_)
for (int x = start_x; x < end_x; x += tile_width_)
{
if (!TIFFReadRGBATile(tif,x,y,buf)) break;
tx0=std::max(x0,(unsigned)x);
tx1=std::min(width+x0,(unsigned)(x+tile_width_));
row=y+ty0-y0;
for (int n=n1;n>=n0;--n)
if (!detail::tiff_reader_traits<ImageData>::read_tile(tif, x, y, buf.get(), tile_width_, tile_height_))
{
image.setRow(row,tx0-x0,tx1-x0,(const unsigned*)&buf[n*tile_width_+tx0-x]);
++row;
std::clog << "read_tile(...) failed at " << x << "/" << y << " for " << width_ << "/" << height_ << "\n";
break;
}
int tx0 = std::max(x0, static_cast<unsigned>(x));
int tx1 = std::min(width + x0, static_cast<unsigned>(x + tile_width_));
int row = y + ty0 - y0;
for (int ty = ty0; ty < ty1; ++ty, ++row)
{
image.setRow(row, tx0 - x0, tx1 - x0, &buf[ty * tile_width_ + tx0 - x]);
}
}
}
_TIFFfree(buf);
}
}
template <typename T>
void tiff_reader<T>::read_stripped(unsigned x0,unsigned y0,image_data_32& image)
void tiff_reader<T>::read_stripped(unsigned x0,unsigned y0,image_data_rgba8& image)
{
TIFF* tif = open(stream_);
if (tif)
{
uint32* buf = (uint32*)_TIFFmalloc(width_*rows_per_strip_*sizeof(uint32));
image_data_rgba8 strip(width_,rows_per_strip_,false);
int width=image.width();
int height=image.height();
unsigned start_y=(y0/rows_per_strip_)*rows_per_strip_;
unsigned end_y=((y0+height)/rows_per_strip_+1)*rows_per_strip_;
bool laststrip=((unsigned)end_y > height_)?true:false;
bool laststrip=(static_cast<unsigned>(end_y) > height_)?true:false;
int row,tx0,tx1,ty0,ty1;
tx0=x0;
tx1=std::min(width+x0,(unsigned)width_);
tx1=std::min(width+x0,static_cast<unsigned>(width_));
for (unsigned y=start_y; y < end_y; y+=rows_per_strip_)
{
ty0 = std::max(y0,y)-y;
ty1 = std::min(height+y0,y+rows_per_strip_)-y;
if (!TIFFReadRGBAStrip(tif,y,buf)) break;
if (!TIFFReadRGBAStrip(tif,y,strip.getData()))
{
std::clog << "TIFFReadRGBAStrip failed at " << y << " for " << width_ << "/" << height_ << "\n";
break;
}
row=y+ty0-y0;
int n0=laststrip ? 0:(rows_per_strip_-ty1);
int n1=laststrip ? (ty1-ty0-1):(rows_per_strip_-ty0-1);
for (int n=n1;n>=n0;--n)
{
image.setRow(row,tx0-x0,tx1-x0,(const unsigned*)&buf[n*width_+tx0]);
image.setRow(row,tx0-x0,tx1-x0,&strip.getData()[n*width_+tx0]);
++row;
}
}
_TIFFfree(buf);
}
}
@ -395,7 +682,7 @@ TIFF* tiff_reader<T>::open(std::istream & input)
{
if (!tif_)
{
tif_ = tiff_ptr(TIFFClientOpen("tiff_input_stream", "rm",
tif_ = tiff_ptr(TIFFClientOpen("tiff_input_stream", "rcm",
reinterpret_cast<thandle_t>(&input),
impl::tiff_read_proc,
impl::tiff_write_proc,

View file

@ -24,6 +24,7 @@
#include <mapnik/warp.hpp>
#include <mapnik/config.hpp>
#include <mapnik/image_data.hpp>
#include <mapnik/image_scaling_traits.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/view_transform.hpp>
@ -47,19 +48,27 @@
namespace mapnik {
void reproject_and_scale_raster(raster & target, raster const& source,
proj_transform const& prj_trans,
double offset_x, double offset_y,
unsigned mesh_size,
scaling_method_e scaling_method)
template <typename T>
MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const& prj_trans,
box2d<double> const& target_ext, box2d<double> const& source_ext,
double offset_x, double offset_y, unsigned mesh_size, scaling_method_e scaling_method, double filter_factor)
{
view_transform ts(source.data_.width(), source.data_.height(),
source.ext_);
view_transform tt(target.data_.width(), target.data_.height(),
target.ext_, offset_x, offset_y);
using image_data_type = T;
using pixel_type = typename image_data_type::pixel_type;
using pixfmt_pre = typename detail::agg_scaling_traits<image_data_type>::pixfmt_pre;
using color_type = typename detail::agg_scaling_traits<image_data_type>::color_type;
using renderer_base = agg::renderer_base<pixfmt_pre>;
using interpolator_type = typename detail::agg_scaling_traits<image_data_type>::interpolator_type;
std::size_t mesh_nx = std::ceil(source.data_.width()/double(mesh_size) + 1);
std::size_t mesh_ny = std::ceil(source.data_.height()/double(mesh_size) + 1);
constexpr std::size_t pixel_size = sizeof(pixel_type);
view_transform ts(source.width(), source.height(),
source_ext);
view_transform tt(target.width(), target.height(),
target_ext, offset_x, offset_y);
std::size_t mesh_nx = std::ceil(source.width()/double(mesh_size) + 1);
std::size_t mesh_ny = std::ceil(source.height()/double(mesh_size) + 1);
image_data<double> xs(mesh_nx, mesh_ny);
image_data<double> ys(mesh_nx, mesh_ny);
@ -69,81 +78,36 @@ void reproject_and_scale_raster(raster & target, raster const& source,
{
for (std::size_t i=0; i<mesh_nx; ++i)
{
xs(i,j) = std::min(i*mesh_size,source.data_.width());
ys(i,j) = std::min(j*mesh_size,source.data_.height());
xs(i,j) = std::min(i*mesh_size,source.width());
ys(i,j) = std::min(j*mesh_size,source.height());
ts.backward(&xs(i,j), &ys(i,j));
}
}
prj_trans.backward(xs.getData(), ys.getData(), nullptr, mesh_nx*mesh_ny);
// Initialize AGG objects
using pixfmt = agg::pixfmt_rgba32_pre;
using color_type = pixfmt::color_type;
using renderer_base = agg::renderer_base<pixfmt>;
agg::rasterizer_scanline_aa<> rasterizer;
agg::scanline_bin scanline;
agg::rendering_buffer buf((unsigned char*)target.data_.getData(),
target.data_.width(),
target.data_.height(),
target.data_.width()*4);
pixfmt pixf(buf);
agg::rendering_buffer buf(target.getBytes(),
target.width(),
target.height(),
target.width() * pixel_size);
pixfmt_pre pixf(buf);
renderer_base rb(pixf);
rasterizer.clip_box(0, 0, target.data_.width(), target.data_.height());
rasterizer.clip_box(0, 0, target.width(), target.height());
agg::rendering_buffer buf_tile(
(unsigned char*)source.data_.getData(),
source.data_.width(),
source.data_.height(),
source.data_.width() * 4);
const_cast<unsigned char*>(source.getBytes()),
source.width(),
source.height(),
source.width() * pixel_size);
pixfmt pixf_tile(buf_tile);
pixfmt_pre pixf_tile(buf_tile);
using img_accessor_type = agg::image_accessor_clone<pixfmt>;
using img_accessor_type = agg::image_accessor_clone<pixfmt_pre>;
img_accessor_type ia(pixf_tile);
agg::span_allocator<color_type> sa;
// Initialize filter
agg::image_filter_lut filter;
switch(scaling_method)
{
case SCALING_NEAR: break;
case SCALING_BILINEAR:
filter.calculate(agg::image_filter_bilinear(), true); break;
case SCALING_BICUBIC:
filter.calculate(agg::image_filter_bicubic(), true); break;
case SCALING_SPLINE16:
filter.calculate(agg::image_filter_spline16(), true); break;
case SCALING_SPLINE36:
filter.calculate(agg::image_filter_spline36(), true); break;
case SCALING_HANNING:
filter.calculate(agg::image_filter_hanning(), true); break;
case SCALING_HAMMING:
filter.calculate(agg::image_filter_hamming(), true); break;
case SCALING_HERMITE:
filter.calculate(agg::image_filter_hermite(), true); break;
case SCALING_KAISER:
filter.calculate(agg::image_filter_kaiser(), true); break;
case SCALING_QUADRIC:
filter.calculate(agg::image_filter_quadric(), true); break;
case SCALING_CATROM:
filter.calculate(agg::image_filter_catrom(), true); break;
case SCALING_GAUSSIAN:
filter.calculate(agg::image_filter_gaussian(), true); break;
case SCALING_BESSEL:
filter.calculate(agg::image_filter_bessel(), true); break;
case SCALING_MITCHELL:
filter.calculate(agg::image_filter_mitchell(), true); break;
case SCALING_SINC:
filter.calculate(agg::image_filter_sinc(source.get_filter_factor()), true); break;
case SCALING_LANCZOS:
filter.calculate(agg::image_filter_lanczos(source.get_filter_factor()), true); break;
case SCALING_BLACKMAN:
filter.calculate(agg::image_filter_blackman(source.get_filter_factor()), true); break;
}
// Project mesh cells into target interpolating raster inside each one
for(std::size_t j = 0; j < mesh_ny - 1; ++j)
for (std::size_t j = 0; j < mesh_ny - 1; ++j)
{
for (std::size_t i = 0; i < mesh_nx - 1; ++i)
{
@ -166,33 +130,97 @@ void reproject_and_scale_raster(raster & target, raster const& source,
std::size_t y0 = j * mesh_size;
std::size_t x1 = (i+1) * mesh_size;
std::size_t y1 = (j+1) * mesh_size;
x1 = std::min(x1, source.data_.width());
y1 = std::min(y1, source.data_.height());
x1 = std::min(x1, source.width());
y1 = std::min(y1, source.height());
agg::trans_affine tr(polygon, x0, y0, x1, y1);
if (tr.is_valid())
{
using interpolator_type = agg::span_interpolator_linear<agg::trans_affine>;
interpolator_type interpolator(tr);
if (scaling_method == SCALING_NEAR)
{
using span_gen_type = agg::span_image_filter_rgba_nn
<img_accessor_type, interpolator_type>;
using span_gen_type = typename detail::agg_scaling_traits<image_data_type>::span_image_filter;
span_gen_type sg(ia, interpolator);
agg::render_scanlines_bin(rasterizer, scanline, rb,
sa, sg);
agg::render_scanlines_bin(rasterizer, scanline, rb, sa, sg);
}
else
{
using span_gen_type = agg::span_image_resample_rgba_affine
<img_accessor_type>;
using span_gen_type = typename detail::agg_scaling_traits<image_data_type>::span_image_resample_affine;
agg::image_filter_lut filter;
detail::set_scaling_method(filter, scaling_method, filter_factor);
span_gen_type sg(ia, interpolator, filter);
agg::render_scanlines_bin(rasterizer, scanline, rb,
sa, sg);
agg::render_scanlines_bin(rasterizer, scanline, rb, sa, sg);
}
}
}
}
}
namespace detail {
struct warp_image_visitor : util::static_visitor<void>
{
warp_image_visitor (raster & target_raster, proj_transform const& prj_trans, box2d<double> const& source_ext,
double offset_x, double offset_y, unsigned mesh_size,
scaling_method_e scaling_method, double filter_factor)
: target_raster_(target_raster),
prj_trans_(prj_trans),
source_ext_(source_ext),
offset_x_(offset_x),
offset_y_(offset_y),
mesh_size_(mesh_size),
scaling_method_(scaling_method),
filter_factor_(filter_factor) {}
void operator() (image_data_null const&) {}
template <typename T>
void operator() (T const& source)
{
using image_data_type = T;
//source and target image data types must match
if (target_raster_.data_.template is<image_data_type>())
{
image_data_type & target = util::get<image_data_type>(target_raster_.data_);
warp_image (target, source, prj_trans_, target_raster_.ext_, source_ext_,
offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_);
}
}
raster & target_raster_;
proj_transform const& prj_trans_;
box2d<double> const& source_ext_;
double offset_x_;
double offset_y_;
unsigned mesh_size_;
scaling_method_e scaling_method_;
double filter_factor_;
};
}
void reproject_and_scale_raster(raster & target, raster const& source,
proj_transform const& prj_trans,
double offset_x, double offset_y,
unsigned mesh_size,
scaling_method_e scaling_method)
{
detail::warp_image_visitor warper(target, prj_trans, source.ext_, offset_x, offset_y, mesh_size,
scaling_method, source.get_filter_factor());
util::apply_visitor(warper, source.data_);
}
template MAPNIK_DECL void warp_image (image_data_rgba8&, image_data_rgba8 const&, proj_transform const&,
box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double);
template MAPNIK_DECL void warp_image (image_data_gray8&, image_data_gray8 const&, proj_transform const&,
box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double);
template MAPNIK_DECL void warp_image (image_data_gray16&, image_data_gray16 const&, proj_transform const&,
box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double);
template MAPNIK_DECL void warp_image (image_data_gray32f&, image_data_gray32f const&, proj_transform const&,
box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double);
}// namespace mapnik

View file

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

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>(black,white)), to_string(black) );
// https://github.com/mapnik/mapnik/issues/1452#issuecomment-8154646
color near_white(254,254,254,254); // Source
color near_trans(1,1,1,1); // Dest
color expected_color(252,252,252,255); // expected result
BOOST_TEST_EQ( to_string(blend<source_over_old_agg>(near_white,near_trans)), to_string(color(252,252,252,254)) );
color expected_color(253,253,253,255); // expected result
BOOST_TEST_EQ( to_string(blend<source_over_old_agg>(near_white,near_trans)), to_string(color(253,253,253,254)) );
BOOST_TEST_EQ( to_string(blend<source_over>(near_white,near_trans)), to_string(expected_color) );
BOOST_TEST_EQ( to_string(normal_blend(near_white,near_trans)), to_string(expected_color) );

View file

@ -1,5 +1,7 @@
#include <boost/detail/lightweight_test.hpp>
#include <iostream>
#include <mapnik/graphics.hpp>
#include <mapnik/image_data.hpp>
#include <mapnik/image_reader.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/util/fs.hpp>
@ -38,6 +40,26 @@ int main(int argc, char** argv)
}
#endif
try
{
mapnik::image_32 im(-10,-10); // should throw rather than overflow
BOOST_TEST( im.width() < 10 ); // should not get here, but if we did this test should fail
}
catch (std::exception const& ex)
{
BOOST_TEST( true ); // should hit bad alloc here
}
try
{
mapnik::image_data_rgba8 im(-10,-10); // should throw rather than overflow
BOOST_TEST( im.width() < 10 ); // should not get here, but if we did this test should fail
}
catch (std::exception const& ex)
{
BOOST_TEST( true ); // should hit bad alloc here
}
#if defined(HAVE_PNG)
should_throw = "./tests/cpp_tests/data/blank.png";
BOOST_TEST( mapnik::util::exists( should_throw ) );

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

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