最近一直忙于cairo渲染接口的封装,目前该任务已接近尾声,在此记录一下学习cairo的心得体会。

cairo是linux系统上一款高质量2D图形渲染库,与Gdiplus库相比,其优势是支持绘制<1.0的线宽、提供了直接输出到内存buffer、pdf文件、png文件、ps、xlib、XCB、win32、svg的接口。关于cairo的简单介绍,详见这里

学习cairo的过程,也是“山重水复疑无路,柳暗花明又一村”的一种体验。当前网上对cairo的介绍仅限于粗略的入门,想要很好的完成封装cairo画图接口的任务,还必须结合实际情况,深入到cairo源码的底层,去分析它的具体实现思路。此外,价值量最大的就是去查阅官方文档,在这里先放上“导学”部分的翻译内容,以及官方的函数文档

使用cairo,重点在于对path的理解,以及对内存图像缓冲区数据的灵活读取(例如,使用cairo_image_surface_get_data或者使用cairo_image_surface_create_for_data取出或绑定的内存,其半透明像素点的颜色值与实际保存到png文件的颜色值并不相同,解决这个问题最简单的办法就是使用cairo提供的cairo_surface_write_to_png_stream和cairo_image_surface_create_from_png_stream接口,并且自定义满足自己任务要求的回调函数,如下所示)。

struct st_png_data
{
	unsigned char* pdata;
	unsigned int length;
};

static cairo_status_t cairo_read_func_mine (void *closure, unsigned char *data, unsigned int length)
{
	st_png_data* pPngData = (st_png_data*)closure;
	memcpy(data, pPngData->pdata + pPngData->length, length);
	pPngData->length += length;
	return CAIRO_STATUS_SUCCESS;
}

static cairo_status_t cairo_write_func_mine (void *closure, const unsigned char *data, unsigned int length)
{
	vector<unsigned char>& vecData = *((vector<unsigned char>*)closure);
	for (unsigned int i = 0; i < length; ++i)
	{
		vecData.push_back(data[i]);
	}
	return CAIRO_STATUS_SUCCESS;
}

st_png_data pngData = {(unsigned char*)pImgBinary, 0};
m_surface = cairo_image_surface_create_from_png_stream(cairo_read_func_mine, &pngData);

vector<unsigned char> vecData;
cairo_surface_write_to_png_stream(m_surface, cairo_write_func_mine, &vecData);
此外,在绘制字体部分,你会发现cairo默认不支持输出汉字。仔细分析其原因,是因为其接口仅接受utf-8格式的字符串,而我们输入的字符串是ANSI编码格式或者Unicode编码格式,因此,我们只需转化一下输入字符串的编码格式便可以支持输出汉字了,比如使用boost库提供的boost::locale::conv::between方法进行转化。

写本文的目的只是想给初学cairo的新手一个快速入门的方法指导,以及对我遇到的一些难点的简单分析,如果你对GDI+十分熟悉,学习cairo也是大同小异的,凡是GDI+能实现的功能,我们都可以使用cairo实现,在此处顺便向大家推荐一篇不错的GDI+博文,可供大家对比学习。

Logo

更多推荐