2次元描画ライブラリの Cairo と AGG (Anti-Grain Geometry) を組み合わせて処理してみた。
C++によるサンプルコード。
#include <string>
#include <cairo/cairo.h>
#include <agg_rendering_buffer.h>
#include <agg_rasterizer_scanline_aa.h>
#include <agg_pixfmt_rgba.h>
#include <agg_renderer_scanline.h>
static cairo_surface_t* create_scaling_surface(cairo_surface_t& src, int width, int height){
double w = cairo_image_surface_get_width(&src);
double h = cairo_image_surface_get_height(&src);
cairo_surface_t* s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
cairo_t* c = cairo_create(s);
cairo_scale(c, width / w, height / h);
cairo_set_source_surface(c, &src, 0.0, 0.0);
cairo_paint(c);
cairo_destroy(c);
return s;
}
static agg::rendering_buffer* create_rendering_buffer(cairo_surface_t& src){
unsigned char* d = cairo_image_surface_get_data(&src);
int w = cairo_image_surface_get_width(&src);
int h = cairo_image_surface_get_height(&src);
int s = cairo_image_surface_get_stride(&src);
agg::rendering_buffer* rb = new agg::rendering_buffer();
rb->attach(d, w, h, s);
return rb;
}
static void draw_image(agg::renderer_base<agg::pixfmt_rgba32>& rbase, cairo_surface_t& image, double dx, double dy, double scale){
cairo_surface_t* s = ℑ
cairo_surface_t* ss = NULL;
int w = cairo_image_surface_get_width(s);
int h = cairo_image_surface_get_height(s);
if(scale != 1.0){
w = (int)(w * scale);
h = (int)(h * scale);
ss = create_scaling_surface(*s, w, h);
s = ss;
}
agg::rendering_buffer* rb = create_rendering_buffer(*s);
agg::pixfmt_alpha_blend_rgba<agg::blender_rgba<agg::rgba8, agg::order_rgba>, agg::rendering_buffer, agg::int32u> srcPixelFormatRenderer(*rb);
agg::rect_i rect_src(0, 0, w, h);
rbase.blend_from(srcPixelFormatRenderer, &rect_src, dx, dy, agg::cover_full);
delete rb;
if(ss){
cairo_surface_destroy(ss);
}
}
int main(void){
int width = 600;
int height = 400;
int bytes_per_pixel = 4;
// canvas
cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
unsigned char* data = cairo_image_surface_get_data(surface);
agg::rendering_buffer rbuf;
rbuf.attach(data, width, height, width * bytes_per_pixel);
agg::pixfmt_rgba32 pixf(rbuf);
agg::renderer_base<agg::pixfmt_rgba32> rbase(pixf);
rbase.clear(agg::rgba8(255, 255, 255, 255));
// load png image
std::string image1_path = "input1.png";
cairo_surface_t* image1_surface = cairo_image_surface_create_from_png(image1_path.c_str());
// load png image
std::string image2_path = "input2.png";
cairo_surface_t* image2_surface = cairo_image_surface_create_from_png(image2_path.c_str());
// drawing
draw_image(rbase, *image1_surface, 10, 20, 1.0);
draw_image(rbase, *image2_surface, 30, 40, 1.0);
draw_image(rbase, *image1_surface, 50, 60, 1.5);
draw_image(rbase, *image2_surface, 70, 80, 1.5);
draw_image(rbase, *image1_surface, 90, 100, 2.0);
draw_image(rbase, *image2_surface, 110, 120, 2.0);
// save image
std::string path = "output.png";
cairo_status_t status = cairo_surface_write_to_png(surface, path.c_str());
// delete cairo surface
cairo_surface_destroy(surface);
cairo_surface_destroy(image1_surface);
cairo_surface_destroy(image2_surface);
return 0;
}
コンパイルと実行は Mac OS X Lion 上にて、以下のシェルスクリプトでやっている。image_scaling.cpp がサンプルコードのファイル。
#!/bin/bash
rm ./a.out
rm ./output.png
g++ -I/usr/local/include/agg2 -I/usr/local/Cellar/cairo/1.10.2/include -L/usr/local/lib -L/usr/local/Cellar/cairo/1.10.2/lib -lagg -lcairo ./image_scaling.cpp
chmod 744 ./a.out
./a.out
実行環境は Mac OS X Lion + AGG 2.5 + cairo 1.10.2
重ねる入力画像: input1.png
重ねる入力画像: input2.png
この画像は [ヅ] Javaで透過度(アルファ値)のあるPNGファイルを出力する で作成した「背景が new Color(255, 255, 255, 0), // white (transparent)」の画像。
サンプルコードが出力する画像: output.png
拡大して重ねて描画することはできたけど、なぜかちょっと黒っぽくなっている。やっぱりアルファ半透明画像の処理がAGGは苦手なのかなぁ。。。
Ref.
- Anti-Grain Geometry -
- cairographics.org
- Anti-Grain Geometry - AGG (libagg): agg::renderer_base< PixelFormat > Class Template Reference
- Anti-Grain Geometry - AGG (libagg): agg::pixfmt_alpha_blend_rgba< Blender, RenBuf, PixelT > Class Template Reference
tags: agg cairo c++
Posted by NI-Lab. (@nilab)