罗昊 摘要 使用图形界面会提高产品的外观及操作便利性,而图形数据需要占用大量的存储空间。对比按像素方式与矢量方式图像。将图形矢量化存储能节省空间。使用 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 i mplement some effect such as magnify, animation. Key words: Vector graphic, GUI, MCU 引言 在产品中使用 GUI 已经成为驱势。随着 LCD 屏分辨率提高,色彩更丰富。用于显示的图片需要大量的存储空间。一幅 320*240 的图片,每个像素占一个字节,需要占用 76KB 。还需要存储 8 位调色板接近 1KB 空间。这对于捉襟见肘的单片机存储资源显然是无法接受的。即使使用如 JPEG 压缩图片,图片解码时需要的 RAM 资源也很多。如果使用矢量方法进行图形处理,存储与处理都会有较大的改善,并且容易实现一些如扩大缩小,动画等功能。 图片存储方式 以点阵方式处理图片是当前常规的方法,图片是按点存储,按点处理。一幅多大尺寸的图形就需要多大尺寸的存储空间。单片机常用的图形用户界面如μ cgui 一般都能提供 GUI_DrawBitmap 这样的函数。按点读取颜色数据,索引调色板中的颜色值,然后写到显示存储器中。 矢量处理方式将图片分成椭圆弧、多边形和路径。其中路径以直线,曲线组成,参照 SVG 文件标准 ,以文本的形式存储图像。格式示例如下:以命令开头后跟点座标参数。 所有命令均允许小写字母。大写表示绝对定位,小写表示相对定位。使用相对定位仅存储差值能缩小存储空间。为保证必要的精度,所有的座标用 1 位小数表示。 以上表方式将图形编码。图形越简单需要的存储空间越小。 如图 1 所示, a 中 128*128 的图像,如果使用 2bit 表示一个像素位, 128*128 的图像需要 4K 存储空间。以矢量方式存储,由两个路径一个多边形一个椭圆组成,占用空间不超过 0.5K 图形编码数据结构 定义一个结构体描述图形,包含数据类型,颜色,数据指针和下一个数据的指针。 typedef struct VectList{ uint8_t type; //类型,指示数据类型为椭圆弧、多边形或路径 uint32_t fillcolor; //填充颜色值,按RGB uint32_t strokecolor; //边线颜色 uint32_t strokewidth; //边线宽度 uint8_t *PicStr; //图片数据指针 struct VectList *next; //指向下一个 }; 图像数据以结构体的方式,存储在结构体内,结构体中包含指向一下一条数据结构的指针,最后一条指向空指针。形成单向链表。如图 2 所示。 数据解析 显示一幅矢量图的过程如下,首先获取指向第一条图片记录的结构,如果类型为椭圆或多边形,从 PicStr 中取得参数,调用画圆,画多边型的函数绘制图片,调用圆填充,多边形填充函数填充图片。如果类型为路径。需要先找到 M 获得起点座标 ,依次寻找线形,如果为 L 或 l ,获取后面的数据作为 调用画线函数,画直线。如果为 c 获取后面的数据 作为控制点, 为终点,调用绘图函数三次贝塞尔曲线函数绘制图片。其它数据依此类推处理。画线完毕后,再调用填充函数填充图片。所有操作顺序处理,前后基本无关联。 绘图函数 从表中可以看出,需要一些绘图函数来实现矢量图绘制的功能,参考μ cgui ,在核心中会提供画点,线,椭圆,圆弧,多边形等函数。但没有二次和三次贝塞尔曲线的函数。构造一个函数如下: 可知,只要规定好起点终点和中间的控制点,变化参数 t 就能计算出中间的任意点的座标。为减少计算量,参数 t 的变化越少越好,可以依据点坐标之间的差值取大值作为点数。确定好点数后,线性变化 t 求出一系列座标点。用画线函数将这些点连起来就能得到满意的效果。 颜色填充 按上述方法,路径中的贝塞尔曲线实际上已经变换为分段直线,整个路径实际上已经成为由一系列顶点构成的多边形。在画路径的过程中,需要将原有顶点以及计算得到的顶点座标存储成一个阵列。 目前应用较广的多边形区域填充算法是标准扫描线算法和边填充算法 ,扫描线算法需要存储一系列边表,用类似于扫描的方式,将边表之间的区域画线填充,边填充算法则是在原有的边的基础上往内部缩进填充所有内部区域。可以使用 GUI 自带的多边形填充函数 GUI_FillPolygon 完成填充工作。 一些特殊效果 绘图中需要一些特殊效果如放大,缩小,动画等。使用矢量方式处理图形,进行放大缩小具有无可比拟的优势。所有的座标只需要按照需要的倍数进行乘积变换。甚至可以进行小数位放大缩小,不会有边沿锯齿产生。产生动画效果,需要可以将需要动作的部件独立存储成矢量,在绘制动画之前,将图形拼合成矢量序列。然后按新的矢量序列绘制,即可产生动画效果。 图片数据生成 可以使用矢量图形编辑工具,将所需要的图片转换成矢量图形,然后存储为 SVG 文本格式的文件。从文件中摘取所需要的内容,按上面定义的数据结构组成图片数据。 结论 在实际应用中发现,使用矢量方法处理图形,如显示产品 LOGO ,绘制产品线框图使用说明,显示大字号的文字,对节省存储空间,提高显示性能都特别有效。