当前位置: 首页 > news >正文

为什么做腾讯网站企业品牌logo设计

为什么做腾讯网站,企业品牌logo设计,四川公司网站建设招标,我要注册目录 什么是FrameBufferLCD 的基础知识使用ioctl()获取屏幕参数信息使用mmap()将显示缓冲区映射到用户空间 LCD 应用编程练习之LCD 基本操作LCD 应用编程练习之显示BMP 图片BMP 图像介绍在LCD 上显示BMP 图像在开发板上测试 在LCD 上显示jpeg 图像在LCD 上显示png 图片LCD 横屏… 目录 什么是FrameBufferLCD 的基础知识使用ioctl()获取屏幕参数信息使用mmap()将显示缓冲区映射到用户空间 LCD 应用编程练习之LCD 基本操作LCD 应用编程练习之显示BMP 图片BMP 图像介绍在LCD 上显示BMP 图像在开发板上测试 在LCD 上显示jpeg 图像在LCD 上显示png 图片LCD 横屏切换为竖屏在LCD 上显示字符 本章学习Linux 下的Framebuffer 应用编程通过对本章内容的学习大家将会了解到Framebuffer 设备究竟是什么以及如何编写应用程序来操控FrameBuffer 设备。 什么是FrameBuffer Frame 是帧的意思buffer 是缓冲的意思所以Framebuffer 就是帧缓冲这意味着Framebuffer 就是一块内存里面保存着一帧图像。帧缓冲framebuffer是Linux 系统中的一种显示驱动接口它将显示设备譬如LCD进行抽象、屏蔽了不同显示设备硬件的实现对应用层抽象为一块显示内存显存它允许上层应用程序直接对显示缓冲区进行读写操作而用户不必关心物理显存的位置等具体细节这些都由 Framebuffer 设备驱动来完成。 所以在Linux 系统中显示设备被称为FrameBuffer 设备帧缓冲设备所以LCD 显示屏自然而言就是FrameBuffer 设备。FrameBuffer 设备对应的设备文件为/dev/fbXX 为数字0、1、2、3 等Linux 下可支持多个FrameBuffer 设备最多可达32 个分别为/dev/fb0 到/dev/fb31开发板出厂系统中/dev/fb0 设备节点便是LCD 屏。 应用程序读写/dev/fbX 就相当于读写显示设备的显示缓冲区显存譬如LCD 的分辨率是800480每一个像素点的颜色用24 位譬如RGB888来表示那么这个显示缓冲区的大小就是800 x 480 x 24 / 8 1152000 个字节。譬如执行下面这条命令将LCD 清屏也就是将其填充为黑色假设LCD 对应的设备节点是/dev/fb0分辨率为800480RGB888 格式 dd if/dev/zero of/dev/fb0 bs1024 count1125 这条命令的作用就是将1125x1024 个字节数据全部写入到LCD 显存中并且这些数据都是0x0。 LCD 的基础知识 关于LCD 相关的基础知识本书不再介绍开发板配套提供的驱动教程中已经有过详细的介绍除此之外网络上也能找到相关内容。 19.3 LCD 应用编程介绍 本小节介绍如何对FrameBuffer 设备譬如LCD进行应用编程通过上面的介绍相信大家应该已经知道如何操作LCD 显示设备了应用程序通过对LCD 设备节点/dev/fb0假设LCD 对应的设备节点是 /dev/fb0进行I/O 操作即可实现对LCD 的显示控制实质就相当于读写了LCD 的显存而显存是LCD 的显示缓冲区LCD 硬件会从显存中读取数据显示到LCD 液晶面板上。 在应用程序中操作/dev/fbX 的一般步骤如下 ①、首先打开/dev/fbX 设备文件。 ②、使用ioctl()函数获取到当前显示设备的参数信息譬如屏幕的分辨率大小、像素格式根据屏幕参数计算显示缓冲区的大小。 ③、通过存储映射I/O 方式将屏幕的显示缓冲区映射到用户空间mmap。 ④、映射成功后就可以直接读写屏幕的显示缓冲区进行绘图或图片显示等操作了。 ⑤、完成显示后调用munmap()取消映射、并调用close()关闭设备文件。 从上面介绍的操作步骤来看LCD 的应用编程还是非常简单的这些知识点都是在前面的入门篇中给大家介绍过。 使用ioctl()获取屏幕参数信息 当打开LCD 设备文件之后需要先获取到LCD 屏幕的参数信息譬如LCD 的X 轴分辨率、Y 轴分辨率以及像素格式等信息通过这些参数计算出LCD 显示缓冲区的大小。 通过ioctl() 函数来获取屏幕参数信息对于Framebuffer 设备来说常用的request 包括 FBIOGET_VSCREENINFO、FBIOPUT_VSCREENINFO、FBIOGET_FSCREENINFO。 ⚫ FBIOGET_VSCREENINFO表示获取FrameBuffer 设备的可变参数信息可变参数信息使用struct fb_var_screeninfo 结构体来描述所以此时ioctl() 需要有第三个参数它是一个struct fb_var_screeninfo *指针指向struct fb_var_screeninfo 类型对象调用ioctl()会将LCD 屏的可变参数信息保存在struct fb_var_screeninfo 类型对象中如下所示 struct fb_var_screeninfo fb_var; ioctl(fd, FBIOGET_VSCREENINFO, fb_var); ⚫ FBIOPUT_VSCREENINFO表示设置FrameBuffer 设备的可变参数信息既然是可变参数那说明应用层可对其进行修改、重新配置当然前提条件是底层驱动支持这些参数的动态调整譬如在我们的Windows 系统中用户可以修改屏幕的显示分辨率这就是一种动态调整。同样此时ioctl() 需要有第三个参数也是一个struct fb_var_screeninfo *指针指向struct fb_var_screeninfo 类型对象表示用struct fb_var_screeninfo 对象中填充的数据设置LCD如下所示 struct fb_var_screeninfo fb_var {0}; /* 对fb_var 进行数据填充*/ ...... ...... /* 设置可变参数信息*/ ioctl(fd, FBIOPUT_VSCREENINFO, fb_var);⚫ FBIOGET_FSCREENINFO表示获取FrameBuffer 设备的固定参数信息既然是固定参数那就意味着应用程序不可修改。固定参数信息使用struct fb_fix_screeninfo 结构体来描述所以此时ioctl() 需要有第三个参数它是一个struct fb_fix_screeninfo *指针指向struct fb_fix_screeninfo 类型对象调用ioctl()会将LCD 的固定参数信息保存在struct fb_fix_screeninfo 对象中如下所示 struct fb_fix_screeninfo fb_fix; ioctl(fd, FBIOGET_FSCREENINFO, fb_fix);上面所提到的三个宏定义FBIOGET_VSCREENINFO 、FBIOPUT_VSCREENINFO 、 FBIOGET_FSCREENINFO 以及2 个数据结构struct fb_var_screeninfo 和struct fb_fix_screeninfo 都定义在 linux/fb.h头文件中所以在我们的应用程序中需要包含该头文件。 #define FBIOGET_VSCREENINFO 0x4600 #define FBIOPUT_VSCREENINFO 0x4601 #define FBIOGET_FSCREENINFO 0x4602struct fb_var_screeninfo 结构体 struct fb_var_screeninfo 结构体内容如下所示 struct fb_var_screeninfo {__u32 xres; /* 可视区域一行有多少个像素点X 分辨率*/__u32 yres; /* 可视区域一列有多少个像素点Y 分辨率*/__u32 xres_virtual; /* 虚拟区域一行有多少个像素点*/__u32 yres_virtual; /* 虚拟区域一列有多少个像素点*/__u32 xoffset; /* 虚拟到可见屏幕之间的行偏移*/__u32 yoffset; /* 虚拟到可见屏幕之间的列偏移*/__u32 bits_per_pixel; /* 每个像素点使用多少个bit 来描述也就是像素深度bpp */__u32 grayscale; /* 0 表示彩色, 1 表示灰度, 1 表示FOURCC 颜色*//* 用于描述R、G、B 三种颜色分量分别用多少位来表示以及它们各自的偏移量*/struct fb_bitfield red; /* Red 颜色分量色域偏移*/struct fb_bitfield green; /* Green 颜色分量色域偏移*/struct fb_bitfield blue; /* Blue 颜色分量色域偏移*/struct fb_bitfield transp; /* 透明度分量色域偏移*/__u32 nonstd; /* nonstd 等于0表示标准像素格式不等于0 则表示非标准像素格式*/__u32 activate;__u32 height; /* 用来描述LCD 屏显示图像的高度以毫米为单位*/__u32 width; /* 用来描述LCD 屏显示图像的宽度以毫米为单位*/__u32 accel_flags;/* 以下这些变量表示时序参数*/__u32 pixclock; /* pixel clock in ps (pico seconds) */__u32 left_margin; /* time from sync to picture */__u32 right_margin; /* time from picture to sync */__u32 upper_margin; /* time from sync to picture */__u32 lower_margin;__u32 hsync_len; /* length of horizontal sync */__u32 vsync_len; /* length of vertical sync */__u32 sync; /* see FB_SYNC_* */__u32 vmode; /* see FB_VMODE_* */__u32 rotate; /* angle we rotate counter clockwise */__u32 colorspace; /* colorspace for FOURCC-based modes */__u32 reserved[4]; /* Reserved for future compatibility */ }; 通过xres、yres 获取到屏幕的水平分辨率和垂直分辨率bits_per_pixel 表示像素深度bpp即每一个像素点使用多少个bit 位来描述它的颜色通过xres * yres * bits_per_pixel / 8 计算可得到整个显示缓存区的大小。 red、green、blue 描述了RGB 颜色值中R、G、B 三种颜色通道分别使用多少bit 来表示以及它们各自的偏移量通过red、green、blue 变量可知道LCD 的RGB 像素格式譬如是RGB888 还是RGB565亦或者是BGR888、BGR565 等。struct fb_bitfield 结构体如下所示 struct fb_bitfield {__u32 offset; /* 偏移量*/__u32 length; /* 长度*/__u32 msb_right; /* ! 0 : Most significant bit is right */ }; struct fb_fix_screeninfo 结构体 struct fb_fix_screeninfo 结构体内容如下所示 struct fb_fix_screeninfo {char id[16]; /* 字符串形式的标识符*/unsigned long smem_start; /* 显存的起始地址物理地址*/__u32 smem_len; /* 显存的长度*/__u32 type;__u32 type_aux;__u32 visual;__u16 xpanstep;__u16 ypanstep;__u16 ywrapstep;__u32 line_length; /* 一行的字节数*/unsigned long mmio_start; /* Start of Memory Mapped I/O(physical address) */__u32 mmio_len; /* Length of Memory Mapped I/O */__u32 accel; /* Indicate to driver which specific chip/card we have */__u16 capabilities;__u16 reserved[2]; }; smem_start 表示显存的起始地址这是一个物理地址当然在应用层无法直接使用smem_len 表示显存的长度这个长度并一定等于LCD 实际的显存大小。line_length 表示屏幕的一行像素点有多少个字节通常可以使用line_length * yres 来得到屏幕显示缓冲区的大小。 通过上面介绍接下来我们编写一个示例代码获取LCD 屏幕的参数信息示例代码如下所示 本例程源码对应的路径为开发板光盘-11、Linux C 应用编程例程源码-19_lcd-lcd_info.c。 #include stdio.h #include stdlib.h #include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h #include sys/ioctl.h #include linux/fb.h int main(int argc, char *argv[]) {struct fb_fix_screeninfo fb_fix;struct fb_var_screeninfo fb_var;int fd;/* 打开framebuffer 设备*/if (0 (fd open(/dev/fb0, O_WRONLY))){perror(open error);exit(-1);}/* 获取参数信息*/ioctl(fd, FBIOGET_VSCREENINFO, fb_var);ioctl(fd, FBIOGET_FSCREENINFO, fb_fix);printf(分辨率: %d*%d\n像素深度bpp: %d\n一行的字节数: %d\n像素格式: R%d %d G%d %d B%d %d\n,fb_var.xres, fb_var.yres, fb_var.bits_per_pixel,fb_fix.line_length,fb_var.red.offset, fb_var.red.length,fb_var.green.offset, fb_var.green.length,fb_var.blue.offset, fb_var.blue.length);/* 关闭设备文件退出程序*/close(fd);exit(0); } 首先打开LCD 设备文件开发板出厂系统LCD 对应的设备文件为/dev/fb0打开设备文件之后得到文件描述符fd接着使用ioctl()函数获取LCD 的可变参数信息和固定参数信息并将这些信息打印出来。 在测试之前需将LCD 屏通过软排线连接到开发板掉电情况下连接连接好之后启动开发板。 使用交叉编译工具编译上述示例代码将编译得到的可执行文件拷贝到开发板Linux 系统的用户家目录下并直接运行它如下所示 笔者使用的是7 寸800480 RGB 屏与上图打印显示的分辨率800480 是相符的像素深度为16也就意味着一个像素点的颜色值将使用16bit也就是2 个字节来表示一行的字节数为1600一行共有800 个像素点每个像素点使用16bit 来描述一共就是80016/81600 个字节数据这也是没问题的。 打印出像素格式为R11 5 G5 6 B0 5分别表示R、G、B 三种颜色分量对应的偏移量和长度第一个数字表示偏移量第二个参数为长度从打印的结果可知16bit 颜色值中高5 位表示R 颜色通道、中间6 位表示G 颜色通道、低5 位表示B 颜色通道所以这是一个RGB565 格式的显示设备。 Tips正点原子的RGB LCD 屏幕包括4.3 寸800480、4.3 寸480272、7 寸800480、7 寸1024600 以及10.1 寸1280800 硬件上均支持RGB888但ALPHA/Mini I.MX6U 开发板出厂系统中LCD 驱动程序将其实现为一个RGB565 格式的显示设备用户可修改设备树使其支持RGB888或者通过ioctl 修改。 前面我们提到可以通过ioctl()去设置LCD 的可变参数使用FBIOPUT_VSCREENINFO 宏但不太建议大家去改这些参数如果FrameBuffer 驱动程序支持不够完善改完之后可能会出现一些问题这里就不再演示了。 使用mmap()将显示缓冲区映射到用户空间 在入门篇13.5 小节中给大家介绍了存储映射I/O 这种高级I/O 方式它的一个非常经典的使用场景便是用在Framebuffer 应用编程中。通过mmap()将显示器的显示缓冲区显存映射到进程的地址空间中这样应用程序便可直接对显示缓冲区进行读写操作。 为什么这里需要使用存储映射I/O 这种方式呢其实使用普通的I/O 方式譬如直接read、write也是可以的只是当数据量比较大时普通I/O 方式效率较低。假设某一显示器的分辨率为1920 * 1080像素格式为ARGB8888针对该显示器刷一帧图像的数据量为1920 x 1080 x 32 / 8 8294400 个字节约等于8MB这还只是一帧的图像数据而对于显示器来说显示的图像往往是动态改变的意味着图像数据会被不断更新。 在这种情况下数据量是比较庞大的使用普通I/O 方式必然导致效率低下所以才会采用存储映射 I/O 方式。 LCD 应用编程练习之LCD 基本操作 本小节编写应用程序在LCD 上实现画点俗称打点、画线、画矩形等基本LCD 操作示例代码如下所示 本例程源码对应的路径为开发板光盘-11、Linux C 应用编程例程源码-19_lcd-lcd_test.c。 #include stdio.h #include stdlib.h #include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h #include sys/ioctl.h #include sys/mman.h #include linux/fb.h #define argb8888_to_rgb565(color) ({ \unsigned int temp (color); \((temp 0xF80000UL) 8) | \((temp 0xFC00UL) 5) | \((temp 0xF8UL) 3); \ }) static int width; // LCD X 分辨率 static int height; // LCD Y 分辨率 static unsigned short *screen_base NULL; // 映射后的显存基地址 /********************************************************************* 函数名称lcd_draw_point* 功能描述打点* 输入参数x, y, color* 返回值无********************************************************************/ static void lcd_draw_point(unsigned int x, unsigned int y, unsigned int color) {unsigned short rgb565_color argb8888_to_rgb565(color); // 得到RGB565 颜色值/* 对传入参数的校验*/if (x width)x width - 1;if (y height)y height - 1;/* 填充颜色*/screen_base[y * width x] rgb565_color; } /********************************************************************* 函数名称lcd_draw_line* 功能描述画线水平或垂直线* 输入参数x, y, dir, length, color* 返回值无********************************************************************/ static void lcd_draw_line(unsigned int x, unsigned int y, int dir,unsigned int length, unsigned int color) {unsigned short rgb565_color argb8888_to_rgb565(color); // 得到RGB565 颜色值unsigned int end;unsigned long temp;/* 对传入参数的校验*/if (x width)x width - 1;if (y height)y height - 1;/* 填充颜色*/temp y * width x; // 定位到起点if (dir){ // 水平线end x length - 1;if (end width)end width - 1;for (; x end; x, temp)screen_base[temp] rgb565_color;}else{ // 垂直线end y length - 1;if (end height)end height - 1;for (; y end; y, temp width)screen_base[temp] rgb565_color;} } /********************************************************************* 函数名称lcd_draw_rectangle* 功能描述画矩形* 输入参数start_x, end_x, start_y, end_y, color* 返回值无********************************************************************/ static void lcd_draw_rectangle(unsigned int start_x, unsigned int end_x,unsigned int start_y, unsigned int end_y,unsigned int color) {int x_len end_x - start_x 1;int y_len end_y - start_y - 1;lcd_draw_line(start_x, start_y, 1, x_len, color); // 上边lcd_draw_line(start_x, end_y, 1, x_len, color); // 下边lcd_draw_line(start_x, start_y 1, 0, y_len, color); // 左边lcd_draw_line(end_x, start_y 1, 0, y_len, color); // 右边 } /********************************************************************* 函数名称lcd_fill* 功能描述将一个矩形区域填充为参数color 所指定的颜色* 输入参数start_x, end_x, start_y, end_y, color* 返回值无********************************************************************/ static void lcd_fill(unsigned int start_x, unsigned int end_x,unsigned int start_y, unsigned int end_y,unsigned int color) {unsigned short rgb565_color argb8888_to_rgb565(color); // 得到RGB565 颜色值unsigned long temp;unsigned int x;/* 对传入参数的校验*/if (end_x width)end_x width - 1;if (end_y height)end_y height - 1;/* 填充颜色*/temp start_y * width; // 定位到起点行首for (; start_y end_y; start_y, temp width){for (x start_x; x end_x; x)screen_base[temp x] rgb565_color;} } int main(int argc, char *argv[]) {struct fb_fix_screeninfo fb_fix;struct fb_var_screeninfo fb_var;unsigned int screen_size;int fd;/* 打开framebuffer 设备*/if (0 (fd open(/dev/fb0, O_RDWR))){perror(open error);exit(EXIT_FAILURE);}/* 获取参数信息*/ioctl(fd, FBIOGET_VSCREENINFO, fb_var);ioctl(fd, FBIOGET_FSCREENINFO, fb_fix);screen_size fb_fix.line_length * fb_var.yres;width fb_var.xres;height fb_var.yres;/* 将显示缓冲区映射到进程地址空间*/screen_base mmap(NULL, screen_size, PROT_WRITE, MAP_SHARED, fd, 0);if (MAP_FAILED (void *)screen_base){perror(mmap error);close(fd);exit(EXIT_FAILURE);}/* 画正方形方块*/int w height * 0.25; // 方块的宽度为1/4 屏幕高度lcd_fill(0, width - 1, 0, height - 1, 0x0); // 清屏屏幕显示黑色lcd_fill(0, w, 0, w, 0xFF0000); // 红色方块lcd_fill(width - w, width - 1, 0, w, 0xFF00); // 绿色方块lcd_fill(0, w, height - w, height - 1, 0xFF); // 蓝色方块lcd_fill(width - w, width - 1, height - w, height - 1, 0xFFFF00); // 黄色方块/* 画线: 十字交叉线*/lcd_draw_line(0, height * 0.5, 1, width, 0xFFFFFF); // 白色线lcd_draw_line(width * 0.5, 0, 0, height, 0xFFFFFF); // 白色线/* 画矩形*/unsigned int s_x, s_y, e_x, e_y;s_x 0.25 * width;s_y w;e_x width - s_x;e_y height - s_y;for (; (s_x e_x) (s_y e_y);s_x 5, s_y 5, e_x - 5, e_y - 5)lcd_draw_rectangle(s_x, e_x, s_y, e_y, 0xFFFFFF);/* 退出*/munmap(screen_base, screen_size); // 取消映射close(fd); // 关闭文件exit(EXIT_SUCCESS); // 退出进程 } 在示例代码中定义了一个宏argb8888_to_rgb565用于实现将unsigned int 类型的颜色也就是 ARGB8888 颜色转换为RGB565 颜色。 程序中自定义了4 个函数 lcd_draw_point用于实现画点、打点操作参数x 和y 指定像素点的位置参数color 表示颜色。 lcd_draw_line用于实现画线操作参数x 和y 指定线的起始位置参数dir 表示方向水平方向dir!0还是垂直方向dir0不支持斜线画法画斜线需要一些算法去操作这不是本章内容需要去关注的知识点参数length 表示线的长度以像素为单位参数color 表示线条的颜色。 lcd_draw_rectangle用于实现画矩形操作参数start_x 和start_y 指定矩形左上角的位置参数end_x 和end_y 指定矩形右下角的位置参数color 指定矩形4 个边的线条颜色。 lcd_fill将一个指定的矩形区域填充为参数color 指定的颜色参数start_x 和start_y 指定矩形左上角的位置参数end_x 和end_y 指定矩形右下角的位置参数color 指定矩形区域填充的颜色。 具体代码的实现各位读者自己去看非常简单来看下main()中做了哪些事情 ⚫ 首先调用open()打开LCD 设备文件得到文件描述符fd ⚫ 接着使用ioctl 函数获取LCD 的可变参数信息和固定参数信息通过得到的信息计算LCD 显存大小、得到LCD 屏幕的分辨率从图19.3.1 可知ALPHA/Mini I.MX6U 开发板出厂系统将LCD 实现为一个RGB565 显示设备所以程序中自定义的4 个函数在操作LCD 像素点时、都是以RGB565 的格式写入颜色值。 ⚫ 接着使用mmap 建立映射 ⚫ 映射成功之后就可以在应用层直接操作LCD 显存了调用自定义的函数在LCD 上画线、画矩形、画方块 ⚫ 操作完成之后调用munmap 取消映射调用close 关闭LCD 设备文件退出程序。 编译应用程序 将编译得到的可执行文件拷贝到开发板Linux 系统的用户家目录下执行应用程序在测试之前先将出厂系统对应的Qt GUI 应用程序退出 此时LCD 屏上将会显示程序中绘制的方块、矩形、以及线条 忽略手机拍摄的问题实际效果各位读者运行程序便知。 LCD 应用编程练习之显示BMP 图片 本小节介绍如何在LCD 上显示一张BMP 图片在编写程序之前首先需要对BMP 格式图片进行简单地介绍。 BMP 图像介绍 我们常用的图片格式有很多一般最常用的有三种JPEG或JPG、PNG、BMP 和GIF。其中JPEG 或JPG、PNG 以及BMP 都是静态图片而GIF 则可以实现动态图片。在本小节实验中我们选择使用 BMP 图片格式。 BMP全称Bitmap是Window 操作系统中的标准图像文件格式文件后缀名为“.bmp”使用非常广。它采用位映射存储格式除了图像深度可选以外图像数据没有进行任何压缩因此BMP 图像文件所占用的空间很大但是没有失真、并且解析BMP 图像简单。 BMP 文件的图像深度可选lbit、4bit、8bit、16bit、24bit 以及32bit典型的BMP 图像文件由四部分组成 ①、BMP 文件头BMP file header它包含BMP 文件的格式、大小、位图数据的偏移量等信息 ②、位图信息头bitmap information它包含位图信息头大小、图像的尺寸、图像大小、位平面数、压缩方式以及颜色索引等信息 ③、调色板color palette这部分是可选的如果使用索引来表示图像调色板就是索引与其对应颜色的映射表 ④、位图数据bitmap data也就是图像数据。 BMP 文件头、位图信息头、调色板和位图数据总结如下表所示 一般常见的图像都是以16 位R、G、B 三种颜色分别使用5bit、6bit、5bit 来表示、24 位R、G、 B 三种颜色都使用8bit 来表示色图像为主我们称这样的图像为真彩色图像真彩色图像是不需要调色板的即位图信息头后面紧跟的就是位图数据了。 对某些BMP 位图文件说并非如此譬如16 色位图、256 色位图它们需要使用到调色板具体调色板如何使用我们不关心本节我们将会以16 位色RGB565BMP 图像为例。 以一张16 位BMP 图像为例如何的到16 位色BMP 图像后面向大家介绍如下图所示 首先在Windows 下查看该图片的属性如下所示 可以看到该图片的分辨率为800*480位深度为16bit每个像素点使用16 位表示也就是RGB565。为了向大家介绍BMP 文件结构接下来使用十六进制查看工具将image.bmp 文件打开文件头部分的内容如下所示 一、bmp 文件头 Windows 下为bmp 文件头定义了如下结构体 typedef struct tagBITMAPFILEHEADER {UINT16 bfType;DWORD bfSize;UINT16 bfReserved1;UINT16 bfReserved2;DWORD bfOffBits; } BITMAPFILEHEADER;结构体中每一个成员说明如下 从上面的描述信息再来对照文件数据 00~01H0x42、0x4D 对应的ASCII 字符分别为为B、M表示这是Windows 所支持的位图格式该字段必须是“BM”才是Windows 位图文件。 02~05H对应于文件大小0x000BB848768072 字节与image.bmp 文件大小是相符的。 06~09H保留字段。 0A~0D0x0000004670即从文件头部开始到位图数据需要偏移70 个字节。 bmp 文件头的大小固定为14 个字节。 二、位图信息头 同样Windows 下为位图信息头定义了如下结构体 typedef struct tagBITMAPINFOHEADER {DWORD biSize;LONG biWidth;LONG biHeight;WORD biPlanes;WORD biBitCount;DWORD biCompression;DWORD biSizeImage;LONG biXPelsPerMeter;LONG biYPelsPerMeter;DWORD biClrUsed;DWORD biClrImportant; } BITMAPINFOHEADER;结构体中每一个成员说明如下 从上面的描述信息再来对照文件数据 0E~11H0x0000003856这说明这个位图信息头的大小为56 个字节。 12~15H0x00000320800图像宽度为800 个像素与文件属性一致。 16~19H0x000001E0480图像高度为480 个像素与文件属性一致这个数是一个正数说明是一个倒向的位图什么是正向的位图、什么是倒向的位图说的是图像数据的排列问题如果是正向的位图 图像数据是按照图像的左上角到右下角方式排列的水平方向从左到右垂直方向从上到下。倒向的位图图像数据则是按照图像的左下角到右上角方式排列的水平方向依然从左到右垂直方向改为从下到上。 1A~1BH0x00011这个值总为1。 1C~1DH0x001016表示每个像素占16 个bit。 1E~21H0x000000033bit-fileds 方式。 22~25H0x000BB802768002图像的大小注意图像的大小并不是BMP 文件的大小而是图像数据的大小。 26~29H0x00000EC23778水平分辨率为3778 像素/米。 2A~2DH0x00000EC23778垂直分辨率为3778 像素/米。 2E~31H0x000000000本位图未使用调色板。 32~35H0x000000000。 只有压缩方式选项被设置为bit-fileds0x3时位图信息头的大小才会等于56 字节否则为40 字节。56 个字节相比于40 个字节多出了16 个字节那么多出的16 个字节数据描述了什么信息呢稍后再给大家介绍。 三、调色板 调色板是单色、16 色、256 色位图图像文件所持有的如果是16 位、24 位以及32 位位图文件则BMP 文件组成部分中不包含调色板关于调色板这里不过多介绍有兴趣可以自己去了解。 四、位图数据 位图数据其实就是图像的数据对于24 位位图使用3 个字节数据来表示一个像素点的颜色对于16 位位图使用2 个字节数据来表示一个像素点的颜色同理32 位位图则使用4 个字节来描述。 BMP 位图分为正向的位图和倒向的位图主要区别在于图像数据存储的排列方式前面已经给大家解释的比较清楚了如下如所示左边对应的是正向位图右边对应的则是倒向位图 所以正向位图先存储图像的第一行数据从左到右依次存放接着存放第二行依次这样而倒向位图则先存储图像的最后一行倒数第一行数据也是从左到右依次存放接着倒数二行依次这样。 RGB 和Bit-Fields 当图像中引用的色彩超过256 种时就需要16bpp 或更高bpp 的位图24 位、32 位。调色板不适合 bpp 较大的位图因此16bpp 及以上的位图都不使用调色板不使用调色板的位图图像有两种编码格式 RGB 和Bit-Fields下称BF。 RGB 编码格式是一种均分的思想使Red、Green、Blue 三种颜色信息容量一样大譬如24bpp-RGB它通常只有这一种编码格式在24bits 中低8 位表示Blue 分量中8 为表示Green 分量高8 位表示Red 分量。 而在32bpp-RGB 中低24 位的编码方式与24bpp 位图相同最高8 位用来表示透明度Alpha 分量。 32bpp 的位图尺寸太大一般只有在图像处理的中间过程中使用。对于需要半透过效果的图像更好的选择是PNG 格式。 BF 编码格式与RGB 不同它利用位域操作人为地确定RGB 三分量所包含的信息容量。位图信息头介绍中提及到当压缩方式选项置为BF 时位图信息头大小比平时多出16 字节这16 个字节实际上是4 个32bit 的位域掩码按照先后顺序它们分别是R、G、B、A 四个分量的位域掩码当然如果没有Alpha 分量则Alpha 掩码没有实际意义。 位域掩码的作用是指出R、G、B 三种颜色信息容量的大小分别使用多少个bit 数据来表示以及三种颜色分量的位置偏移量。譬如对于16 位色的RGB565 图像通常使用BF 编码格式同样这也是BF 编码格式最著名和最普遍的应用之一它的R、G 和B 分量的位域掩码分别是0xF800、0x07E0 和0x001F也就是R 通道使用2 个字节中的高5 位表示G 通道使用2 个字节中的中间6 位表示。而B 通道则使用2 个字节中的最低5 位表示如下图所示 关于BMP 图像文件的格式就给大家介绍这么多后面的程序代码中将不会再做解释 如何得到16 位色RGB565 格式BMP 图像 在Windows 下我们转换得到的BMP 位图通常是24 位色的RGB888 格式图像那如何得到RGB565 格式BMP 位图呢当然这个方法很多这里笔者向大家介绍一种方法就是通过Photoshop 软件来得到RGB565 格式的BMP 位图。 首先找一张图片图片格式无所谓只要Photoshop 软件能打开即可确定图片之后我们启动Photoshop 软件并且使用Photoshop 软件打开这张图片打开之后点击菜单栏中的文件—存储为接着出现如下界面 在这个界面中首先选择文件保存的路径然后设置文件名以及文件格式选择文件格式为BMP 格式之后点击保存如下 点击选择16 位色图接着点击高级模式按钮 点击选择RGB565接着点击确定按钮即可这样就可得到16 位色RGB565 格式的BMP 图像。 在LCD 上显示BMP 图像 通过上小节对BMP 图像的介绍之后相信大家对BMP 文件的格式已经非常了解了那么本小节我们将编写一个示例代码在LCD 上显示一张指定的BMP 图像示例代码笔者已经完成了如下所示。 本例程源码对应的路径为开发板光盘-11、Linux C 应用编程例程源码-19_lcd-bmp_show.c。 #include stdio.h #include stdlib.h #include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h #include sys/ioctl.h #include string.h #include linux/fb.h #include sys/mman.h /**** BMP 文件头数据结构****/ typedef struct {unsigned char type[2]; // 文件类型unsigned int size; // 文件大小unsigned short reserved1; // 保留字段1unsigned short reserved2; // 保留字段2unsigned int offset; // 到位图数据的偏移量 } __attribute__((packed)) bmp_file_header; /**** 位图信息头数据结构****/ typedef struct {unsigned int size; // 位图信息头大小int width; // 图像宽度int height; // 图像高度unsigned short planes; // 位面数unsigned short bpp; // 像素深度unsigned int compression; // 压缩方式unsigned int image_size; // 图像大小int x_pels_per_meter; // 像素/米int y_pels_per_meter; // 像素/米unsigned int clr_used;unsigned int clr_omportant; } __attribute__((packed)) bmp_info_header; /**** 静态全局变量****/ static int width; // LCD X 分辨率 static int height; // LCD Y 分辨率 static unsigned short *screen_base NULL; // 映射后的显存基地址 static unsigned long line_length; // LCD 一行的长度字节为单位 /********************************************************************* 函数名称show_bmp_image* 功能描述在LCD 上显示指定的BMP 图片* 输入参数文件路径* 返回值成功返回0, 失败返回-1********************************************************************/ static int show_bmp_image(const char *path) {bmp_file_header file_h;bmp_info_header info_h;unsigned short *line_buf NULL; // 行缓冲区unsigned long line_bytes; // BMP 图像一行的字节的大小unsigned int min_h, min_bytes;int fd -1;int j;/* 打开文件*/if (0 (fd open(path, O_RDONLY))){perror(open error);return -1;}/* 读取BMP 文件头*/if (sizeof(bmp_file_header) !read(fd, file_h, sizeof(bmp_file_header))){perror(read error);close(fd);return -1;}if (0 ! memcmp(file_h.type, BM, 2)){fprintf(stderr, its not a BMP file\n);close(fd);return -1;}/* 读取位图信息头*/if (sizeof(bmp_info_header) !read(fd, info_h, sizeof(bmp_info_header))){perror(read error);close(fd);return -1;}/* 打印信息*/printf(文件大小: %d\n位图数据的偏移量: %d\n位图信息头大小: %d\n图像分辨率: %d*%d\n像素深度: %d\n,file_h.size, file_h.offset,info_h.size, info_h.width, info_h.height,info_h.bpp);/* 将文件读写位置移动到图像数据开始处*/if (-1 lseek(fd, file_h.offset, SEEK_SET)){perror(lseek error);close(fd);return -1;}/* 申请一个buf、暂存bmp 图像的一行数据*/line_bytes info_h.width * info_h.bpp / 8;line_buf malloc(line_bytes);if (NULL line_buf){fprintf(stderr, malloc error\n);close(fd);return -1;}if (line_length line_bytes)min_bytes line_bytes;elsemin_bytes line_length;/**** 读取图像数据显示到LCD ****//******************************************** 为了软件处理上方便这个示例代码便不去做兼容性设计了* 如果你想做兼容, 可能需要判断传入的BMP 图像是565 还是888* 如何判断呢文档里边说的很清楚了* 我们默认传入的bmp 图像是RGB565 格式*******************************************/if (0 info_h.height){ // 倒向位图if (info_h.height height){min_h height;lseek(fd, (info_h.height - height) * line_bytes, SEEK_CUR);screen_base width * (height - 1); // 定位到屏幕左下角位置}else{min_h info_h.height;screen_base width * (info_h.height - 1); // 定位到....不知怎么描述懂的人自然懂!}for (j min_h; j 0; screen_base - width, j--){read(fd, line_buf, line_bytes); // 读取出图像数据memcpy(screen_base, line_buf, min_bytes); // 刷入LCD 显存}}else{ // 正向位图int temp 0 - info_h.height; // 负数转成正数if (temp height)min_h height;elsemin_h temp;for (j 0; j min_h; j, screen_base width){read(fd, line_buf, line_bytes);memcpy(screen_base, line_buf, min_bytes);}}/* 关闭文件、函数返回*/close(fd);free(line_buf);return 0; } int main(int argc, char *argv[]) {struct fb_fix_screeninfo fb_fix;struct fb_var_screeninfo fb_var;unsigned int screen_size;int fd;/* 传参校验*/if (2 ! argc){fprintf(stderr, usage: %s bmp_file\n, argv[0]);exit(-1);}/* 打开framebuffer 设备*/if (0 (fd open(/dev/fb0, O_RDWR))){perror(open error);exit(EXIT_FAILURE);}/* 获取参数信息*/ioctl(fd, FBIOGET_VSCREENINFO, fb_var);ioctl(fd, FBIOGET_FSCREENINFO, fb_fix);screen_size fb_fix.line_length * fb_var.yres;line_length fb_fix.line_length;width fb_var.xres;height fb_var.yres;/* 将显示缓冲区映射到进程地址空间*/screen_base mmap(NULL, screen_size, PROT_WRITE, MAP_SHARED, fd, 0);if (MAP_FAILED (void *)screen_base){perror(mmap error);close(fd);exit(EXIT_FAILURE);}/* 显示BMP 图片*/memset(screen_base, 0xFF, screen_size);show_bmp_image(argv[1]);/* 退出*/munmap(screen_base, screen_size); // 取消映射close(fd); // 关闭文件exit(EXIT_SUCCESS); // 退出进程 } 代码中有两个自定义结构体bmp_file_header 和bmp_info_header描述bmp 文件头的数据结构 bmp_file_header、以及描述位图信息头的数据结构bmp_info_header。 当执行程序时候需要传入参数指定一个bmp 文件。main()函数中会调用show_bmp_image()函数在 LCD 上显示bmp 图像show_bmp_image()函数的参数为bmp 文件路径在show_bmp_image()函数中首先会打开指定路径的bmp 文件得到对应的文件描述符fd接着调用read()函数读取bmp 文件头和位图信息头。 获取到信息之后使用printf 将其打印出来接着使用lseek()函数将文件的读写位置移动到图像数据起始位置处也就是bmp_file_header 结构体中的offset 变量指定的地址偏移量。 通过info_h.height 判断该BMP 位图是正向的位图还是倒向的位图它们的处理方式不一样这些代码自己去看笔者不好去解释毕竟这只是文字描述的形式不太好表述代码只是一种参考自己能够独立写出来才是硬道理 关于本示例代码就介绍这么多接下来使用交叉编译工具编译上述示例代码如下 在开发板上测试 将上小节编译得到的可执行文件testApp 以及测试使用的bmp 图像文件拷贝到开发板Linux 系统的用户家目录下 接着执行测试程序在测试之前先将出厂系统对应的Qt GUI 应用程序退出 此时LCD 屏上会显示image.bmp 图像。 如下所示 忽略手机拍摄的问题由于周围物体以及光线导致上图显示的结果与实际LCD 显示的图像存在差异 image.bmp 原图如下所示 在LCD 上显示jpeg 图像 在LCD 上显示png 图片 LCD 横屏切换为竖屏 在LCD 上显示字符
http://www.yutouwan.com/news/212882/

相关文章:

  • 阿升网站免费学设计网站改版方案策划书
  • 网站制作教程迅雷下载网店推广有哪些
  • 网站建设网络推广平台网站关于我们页面设计
  • 百度收录公司网站wordpress后台账户密码登不进
  • 计算机 网站开发 文章百度网页版官网首页
  • 深圳网站建设服务哪个便宜啊柳市网站建设哪家好
  • 网站建设合同怎么写定制网站制作费用
  • 首页关键词是不是一个网站的核心关键词所在企业邮箱怎么申请免费的
  • 学院网站设计案例设计公司的网站建设
  • 商务型网站建设做网站公司那家好
  • 江苏备案网站名称html代码小游戏
  • 赤峰市建设网站建站多少钱一个
  • 建外贸企业网站校园网络建设
  • 太原网站制作小程序手机网站绑定域名是什么意思
  • 网站建设图片教程衡阳网站优化公司
  • 引擎网站推广法河北seo公司
  • 网站建设成功案例宣传豌豆荚官网入口
  • 提供网站建设哪家好企业163邮箱登录入口
  • 设计了网站flashfxp怎么做网站
  • 外包网站设计公司上海建设工程交易服务中心
  • 泉州网站建设选择讯呢网站建设2018需要什么
  • 汽车网站开发背景用html表格做的网站
  • 深圳夫博网站建设有限公司白人与黑人做爰网站
  • 百度索引量和网站排名佳木斯哈尔滨网站建设
  • 建网站的软件嘉定公司网站设计
  • 做网站图片不够大服务器网络
  • 株洲网站建设企业windows优化大师
  • 专门做消防器材的网站找游戏的手游平台
  • 哈密地网站建设wordpress 多用户插件
  • 制作网站流程图东莞网站建设乐云seo在线制作