原创 单片机矢量图形显示方法.

2021-2-4 09:02 8673 43 12 分类: MCU/ 嵌入式

罗昊

摘要 使用图形界面会提高产品的外观及操作便利性,而图形数据需要占用大量的存储空间。对比按像素方式与矢量方式图像。将图形矢量化存储能节省空间。使用SVG格式将图形编码存储,顺序解析矢量图形数据,配合常用图形用户界面,增加贝塞尔曲线绘制函数,将图片绘制出来。使用矢量方法容易实现放大、缩小和动画效果。

关键字:矢量图形、图形用户界面、单片机

Vector graphic storage and display by MCU

Luohao Beijing KellyMed co.,ltd.

Abstract Use GUI improve convenient and get good appearance, generally, graphic data consume massive storage. Compare bit and vector graphic, Use vector method can save memory. Graphic save in SVG format, serial resolve vector data, along with Bessel curve extend GUI to draw graphic. It is easy to implement some effect such as magnify, animation.

Key words: Vector graphic, GUI, MCU

引言

在产品中使用GUI已经成为驱势。随着LCD屏分辨率提高,色彩更丰富。用于显示的图片需要大量的存储空间。一幅320*240的图片,每个像素占一个字节,需要占用76KB。还需要存储8位调色板接近1KB空间。这对于捉襟见肘的单片机存储资源显然是无法接受的。即使使用如JPEG压缩图片,图片解码时需要的RAM资源也很多。如果使用矢量方法进行图形处理,存储与处理都会有较大的改善,并且容易实现一些如扩大缩小,动画等功能。

图片存储方式

以点阵方式处理图片是当前常规的方法,图片是按点存储,按点处理。一幅多大尺寸的图形就需要多大尺寸的存储空间。单片机常用的图形用户界面如μcgui[1]一般都能提供GUI_DrawBitmap这样的函数。按点读取颜色数据,索引调色板中的颜色值,然后写到显示存储器中。

矢量处理方式将图片分成椭圆弧、多边形和路径。其中路径以直线,曲线组成,参照SVG文件标准[2],以文本的形式存储图像。格式示例如下:以命令开头后跟点座标参数。

所有命令均允许小写字母。大写表示绝对定位,小写表示相对定位。使用相对定位仅存储差值能缩小存储空间。为保证必要的精度,所有的座标用1位小数表示。以上表方式将图形编码。图形越简单需要的存储空间越小。

如图1所示,a 128*128的图像,如果使用2bit 表示一个像素位,128*128的图像需要4K存储空间。以矢量方式存储,由两个路径一个多边形一个椭圆组成,占用空间不超过0.5K

图形编码数据结构

定义一个结构体描述图形,包含数据类型,颜色,数据指针和下一个数据的指针。

  1. typedef struct VectList{
  2. uint8_t type; //类型,指示数据类型为椭圆弧、多边形或路径
  3. uint32_t fillcolor; //填充颜色值,按RGB
  4. uint32_t strokecolor; //边线颜色
  5. uint32_t strokewidth; //边线宽度
  6. uint8_t *PicStr; //图片数据指针
  7. struct VectList *next; //指向下一个
  8. };

图像数据以结构体的方式,存储在结构体内,结构体中包含指向一下一条数据结构的指针,最后一条指向空指针。形成单向链表。如图2所示。

数据解析

显示一幅矢量图的过程如下,首先获取指向第一条图片记录的结构,如果类型为椭圆或多边形,从PicStr中取得参数,调用画圆,画多边型的函数绘制图片,调用圆填充,多边形填充函数填充图片。如果类型为路径。需要先找到M获得起点座标 ,依次寻找线形,如果为Ll,获取后面的数据作为 调用画线函数,画直线。如果为c获取后面的数据 作为控制点, 为终点,调用绘图函数三次贝塞尔曲线函数绘制图片。其它数据依此类推处理。画线完毕后,再调用填充函数填充图片。所有操作顺序处理,前后基本无关联。

绘图函数

从表中可以看出,需要一些绘图函数来实现矢量图绘制的功能,参考μcgui[1],在核心中会提供画点,线,椭圆,圆弧,多边形等函数。但没有二次和三次贝塞尔曲线的函数。构造一个函数如下:

可知,只要规定好起点终点和中间的控制点,变化参数t就能计算出中间的任意点的座标。为减少计算量,参数t的变化越少越好,可以依据点坐标之间的差值取大值作为点数。确定好点数后,线性变化t求出一系列座标点。用画线函数将这些点连起来就能得到满意的效果。

颜色填充

按上述方法,路径中的贝塞尔曲线实际上已经变换为分段直线,整个路径实际上已经成为由一系列顶点构成的多边形。在画路径的过程中,需要将原有顶点以及计算得到的顶点座标存储成一个阵列。目前应用较广的多边形区域填充算法是标准扫描线算法和边填充算法,扫描线算法需要存储一系列边表,用类似于扫描的方式,将边表之间的区域画线填充,边填充算法则是在原有的边的基础上往内部缩进填充所有内部区域。可以使用GUI自带的多边形填充函数GUI_FillPolygon完成填充工作。

一些特殊效果

绘图中需要一些特殊效果如放大,缩小,动画等。使用矢量方式处理图形,进行放大缩小具有无可比拟的优势。所有的座标只需要按照需要的倍数进行乘积变换。甚至可以进行小数位放大缩小,不会有边沿锯齿产生。产生动画效果,需要可以将需要动作的部件独立存储成矢量,在绘制动画之前,将图形拼合成矢量序列。然后按新的矢量序列绘制,即可产生动画效果。

图片数据生成

可以使用矢量图形编辑工具,将所需要的图片转换成矢量图形,然后存储为SVG文本格式的文件。从文件中摘取所需要的内容,按上面定义的数据结构组成图片数据。

结论

在实际应用中发现,使用矢量方法处理图形,如显示产品LOGO,绘制产品线框图使用说明,显示大字号的文字,对节省存储空间,提高显示性能都特别有效。

作者: southcreek, 来源:面包板社区

链接: https://mbb.eet-china.com/blog/uid-me-408807.html

版权声明:本文为博主原创,未经本人允许,禁止转载!

给作者打赏,鼓励TA抓紧创作!

赞赏支持
点赞 43
赞赏0

文章评论1条评论)

登录后参与讨论

moniqiuwen 2021-2-8 16:44

代码后面第二段图标没有显示
相关推荐阅读
southcreek 2023-11-17 15:39
QT 折线图增加鼠标操作功能
QGraphicsView 本身并没有鼠标操作功能。需要另写函数实现。基本的思路是写一个新的类,继承QGraphicsView, class ChartView : public QCh...
southcreek 2023-10-23 11:08
2运放构建仪表放大器分析
仪表放大器可以实现输入差分信号放大,抑制共模偏置。生成单端信号。常规的,可以使用三个运放实现信号缓冲和差分放大。也可以使用两个运放实现仪表放大器功能。 如图,差分信号均由运放的正端输入,两个运放...
southcreek 2023-10-04 20:36
单键开关机电路
这个电路是从B站看看到的。按键按下实现对外供电和断电。原图不容易看明白,重新画成如下图:上电后,Q3如果不导通,C1 通过R2 R4充电,此时Q1是截止的Q3栅极被R3下拉到地。约100ms后C1被充...
southcreek 2023-09-12 17:44
用QT做一个搜索DC-DC配置电阻的工具
设计DC-DC电路时,常常需要依据芯片的参考电压和需要的输出电压来计算配置电阻。在常用的电阻中找到合适的组合。 一个条件,求两个未知数。实际上并不容易得到想要的数据。不过可以将可选电阻值范围内,尝试...
southcreek 2023-09-06 17:37
QT中使用全局的类
在QT中不同模块之间传递数据可以使用全局共享的方式,比如建立一个称为SysPara 的类继承于QObject 类。 头文件中公有函数中提供一个获取这个类的指针 GetInstance() ...
southcreek 2023-08-25 11:48
QT 独立的窗口显示折线
在原工程中新创建一个界面类。系统会生成一个窗口ui及相应的描述这个form的类头文件和CPP文件并加入到工程中。 将类名修改成想要的类型后。直接生成。   ...
我要评论
1
43
1
2
3
4
5
6
7
8
9
0
关闭 站长推荐上一条 /3 下一条