我的Qt作品(9)Qt使用Cairo绘图引擎提升抗锯齿效果【开源】

之前写了一篇文章《Qt使用GDI绘图(仅Windows平台)》

Qt使用GDI绘图(仅Windows平台)_libaineu2004的博客-CSDN博客

本篇重点介绍Cairo绘图引擎,Qt自带的QPainter的绘图效率和抗锯齿效果都没有cairo的好。cairo 的目标是以跨平台的方式在打印机和屏幕上产生相同的输出,它正在成为 Linux® 图形领域的重要软件。GNOME、GTK+、Pango 等许多软件已经使用了它提供的 2D 功能。另外,cairo 还支持生成 PostScript 或 PDF 输出,从而产生高质量的打印结果。在理想情况下,cairo 的用户可以在打印机和屏幕上获得非常接近的输出效果。

一、Cairo简介

Cairo:C编写的开源绘图引擎(基于LGPL协议),大名鼎鼎的FireFox就是用这个绘图引擎的。Cairo是非常流行的开源2D图形渲染引擎库,它支持包括X-Windos,Win32,图像,pdf在内的各种输出设备。目前,Cairo已被广泛的使用在多个平台上来渲染图形界面,包括Firefox/Webkit-EFL/GTK+/Poppler/Qt等等。Qt的QPainter提供的抗锯齿效果没有cairo的好。cairo是用C编写的,但是为大多数常用的语言提供了绑定。选用 C 语言有助于创建新的绑定,同时在进行C语言调用时可以提供高性能。应该特别注意Python绑定,它支持快速原型开发,而且降低了学习cairo绘图API的门槛。Cairo的绘图效率是接近GDI/GDIPlus的。经过优化算法,可以做到完全忽略绘图效率上的差别。此外,gtk不如qt流行,Qt支持cairo。

cairo 是一个矢量绘图(vector drawing)库,因此绘图需要对图形进行几何描述,而不是描述位图中填充的像素。在采用位图绘图(bitmap drawing)时,按照预先决定的布局用预先决定的颜色填充一系列像素,而且图形的质量与位图的大小成正比。 在放大或修改位图图像时,位图绘图方法的效果就会变差。图像常常会变得模糊,就像是近距离观看背投电视或其他大屏幕电视时的效果。在某一距离上,图像可能看起来很清楚,但是靠近之后就会看到许多离散的点。因为数据无法定义预先定义的像素之间应该是什么,所以放大时会很明显地损失清晰度。计算机绘图系统和体系结构很早就出现了,cairo 的设计借鉴了 PostScript 和 PDF 模型的许多经验。cairo 之所以借鉴 PostScript 和 Portable Document Format(PDF)方法是因为,它们都使用数学语句定义图像。由于用几何方法表示图像,所以可以在任何时候在一定范围内计算几何描述,从而重新创建整个图像(或一部分图像)。图形的几何性质被表示为点、曲线和直线(这些元素构成了矢量)。

cairographics.org

Cairo samples 官方样例

Examples 官方案例

Download

Index of /snapshots 抢鲜版源码

Index of /releases 稳定版源码,提供了C/C++,Python,R语言的支持。pixman是它的依赖库。

https://github.com/freedesktop/cairo C语言源码

https://github.com/pygobject/pycairo Python bindings for cairo

cairo / cairo-demos · GitLab

二、Cairo使用示例

例1、和Qt结合的原理是:Cairo画图到QImage的缓存(image.bits),再用QPainter把QImae贴图出来。

void MainWindow::paintEvent(QPaintEvent *pEvent)
{
    Q_UNUSED(pEvent);

    //原生的绘图
    QPainter p(this);
    p.drawLine(QPoint(0, 0), QPoint(150, 220));

    //使用cairo绘图引擎
    const char *pVersion = cairo_version_string();
    qDebug() << pVersion;

    //创建一张图QImage
    int iW = this->width();
    int iH = this->height();
    QImage image(iW, iH, QImage::Format_ARGB32);
    unsigned char *pData = image.bits();
    int iLineStride = image.bytesPerLine();

    //将此图转换为cairo图
    cairo_surface_t *pCairoSurface = cairo_image_surface_create_for_data(pData, CAIRO_FORMAT_ARGB32, iW, iH, iLineStride);
    cairo_surface_set_device_scale(pCairoSurface, 1, 1);
    cairo_t *pCairoContext = cairo_create(pCairoSurface);
    cairo_surface_destroy(pCairoSurface);

    if (pCairoContext)
    {
        double x = 100.6, y = 328.0;
        double x1 = 102.4 + 100, y1 = 130.4,
               x2 = 153.6 + 240, y2 = 405.6,
               x3 = 230.4 + 400, y3 = 200;

        cairo_move_to(pCairoContext, x, y);
        cairo_curve_to(pCairoContext, x1, y1, x2, y2, x3, y3);

        cairo_set_line_width(pCairoContext, 1.0);           //设置线宽
        cairo_set_source_rgb(pCairoContext, 1.0, 0.0, 0.0); //设置线颜色
        cairo_stroke(pCairoContext);

        cairo_destroy(pCairoContext);
    }

    //贴图
    p.drawImage(this->rect(), image);
}

例2、读图片文件,并显示

//define params
int width, height, channels;
//read image data from file using stb_image.h
unsigned char* data = stbi_load(imagePath.c_str(), &width, &height, &channels, STBI_rgb_alpha);
//create surface with image size and format is ARGB32
this->imageSource = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
//get pointer of cairo data
unsigned char * surface_data = cairo_image_surface_get_data(this->imageSource);
//copy current data to surface pointer
memcpy(surface_data, data, width * height * 4 * sizeof(unsigned char));
//mark as dirty to refresh surface
cairo_surface_mark_dirty(this->imageSource);
//free image data
free(data);

或者

int              w, h;
cairo_surface_t *image;

image = cairo_image_surface_create_from_png ("data/romedalen.png");
w = cairo_image_surface_get_width (image);
h = cairo_image_surface_get_height (image);

cairo_translate (cr, 128.0, 128.0);
cairo_rotate (cr, 45* M_PI/180);
cairo_scale  (cr, 256.0/w, 256.0/h);
cairo_translate (cr, -0.5*w, -0.5*h);

cairo_set_source_surface (cr, image, 0, 0);
cairo_paint (cr);
cairo_surface_destroy (image);

三、完整的工程源码及库文件

本人使用的编程环境是QtCreator + MSVC2019 32/64位

https://gitee.com/libaineu2004/cairo_demo

四、cairo的开源应用案例是scribus软件

scribus是开源项目,使用C++/Qt GUI

源码检索关键词【cairo_image_surface_create_for_data】 

 Cairo画图到QImage的缓存(image.bits),再用QPainter把QImae贴图出来。

canvas.cpp
void Canvas::drawContents(QPainter *psx, int clipx, int clipy, int clipw, int cliph)
{
	ScPainter *painter=nullptr;
	QImage img = QImage(clipw * devicePixelRatio(), cliph * devicePixelRatio(), QImage::Format_ARGB32_Premultiplied);
	img.setDevicePixelRatio(devicePixelRatio());
	painter = new ScPainter(&img, img.width(), img.height(), 1.0, 0);
	painter->clear(palette().color(QPalette::Window));
painter->newPath();
	painter->moveTo(0, 0);
	painter->lineTo(clipw, 0);
	painter->lineTo(clipw, cliph);
	painter->lineTo(0, cliph);
	painter->closePath();
	painter->setClipPath();
	painter->translate(-clipx, -clipy);
	painter->setZoomFactor(m_viewMode.scale);
	painter->translate(-m_doc->minCanvasCoordinate.x(), -m_doc->minCanvasCoordinate.y());
	painter->setLineWidth(1);
	painter->setFillMode(ScPainter::Solid);

painter->end();
	psx->drawImage(clipx, clipy, img);
	delete painter;
	painter=nullptr;
}

桌面排版软件Scribus v1.5.5源码编译,使用VS2017+Qt5.12.7环境_libaineu2004的博客-CSDN博客

x1.skia

Skia是一个开源的二维图形库,提供各种常用的API,并可在多种软硬件平台上运行。谷歌Chrome浏览器、Chrome OS、Fuchsia、安卓、Flutter、火狐浏览器、火狐操作系统以及其它许多产品都使用它作为图形引擎。Skia由谷歌出资管理,任何人都可基于BSD免费软件许可证使用Skia。Skia开发团队致力于开发其核心部分, 并广泛采纳各方对于Skia的开源贡献。
Qt+Skia组合也是绘图的好方案

Windows环境VS2017编译skia库,亲测成功,借助skui的方法_libaineu2004的博客-CSDN博客

x2.geogebra

GeoGebra是自由且跨平台的动态数学软件,提供各级教育使用,包含了几何、代数、表格、图形、统计和微积分,集中在一个容易使用的软件。

www.geogebra.org/classic

www.geogebra.org/calculator

GeoGebra Classic - GeoGebra

在图形处理中,抗锯齿(Anti-aliasing)是一种用于减少或消除图像边缘锯齿状物的技术。在C语言中,可以通过以下两种方法提高图形抗锯齿: 1. 抗锯齿算法 抗锯齿算法是一种通过对图像边缘像素进行插值计算来减少锯齿状物的技术。常见的抗锯齿算法包括超采样抗锯齿(Supersampling Anti-aliasing,SSAA)、多重采样抗锯齿(Multisample Anti-aliasing,MSAA)等。这些算法可以在图像处理中使用,但是需要较高的计算能力和内存消耗。 2. 使用外部 在C语言中,可以使用外部来实现图形抗锯齿。例如,可以使用Cairo来绘制抗锯齿图形。Cairo是一个开源的2D图形,支持多种输出设备和多种图形渲染方式,包括抗锯齿渲染。使用Cairo,可以通过以下步骤来实现抗锯齿: - 引入Cairo的头文件。 - 创建一个Cairo绘图上下文。 - 设置绘图上下文的抗锯齿属性。 - 使用绘图上下文绘制图形。 - 销毁绘图上下文。 以下是一个使用Cairo绘制抗锯齿图形的示例代码: ```c #include <cairo.h> int main() { cairo_surface_t *surface; cairo_t *cr; surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 512, 512); cr = cairo_create(surface); cairo_set_antialias(cr, CAIRO_ANTIALIAS_BEST); cairo_set_source_rgba(cr, 1, 0, 0, 1); cairo_rectangle(cr, 10, 10, 100, 100); cairo_fill(cr); cairo_destroy(cr); cairo_surface_write_to_png(surface, "test.png"); cairo_surface_destroy(surface); return 0; } ``` 这段代码创建了一个512x512的绘图表面,并使用Cairo绘制了一个红色矩形。在绘制之前,使用cairo_set_antialias函数设置了绘图上下文的抗锯齿属性为最佳效果CAIRO_ANTIALIAS_BEST)。 希望以上内容能够帮助你实现图形抗锯齿
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值