trim down image_32 - refs #2627
This commit is contained in:
parent
e4cb1b33a0
commit
acb3bb0821
6 changed files with 125 additions and 81 deletions
|
@ -44,6 +44,7 @@
|
|||
// cairo
|
||||
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
|
||||
#include <mapnik/cairo/cairo_context.hpp>
|
||||
#include <mapnik/cairo/cairo_image_util.hpp>
|
||||
#include <pycairo.h>
|
||||
#include <cairo.h>
|
||||
#endif
|
||||
|
@ -217,7 +218,8 @@ void composite(image_32 & dst, image_32 & src, mapnik::composite_mode_e mode, fl
|
|||
std::shared_ptr<image_32> from_cairo(PycairoSurface* py_surface)
|
||||
{
|
||||
mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer());
|
||||
std::shared_ptr<image_32> image_ptr = std::make_shared<image_32>(surface);
|
||||
std::shared_ptr<image_32> image_ptr = std::make_shared<image_32>(cairo_image_surface_get_width(&*surface), cairo_image_surface_get_height(&*surface));
|
||||
cairo_image_to_rgba8(image_ptr->data(), image_surface);
|
||||
return image_ptr;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#if defined(HAVE_CAIRO)
|
||||
#include <mapnik/cairo/cairo_renderer.hpp>
|
||||
#include <mapnik/cairo/cairo_image_util.hpp>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
@ -352,8 +353,9 @@ int main ( int, char** )
|
|||
cairo_surface_write_to_png(&*image_surface, "cairo-demo.png");
|
||||
// but we can also benefit from quantization by converting
|
||||
// to a mapnik image object and then saving that
|
||||
image_32 im(image_surface);
|
||||
save_to_file(im, "cairo-demo256.png","png8");
|
||||
mapnik::image_data_rgba8 im_data(cairo_image_surface_get_width(&*image_surface), cairo_image_surface_get_height(&*image_surface));
|
||||
cairo_image_to_rgba8(im_data, image_surface);
|
||||
save_to_file(im_data, "cairo-demo256.png","png8");
|
||||
cairo_surface_finish(&*image_surface);
|
||||
|
||||
std::cout << "Three maps have been rendered using Cairo in the current directory:\n"
|
||||
|
|
84
include/mapnik/cairo/cairo_image_util.hpp
Normal file
84
include/mapnik/cairo/cairo_image_util.hpp
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2015 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_CAIRO_IMAGE_UTIL_HPP
|
||||
#define MAPNIK_CAIRO_IMAGE_UTIL_HPP
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/image_data.hpp>
|
||||
#include <mapnik/cairo/cairo_context.hpp> // for cairo_surface_ptr
|
||||
|
||||
// stl
|
||||
#include <stdexcept>
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
static inline void cairo_image_to_rgba8(mapnik::image_data_rgba8 & data,
|
||||
cairo_surface_ptr const& surface)
|
||||
{
|
||||
if (cairo_image_surface_get_format(&*surface) != CAIRO_FORMAT_ARGB32)
|
||||
{
|
||||
throw std::runtime_error("Unable to convert this Cairo format to rgba8 image");
|
||||
}
|
||||
|
||||
if (cairo_image_surface_get_width(&*surface) != data.width() ||
|
||||
cairo_image_surface_get_height(&*surface) != data.height())
|
||||
{
|
||||
throw std::runtime_error("Mismatch in dimensions: size of image must match side of cairo surface");
|
||||
}
|
||||
|
||||
int stride = cairo_image_surface_get_stride(&*surface) / 4;
|
||||
|
||||
const std::unique_ptr<unsigned int[]> out_row(new unsigned int[data.width()]);
|
||||
const unsigned int *in_row = (const unsigned int *)cairo_image_surface_get_data(&*surface);
|
||||
|
||||
for (unsigned int row = 0; row < data.height(); row++, in_row += stride)
|
||||
{
|
||||
for (unsigned int column = 0; column < data.width(); column++)
|
||||
{
|
||||
unsigned int in = in_row[column];
|
||||
unsigned int a = (in >> 24) & 0xff;
|
||||
unsigned int r = (in >> 16) & 0xff;
|
||||
unsigned int g = (in >> 8) & 0xff;
|
||||
unsigned int b = (in >> 0) & 0xff;
|
||||
|
||||
#define DE_ALPHA(x) do { \
|
||||
if (a == 0) x = 0; \
|
||||
else x = x * 255 / a; \
|
||||
if (x > 255) x = 255; \
|
||||
} while(0)
|
||||
|
||||
DE_ALPHA(r);
|
||||
DE_ALPHA(g);
|
||||
DE_ALPHA(b);
|
||||
|
||||
out_row[column] = color(r, g, b, a).rgba();
|
||||
}
|
||||
data.setRow(row, out_row.get(), data.width());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // MAPNIK_CAIRO_IMAGE_UTIL_HPP
|
|
@ -39,29 +39,19 @@
|
|||
// boost
|
||||
#include <boost/optional/optional.hpp>
|
||||
|
||||
struct _cairo_surface;
|
||||
typedef struct _cairo_surface cairo_surface_t;
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
|
||||
using cairo_surface_ptr = std::shared_ptr<cairo_surface_t>;
|
||||
|
||||
class MAPNIK_DECL image_32
|
||||
{
|
||||
private:
|
||||
unsigned width_;
|
||||
unsigned height_;
|
||||
boost::optional<color> background_;
|
||||
image_data_rgba8 data_;
|
||||
boost::optional<color> background_;
|
||||
bool painted_;
|
||||
bool premultiplied_;
|
||||
public:
|
||||
image_32(int width,int height);
|
||||
image_32(image_32 const& rhs);
|
||||
#ifdef HAVE_CAIRO
|
||||
explicit image_32(cairo_surface_ptr const& surface);
|
||||
#endif
|
||||
~image_32();
|
||||
|
||||
void painted(bool painted)
|
||||
|
@ -127,7 +117,7 @@ private:
|
|||
|
||||
inline bool checkBounds(int x, int y) const
|
||||
{
|
||||
return (x >= 0 && x < static_cast<int>(width_) && y >= 0 && y < static_cast<int>(height_));
|
||||
return (x >= 0 && x < static_cast<int>(data_.width()) && y >= 0 && y < static_cast<int>(data_.height()));
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -143,17 +133,17 @@ public:
|
|||
|
||||
inline unsigned width() const
|
||||
{
|
||||
return width_;
|
||||
return data_.width();
|
||||
}
|
||||
|
||||
inline unsigned height() const
|
||||
{
|
||||
return height_;
|
||||
return data_.height();
|
||||
}
|
||||
|
||||
inline void set_rectangle(int x0,int y0,image_data_rgba8 const& data)
|
||||
{
|
||||
box2d<int> ext0(0,0,width_,height_);
|
||||
box2d<int> ext0(0,0,data_.width(),data_.height());
|
||||
box2d<int> ext1(x0,y0,x0+data.width(),y0+data.height());
|
||||
|
||||
if (ext0.intersects(ext1))
|
||||
|
@ -177,7 +167,7 @@ public:
|
|||
|
||||
inline void set_rectangle_alpha(int x0,int y0,const image_data_rgba8& data)
|
||||
{
|
||||
box2d<int> ext0(0,0,width_,height_);
|
||||
box2d<int> ext0(0,0,data_.width(),data_.height());
|
||||
box2d<int> ext1(x0,y0,x0 + data.width(),y0 + data.height());
|
||||
|
||||
if (ext0.intersects(ext1))
|
||||
|
@ -221,7 +211,7 @@ public:
|
|||
|
||||
inline void set_rectangle_alpha2(image_data_rgba8 const& data, unsigned x0, unsigned y0, float opacity)
|
||||
{
|
||||
box2d<int> ext0(0,0,width_,height_);
|
||||
box2d<int> ext0(0,0,data_.width(),data_.height());
|
||||
box2d<int> ext1(x0,y0,x0 + data.width(),y0 + data.height());
|
||||
|
||||
if (ext0.intersects(ext1))
|
||||
|
@ -269,7 +259,7 @@ public:
|
|||
template <typename MergeMethod>
|
||||
inline void merge_rectangle(image_data_rgba8 const& data, unsigned x0, unsigned y0, float opacity)
|
||||
{
|
||||
box2d<int> ext0(0,0,width_,height_);
|
||||
box2d<int> ext0(0,0,data_.width(),data_.height());
|
||||
box2d<int> ext1(x0,y0,x0 + data.width(),y0 + data.height());
|
||||
|
||||
if (ext0.intersects(ext1))
|
||||
|
|
|
@ -39,74 +39,24 @@
|
|||
namespace mapnik
|
||||
{
|
||||
image_32::image_32(int width,int height)
|
||||
:width_(width),
|
||||
height_(height),
|
||||
data_(width,height),
|
||||
: data_(width,height),
|
||||
painted_(false),
|
||||
premultiplied_(false) {}
|
||||
|
||||
|
||||
image_32::image_32(image_32 const& rhs)
|
||||
:width_(rhs.width_),
|
||||
height_(rhs.height_),
|
||||
data_(rhs.data_),
|
||||
: data_(rhs.data_),
|
||||
painted_(rhs.painted_),
|
||||
premultiplied_(rhs.premultiplied_) {}
|
||||
|
||||
#ifdef HAVE_CAIRO
|
||||
image_32::image_32(cairo_surface_ptr const& surface)
|
||||
:width_(cairo_image_surface_get_width(&*surface)),
|
||||
height_(cairo_image_surface_get_height(&*surface)),
|
||||
data_(width_, height_),
|
||||
premultiplied_(false)
|
||||
{
|
||||
painted_ = true;
|
||||
if ( cairo_image_surface_get_format(&*surface) != CAIRO_FORMAT_ARGB32)
|
||||
{
|
||||
MAPNIK_LOG_WARN(graphics) << "Unable to convert this Cairo format";
|
||||
throw;
|
||||
}
|
||||
|
||||
int stride = cairo_image_surface_get_stride(&*surface) / 4;
|
||||
|
||||
const std::unique_ptr<unsigned int[]> out_row(new unsigned int[width_]);
|
||||
const unsigned int *in_row = (const unsigned int *)cairo_image_surface_get_data(&*surface);
|
||||
|
||||
for (unsigned int row = 0; row < height_; row++, in_row += stride)
|
||||
{
|
||||
for (unsigned int column = 0; column < width_; column++)
|
||||
{
|
||||
unsigned int in = in_row[column];
|
||||
unsigned int a = (in >> 24) & 0xff;
|
||||
unsigned int r = (in >> 16) & 0xff;
|
||||
unsigned int g = (in >> 8) & 0xff;
|
||||
unsigned int b = (in >> 0) & 0xff;
|
||||
|
||||
#define DE_ALPHA(x) do { \
|
||||
if (a == 0) x = 0; \
|
||||
else x = x * 255 / a; \
|
||||
if (x > 255) x = 255; \
|
||||
} while(0)
|
||||
|
||||
DE_ALPHA(r);
|
||||
DE_ALPHA(g);
|
||||
DE_ALPHA(b);
|
||||
|
||||
out_row[column] = color(r, g, b, a).rgba();
|
||||
}
|
||||
data_.setRow(row, out_row.get(), width_);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
image_32::~image_32() {}
|
||||
|
||||
void image_32::set_grayscale_to_alpha()
|
||||
{
|
||||
for (unsigned int y = 0; y < height_; ++y)
|
||||
for (unsigned int y = 0; y < data_.height(); ++y)
|
||||
{
|
||||
unsigned int* row_from = data_.getRow(y);
|
||||
for (unsigned int x = 0; x < width_; ++x)
|
||||
for (unsigned int x = 0; x < data_.width(); ++x)
|
||||
{
|
||||
unsigned rgba = row_from[x];
|
||||
unsigned r = rgba & 0xff;
|
||||
|
@ -123,10 +73,10 @@ void image_32::set_grayscale_to_alpha()
|
|||
|
||||
void image_32::set_color_to_alpha(const color& c)
|
||||
{
|
||||
for (unsigned y = 0; y < height_; ++y)
|
||||
for (unsigned y = 0; y < data_.height(); ++y)
|
||||
{
|
||||
unsigned int* row_from = data_.getRow(y);
|
||||
for (unsigned x = 0; x < width_; ++x)
|
||||
for (unsigned x = 0; x < data_.width(); ++x)
|
||||
{
|
||||
unsigned rgba = row_from[x];
|
||||
unsigned r = rgba & 0xff;
|
||||
|
@ -142,10 +92,10 @@ void image_32::set_color_to_alpha(const color& c)
|
|||
|
||||
void image_32::set_alpha(float opacity)
|
||||
{
|
||||
for (unsigned int y = 0; y < height_; ++y)
|
||||
for (unsigned int y = 0; y < data_.height(); ++y)
|
||||
{
|
||||
unsigned int* row_to = data_.getRow(y);
|
||||
for (unsigned int x = 0; x < width_; ++x)
|
||||
for (unsigned int x = 0; x < data_.width(); ++x)
|
||||
{
|
||||
unsigned rgba = row_to[x];
|
||||
unsigned a0 = (rgba >> 24) & 0xff;
|
||||
|
@ -175,7 +125,7 @@ boost::optional<color> const& image_32::get_background() const
|
|||
|
||||
void image_32::premultiply()
|
||||
{
|
||||
agg::rendering_buffer buffer(data_.getBytes(),width_,height_,width_ * 4);
|
||||
agg::rendering_buffer buffer(data_.getBytes(),data_.width(),data_.height(),data_.width() * 4);
|
||||
agg::pixfmt_rgba32 pixf(buffer);
|
||||
pixf.premultiply();
|
||||
premultiplied_ = true;
|
||||
|
@ -183,7 +133,7 @@ void image_32::premultiply()
|
|||
|
||||
void image_32::demultiply()
|
||||
{
|
||||
agg::rendering_buffer buffer(data_.getBytes(),width_,height_,width_ * 4);
|
||||
agg::rendering_buffer buffer(data_.getBytes(),data_.width(),data_.height(),data_.width() * 4);
|
||||
agg::pixfmt_rgba32_pre pixf(buffer);
|
||||
pixf.demultiply();
|
||||
premultiplied_ = false;
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
#include <mapnik/util/fs.hpp>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#if defined(HAVE_CAIRO)
|
||||
#include <mapnik/cairo/cairo_context.hpp>
|
||||
#include <mapnik/cairo/cairo_image_util.hpp>
|
||||
#endif
|
||||
|
||||
#include "utils.hpp"
|
||||
|
||||
|
@ -60,6 +64,18 @@ int main(int argc, char** argv)
|
|||
BOOST_TEST( true ); // should hit bad alloc here
|
||||
}
|
||||
|
||||
#if defined(HAVE_CAIRO)
|
||||
mapnik::cairo_surface_ptr image_surface(
|
||||
cairo_image_surface_create(CAIRO_FORMAT_ARGB32,256,257),
|
||||
mapnik::cairo_surface_closer());
|
||||
mapnik::image_data_rgba8 im_data(cairo_image_surface_get_width(&*image_surface), cairo_image_surface_get_height(&*image_surface));
|
||||
im_data.set(1);
|
||||
BOOST_TEST( (unsigned)im_data(0,0) == unsigned(1) );
|
||||
// Should set back to fully transparent
|
||||
mapnik::cairo_image_to_rgba8(im_data, image_surface);
|
||||
BOOST_TEST( (unsigned)im_data(0,0) == unsigned(0) );
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PNG)
|
||||
should_throw = "./tests/cpp_tests/data/blank.png";
|
||||
BOOST_TEST( mapnik::util::exists( should_throw ) );
|
||||
|
|
Loading…
Reference in a new issue