1.lcd屏幕显示的基本原理
- 像素:
屏幕上显示颜色的最小单位,英文叫 pixel。注意,位图(如jpg、bmp等格式的常见图片)也是由一个个的像素点构成的,跟屏幕的像素点的概念一样。原理上讲,将一张位图显示到屏幕上,就是将图片上的像素点一个个复制到屏幕像素点上。
- 分辨率:
- 宽、高两个维度上的像素点数目。
- 分辨率越高,所需要的显存越大。
- 色深:
- 每个像素所对应的内存字节数,一般有8位、16位、24位或32位
- GEC6818开发板的屏幕的色深是32位的
- 32位色深的屏幕一般被称为真彩屏,或1600万色屏。
色深决定了一个像素点所能表达的颜色的丰富程度,色深越大,色彩表现力越强。
2. mmap映射
虽然LCD设备本质上也可以看作是一个文件,在文件系统中有其对应的设备节点,可以像普通文件一样对其进行读写操作(read/write),但由于对字符设备的读写操作是以字节流的方式进行的,因此除非操作的图像尺寸刚好与屏幕尺寸完全一致,如下图所示,图片的宽高与LCD的宽高完全一致,否则将会画面会乱。并且效率相对较低
图像的尺寸大小是随机的,因此更方便的做法是为LCD做内存映射,将屏幕的每一个像素点跟映射内存一一对应,而映射内存可以是二维数组,因此就可以非常方便地通过操作二维数组中的任意元素,来操作屏幕中的任意像素点了。这里的映射内存,有时被称为显存。
- LCD上面显示的图像色彩,由其对应的内存的数据决定
- 映射内存的大小至少得等于LCD的真实尺寸大小
- 映射内存的大小可以大于LCD的真实尺寸,有利于优化动态画面(视频)体验
bmp格式
文件组成
特征是都没有任何的压缩,因此文件尺寸都比较大,不适合在互联网上传播,优点是数据读取出来即可使用,无需任何解码器支持。
数据段名称 | 对应大小 |
bmp头文件 | 14 |
信息头 | 40 |
调色板 | 从54开始,有像素点的大小决定 |
注意
a. 4字节倍数行距
BMP图片文件的一个重要规则是,每行数据字节数必须是4的倍数,假设某BMP图片的分辨率是 65 × 200,也就是说宽是 65
像素,假设每个字节色深是24bits(即3字节),那么这张图片一行的实际数据量是 65×3=195
个字节,但195不是4的倍数,因此在每一行的末尾都会添加一个无效字节,将行距尺寸补到196个字节。
int pad = ((4-( width * bpp/8 ) % 4)) % 4;//计算增加的无效字节
其次,在处理图像数据的时候,直接跳过这些无效字节就好了。
b. 上下颠倒
BMP图片中的RGB数据是上下颠倒的,因此文件数据中的最后一行是图像的最上面第一行。需要注意的是,上下是颠倒的,但是左右是正常的,因此在处理数据的时候不能从最后一个字节开始,而是从最末一行的首字节开始。
3.jpg格式
在bmp格式下可以直接读文件中RGB值进行显示,但是在jpg格式下的文件必须先进行解码
jpg第三方开源解码器下载与配置使用
在嵌入式来发中,运用第三方库套路基本一致,所以在这详细介绍一下
(1)下载
直接官方进行下载Independent JPEG Group
不要在Windows下进行解压,会导致问价损坏,将压缩包放在Linux下进行解压
可以阅读README了解开发原理
如何安装
如何使用和例程
在install.txt中
移植三件套./config make makefile
当运行config的时候会检查各种配置,配置检查完成会生成makefile
在开发板中使用的编译工具为gcc
在install,txt中说明需要使用CC=命令进行改变便以及
将所有的编译命令的前缀改为arrch64-linux
生成makefile
指定其他路径
开启4条线程
提取
提取完成后需要将。文件夹中的lib 与include 中的文件导入到所要使用的文件对应目录中使用一下命令进行编译
-L:指定库路径 -l指定库名称 -I(i)指定头文件路径
需要将lib的函数库文件拷贝到开发板的/lib/里面 解决掉找不到库文件的问题
用于指明编译工具
--host=编译工具
用于指明存放路径
--prifix=存放路径
(2)通过官方例程example进行修改
以下为例程
METHODDEF(void)
my_error_exit (j_common_ptr cinfo)
{
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
my_error_ptr myerr = (my_error_ptr) cinfo->err;
/* Always display the message. */
/* We could postpone this until after returning, if we chose. */
(*cinfo->err->output_message) (cinfo);
/* Return control to the setjmp point */
longjmp(myerr->setjmp_buffer, 1);
}
struct RGB
{
char rad;
cahr green;
char blue;
};
int read_JPEG_file(char *filename, int *screen_buf)
{
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
FILE *infile; /* source file */
struct RGB *buffer; /* Output row buffer */
int row_stride; /* physical row width in output buffer */
if ((infile = fopen(filename, "rb")) == NULL)
{
fprintf(stderr, "can't open %s\n", filename);
return 0;
}
/* Step 1: allocate and initialize JPEG decompression object */
/* We set up the normal JPEG error routines, then override error_exit. */
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
/* Establish the setjmp return context for my_error_exit to use. */
if (setjmp(jerr.setjmp_buffer))
{
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object, close the input file, and return.
*/
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return 0;
}
if ((infile = fopen(filename, "r")) == NULL) // 打开源文件
{
fprintf(stderr, "can't open %s\n", filename);
return 0;
}
/* Step 1: allocate and initialize JPEG decompression object */
jpeg_create_decompress(&cinfo);
/* Step 2: specify data source (eg, a file) */
jpeg_stdio_src(&cinfo, infile);
/* Step 3: read file parameters with jpeg_read_header() */
(void)jpeg_read_header(&cinfo, TRUE);
/*开始解码*/
(void)jpeg_start_decompress(&cinfo);
row_stride = cinfo.output_width * cinfo.output_components;
/* Make a one-row-high sample array that will go away when done with image */
buffer = malloc(row_stride);
int x, y;
int calor;
/*逐行进行数据读取 */
for (y = 0; cinfo.output_scanline < cinfo.output_height; y++)
{
/*将数据的一行读取出来方入buffer中 */
(void)jpeg_read_scanlines(&cinfo, (JSAMPARRAY)&buffer, 1);
for (x = 0; x < cinfo.output_width; x++)
{
calor = (buffer[x].rad << 16) | (buffer[x].green << 8) | (buffer[x].blue);
screen_disp(x, y, screen_buf, calor);
}
/* Assume put_scanline_someplace wants a pointer and sample count. */
// put_scanline_someplace(buffer[0], row_stride);
}
(void)jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return 1;
}