嵌入式 在开发板显示bmp图片、jpeg图片

一、简述

        记--在GEC6818开发板(800W*480H)显示24位的bmp图片、使用开源的jpeg库显示jpeg图片。

        代码:链接: https://pan.baidu.com/s/1G3jzvdncocDMRbwCvsmSlg 密码: gz6m

二、效果

        执行开始显示bmp图片,回车后显示jpg图片。



三、工程结构

        

        

四、源代码

        display_bmp.c文件

        
#include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include
<sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>
#include "lcd.h" #include "freetype.h" #include "to_wchar.h" #include
"display_bmp.h" /*display_bmp:显示bmp图片 *pathname:图片的路径名 *lcd_ptr:指向LCD映射首地址
*x_s,y_s:左上角起始点 */ int display_bmp(const char *pathname, unsigned int
*lcd_ptr,unsigned int x_s, unsigned int y_s) { unsigned int
bmp_width,bmp_height; unsigned int x, y, color; unsigned char *pic_buf_ptr,
*ptr_save; if( get_bmp_width_and_height( pathname, &bmp_width, &bmp_height) !=
0 )//获取图片的宽高 { fprintf(stderr, "get bmp width and height failed!\n"); return
-1; } if( get_pic_data_to_buffer(pathname, &pic_buf_ptr) == -1 )//获取图片的像素数据 {
fprintf(stderr, "get picture data error\n"); return -1; } ptr_save =
pic_buf_ptr; for(y=y_s; y<y_s+bmp_height && y< LCD_HEIGHT; y++) { for(x=x_s; x<
x_s+bmp_width ; x++) { if(x>=0 && x< LCD_WIDTH) { //将RGB的3个字节颜色数据装到4字节 RGB:红绿蓝
color = (*(pic_buf_ptr+2)<<16) | (*(pic_buf_ptr+1)<<8) | (*pic_buf_ptr);
lcd_draw_point(x, LCD_HEIGHT-y-1, color, lcd_ptr);//LCD_HEIGHT-y-1:镜像翻转 }
pic_buf_ptr += 3;//三个字节一个颜色像素点 } } //显示图片路径名 wchar_t *w_pathname = NULL; if(
mchars_to_wchars(pathname, &w_pathname) == 0)//将多字节转换为宽字符(汉字未能转换成功) { //显示字体
Lcd_Show_FreeType(w_pathname,32,0x00,x_s+10,y_s+50, lcd_ptr); free(w_pathname);
} free( ptr_save ); return 0; } /*get_pic_data_to_buffer:获取图片的像素数据
*pathname:图片的路径名 *pic_buf_ptr:用来指向 存放图片的像素数据缓冲区 */ int
get_pic_data_to_buffer(const char *pathname, unsigned char **pic_buf_ptr) {
FILE *pic_fp; off_t file_size; struct stat file_info; pic_fp = fopen(pathname,
"r"); if(pic_fp == NULL) { perror("open %s error\n"); return -1; } if(
stat(pathname, &file_info) == -1) { perror("get file info error\n"); return -1;
} file_size = file_info.st_size;//获取图片大小 *pic_buf_ptr = (unsigned char
*)malloc(file_size-54); fseek(pic_fp, 54,SEEK_SET);//跳过文件头(存在内存对齐,可能是56字节)
fread(*pic_buf_ptr, file_size-54, 1, pic_fp);//读取图片颜色数据 if(ferror(pic_fp)) {
perror("read picture data error\n"); return -1; } return fclose(pic_fp); }
/*get_bmp_width_and_height:获取bmp图片的宽高信息 *pathname:图片路径名 *width:图片的宽度
*height:图片的高度 */ int get_bmp_width_and_height(const char *pathname, unsigned
int *width, unsigned int *height) { FILE *pic_fp; unsigned char file_head[54];
pic_fp = fopen(pathname, "r"); if(pic_fp == NULL) { perror("open %s error\n");
return -1; } fread( file_head, 54, 1, pic_fp); if( ferror( pic_fp ) ) {
perror("read picture head error\n"); return -1; } fclose(pic_fp); *width =
*((int*)&file_head[18]);//宽:18~21共4个字节 *height = file_head[22] |
file_head[23]<<8;//高:22~23共两个字节 return 0; }
        display_jpeg.c文件
#include <stdio.h> #include <stdlib.h> #include <setjmp.h> #include
<jpeglib.h> #include <jerror.h> #include "lcd.h" #include "to_wchar.h" extern
JSAMPLE * image_buffer; /* Points to large array of R,G,B-order data */ extern
int image_height; /* Number of rows in image */ extern int image_width; struct
my_error_mgr { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf
setjmp_buffer; /* for return to caller */ }; typedef struct my_error_mgr *
my_error_ptr; METHODDEF(void) my_error_exit (j_common_ptr cinfo) { my_error_ptr
myerr = (my_error_ptr) cinfo->err; (*cinfo->err->output_message) (cinfo);
longjmp(myerr->setjmp_buffer, 1); } /*display_jpeg:显示jpeg图片 *filename:图片的路径名
*lcd_ptr:指向LCD映射首地址 *x_s,y_s:左上角起始点 */ int display_jpeg (char * filename,
unsigned int *lcd_ptr,unsigned int x_s, unsigned int y_s) { struct my_error_mgr
jerr; struct jpeg_decompress_struct cinfo; int row_stride; /* physical row
width in output buffer */ FILE * infile; /* source file */ if((infile =
fopen(filename, "rb")) == NULL) { fprintf(stderr, "can't open %s\n", filename);
return -1; } cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit =
my_error_exit; if(setjmp(jerr.setjmp_buffer)) {
jpeg_destroy_decompress(&cinfo); fclose(infile); return -1; }
jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, infile);
jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); row_stride =
cinfo.output_width * cinfo.output_components; char *buffer; buffer =
(char*)(*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE,
row_stride, 1); unsigned int x, y; unsigned int color; char * ptr_save =
buffer; y = y_s; while(cinfo.output_scanline < cinfo.output_height && y <
cinfo.output_height) { buffer = ptr_save; jpeg_read_scanlines(&cinfo,
(JSAMPARRAY)&buffer, 1); for(x=x_s; x< x_s+cinfo.output_width && x<LCD_WIDTH;
x++) { color = buffer[2] | buffer[1]<<8 | buffer[0]<<16; lcd_draw_point(x, y,
color, lcd_ptr); buffer += 3; } y++; } //显示图片路径 wchar_t *w_pathname = NULL; if(
mchars_to_wchars(filename, &w_pathname) == 0) { //显示图片路径
Lcd_Show_FreeType(w_pathname,32,0x00,x_s+10,y_s+50, lcd_ptr); free(w_pathname);
} jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo);
fclose(infile); return 0; }
        freetype.c文件
#include <sys/mman.h> #include <stdio.h> #include <linux/fb.h> #include
<string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
#include <unistd.h> #include <wchar.h> #include <string.h> #include
<ft2build.h> #include FT_FREETYPE_H #include <lcd.h> #define SIM_TTY_PATH
"font/simsun.ttc" /* 功能:根据得到的RGB24数据,进行图像任意位置显示 (主要是迎合上面的各种转换函数的显示测试) x:显示的x轴起点
y:显示的y轴起点 w:显示图像宽度。 h:显示图像高度。 bit_dept:要显示的图像位深 24/32 pbmp_data:要进行显示的RGB24_buf
*/ int Show_FreeType_Bitmap(FT_Bitmap* bitmap,int start_x,int start_y,int
color, unsigned int *lcd_buf_ptr) { int buff_x, buff_y; //遍历bitmap时使用 int x,y;
//循环遍历使用 int end_x = start_x + bitmap->width; //图像宽度 int end_y = start_y +
bitmap->rows; //图像高度 for ( x = start_x, buff_x = 0; x < end_x; buff_x++, x++ )
//y表示起点y,x表示起点x { for ( y = start_y, buff_y = 0; y < end_y; buff_y++, y++ )
//y表示起点y,x表示起点x { //LCD边界处理 if ( x < 0 || y < 0 || x >=800 || y >= 480 )
continue; if(bitmap->buffer[buff_y * bitmap->width + buff_x] )
//判断该位上是不是为1,1则表明需要描点 lcd_draw_point(start_x+buff_x , start_y+buff_y , color,
lcd_buf_ptr); //在当前x位置加上p的偏移量(p表示buff中列的移动) //在当前y位置加上q的偏移量(q表示buff中行的移动) } } }
void Lcd_Show_FreeType(wchar_t *wtext, int size, int color, int start_x, int
start_y, unsigned int *lcd_buf_ptr) { //1.定义库所需要的变量 FT_Library library; FT_Face
face; FT_GlyphSlot slot; //用于指向face中的glyph FT_Vector pen; FT_Error error; int
n; //2.初始化库 error = FT_Init_FreeType( &library ); //3.打开一个字体文件,并加载face对象: error
= FT_New_Face( library, SIM_TTY_PATH, 0, &face ); slot = face->glyph;
//4.设置字体大小 error = FT_Set_Pixel_Sizes(face, size, 0); //x起点位置:start_x。需要*64
pen.x = start_x * 64; //y起点位置:LCD高度 - start_y。需要*64 pen.y = ( 480 - start_y ) *
64; //每次取出显示字符串中的一个字 for ( n = 0; n < wcslen( wtext ); n++ ) {
//5.设置显示位置和旋转角度,0为不旋转,pen为提前设置好的坐标 FT_Set_Transform( face, 0, &pen );
//将字形槽的字形图像,转为位图,并存到 face->glyph->bitmap->buffer[],并且更新bitmap下的其他成员, //
face->glyph->bitmap.rows:图像总高度 // face->glyph->bitmap.width:图像总宽度 //
face->glyph->bitmap.pitch:每一行的字节数 // face->glyph->bitmap.pixel_mode:像素模式(1单色
8反走样灰度) // face->glyph->bitmap.buffer:点阵位图的数据缓冲区 error = FT_Load_Char( face,
wtext[n], FT_LOAD_RENDER ); //FT_LOAD_RENDER表示转换RGB888的位图像素数据 //出错判断 if ( error
) continue; Show_FreeType_Bitmap(&slot->bitmap, slot->bitmap_left, 480 -
slot->bitmap_top, color, lcd_buf_ptr); //增加笔位 pen.x += slot->advance.x; }
FT_Done_Face(face); FT_Done_FreeType(library); }
        lcd.c文件
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include
<sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include "lcd.h"
/*lcd_draw_point:在lcd上画一个点 *x:x轴坐标 (左上角为原点,x轴分别向右,y轴下递增) *y:y轴坐标 *color:点的颜色
*lcd_ptr:LCD的操作指针 */ void lcd_draw_point(unsigned int x, unsigned int y,
unsigned int color, unsigned int *lcd_ptr) { if( x>=0 && x<LCD_WIDTH && y>=0 &&
y<LCD_HEIGHT ) { *(lcd_ptr+LCD_WIDTH*y+x) = color; } }
/*lcd_draw_full_srceen_single_color:用一种颜色画满整个屏幕 *color:点的颜色 *lcd_ptr:LCD的操作指针
*/ void lcd_draw_full_srceen_single_color(unsigned int color, unsigned int
*lcd_ptr) { int x, y; for(y=0;y<LCD_HEIGHT;++y) { for(x=0;x<LCD_WIDTH;++x) {
lcd_draw_point(x, y, color, lcd_ptr); } } } /*open_lcd_device:打开LCD
*lcd_ptr:LCD的内存映射首地址 *返回值:lcd_fd:LCD的描述符 */ int open_lcd_device(unsigned int
**lcd_ptr) { int lcd_fd; lcd_fd = open("/dev/fb0", O_RDWR);//打开LCD设备 if(lcd_fd
== -1) { perror("open lcd device failed\n"); return -1; } //内存映射 *lcd_ptr =
mmap( NULL, LCD_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd, 0); if(lcd_ptr
== MAP_FAILED) { perror("map lcd_fb error\n"); return -1; } return lcd_fd; }
/*close_lcd_device:关闭LCD *lcd_fd:LCD的描述符 *lcd_ptr:LCD的内存映射首地址 */ int
close_lcd_device(int lcd_fd, unsigned int *lcd_ptr) { munmap(lcd_ptr,
LCD_SIZE); return close(lcd_fd); }
        main.c文件
#include <stdio.h> #include <stdlib.h> #include "lcd.h" #include "freetype.h"
#include "display_bmp.h" #include "display_jpeg.h" int main(int argc, char
*argv[]) { int lcd_fd; int dis_ret; unsigned int *lcd_ptr; //打开LCD lcd_fd =
open_lcd_device(&lcd_ptr); if(lcd_fd == -1) { return -1; } //显示bmp图片 dis_ret =
display_bmp("pic/test.bmp", lcd_ptr, 0, 0); if(dis_ret != 0) { printf("display
bmp error\n"); } printf("please enter any key continue!\n"); getchar();
//显示jpeg图片 dis_ret = display_jpeg("pic/bird.jpg", lcd_ptr, 0, 0); if(dis_ret !=
0) { printf("display jpeg error\n"); } //关闭LCD close_lcd_device(lcd_fd,
lcd_ptr); return 0; }
       to_wchar.c文件
#include <wctype.h> #include <locale.h> #include <wchar.h> #include <stdio.h>
#include <string.h> #include <stdlib.h> /*mchars_to_wchars:多字节转宽字符
*mbs_char:多字节字符串 *w_char:宽字符 */ int mchars_to_wchars(const char *mbs_char,
wchar_t **w_char) { int mbslen = mbstowcs(NULL, mbs_char, 0); if (mbslen ==
(size_t) -1) { perror("mbstowcs"); return -1; } *w_char = NULL; /* if
(setlocale(LC_CTYPE, "zh_CN.utf8") == NULL) { perror("setlocale"); return -1; }
*/ *w_char = calloc(mbslen + 1, sizeof(wchar_t)); if(*w_char == NULL ) {
perror("calloc\n"); return -1; } if (mbstowcs(*w_char, mbs_char, mbslen + 1) ==
(size_t) -1) { perror("mbstowcs"); free(*w_char); return -1; } //printf("Wide
character string is: %ls (%zu characters)\n", *w_char, mbslen); return 0; }
Makefile文件
make: arm-linux-gcc src/*.c -o lcd -I include -I include/freetype2 -L lib
-ljpeg -lfreetype
五、待添加功能

       1、图片根据显示屏的大小自适应(缩放操作:"偷工减料"; 复制周边)

       2、百叶窗式显示图片

       3、从左到右滚动

       4、扇形显示图片

=================================以下 回复 qq_37261494 ==================

百叶窗式显示图片测试

主要思路:将图片数据分为几个部分显示,每个部分交由子线程同时显示/隐藏。

测试代码:
#include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include
<sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h>
#include <unistd.h> #define LCD_HEIGHT 480 #define LCD_WIDTH 800 #define
LCD_SIZE ((LCD_WIDTH)*(LCD_HEIGHT)*4) #define ON 1 #define OFF 0 #define BLIND
5 int open_lcd_device(unsigned int **lcd_ptr); void lcd_draw_point(unsigned int
x, unsigned int y, unsigned int color, unsigned int *lcd_ptr); int
get_pic_data_to_buffer(const char *pathname, unsigned char **pic_buffer); void
blind_window(int lcd, unsigned char *image, int flag); //打包数据给子线程使用 struct
argument { unsigned int *lcd_ptr;//LCD显示屏的显示内存空间指针 unsigned char
*pic_buf_ptr;;//图片数据 int offset;//每叶的像素数据的偏移量(距离全部数据的起始位置)起始就是用来记录每叶的起始行 int
flag;//用来控制类似开窗关窗 }; int main(int argc, char *argv[]) { int lcd_fd; int ret;
unsigned int *lcd_ptr; if(argc !=2) { printf("argc !=2\n"); return -1; }
//打开LCD lcd_fd = open_lcd_device(&lcd_ptr); if(lcd_fd == -1) { return -1; }
//获取图片的像素数据 unsigned char *pic_ptr; ret = get_pic_data_to_buffer(argv[1],
&pic_ptr); if(ret == -1) { printf("get_pic_data_to_buffer erro\n"); } //百叶窗显示
blind_window(lcd_fd, pic_ptr, ON);//关窗 blind_window(lcd_fd, pic_ptr, OFF);//开窗
munmap(lcd_ptr, LCD_SIZE);//接触映射 close(lcd_fd);//关闭LCD设备 return 0; } void
*routine(void *_arg)//子线程执行的动作---显示1叶图片数据 { struct argument *arg = (struct
argument *)_arg; unsigned int color; int x,y; if(arg->flag == ON) {
arg->pic_buf_ptr += (4*(LCD_HEIGHT/BLIND)-arg->offset) * LCD_WIDTH * 3;
for(y=arg->offset+LCD_HEIGHT/BLIND-1; y>=arg->offset;
y--)//显示每叶数据-从下往上,有HEIGHT/BLIN行 { for(x=0; x<LCD_WIDTH; x++) { color =
(arg->pic_buf_ptr[2]<<16) | (arg->pic_buf_ptr[1]<<8) | arg->pic_buf_ptr[0];
lcd_draw_point(x, y, color, arg->lcd_ptr); arg->pic_buf_ptr += 3; }
usleep(10000); } } else if(arg->flag == OFF)//清除每叶数据-从上往下,有HEIGHT/BLIN行 {
for(y=arg->offset; y<arg->offset+LCD_HEIGHT/BLIND; y++) { for(x=0; x<LCD_WIDTH;
x++) { lcd_draw_point(x, y, 0, arg->lcd_ptr); } usleep(10000); } } sleep(1);
pthread_exit(NULL); } //百叶窗式显示图片 void blind_window(int lcd_fd, unsigned char
*image, int flag) { unsigned int *p = mmap( NULL, LCD_SIZE,
PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd,
0);//内存映射,将LCD显示屏显示空间映射为内存空间,方便操作,这样给内存赋值为像素数据就是显示图片了 int i; pthread_t
tid[BLIND]; for(i=0; i<BLIND; i++)//每1叶交由一条子线程显示 { struct argument *arg =
malloc(sizeof(struct argument)); arg->lcd_ptr = p; arg->pic_buf_ptr = image;
arg->offset = i*(LCD_HEIGHT/BLIND);//设置偏移量 arg->flag = flag;
//printf("offset=%d\n", arg->offset); pthread_create(&tid[i], NULL, routine,
(void *)arg);//创建线程 } for(i=0; i<BLIND; i++) { pthread_join(tid[i],
NULL);//等待子线程结束 } } /*lcd_draw_point:在lcd上画一个点 *x:x轴坐标 (左上角为原点,x轴分别向右,y轴下递增)
*y:y轴坐标 *color:点的颜色 *lcd_ptr:LCD的操作指针 */ void lcd_draw_point(unsigned int x,
unsigned int y, unsigned int color, unsigned int *lcd_ptr) { if( x>=0 &&
x<LCD_WIDTH && y>=0 && y<LCD_HEIGHT ) { *(lcd_ptr+LCD_WIDTH*y+x) = color; } }
/*open_lcd_device:打开LCD *lcd_ptr:LCD的内存映射首地址 *返回值:lcd_fd:LCD的描述符 */ int
open_lcd_device(unsigned int **lcd_ptr) { int lcd_fd; lcd_fd = open("/dev/fb0",
O_RDWR);//打开LCD设备 if(lcd_fd == -1) { perror("open lcd device failed\n"); return
-1; } //内存映射 *lcd_ptr = mmap( NULL, LCD_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED,
lcd_fd, 0); if(lcd_ptr == MAP_FAILED) { perror("map lcd_fb error\n"); return
-1; } return lcd_fd; } /*get_pic_data_to_buffer:获取图片的像素数据 *pathname:图片的路径名
*pic_buf_ptr:用来指向 存放图片的像素数据缓冲区 */ int get_pic_data_to_buffer(const char
*pathname, unsigned char **pic_buf_ptr) { FILE *pic_fp; off_t file_size; struct
stat file_info; pic_fp = fopen(pathname, "r"); if(pic_fp == NULL) {
perror("open %s error\n"); return -1; } if( stat(pathname, &file_info) == -1) {
perror("get file info error\n"); return -1; } file_size =
file_info.st_size;//获取图片大小 *pic_buf_ptr = (unsigned char
*)malloc(file_size-54); fseek(pic_fp, 54,SEEK_SET);//跳过文件头(存在内存对齐,可能是56字节)
fread(*pic_buf_ptr, file_size-54, 1, pic_fp);//读取图片颜色数据 if(ferror(pic_fp)) {
perror("read picture data error\n"); return -1; } return fclose(pic_fp); }
测试结果:



完整版:链接:https://pan.baidu.com/s/1cRO5tSMAnZdFeTii-qnYZA 提取码:9xfh

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信