通过framebuffer显示jpg图片
2023-06-05 来源:elecfans
一、前言
本文jpg解压的关键性代码来自于一篇博客:https://blog.csdn.net/u012372584/article/details/50618739
如果想读懂jpg解压缩的代码,建议去看这篇博客,本文主要是在这篇博客的基础上进行修改,使用framebuffer显示jpg图片。
二、代码
1 /**
2 * filename: jpg.c
3 * author: Suzkfly
4 * date: 2021-07-28
5 * platform: S3C6410或Ubuntu
6 * 注意事项:
7 * 1、需要在当前目录下准备两张jpg图片,分别命名为apple.jpg和orange.jpg。
8 * 2、编译时需要加 -ljpeg 参数
9 */
10 #include 11 #include 12 #include 13 #include 14 #include 15 #include 16 #include 17 #include 18 #include 19 #include 20 #include 21 #include 22 23 /**< brief 根据实际情况修改,此处为unsigned short是565的屏,根据程序打印出的 24 bits_per_pixel的值可以判断出输出格式是565还是888 */ 25 //typedef unsigned int color_t; 26 typedef unsigned short color_t; 27 /**< brief 定义每个像素点对应的位数,如果是565的屏则为16,如果是888的屏则为32 */ 28 //#define BITS_PER_PIXEL 32 29 #define BITS_PER_PIXEL 16 30 31 32 static struct fb_var_screeninfo __g_vinfo; 33 static color_t *__gp_frame = NULL; 34 35 /* framebuffer初始化 */ 36 int framebuffer_init (void) 37 { 38 int fd = 0; 39 40 fd = open('/dev/fb0', O_RDWR); 41 if (fd == -1) { 42 perror('fail to open /dev/fb0n'); 43 return -1; 44 } 45 46 ioctl(fd, FBIOGET_VSCREENINFO, &__g_vinfo); /* 获取显示信息 */ 47 printf('bits_per_pixel = %dn', __g_vinfo.bits_per_pixel); /* 一个像素点对应的位数,如果值为16则为565格式输出,如果值为32则为888格式输出 */ 48 printf('xres_virtual = %dn', __g_vinfo.xres_virtual); /* 虚拟x轴像素点数 */ 49 printf('yres_virtual = %dn', __g_vinfo.yres_virtual); /* 虚拟y轴像素点数 */ 50 printf('xres = %dn', __g_vinfo.xres); /* x轴像素点数 */ 51 printf('yres = %dn', __g_vinfo.yres); /* y轴像素点数 */ 52 53 __gp_frame = mmap(NULL, /* 映射区的开始地址,为NULL表示由系统决定映射区的起始地址 */ 54 __g_vinfo.xres_virtual * __g_vinfo.yres_virtual * __g_vinfo.bits_per_pixel / 8, /* 映射区大小 */ 55 PROT_WRITE | PROT_READ, /* 内存保护标志(可读可写) */ 56 MAP_SHARED, /* 映射对象类型(与其他进程共享) */ 57 fd, /* 有效的文件描述符 */ 58 0); /* 被映射内容的偏移量 */ 59 if (__gp_frame == NULL) { 60 perror('fail to mmapn'); 61 return -1; 62 } 63 64 return 0; 65 } 66 67 /* 显示JPG图片 */ 68 int show_jpg(unsigned int x, unsigned int y, const char *name) 69 { 70 int i; 71 color_t col; 72 struct jpeg_decompress_struct cinfo; 73 struct jpeg_error_mgr jerr; 74 JSAMPARRAY buffer; 75 int row_stride; 76 FILE * infile; 77 int line; 78 79 //绑定标准错误处理结构 80 cinfo.err = jpeg_std_error(&jerr); 81 82 //初始化JPEG对象 83 jpeg_create_decompress(&cinfo); 84 85 //指定图像文件 86 if ((infile = fopen(name, 'rb')) == NULL) 87 { 88 perror('fopen fail'); 89 return -1; 90 } 91 jpeg_stdio_src(&cinfo, infile); 92 93 //读取图像信息 94 jpeg_read_header(&cinfo, TRUE); 95 printf('cinfo.image_width = %dn', cinfo.image_width); 96 printf('cinfo.image_height = %dn', cinfo.image_height); 97 printf('cinfo.jpeg_color_space = %dn', cinfo.jpeg_color_space); 98 printf('cinfo.num_components = %dn', cinfo.num_components); 99 100 101 //设定解压缩参数,图像的长宽变为原来的 (scale_num/scale_denom),只能缩小不能放大 102 //cinfo.scale_num = 1; 103 //cinfo.scale_denom = 2; 104 105 //开始解压缩图像 106 printf('-------------n'); 107 jpeg_start_decompress(&cinfo); 108 //本程序功能是应用GDI+在客户区绘制图像 109 110 //分配缓冲区空间 111 row_stride = cinfo.output_width * cinfo.output_components; 112 printf('width = %dn', cinfo.output_width); 113 printf('height = %dn', cinfo.output_height); 114 buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); 115 116 //读取数据 117 while (cinfo.output_scanline < cinfo.output_height) 118 { 119 jpeg_read_scanlines(&cinfo, buffer, 1); /* 按行读取,一次读1行 */ 120 //output_scanline是从1开始,所以需要减1 121 line = cinfo.output_scanline - 1 + y; 122 for(i = 0; i < cinfo.output_width; i++) { 123 #if (BITS_PER_PIXEL == 16) 124 /* 由于jpg图片的颜色深度是24位,适用于888的屏,但如果一定要在565的屏 125 上显示,则取红色的高5位,绿色的高6位和蓝色的高5位,拼成16位的数据 126 进行显示。这样做并不是最好的办法,更好的方法是将需要丢失的部分数 127 据进行进位或舍去。 */ 128 char b, g, r; 129 r = (buffer[0][i*3] >> 3); 130 g = ((buffer[0][i*3+1] >> 2)); 131 b = (buffer[0][i*3+2] >> 3); 132 133 col = (r << 11) | (g << 5) | b; 134 #elif (BITS_PER_PIXEL == 32) 135 col = (buffer[0][i*3] << 16) | (buffer[0][i*3+1] << 8) | buffer[0][i*3+2]; 136 #endif 137 *(__gp_frame + line * __g_vinfo.xres + i + x) = col; //如果在Ubuntu下运行,则应该使用xres_virtual 138 } 139 if (line >= __g_vinfo.yres) { /* 如果行数大于等于y的像素点,说明已经显示到最后一行了 */ 140 break; 141 } 142 } 143 144 //结束解压缩操作 145 (void)jpeg_finish_decompress(&cinfo); 146 147 //释放资源 148 jpeg_destroy_decompress(&cinfo); 149 fclose(infile); 150 151 return 0; 152 } 153 154 int main(void) 155 { 156 framebuffer_init(); 157 show_jpg(0, 0, 'apple.jpg'); 158 show_jpg(200, 100, 'orange.jpg'); 159 160 return 0; 161 } 显示效果: 注:苹果和橘子的图片需要自己准备。 1、编译时报错,如下图: 原因是没有加-ljpeg编译,需要使用gcc jpg.c -ljpeg或arm-none-linux-gnueabi-gcc jpg.c -ljpeg编译 2. 在S3C2416平台上运行时报错: error while loading shared libraries: libjpeg.so.62: cannot open shared object file: No such file or directory 这是因为开发板上缺少libjpeg.so.62这个库,找到这个库,将之复制到开发板上的/lib目录下即可。 可以使用find指令寻找,一般在交叉编译工具目录下会有这个库,如下图: 三、问题解答