Qt开发技术:Qt绘图系统(一)绘图系统介绍

简介: Qt开发技术:Qt绘图系统(一)绘图系统介绍

Qt开发专栏:开发技术(点击传送门)

Qt开发技术:Qt绘图系统(一)绘图系统介绍

Qt开发技术:Qt绘图系统(二)QPainter详解

 

前话

     红胖子,来也!

     Qt的图形绘制系统,(分为2D图形和3D图形,本篇章主要介绍2D图形绘制系统)。

 

Qt绘图系统

Qt5中的图形主要是通过命令式QPainter API或Qt的声明性UI语言Qt Quick及其场景图后端来完成的。Qt5的图形功能还包括对打印以及加载和保存各种图像格式的支持

QPainter绘制2D图形

QPainter提供了将矢量图形、文本和图像绘制到不同面(可理解为画布)或QPaintDevice实例(如QImage、QOpenGlPaintDevice、QWidget和QPrinter)上的API。实际的绘图发生在QPaintDevice的QPaintEngine软件光栅器和OpenGL(ES)2.0后端是两个最重要的QPaintEngine实现。光栅绘制引擎是Qt的软件光栅化器,在绘制QImage或QWidget时使用。它在OpenGL绘制引擎上的优势在于启用抗锯齿时的高质量,以及完整的功能集。

  • 绘制系统:概述QPainer类和架构。
  • 坐标系统:说明QPainer坐标系的工作原理。
  • 绘制和填充:说明QPainter如何执行矢量形状的填充和大纲绘制。

QPainer最重要的渲染目标是:

  • QImage:一种与硬件无关的直接像素访问图像表示。QPainer将使用软件光栅器绘制QImage实例。
  • QPixmap:一种适合在屏幕上显示的图像表示。QPainer将主要使用软件光栅器绘制到QPixmap实例。
  • QOpenGLPaintDevice:一个要呈现到当前OpenGL 2.0上下文的绘制设备。QPainter将使用硬件加速的OpenGL调用来绘制QopenglPaintDevice实例。
  • QBackingStore:顶级窗口的backbuffer。QPainer将主要使用软件光栅器绘制到QBackingStore实例。
  • QWidget:用于预qt快速用户界面类的基类。qpainter将使用qbackingstore呈现小部件。
  • QOpenGLWidget:画家也可以在QOpenGLWidget上打开。这是为了方便起见,因为从技术上讲,这与使用QopenGLPaintDevice没有什么不同。

QPainer和相关类是Qt GUI模块的一部分。

OpenGL and 3D

OpenGL是硬件加速和3D图形最广泛采用的图形API,在所有桌面平台以及几乎所有移动和嵌入式平台上实现。Qt库包含许多类,可方便的将OpenGL集成到其应用程序中。

  • Qt GUI中的OpenGL—OpenGL如何与qt-gui模块集成的概述。
  • QopenglWidget是一个小部件,允许将OpenGL场景添加到基于QWidget的用户界面中。
  • OpenGL和Qt Quick 2.0-如何将OpenGL集成到Qt Quick 2.0场景图中。
  • www.khronos.org/opengl-官方OpenGL页面。
  • qt canvas 3d-一个附加模块,提供了一种使用javascript从qt quick调用OpenGL类3d绘图的方法。

在Qt5.0之前,Qt中的OpenGL支持由Qt OpenGL模块处理。这个模块仍然存在,但是新的代码应该旨在使用Qt GUI模块中的新类。类很容易根据其名称进行区分:不应使用带有QGL前缀的类。相反,更喜欢从QOpenGl开始的。

 

绘图系统

Qt的绘图系统可以使用相同的API在屏幕和打印设备上进行绘制,并且主要基于QPainter、QPaintDevice和QPaintEngine类。(对于一般绘图开发者主要关注QPainter

QPainter用于执行绘图操作,QPaintDevice是可以使用QPainter绘制的二维空间的抽象,QPainter提供了用于绘制不同类型设备的界面。QPaintEngine类由QPainter和QPaintDevice在内部使用,除非应用程序程序员创建自己的设备类型,否则对他们隐藏。

这种方法的主要好处是,所有的绘制都遵循相同的绘制管道,因此很容易添加对新特性的支持,并为不支持的特性提供默认实现。

绘图类

这些类为在绘制设备上绘制提供支持。

序号

类名

描述

1

QLine             

使用整数精度的二维矢量(直线)

2

QLineF

使用浮点精度的二维矢量(直线)

3

QMargins

使用整数精度定义矩形的四个边距

4

QMarginsF

使用浮点精度定义矩形的四个边距

5

QPoint

使用整数精度定义平面中的点

6

QPointF

使用浮点精度定义平面中的点

7

QRect

使用整数精度定义平面中的矩形

8

QRectF

使用浮点精度定义平面中的矩形

9

QSize

使用整数精度定义二维对象的大小

10

QSizeF

使用浮点精度定义二维对象的大小

11

QBitmap

单色(1位深度)像素地图

12

QIcon

不同模式和状态下的可缩放图标

13

QIconEngine

QIcon呈现器的抽象基类

14

QImage

与硬件无关的图像表示,允许直接访问像素数据,并可用作绘制设备。

15

QImageReader

格式独立的接口,用于从文件或其他设备读取图像

16

QImageWriter

格式独立的接口,用于将图像写入文件或其他设备

17

QPixmap

可以用作绘制设备的屏幕外图像表示

18

QGenericMatrix

表示具有n列和m行的NXM转换矩阵的模板类

19

QVector2D

表示二维空间中的向量或顶点

20

QBrush

定义由QPainer绘制的形状的填充图案

21

QConicalGradient

与QBrush结合使用以指定圆锥形渐变画笔

22

QGradient

QBrush结合使用以指定渐变填充

23

QLinearGradient

与QBrush结合使用以指定线性渐变画笔

24

QRadialGradient

QBrush结合使用以指定线性渐变画笔

25

QColor

基于RGB、HSV或CMYK值的颜色

26

QPagedPaintDevice

表示支持多页的绘画设备

27

QPaintDevice

可以用QPainer绘制的对象的基类

28

QPaintEngine

关于QPainer如何在给定平台上绘制给定设备的抽象定义

29

QPainter

对小部件和其他绘制设备执行低级绘制

30

QPainterPath

用于绘制操作的容器,允许构造和重用图形形状

31

QPainterPathStroker

用于生成给定绘制路径的可填充轮廓

32

QPdfWriter

类以生成可用作绘制设备的pdf

33

QPen

定义QPainer应如何绘制形状的线条和轮廓

34

QPolygon

使用整数精度点向量

35

QPolygonF

使用浮点精度点向量

36

QRegion

为绘制者指定剪辑区域

37

QRgba64

结构包含64位RGB颜色

38

QTransform

指定坐标系的二维转换

39

QFont

指定用于绘制文本的字体

40

QFontMetrics

使用整数精度字体度量信息

41

QFontMetricsF

使用浮点精度字体度量信息

42

QPlatformFontDatabase

使自定义如何发现字体以及如何呈现字体成为可能

43

QSupportedWritingSystems

在内部Qt fontdatabase中注册字体时使用

44

QStylePainter

用于在窗口中绘制QStyle元素的类

45

QColormap

将与设备无关的QColors映射到与设备相关的像素值

46

QSvgGenerator

用于创建SVG图形的绘制设备

47

QSvgRenderer

用于将SVG文件的内容绘制到绘制设备上

48

QSvgWidget

用于显示可缩放矢量图形(SVG)文件内容的窗口

绘制设备和后端处理

创建绘图设备

QPaintDevice类是可以绘制的对象的基类,即QPainter可以绘制任何QPaintDevice子类。QPaintDevice的绘图功能由QWidget、QImage、QPixmap、QPicture、QPrinter和QOpenGLPaintDevice实现。

QWidget

QWidget类是Qt Widgets模块中用户界面元素的基类。它从窗口系统接收鼠标、键盘和其他事件,并在屏幕上绘制自身的表示。

QImage

QImage类提供了一种独立于硬件的图像表示,它针对I/O和直接像素访问和操作进行了设计和优化。QImage支持多种图像格式,包括单色、8位、32位和阿尔法混合图像。

使用QImage作为绘制设备的一个优点是可以以平台独立的方式保证任何绘制操作的像素精确性。另一个好处是,可以在当前GUI线程之外的其他线程中执行绘制。

QPixmap

QPixmap类是一种非屏幕图像表示,它是为在屏幕上显示图像而设计和优化的。与QImage不同,pixmap中的像素数据是内部的,由底层窗口系统管理,即只能通过QPainter函数或通过将QPixmap转换为QImage来访问像素。

为了使用QPixmap优化绘图,Qt提供了QPixmapCache类,该类可用于存储生成成本高昂的临时pixmap,而不使用比缓存限制更多的存储空间

Qt还提供QBitmap便利类,继承QPixmap。QBitmap保证单色(1位深度)像素映射,主要用于创建自定义QCursor和QBrush对象,构建QRegion对象。

OpenGL Paint Device

如前所述,Qt提供的类使在Qt应用程序中使用OpenGL变得容易。例如,QOpenGLPaintDevice启用OpenGL API以使用QPainter进行渲染。

QPicture

QPicture类是一个绘制设备,用于记录和重放QPainter命令。图片以独立于平台的格式将painter命令序列化到IO设备。QPicture也与分辨率无关,即QPicture可以显示在看起来相同的不同设备上(例如svg、pdf、ps、打印机和屏幕)。

Qt提供QPicture::load()和QPicture::save()函数以及用于加载和保存图片的流式运算符。

定义后端处理

可以通过从QPaintDevice类派生并重新实现重载QPaintDevice::paintEngine()函数来实现对新后端的支持,以告诉QPainter应该使用哪个绘制引擎来绘制此特定设备。要实际能够在设备上绘制,此绘制引擎必须是通过从QPaintEngine类派生而创建的自定义绘制引擎。

绘制和填充

绘制

Painter提供高度优化的功能来完成大多数图形用户界面程序所需的工作。它可以绘制从简单的图形原语(由QPointQLineQRectQRegionQPolygon类表示)到矢量路径等复杂形状的所有内容。在qt中,矢量路径由QPainterPath类表示。QPainterPath提供了一个用于绘制操作的容器,使图形能够被构造和重用。

使用QPen类绘制线条和轮廓。笔由其样式(即线条类型)宽度画笔端点的绘制方式(笔帽样式)以及两条连接线之间的连接方式(连接样式)定义。笔的画笔是用于填充笔生成的笔画的QBrush对象,即QBrush类定义填充图案。

QPainer还可以绘制对齐的文本和像素图。

绘制文本时,使用QFont类指定字体。Qt将使用具有指定属性的字体,或者如果不存在匹配的字体,Qt将使用最接近的匹配安装字体。实际使用的字体属性可以使用QFortInfo类来检索。此外,QFontMetrics类提供字体度量,而QFontDatabase类提供有关底层窗口系统中可用字体的信息。

通常,QPainer绘制一个“自然”坐标系,但它能够使用QTransform类执行视图和世界转换。有关详细信息,请参见坐标系,该坐标系还描述渲染过程,即逻辑表示与渲染像素之间的关系,以及抗锯齿绘制的好处。

抗锯齿绘图

绘制时,像素渲染由QPaint::Antialising指令控制。QPainter::RenderHint枚举用于指定任何给定引擎可能遵守或不遵守的QPainter标志。

QPaint::Antialising值指示引擎应尽可能消除基本体的边,即使用不同的颜色强度平滑边(抗锯齿)。

填充

使用QBrush类填充形状。画笔由其颜色和样式(即填充图案)定义。

Qt中的任何颜色都由支持RGB、HSV和CMYK颜色模型的QColor类表示。QColor还支持alpha混合的大纲和填充(指定透明度效果),类是平台和设备独立的(颜色使用QColormap类映射到硬件)。有关更多信息,请参见QColor类文档。

可用的填充模式由Qt::BrushStyle枚举描述。这些包括基本图案,从均匀的颜色到非常稀疏的图案各种线条组合渐变填充纹理。Qt支持自定义填充背景,提供QGradient类来定义自定义渐变填充,而纹理模式是使用QPixmap类指定的。

坐标系统

坐标系由QPainer类控制。与QPaintDevice和QPaintEngine类一起,QPainter构成了qt绘画系统的基础,Arthur。QPainter用于执行绘图操作,QPaintDevice是可以使用QPainter绘制的二维空间的抽象,QPaintEngine提供了用于绘制不同类型设备的界面。

QPaintDevice类是可以绘制的对象的基类:其绘图功能由QWidget、QImage、QPixmap、QPicture和QOPenGLPaintDevice类继承。绘制设备的默认坐标系的原点位于左上角。X值向右增加,Y值向下增加。默认单位是基于像素的设备上的一个像素和打印机上的一个点(1/72英寸)。

逻辑QPainter坐标到物理QPaintDevice坐标的映射由QPainter的转换矩阵、视区和“窗口”处理。默认情况下,逻辑坐标系和物理坐标系是一致的。QPainter还支持坐标转换(例如旋转和缩放)。

渲染:逻辑表示

图形元素的大小(宽度和高度)始终对应于其数学模型,而忽略了用以下方式呈现的笔的宽度:

渲染:锯齿绘制

绘制时,像素渲染锯齿由QPainter::Antialising控制。

RenderHint枚举用于向QPainer指定任何给定引擎可能遵守或不遵守的标志。QPainter::Antialising值指示引擎应尽可能消除基本体的边(抗锯齿),即使用不同的颜色强度使边缘平滑。

默认情况下,QPainter 绘制时有锯齿,并且有其它规则:当用 1 像素宽的画笔绘制时,像素会被绘制在右下角。例如:

使用偶数像素的笔进行渲染时,像素将围绕数学定义的点对称渲染,使用奇数像素的笔进行渲染时,备用像素将渲染到数学点的右侧和下方,就像在一个像素的情况下一样。具体示例见下面的QRectF图。

请注意,由于历史原因,QRect::right()和QRect::bottom()函数的返回值偏离了矩形的右下角。

QRect::right()函数返回left()+width()-1,bottom()函数返回top()+height()-1。图中右下角的绿点显示了这些函数的返回坐标。

建议使用QRectF替代,QRectF类使用浮点坐标定义平面中的一个矩形以实现精确性(QRect使用整数坐标),而QRectF::right()和QRectF::bottom()函数确实返回真正的右下角。

或者,使用QRect,应用x()+width()和y()+height()查找右下角,并避免使用right()和bottom()函数。

渲染:抗锯齿绘制

如果设置QPainter的抗混叠渲染,像素将在数学定义的点的两侧对称渲染:

渲染:抗锯齿枚举参数定义

序号

枚举

描述

1

QPainter::Antialiasing

指示引擎应尽可能消除锯齿。

2

QPainter::TextAntialiasing

指示引擎应尽可能消除文本的锯齿。若要强制禁用文本的抗锯齿,请不要使用此提示。相反,在字体的样式策略上设置QFont::NoAntialias

3

QPainter::SmoothPixmapTransform

指示引擎应使用平滑的pixmap转换算法(如双线性)而不是最邻近的。

4

QPainter::HighQualityAntialiasing

此值已过时并将被忽略,请改用反锯齿渲染提示。

5

QPainter::NonCosmeticDefaultPen

此值已过时,QPen的默认值现在为非外观

6

QPainter::Qt4CompatiblePainting

兼容性提示,告诉引擎使用与qt 4中相同的基于x11的填充规则,其中混叠渲染的偏移量略小于半个像素。也会将默认构造的钢笔视为化妆品。将Qt4应用程序移植到Qt5时可能有用。

变换:常规操作

默认情况下,QPainter在相关设备自己的坐标系上运行,但它也完全支持仿射坐标转换

可以使用QPainter::scale()函数按给定的偏移量缩放坐标系,可以使用QPainter::rotate()函数顺时针旋转坐标系,也可以使用QPainter::translate()函数转换坐标系(即向点添加给定偏移量)。

还可以使用QPainer::shear()函数围绕原点扭曲坐标系。所有转换操作都是在QPainer的转换矩阵上进行的,您可以使用QPainer::worldTransform()函数来检索该矩阵。矩阵将平面中的一个点转换为另一个点。

如果您需要反复进行相同的转换,还可以使用qTransform对象和QPainer::worldTransform()QPainer::setWorldTransform()函数。您可以随时通过调用QPainter::save()函数来保存QPainter的转换矩阵,该函数将矩阵保存在内部堆栈上。函数的作用是:恢复。

转换矩阵的一个常见需求是在各种绘制设备上重复使用相同的绘图代码。如果不进行转换,结果将与绘制设备的分辨率紧密相连。打印机具有高分辨率,例如每英寸600点,而屏幕通常每英寸72到100点。

变换:Analog Clock Example

模拟时钟示例演示如何使用qpainer的转换矩阵绘制自定义小部件的内容。我们建议您在进一步阅读之前编译并运行这个示例。尤其是,尝试将窗口大小调整为不同的大小。

转换坐标系,使点(0,0)在小部件的中心,而不是在左上角。我们还按side/100缩放系统,其中side是小部件的宽度或高度,以最短者为准。我们希望时钟是方形的,即使设备不是。

这将给我们一个200 x 200平方的面积,原点(0,0)在中间,我们可以利用。我们绘制的图形将显示在适合小部件的最大可能的正方形中。

通过旋转坐标系并调用QPainter::drawConverExpolygon()来绘制时钟的时针。感谢旋转,它画的方向是正确的。

多边形被指定为一个交替的x,y值数组,存储在hourhand静态变量(在函数开头定义)中,该变量对应于四个点(2,0),(0,2),(-2,0)和(0,-25)。

围绕代码对QPainter::save()QPainter::restore()的调用保证了后面的代码不会被我们使用的转换所干扰。

我们对时钟的分针也这样做,它由四个点(1,0),(0,1),(-1,0)和(0,-40)定义。这些坐标指定一只手比分针更薄、更长。

最后,画出钟面,它由12条30度间隔的短线组成。最后,绘制方法采用了一种不太有用的方式旋转,但我们已经完成了绘画,所以这并不重要。

变换:窗口视区转换

使用QPainer绘制时,我们使用逻辑坐标指定点,然后将逻辑坐标转换为绘制设备的物理坐标。

逻辑坐标到物理坐标的映射由QPainter的世界转型worldtransform()(在“转换”部分中描述)和QPainer的viewport()和window()处理。视区表示指定任意矩形的物理坐标。“窗口”以逻辑坐标描述同一个矩形。默认情况下,逻辑和物理坐标系是一致的,并且相当于绘制设备的矩形。

使用窗口-视区转换,可以使逻辑坐标系适合您的首选项。该机构还可以使绘图代码独立于绘图设备。例如,可以通过调用QPainter::setWindow()函数,使逻辑坐标从(-50,-50)扩展到(50,50),其中(0,0)位于中心:

现在,逻辑坐标(-50,-50)对应于绘制设备的物理坐标(0,0)。独立于绘制设备,绘制代码将始终在指定的逻辑坐标上操作。

通过设置“窗口”或视区矩形,可以执行坐标的线性转换。请注意,“窗口”的每个角都映射到视区的相应角,反之亦然。因此,通常最好让视区和“窗口”保持相同的纵横比以防止变形:

如果我们将逻辑坐标系设为正方形,那么还应该使用QPainter::setViewPort()函数将视区设为正方形。在上面的示例中,我们将其等效为适合绘制设备矩形的最大正方形。通过在设置窗口或视区时考虑绘制设备的大小,可以使绘制代码独立于绘制设备。

请注意,窗口视区转换只是线性转换,即它不执行剪切。这意味着,如果在当前设置的“窗口”外绘制,则绘制仍将使用相同的线性代数方法转换为视区。

视区、“窗口”和转换矩阵决定逻辑QPainter坐标如何映射到绘制设备的物理坐标。默认情况下,世界变换矩阵是标识矩阵,“窗口”和“视区”设置等同于绘制设备的设置,即世界,“窗口”和设备坐标系是等效的,但正如我们所看到的,可以使用变换操作和窗口视区转换来操纵系统。上图描述了这个过程。

读取和写入图像文件

最常见的读取图像的方法是通过QPmage和QPixmap的构造函数,或者通过调用QImage::load()QPixmap::load()函数。此外,qt还提供了QImageReader类,它提供了对进程的更多控制。根据图像格式中的底层支持,类提供的函数可以节省内存并加速图像加载。

同样Qt提供了QImageWriter类,它支持在存储图像之前设置格式特定的选项,例如gamma级别、压缩级别和质量。如果不需要这些选项,可以使用QImage::save()QPixmap::save()

QMovie是一个显示动画类,在内部使用QImageReader类。创建后,QMovie类为运行和控制给定动画提供了各种功能。

QImageReader和QImageWriter类依赖于QImageIOHandler类,它是Qt中所有图像格式的通用图像I/O接口。QImageIOHandler对象由QImageReader和QImageWriter在内部使用,以向Qt添加对不同图像格式的支持

通过QImageReader::SupportedImageFormats()QImageWriter::supportedImageFormats()函数可以获得支持的文件格式列表。Qt默认支持几种文件格式,此外,还可以作为插件添加新格式。当前支持的格式列在QImageReader和QImageWriter类文档中。

Qt的插件机制也可以用于编写自定义图像格式处理程序。这是通过从QImageIOHandler类派生并创建一个QImageIOPlugin对象来完成的,该对象是用于创建QImageIOHandler对象的工厂。安装插件后,QImageReader和QImageWriter将自动加载插件并开始使用它



相关文章
|
17天前
|
编解码 UED
Qt侧边栏的动态切换:隐藏与显示技术详解
在现代用户界面设计中,侧边栏(Sidebar)是一个常见的组件,它为用户提供了导航和工具面板的功能。在某些应用场景下,我们可能需要动态地隐藏或显示侧边栏,以优化界面布局或提供更灵活的用户体验。本文将分享如何在Qt框架下实现侧边栏的隐藏与呈现,包括技术细节和代码示例。
79 3
|
2月前
(14)Qt绘图(one)
本文介绍了在Qt中使用QPainter进行绘图的基础操作,包括如何指定绘图设备、使用QPen和QBrush设置线条和填充样式、绘制不同样式的线条和形状,以及如何实现纹理填充和渐变填充等效果。
61 6
(14)Qt绘图(one)
|
2月前
|
存储 Windows
(13) Qt事件系统(two)
文章详细介绍了Qt事件系统,包括事件分发、自定义事件、事件传播机制、事件过滤以及事件与信号的区别。
97 3
(13) Qt事件系统(two)
|
2月前
|
计算机视觉
(15)Qt绘图(two)
Qt框架中QPainter类的多种绘图功能,包括坐标变换、基本图形绘制、文本和图片绘制、图像保存以及碰撞检测等。
46 1
(15)Qt绘图(two)
|
17天前
|
UED
Qt侧边栏的动态展示:隐藏与呈现技术详解
在现代用户界面设计中,侧边栏(Sidebar)是一个常见的组件,它为用户提供了便捷的导航和操作入口。在Qt框架中,实现侧边栏的隐藏与呈现不仅能够提升应用的美观度,还能增强用户体验。本文将详细介绍如何在Qt中实现侧边栏的动态隐藏与呈现,包括技术要点和代码实现。
33 0
|
2月前
|
编解码 程序员
(12)Qt事件系统(one)
本文详细介绍了Qt事件系统,包括各种系统事件、鼠标事件、键盘事件、定时器等的处理方法和示例代码。
91 0
(12)Qt事件系统(one)
|
3月前
|
开发工具 C++
qt开发技巧与三个问题点
本文介绍了三个Qt开发中的常见问题及其解决方法,并提供了一些实用的开发技巧。
|
3月前
|
4月前
|
C++
C++ Qt开发:QUdpSocket网络通信组件
QUdpSocket是Qt网络编程中一个非常有用的组件,它提供了在UDP协议下进行数据发送和接收的能力。通过简单的方法和信号,可以轻松实现基于UDP的网络通信。不过,需要注意的是,UDP协议本身不保证数据的可靠传输,因此在使用QUdpSocket时,可能需要在应用层实现一些机制来保证数据的完整性和顺序,或者选择在适用的场景下使用UDP协议。
191 2
|
5月前
|
数据安全/隐私保护 C++ 计算机视觉
Qt(C++)开发一款图片防盗用水印制作小工具
文本水印是一种常用的防盗用手段,可以将文本信息嵌入到图片、视频等文件中,用于识别和证明文件的版权归属。在数字化和网络化的时代,大量的原创作品容易被不法分子盗用或侵犯版权,因此加入文本水印成为了保护原创作品和维护知识产权的必要手段。 通常情况下,文本水印可以包含版权声明、制作者姓名、日期、网址等信息,以帮助识别文件的来源和版权归属。同时,为了增强防盗用效果,文本水印通常会采用字体、颜色、角度等多种组合方式,使得水印难以被删除或篡改,有效地降低了盗用意愿和风险。 开发人员可以使用图像处理技术和编程语言实现文本水印的功能,例如使用Qt的QPainter类进行文本绘制操作,将文本信息嵌入到图片中,
191 1
Qt(C++)开发一款图片防盗用水印制作小工具