trim down image_32 - refs #2627

This commit is contained in:
Dane Springmeyer 2015-01-08 13:16:32 -08:00
parent e4cb1b33a0
commit acb3bb0821
6 changed files with 125 additions and 81 deletions

View file

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

View file

@ -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"

View 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

View file

@ -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))

View file

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

View file

@ -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 ) );