Added new image_cast method and added its bindings to python, added two new properities to images: offset and scaling. Added way to cast between image types with offset and scaling. Added new unit tests for color and casting. Made it so that pixel setting doesn't result in overflows or underflows. Made the return of get_pixel, dynamic based on what is passed to it. Added new methods for setting pixels that are doubles and ints.

This commit is contained in:
Blake Thompson 2015-01-28 20:20:14 -06:00
parent 939e53e70b
commit de99180a44
15 changed files with 882 additions and 117 deletions

View file

@ -38,6 +38,7 @@
#include <mapnik/color.hpp>
#include <mapnik/palette.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/image_cast.hpp>
#include <mapnik/image_reader.hpp>
#include <mapnik/image_compositing.hpp>
#include <mapnik/image_view_any.hpp>
@ -126,16 +127,56 @@ void background(mapnik::image_any & im, mapnik::color const& c)
mapnik::fill(im, c);
}
void compare(mapnik::image_any const& im1, mapnik::image_any const& im2, double threshold, bool alpha)
std::shared_ptr<image_any> cast(mapnik::image_any const& im, mapnik::image_dtype type, double offset, double scaling)
{
mapnik::compare(im1, im2, threshold, alpha);
return std::make_shared<image_any>(std::move(mapnik::image_cast(im, type, offset, scaling)));
}
uint32_t get_pixel(mapnik::image_any const& im, unsigned x, unsigned y)
unsigned compare(mapnik::image_any const& im1, mapnik::image_any const& im2, double threshold, bool alpha)
{
return mapnik::compare(im1, im2, threshold, alpha);
}
struct get_pixel_visitor
{
get_pixel_visitor(unsigned x, unsigned y)
: x_(x), y_(y) {}
PyObject* operator() (mapnik::image_null const&)
{
throw std::runtime_error("Can not return a null image from a pixel (shouldn't have reached here)");
}
PyObject* operator() (mapnik::image_rgba8 const& im)
{
return PyInt_FromLong(mapnik::get_pixel<uint32_t>(im, x_, y_));
}
PyObject* operator() (mapnik::image_gray8 const& im)
{
return PyInt_FromLong(mapnik::get_pixel<uint8_t>(im, x_, y_));
}
PyObject* operator() (mapnik::image_gray16 const& im)
{
return PyInt_FromLong(mapnik::get_pixel<uint16_t>(im, x_, y_));
}
PyObject* operator() (mapnik::image_gray32f const& im)
{
return PyFloat_FromDouble(mapnik::get_pixel<double>(im, x_, y_));
}
private:
unsigned x_;
unsigned y_;
};
PyObject* get_pixel(mapnik::image_any const& im, unsigned x, unsigned y)
{
if (x < static_cast<unsigned>(im.width()) && y < static_cast<unsigned>(im.height()))
{
return mapnik::get_pixel<mapnik::image_any, uint32_t>(im, x, y);
return mapnik::util::apply_visitor(get_pixel_visitor(x, y), im);
}
PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions");
boost::python::throw_error_already_set();
@ -153,7 +194,7 @@ mapnik::color get_pixel_color(mapnik::image_any const& im, unsigned x, unsigned
return 0;
}
void set_pixel(mapnik::image_any & im, unsigned x, unsigned y, mapnik::color const& c)
void set_pixel_color(mapnik::image_any & im, unsigned x, unsigned y, mapnik::color const& c)
{
if (x >= static_cast<int>(im.width()) && y >= static_cast<int>(im.height()))
{
@ -164,6 +205,28 @@ void set_pixel(mapnik::image_any & im, unsigned x, unsigned y, mapnik::color con
mapnik::set_pixel(im, x, y, c);
}
void set_pixel_double(mapnik::image_any & im, unsigned x, unsigned y, double val)
{
if (x >= static_cast<int>(im.width()) && y >= static_cast<int>(im.height()))
{
PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions");
boost::python::throw_error_already_set();
return;
}
mapnik::set_pixel(im, x, y, val);
}
void set_pixel_int(mapnik::image_any & im, unsigned x, unsigned y, int val)
{
if (x >= static_cast<int>(im.width()) && y >= static_cast<int>(im.height()))
{
PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions");
boost::python::throw_error_already_set();
return;
}
mapnik::set_pixel(im, x, y, val);
}
std::shared_ptr<image_any> open_from_file(std::string const& filename)
{
boost::optional<std::string> type = type_from_filename(filename);
@ -348,10 +411,26 @@ void export_image()
arg("threshold")=0.0,
arg("alpha")=true
))
.def("cast",&cast,
( arg("self"),
arg("type"),
arg("offset")=0.0,
arg("scaling")=1.0
))
.add_property("offset",
&image_any::get_offset,
&image_any::set_offset,
"Gets or sets the offset component.\n")
.add_property("scaling",
&image_any::get_scaling,
&image_any::set_scaling,
"Gets or sets the offset component.\n")
.def("premultiplied",&premultiplied)
.def("premultiply",&premultiply)
.def("demultiply",&demultiply)
.def("set_pixel",&set_pixel)
.def("set_pixel",&set_pixel_color)
.def("set_pixel",&set_pixel_double)
.def("set_pixel",&set_pixel_int)
.def("get_pixel",&get_pixel)
.def("get_pixel_color",&get_pixel_color)
.def("clear",&clear)

View file

@ -29,6 +29,7 @@
#include <algorithm>
#include <cassert>
#include <stdexcept>
#include <iostream>
namespace mapnik {
@ -121,11 +122,21 @@ class image
public:
using pixel_type = T;
static constexpr std::size_t pixel_size = sizeof(pixel_type);
private:
detail::image_dimensions<max_size> dimensions_;
detail::buffer buffer_;
pixel_type *pData_;
double offset_;
double scaling_;
bool premultiplied_alpha_;
bool painted_;
public:
image(int width, int height, bool initialize = true, bool premultiplied = false, bool painted = false)
: dimensions_(width, height),
buffer_(dimensions_.width() * dimensions_.height() * pixel_size),
pData_(reinterpret_cast<pixel_type*>(buffer_.data())),
offset_(0.0),
scaling_(1.0),
premultiplied_alpha_(premultiplied),
painted_(painted)
{
@ -136,6 +147,8 @@ public:
: dimensions_(rhs.dimensions_),
buffer_(rhs.buffer_),
pData_(reinterpret_cast<pixel_type*>(buffer_.data())),
offset_(rhs.offset_),
scaling_(rhs.scaling_),
premultiplied_alpha_(rhs.premultiplied_alpha_),
painted_(rhs.painted_)
{}
@ -144,6 +157,8 @@ public:
: dimensions_(std::move(rhs.dimensions_)),
buffer_(std::move(rhs.buffer_)),
pData_(reinterpret_cast<pixel_type*>(buffer_.data())),
offset_(rhs.offset_),
scaling_(rhs.scaling_),
premultiplied_alpha_(rhs.premultiplied_alpha_),
painted_(rhs.painted_)
{
@ -161,6 +176,8 @@ public:
{
std::swap(dimensions_, rhs.dimensions_);
std::swap(buffer_, rhs.buffer_);
std::swap(offset_, rhs.offset_);
std::swap(scaling_, rhs.scaling_);
std::swap(premultiplied_alpha_, rhs.premultiplied_alpha_);
std::swap(painted_, rhs.painted_);
}
@ -249,6 +266,31 @@ public:
std::copy(buf, buf + (x1 - x0), pData_ + row * dimensions_.width() + x0);
}
inline double get_offset() const
{
return offset_;
}
inline void set_offset(double set)
{
offset_ = set;
}
inline double get_scaling() const
{
return scaling_;
}
inline void set_scaling(double set)
{
if (set != 0.0)
{
scaling_ = set;
return;
}
std::clog << "Can not set scaling to 0.0, offset not set." << std::endl;
}
inline bool get_premultiplied() const
{
return premultiplied_alpha_;
@ -268,13 +310,6 @@ public:
{
return painted_;
}
private:
detail::image_dimensions<max_size> dimensions_;
detail::buffer buffer_;
pixel_type *pData_;
bool premultiplied_alpha_;
bool painted_;
};
using image_rgba8 = image<std::uint32_t>;

View file

@ -38,8 +38,12 @@ struct image_null
std::size_t width() const { return 0; }
std::size_t height() const { return 0; }
bool painted() const { return false; }
double get_offset() const { return 0.0; }
void set_offset(double) {}
double get_scaling() const { return 1.0; }
void set_scaling(double) {}
bool get_premultiplied() const { return false; }
void set_premultiplied(bool) const {}
void set_premultiplied(bool) {}
void set(pixel_type const&) { throw std::runtime_error("Can not set values for null image"); }
pixel_type& operator() (std::size_t, std::size_t)
{
@ -139,6 +143,51 @@ struct get_any_row_size_visitor
return data.getRowSize();
}
};
struct get_offset_visitor
{
template <typename T>
double operator() (T const& data) const
{
return data.get_offset();
}
};
struct get_scaling_visitor
{
template <typename T>
double operator() (T const& data) const
{
return data.get_scaling();
}
};
struct set_offset_visitor
{
set_offset_visitor(double val)
: val_(val) {}
template <typename T>
void operator() (T & data)
{
data.set_offset(val_);
}
private:
double val_;
};
struct set_scaling_visitor
{
set_scaling_visitor(double val)
: val_(val) {}
template <typename T>
void operator() (T & data)
{
data.set_scaling(val_);
}
private:
double val_;
};
} // namespace detail
struct image_any : image_base
@ -196,6 +245,26 @@ struct image_any : image_base
{
return util::apply_visitor(detail::get_any_row_size_visitor(),*this);
}
double get_offset() const
{
return util::apply_visitor(detail::get_offset_visitor(),*this);
}
double get_scaling() const
{
return util::apply_visitor(detail::get_scaling_visitor(),*this);
}
void set_offset(double val)
{
util::apply_visitor(detail::set_offset_visitor(val),*this);
}
void set_scaling(double val)
{
util::apply_visitor(detail::set_scaling_visitor(val),*this);
}
};
inline image_any create_image_any(int width,

View file

@ -20,43 +20,32 @@
*
*****************************************************************************/
// mapnik
#include <mapnik/image_convert.hpp>
#include <mapnik/image.hpp>
#ifndef MAPNIK_IMAGE_CAST_HPP
#define MAPNIK_IMAGE_CAST_HPP
#include <mapnik/image_any.hpp>
#include <mapnik/config.hpp>
namespace mapnik
{
namespace detail
{
template <typename T>
MAPNIK_DECL T image_cast(image_any const&, double offset = 0.0, double scaling = 1.0);
template <typename T0>
struct visitor_convert
{
using dst_type = typename T0::pixel_type;
template <typename T1>
T0 operator() (T1 const& src)
{
T0 dst(src.width(), src.height());
for (unsigned y = 0; y < dst.height(); ++y)
{
for (unsigned x = 0; x < dst.width(); ++x)
{
dst(x,y) = static_cast<dst_type>(src(x,y));
}
}
return T0(std::move(dst));
}
};
template <typename T>
MAPNIK_DECL T image_cast(image_rgba8 const&, double offset = 0.0, double scaling = 1.0);
} // end detail ns
template <typename T>
MAPNIK_DECL T image_cast(image_gray8 const&, double offset = 0.0, double scaling = 1.0);
template <typename T1, typename T2>
MAPNIK_DECL T2 convert_image(T1 const& data)
{
detail::visitor_convert<T2> visit;
return visit(data);
}
template <typename T>
MAPNIK_DECL T image_cast(image_gray16 const&, double offset = 0.0, double scaling = 1.0);
template <typename T>
MAPNIK_DECL T image_cast(image_gray32f const&, double offset = 0.0, double scaling = 1.0);
MAPNIK_DECL image_any image_cast(image_any const&, image_dtype type, double offset = 0.0, double scaling = 1.0);
} // end mapnik ns
#endif // MAPNIK_IMAGE_CAST_HPP

View file

@ -1,36 +0,0 @@
/*****************************************************************************
*
* 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_CONVERT_HPP
#define MAPNIK_IMAGE_CONVERT_HPP
#include <mapnik/config.hpp>
namespace mapnik
{
template <typename T1, typename T2>
MAPNIK_DECL T2 convert_image(T1 const& data);
} // end mapnik ns
#endif // MAPNIK_IMAGE_CONVERT_HPP

View file

@ -149,9 +149,33 @@ MAPNIK_DECL bool check_bounds (T const& data, std::size_t x, std::size_t y)
template <typename T>
MAPNIK_DECL void composite_pixel(T & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity );
template <typename T>
MAPNIK_DECL void set_pixel(image_rgba8 & data, std::size_t x, std::size_t y, T const& val);
template <typename T>
MAPNIK_DECL void set_pixel(image_gray8 & data, std::size_t x, std::size_t y, T const& val);
template <typename T>
MAPNIK_DECL void set_pixel(image_gray16 & data, std::size_t x, std::size_t y, T const& val);
template <typename T>
MAPNIK_DECL void set_pixel(image_gray32f & data, std::size_t x, std::size_t y, T const& val);
template <typename T1, typename T2>
MAPNIK_DECL void set_pixel(T1 & data, std::size_t x, std::size_t y, T2 const& val);
template <typename T>
MAPNIK_DECL T get_pixel(image_rgba8 const& data, std::size_t x, std::size_t y);
template <typename T>
MAPNIK_DECL T get_pixel(image_gray8 const& data, std::size_t x, std::size_t y);
template <typename T>
MAPNIK_DECL T get_pixel(image_gray16 const& data, std::size_t x, std::size_t y);
template <typename T>
MAPNIK_DECL T get_pixel(image_gray32f const& data, std::size_t x, std::size_t y);
template <typename T1, typename T2>
MAPNIK_DECL T2 get_pixel(T1 const& data, std::size_t x, std::size_t y);

View file

@ -121,6 +121,16 @@ public:
return data_.get_premultiplied();
}
inline double get_offset() const
{
return data_.get_offset();
}
inline double get_scaling() const
{
return data_.get_scaling();
}
private:
unsigned x_;
unsigned y_;

View file

@ -70,6 +70,33 @@ struct get_view_row_size_visitor
return data.getRowSize();
}
};
struct get_view_premultiplied_visitor
{
template <typename T>
bool operator()(T const& data) const
{
return data.get_premultiplied();
}
};
struct get_view_offset_visitor
{
template <typename T>
double operator()(T const& data) const
{
return data.get_offset();
}
};
struct get_view_scaling_visitor
{
template <typename T>
double operator()(T const& data) const
{
return data.get_scaling();
}
};
} // namespace detail
struct image_view_any : image_view_base
@ -99,6 +126,21 @@ struct image_view_any : image_view_base
{
return util::apply_visitor(detail::get_view_row_size_visitor(),*this);
}
bool get_premultiplied() const
{
return util::apply_visitor(detail::get_view_premultiplied_visitor(),*this);
}
double get_offset() const
{
return util::apply_visitor(detail::get_view_offset_visitor(),*this);
}
double get_scaling() const
{
return util::apply_visitor(detail::get_view_scaling_visitor(),*this);
}
};
}

View file

@ -152,7 +152,7 @@ source = Split(
miniz_png.cpp
color.cpp
conversions.cpp
image_convert.cpp
image_cast.cpp
image_compositing.cpp
image_scaling.cpp
box2d.cpp

228
src/image_cast.cpp Normal file
View file

@ -0,0 +1,228 @@
/*****************************************************************************
*
* 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
*
*****************************************************************************/
// mapnik
#include <mapnik/image_cast.hpp>
#include <mapnik/image.hpp>
#include <mapnik/image_any.hpp>
// boost
#include <boost/numeric/conversion/cast.hpp>
using boost::numeric_cast;
using boost::numeric::positive_overflow;
using boost::numeric::negative_overflow;
namespace mapnik
{
namespace detail
{
template <typename T0>
struct visitor_image_cast
{
using dst_type = typename T0::pixel_type;
T0 operator() (image_null const&)
{
throw std::runtime_error("Can not cast a null image");
}
T0 operator() (T0 const& src)
{
return T0(src);
}
template <typename T1>
T0 operator() (T1 const& src)
{
T0 dst(src.width(), src.height(), false);
for (unsigned y = 0; y < dst.height(); ++y)
{
for (unsigned x = 0; x < dst.width(); ++x)
{
try
{
dst(x,y) = numeric_cast<dst_type>(src(x,y));
}
catch(negative_overflow&)
{
dst(x,y) = std::numeric_limits<dst_type>::min();
}
catch(positive_overflow&)
{
dst(x,y) = std::numeric_limits<dst_type>::max();
}
}
}
return T0(std::move(dst));
}
};
template <typename T0>
struct visitor_image_cast_so
{
using dst_type = typename T0::pixel_type;
visitor_image_cast_so(double offset, double scaling)
: offset_(offset), scaling_(scaling) {}
T0 operator() (image_null const&)
{
throw std::runtime_error("Can not cast a null image");
}
T0 operator() (T0 const& src)
{
return T0(src);
}
template <typename T1>
T0 operator() (T1 const& src)
{
double src_offset = src.get_offset();
double src_scaling = src.get_scaling();
T0 dst(src.width(), src.height(), false);
dst.set_scaling(scaling_);
dst.set_offset(offset_);
for (unsigned y = 0; y < dst.height(); ++y)
{
for (unsigned x = 0; x < dst.width(); ++x)
{
double scaled_src_val = (numeric_cast<double>(src(x,y)) * src_scaling) + src_offset;
double dst_val = (scaled_src_val - offset_) / scaling_;
try
{
dst(x,y) = numeric_cast<dst_type>(dst_val);
}
catch(negative_overflow&)
{
dst(x,y) = std::numeric_limits<dst_type>::min();
}
catch(positive_overflow&)
{
dst(x,y) = std::numeric_limits<dst_type>::max();
}
}
}
return T0(std::move(dst));
}
private:
double offset_;
double scaling_;
};
} // end detail ns
template <typename T>
MAPNIK_DECL T image_cast(image_any const& data, double offset, double scaling)
{
if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0)
{
return util::apply_visitor(detail::visitor_image_cast<T>(), data);
}
else
{
return util::apply_visitor(detail::visitor_image_cast_so<T>(offset, scaling), data);
}
}
template <typename T>
MAPNIK_DECL T image_cast(image_rgba8 const& data, double offset, double scaling)
{
if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0)
{
detail::visitor_image_cast<T> visit;
return visit(data);
}
else
{
detail::visitor_image_cast_so<T> visit(offset, scaling);
return visit(data);
}
}
template <typename T>
MAPNIK_DECL T image_cast(image_gray8 const& data, double offset, double scaling)
{
if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0)
{
detail::visitor_image_cast<T> visit;
return visit(data);
}
else
{
detail::visitor_image_cast_so<T> visit(offset, scaling);
return visit(data);
}
}
template <typename T>
MAPNIK_DECL T image_cast(image_gray16 const& data, double offset, double scaling)
{
if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0)
{
detail::visitor_image_cast<T> visit;
return visit(data);
}
else
{
detail::visitor_image_cast_so<T> visit(offset, scaling);
return visit(data);
}
}
template <typename T>
MAPNIK_DECL T image_cast(image_gray32f const& data, double offset, double scaling)
{
if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0)
{
detail::visitor_image_cast<T> visit;
return visit(data);
}
else
{
detail::visitor_image_cast_so<T> visit(offset, scaling);
return visit(data);
}
}
MAPNIK_DECL image_any image_cast(image_any const& data, image_dtype type, double offset, double scaling)
{
switch (type)
{
case image_dtype_rgba8:
return image_any(std::move(image_cast<image_rgba8>(data, offset, scaling)));
case image_dtype_gray8:
return image_any(std::move(image_cast<image_gray8>(data, offset, scaling)));
case image_dtype_gray16:
return image_any(std::move(image_cast<image_gray16>(data, offset, scaling)));
case image_dtype_gray32f:
return image_any(std::move(image_cast<image_gray32f>(data, offset, scaling)));
case image_dtype_null:
throw std::runtime_error("Can not cast a null image");
}
throw std::runtime_error("Unknown image type passed");
}
} // end mapnik ns

View file

@ -46,6 +46,13 @@
#include <sstream>
#include <algorithm>
// boost
#include <boost/numeric/conversion/cast.hpp>
using boost::numeric_cast;
using boost::numeric::positive_overflow;
using boost::numeric::negative_overflow;
namespace mapnik
{
@ -1089,7 +1096,19 @@ struct visitor_set_pixel
void operator() (T2 & data)
{
using pixel_type = typename T2::pixel_type;
pixel_type val = static_cast<pixel_type>(val_);
pixel_type val;
try
{
val = numeric_cast<pixel_type>(val_);
}
catch(negative_overflow&)
{
val = std::numeric_limits<pixel_type>::min();
}
catch(positive_overflow&)
{
val = std::numeric_limits<pixel_type>::max();
}
if (check_bounds(data, x_, y_))
{
data(x_, y_) = val;
@ -1160,31 +1179,74 @@ template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, int8_
template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, float const&);
template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, double const&);
// Temporary remove these later!
template <>
MAPNIK_DECL void set_pixel<image_rgba8, color> (image_rgba8 & data, std::size_t x, std::size_t y, color const& val)
template <typename T>
MAPNIK_DECL void set_pixel (image_rgba8 & data, std::size_t x, std::size_t y, T const& val)
{
detail::visitor_set_pixel<color> visitor(x, y, val);
detail::visitor_set_pixel<T> visitor(x, y, val);
visitor(data);
}
// Temporary remove these later!
template <>
MAPNIK_DECL void set_pixel<image_rgba8, uint32_t> (image_rgba8 & data, std::size_t x, std::size_t y, uint32_t const& val)
template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, color const&);
template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, uint32_t const&);
template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, int32_t const&);
template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, uint16_t const&);
template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, int16_t const&);
template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, uint8_t const&);
template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, int8_t const&);
template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, float const&);
template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, double const&);
template <typename T>
MAPNIK_DECL void set_pixel (image_gray8 & data, std::size_t x, std::size_t y, T const& val)
{
detail::visitor_set_pixel<uint32_t> visitor(x, y, val);
detail::visitor_set_pixel<T> visitor(x, y, val);
visitor(data);
}
// Temporary remove these later!
template <>
MAPNIK_DECL void set_pixel<image_rgba8, int32_t> (image_rgba8 & data, std::size_t x, std::size_t y, int32_t const& val)
template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, color const&);
template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, uint32_t const&);
template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, int32_t const&);
template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, uint16_t const&);
template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, int16_t const&);
template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, uint8_t const&);
template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, int8_t const&);
template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, float const&);
template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, double const&);
template <typename T>
MAPNIK_DECL void set_pixel (image_gray16 & data, std::size_t x, std::size_t y, T const& val)
{
detail::visitor_set_pixel<int32_t> visitor(x, y, val);
detail::visitor_set_pixel<T> visitor(x, y, val);
visitor(data);
}
template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, color const&);
template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, uint32_t const&);
template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, int32_t const&);
template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, uint16_t const&);
template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, int16_t const&);
template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, uint8_t const&);
template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, int8_t const&);
template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, float const&);
template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, double const&);
template <typename T>
MAPNIK_DECL void set_pixel (image_gray32f & data, std::size_t x, std::size_t y, T const& val)
{
detail::visitor_set_pixel<T> visitor(x, y, val);
visitor(data);
}
template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, color const&);
template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, uint32_t const&);
template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, int32_t const&);
template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, uint16_t const&);
template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, int16_t const&);
template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, uint8_t const&);
template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, int8_t const&);
template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, float const&);
template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, double const&);
namespace detail {
template <typename T1>
@ -1263,31 +1325,74 @@ template MAPNIK_DECL int8_t get_pixel(image_view_any const&, std::size_t, std::s
template MAPNIK_DECL float get_pixel(image_view_any const&, std::size_t, std::size_t);
template MAPNIK_DECL double get_pixel(image_view_any const&, std::size_t, std::size_t);
// Temporary remove these later!
template <>
MAPNIK_DECL color get_pixel<image_rgba8, color> (image_rgba8 const& data, std::size_t x, std::size_t y)
template <typename T>
MAPNIK_DECL T get_pixel (image_rgba8 const& data, std::size_t x, std::size_t y)
{
detail::visitor_get_pixel<color> visitor(x, y);
detail::visitor_get_pixel<T> visitor(x, y);
return visitor(data);
}
// Temporary remove these later!
template <>
MAPNIK_DECL uint32_t get_pixel<image_rgba8, uint32_t> (image_rgba8 const& data, std::size_t x, std::size_t y)
template MAPNIK_DECL color get_pixel(image_rgba8 const&, std::size_t, std::size_t);
template MAPNIK_DECL uint32_t get_pixel(image_rgba8 const&, std::size_t, std::size_t);
template MAPNIK_DECL int32_t get_pixel(image_rgba8 const&, std::size_t, std::size_t);
template MAPNIK_DECL uint16_t get_pixel(image_rgba8 const&, std::size_t, std::size_t);
template MAPNIK_DECL int16_t get_pixel(image_rgba8 const&, std::size_t, std::size_t);
template MAPNIK_DECL uint8_t get_pixel(image_rgba8 const&, std::size_t, std::size_t);
template MAPNIK_DECL int8_t get_pixel(image_rgba8 const&, std::size_t, std::size_t);
template MAPNIK_DECL float get_pixel(image_rgba8 const&, std::size_t, std::size_t);
template MAPNIK_DECL double get_pixel(image_rgba8 const&, std::size_t, std::size_t);
template <typename T>
MAPNIK_DECL T get_pixel (image_gray8 const& data, std::size_t x, std::size_t y)
{
detail::visitor_get_pixel<uint32_t> visitor(x, y);
detail::visitor_get_pixel<T> visitor(x, y);
return visitor(data);
}
// Temporary remove these later!
template <>
MAPNIK_DECL int32_t get_pixel<image_rgba8, int32_t> (image_rgba8 const& data, std::size_t x, std::size_t y)
template MAPNIK_DECL color get_pixel(image_gray8 const&, std::size_t, std::size_t);
template MAPNIK_DECL uint32_t get_pixel(image_gray8 const&, std::size_t, std::size_t);
template MAPNIK_DECL int32_t get_pixel(image_gray8 const&, std::size_t, std::size_t);
template MAPNIK_DECL uint16_t get_pixel(image_gray8 const&, std::size_t, std::size_t);
template MAPNIK_DECL int16_t get_pixel(image_gray8 const&, std::size_t, std::size_t);
template MAPNIK_DECL uint8_t get_pixel(image_gray8 const&, std::size_t, std::size_t);
template MAPNIK_DECL int8_t get_pixel(image_gray8 const&, std::size_t, std::size_t);
template MAPNIK_DECL float get_pixel(image_gray8 const&, std::size_t, std::size_t);
template MAPNIK_DECL double get_pixel(image_gray8 const&, std::size_t, std::size_t);
template <typename T>
MAPNIK_DECL T get_pixel (image_gray16 const& data, std::size_t x, std::size_t y)
{
detail::visitor_get_pixel<int32_t> visitor(x, y);
detail::visitor_get_pixel<T> visitor(x, y);
return visitor(data);
}
template MAPNIK_DECL color get_pixel(image_gray16 const&, std::size_t, std::size_t);
template MAPNIK_DECL uint32_t get_pixel(image_gray16 const&, std::size_t, std::size_t);
template MAPNIK_DECL int32_t get_pixel(image_gray16 const&, std::size_t, std::size_t);
template MAPNIK_DECL uint16_t get_pixel(image_gray16 const&, std::size_t, std::size_t);
template MAPNIK_DECL int16_t get_pixel(image_gray16 const&, std::size_t, std::size_t);
template MAPNIK_DECL uint8_t get_pixel(image_gray16 const&, std::size_t, std::size_t);
template MAPNIK_DECL int8_t get_pixel(image_gray16 const&, std::size_t, std::size_t);
template MAPNIK_DECL float get_pixel(image_gray16 const&, std::size_t, std::size_t);
template MAPNIK_DECL double get_pixel(image_gray16 const&, std::size_t, std::size_t);
template <typename T>
MAPNIK_DECL T get_pixel (image_gray32f const& data, std::size_t x, std::size_t y)
{
detail::visitor_get_pixel<T> visitor(x, y);
return visitor(data);
}
template MAPNIK_DECL color get_pixel(image_gray32f const&, std::size_t, std::size_t);
template MAPNIK_DECL uint32_t get_pixel(image_gray32f const&, std::size_t, std::size_t);
template MAPNIK_DECL int32_t get_pixel(image_gray32f const&, std::size_t, std::size_t);
template MAPNIK_DECL uint16_t get_pixel(image_gray32f const&, std::size_t, std::size_t);
template MAPNIK_DECL int16_t get_pixel(image_gray32f const&, std::size_t, std::size_t);
template MAPNIK_DECL uint8_t get_pixel(image_gray32f const&, std::size_t, std::size_t);
template MAPNIK_DECL int8_t get_pixel(image_gray32f const&, std::size_t, std::size_t);
template MAPNIK_DECL float get_pixel(image_gray32f const&, std::size_t, std::size_t);
template MAPNIK_DECL double get_pixel(image_gray32f const&, std::size_t, std::size_t);
namespace detail
{

View file

@ -0,0 +1,95 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os, mapnik
from timeit import Timer, time
from nose.tools import *
from utilities import execution_path, run_all, get_unique_colors
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def test_image_16_8_simple():
im = mapnik.Image(2,2,mapnik.ImageType.gray16)
im.set_pixel(0,0, 256)
im.set_pixel(0,1, 999)
im.set_pixel(1,0, 5)
im.set_pixel(1,1, 2)
im2 = im.cast(mapnik.ImageType.gray8)
eq_(im2.get_pixel(0,0), 255)
eq_(im2.get_pixel(0,1), 255)
eq_(im2.get_pixel(1,0), 5)
eq_(im2.get_pixel(1,1), 2)
# Cast back!
im = im2.cast(mapnik.ImageType.gray16)
eq_(im.get_pixel(0,0), 255)
eq_(im.get_pixel(0,1), 255)
eq_(im.get_pixel(1,0), 5)
eq_(im.get_pixel(1,1), 2)
def test_image_32f_8_simple():
im = mapnik.Image(2,2,mapnik.ImageType.gray32f)
im.set_pixel(0,0, 120.1234)
im.set_pixel(0,1, -23.4)
im.set_pixel(1,0, 120.6)
im.set_pixel(1,1, 360.2)
im2 = im.cast(mapnik.ImageType.gray8)
eq_(im2.get_pixel(0,0), 120)
eq_(im2.get_pixel(0,1), 0)
eq_(im2.get_pixel(1,0), 120) # Notice this is truncated!
eq_(im2.get_pixel(1,1), 255)
def test_image_offset_and_scale():
im = mapnik.Image(2,2,mapnik.ImageType.gray16)
eq_(im.offset, 0.0)
eq_(im.scaling, 1.0)
im.offset = 1.0
im.scaling = 2.0
eq_(im.offset, 1.0)
eq_(im.scaling, 2.0)
def test_image_16_8_scale_and_offset():
im = mapnik.Image(2,2,mapnik.ImageType.gray16)
im.set_pixel(0,0, 256)
im.set_pixel(0,1, 258)
im.set_pixel(1,0, 99999)
im.set_pixel(1,1, 615)
offset = 255
scaling = 3
im2 = im.cast(mapnik.ImageType.gray8, offset, scaling)
eq_(im2.get_pixel(0,0), 0)
eq_(im2.get_pixel(0,1), 1)
eq_(im2.get_pixel(1,0), 255)
eq_(im2.get_pixel(1,1), 120)
# pixels will be a little off due to offsets in reverting!
im3 = im2.cast(mapnik.ImageType.gray16)
eq_(im3.get_pixel(0,0), 255) # Rounding error with ints
eq_(im3.get_pixel(0,1), 258) # same
eq_(im3.get_pixel(1,0), 1020) # The other one was way out of range for our scale/offset
eq_(im3.get_pixel(1,1), 615) # same
def test_image_16_32f_scale_and_offset():
im = mapnik.Image(2,2,mapnik.ImageType.gray16)
im.set_pixel(0,0, 256)
im.set_pixel(0,1, 258)
im.set_pixel(1,0, 0)
im.set_pixel(1,1, 615)
offset = 255
scaling = 3.2
im2 = im.cast(mapnik.ImageType.gray32f, offset, scaling)
eq_(im2.get_pixel(0,0), 0.3125)
eq_(im2.get_pixel(0,1), 0.9375)
eq_(im2.get_pixel(1,0), -79.6875)
eq_(im2.get_pixel(1,1), 112.5)
im3 = im2.cast(mapnik.ImageType.gray16)
eq_(im3.get_pixel(0,0), 256)
eq_(im3.get_pixel(0,1), 258)
eq_(im3.get_pixel(1,0), 0)
eq_(im3.get_pixel(1,1), 615)
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -0,0 +1,115 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os, mapnik
from timeit import Timer, time
from nose.tools import *
from utilities import execution_path, run_all, get_unique_colors
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def test_color_init():
c = mapnik.Color(12, 128, 255)
eq_(c.r, 12)
eq_(c.g, 128)
eq_(c.b, 255)
eq_(c.a, 255)
eq_(False, c.get_premultiplied())
c = mapnik.Color(16, 32, 64, 128)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(False, c.get_premultiplied())
c = mapnik.Color(16, 32, 64, 128,True)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(True, c.get_premultiplied())
c = mapnik.Color('rgba(16,32,64,0.5)')
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(False, c.get_premultiplied())
c = mapnik.Color('rgba(16,32,64,0.5)', True)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(True, c.get_premultiplied())
hex_str = '#10204080'
c = mapnik.Color(hex_str)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(hex_str, c.to_hex_string())
eq_(False, c.get_premultiplied())
c = mapnik.Color(hex_str, True)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(hex_str, c.to_hex_string())
eq_(True, c.get_premultiplied())
rgba_int = 2151686160
c = mapnik.Color(rgba_int)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(rgba_int, c.packed())
eq_(False, c.get_premultiplied())
c = mapnik.Color(rgba_int, True)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(rgba_int, c.packed())
eq_(True, c.get_premultiplied())
def test_color_properties():
c = mapnik.Color(16, 32, 64, 128)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
c.r = 17
eq_(c.r, 17)
c.g = 33
eq_(c.g, 33)
c.b = 65
eq_(c.b, 65)
c.a = 128
eq_(c.a, 128)
def test_color_premultiply():
c = mapnik.Color(16, 33, 255, 128)
eq_(c.premultiply(), True)
eq_(c.r, 8)
eq_(c.g, 17)
eq_(c.b, 128)
eq_(c.a, 128)
# Repeating it again should do nothing
eq_(c.premultiply(), False)
eq_(c.r, 8)
eq_(c.g, 17)
eq_(c.b, 128)
eq_(c.a, 128)
c.demultiply()
c.demultiply()
# This will not return the same values as before but we expect that
eq_(c.r,15)
eq_(c.g,33)
eq_(c.b,255)
eq_(c.a,128)
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -127,6 +127,16 @@ def test_set_and_get_pixel():
eq_(c0_pre.b, c1.b)
eq_(c0_pre.a, c1.a)
def test_pixel_overflow():
im = mapnik.Image(4,4,mapnik.ImageType.gray8)
im.set_pixel(0,0,256)
eq_(im.get_pixel(0,0),255)
def test_pixel_underflow():
im = mapnik.Image(4,4,mapnik.ImageType.gray8)
im.set_pixel(0,0,-1)
eq_(im.get_pixel(0,0),0)
@raises(IndexError)
def test_set_pixel_out_of_range_1():
im = mapnik.Image(4,4)

View file

@ -36,17 +36,17 @@ def compare_pixels(pixel1, pixel2, alpha=True, pixel_threshold=0):
def compare(actual, expected, alpha=True):
im1 = mapnik.Image.open(actual)
im2 = mapnik.Image.open(expected)
diff = 0
pixels = im1.width() * im1.height()
delta_pixels = (im2.width() * im2.height()) - pixels
#diff = 0
if delta_pixels != 0:
return delta_pixels
# TODO: convert to C++ to speed this up
for x in range(0,im1.width(),2):
for y in range(0,im1.height(),2):
if compare_pixels(im1.get_pixel(x,y),im2.get_pixel(x,y),alpha=alpha):
diff += 1
return diff
#for x in range(0,im1.width(),2):
# for y in range(0,im1.height(),2):
# if compare_pixels(im1.get_pixel(x,y),im2.get_pixel(x,y),alpha=alpha):
# diff += 1
#return diff
return im1.compare(im2, 0, alpha)
def compare_grids(actual, expected, threshold=0, alpha=True):
global errors