之前寫了一篇文章《Qt使用GDI繪圖(僅Windows平臺)》
Qt使用GDI繪圖(僅Windows平臺)_libaineu2004的博客-CSDN博客
本篇重點(diǎn)介紹Cairo繪圖引擎,Qt自帶的QPainter的繪圖效率和抗鋸齒效果都沒有cairo的好。cairo 的目標(biāo)是以跨平臺的方式在打印機(jī)和屏幕上產(chǎn)生相同的輸出,它正在成為 Linux? 圖形領(lǐng)域的重要軟件。GNOME、GTK+、Pango 等許多軟件已經(jīng)使用了它提供的 2D 功能。另外,cairo 還支持生成 PostScript 或 PDF 輸出,從而產(chǎn)生高質(zhì)量的打印結(jié)果。在理想情況下,cairo 的用戶可以在打印機(jī)和屏幕上獲得非常接近的輸出效果。
Cairo:C編寫的開源繪圖引擎(基于LGPL協(xié)議),大名鼎鼎的FireFox就是用這個(gè)繪圖引擎的。Cairo是非常流行的開源2D圖形渲染引擎庫,它支持包括X-Windos,Win32,圖像,pdf在內(nèi)的各種輸出設(shè)備。目前,Cairo已被廣泛的使用在多個(gè)平臺上來渲染圖形界面,包括Firefox/Webkit-EFL/GTK+/Poppler/Qt等等。Qt的QPainter提供的抗鋸齒效果沒有cairo的好。cairo是用C編寫的,但是為大多數(shù)常用的語言提供了綁定。選用 C 語言有助于創(chuàng)建新的綁定,同時(shí)在進(jìn)行C語言調(diào)用時(shí)可以提供高性能。應(yīng)該特別注意Python綁定,它支持快速原型開發(fā),而且降低了學(xué)習(xí)cairo繪圖API的門檻。Cairo的繪圖效率是接近GDI/GDIPlus的。經(jīng)過優(yōu)化算法,可以做到完全忽略繪圖效率上的差別。此外,gtk不如qt流行,Qt支持cairo。
cairo 是一個(gè)矢量繪圖(vector drawing)庫,因此繪圖需要對圖形進(jìn)行幾何描述,而不是描述位圖中填充的像素。在采用位圖繪圖(bitmap drawing)時(shí),按照預(yù)先決定的布局用預(yù)先決定的顏色填充一系列像素,而且圖形的質(zhì)量與位圖的大小成正比。 在放大或修改位圖圖像時(shí),位圖繪圖方法的效果就會變差。圖像常常會變得模糊,就像是近距離觀看背投電視或其他大屏幕電視時(shí)的效果。在某一距離上,圖像可能看起來很清楚,但是靠近之后就會看到許多離散的點(diǎn)。因?yàn)閿?shù)據(jù)無法定義預(yù)先定義的像素之間應(yīng)該是什么,所以放大時(shí)會很明顯地?fù)p失清晰度。計(jì)算機(jī)繪圖系統(tǒng)和體系結(jié)構(gòu)很早就出現(xiàn)了,cairo 的設(shè)計(jì)借鑒了 PostScript 和 PDF 模型的許多經(jīng)驗(yàn)。cairo 之所以借鑒 PostScript 和 Portable Document Format(PDF)方法是因?yàn)?,它們都使用?shù)學(xué)語句定義圖像。由于用幾何方法表示圖像,所以可以在任何時(shí)候在一定范圍內(nèi)計(jì)算幾何描述,從而重新創(chuàng)建整個(gè)圖像(或一部分圖像)。圖形的幾何性質(zhì)被表示為點(diǎn)、曲線和直線(這些元素構(gòu)成了矢量)。
Cairo samples 官方樣例
Examples 官方案例
Index of /snapshots 搶鮮版源碼
Index of /releases 穩(wěn)定版源碼,提供了C/C++,Python,R語言的支持。pixman是它的依賴庫。
https://github.com/freedesktop/cairo C語言源碼
https://github.com/pygobject/pycairo Python bindings for cairo
例1、和Qt結(jié)合的原理是: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; //創(chuàng)建一張圖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(); //將此圖轉(zhuǎn)換為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); //設(shè)置線寬 cairo_set_source_rgb(pCairoContext, 1.0, 0.0, 0.0); //設(shè)置線顏色 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);
本人使用的編程環(huán)境是QtCreator + MSVC2019 32/64位
https://gitee.com/libaineu2004/cairo_demo
scribus是開源項(xiàng)目,使用C++/Qt GUI
源碼檢索關(guān)鍵詞【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環(huán)境_libaineu2004的博客-CSDN博客
Skia是一個(gè)開源的二維圖形庫,提供各種常用的API,并可在多種軟硬件平臺上運(yùn)行。谷歌Chrome瀏覽器、Chrome OS、Fuchsia、安卓、Flutter、火狐瀏覽器、火狐操作系統(tǒng)以及其它許多產(chǎn)品都使用它作為圖形引擎。Skia由谷歌出資管理,任何人都可基于BSD免費(fèi)軟件許可證使用Skia。Skia開發(fā)團(tuán)隊(duì)致力于開發(fā)其核心部分, 并廣泛采納各方對于Skia的開源貢獻(xiàn)。
Qt+Skia組合也是繪圖的好方案
Windows環(huán)境VS2017編譯skia庫,親測成功,借助skui的方法_libaineu2004的博客-CSDN博客
GeoGebra是自由且跨平臺的動態(tài)數(shù)學(xué)軟件,提供各級教育使用,包含了幾何、代數(shù)、表格、圖形、統(tǒng)計(jì)和微積分,集中在一個(gè)容易使用的軟件。
www.geogebra.org/classic
www.geogebra.org/calculator
聯(lián)系客服