Linux系统编程中对JPG和GIF图片的显示都有集成的软件库可以用,显示JPG图片可用libjpeg库,可以直接用apt在线安装
apt install libjpeg62-turbo libjpeg62-turbo-dev
对于 ARM64架构的系统,会有turbo关键字,而在x86架构系统上面,直接安装libjpeg62即可。安装完毕之后, 开发板的板上代码可以使用jpeglib.h提供的函数接口进行jpg文件的软件解码,直接读取jpg文件并显示在framebuffer外设之上,具体函数如下:
-struct jpeg_decompress_struct cinfo;
-用于存放JPG文件解码数据的结构体
-JSAMPARRAY buffer;
-存放一行图像数据的结构体
-jpeg_create_decompress(&cinfo);
-初始化jpeg_decompress结构体对象的函数
-jpeg_stdio_src(&cinfo,input_file);
-指定解压缩数据源
- void LCD_RGB888_Show_JPG_File(char *dev , int xpos , int ypos , char *filename)
- {
- //int fjpg;
- int i,j;
- FILE *input_file = fopen(filename,"rb");
- struct jpeg_decompress_struct cinfo;
- //JPEG图像在解码过程中
- //使用jpeg_decompress_struct类型的结构体来表示
- //图像的所有信息都存储在结构体中
- struct jpeg_error_mgr jerr;
- //定义一个标准的错误结构体
- JSAMPARRAY buffer;
- //用于存取一行数据
- //fjpg = open((char *)"/home/fa/1.jpg",O_RDONLY);
- cinfo.err = jpeg_std_error(&jerr);
- //绑定错误处理结构对象
- jpeg_create_decompress(&cinfo);
- //初始化cinfo结构
- jpeg_stdio_src(&cinfo,input_file);
- //指定解压缩数据源
- jpeg_read_header(&cinfo,TRUE);
- //获取文件信息
- jpeg_start_decompress(&cinfo);
- //开始解压缩
- int width = cinfo.output_width;
- //图像宽度
- int height = cinfo.output_height;
- //图像高度
- int depth = cinfo.output_components;
- //图像深度
- uint8_t img_byte = cinfo.jpeg_color_space;
- //像素字节数(1/2/3/4个字节,对应8/16/24/32位格式)
- memset(bmp_buf , 0 , sizeof(unsigned char) * width * height * depth);
- buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo,JPOOL_IMAGE , width * depth , 1);
- //分配一行数据空间
- point = bmp_buf;
- while(cinfo.output_scanline < height)//逐行读取位图数据
- {
- jpeg_read_scanlines(&cinfo , buffer , 1);
- //读取一行jpg图像数据到buffer
- memcpy(point , *buffer , width * depth);
- //将buffer中的数据逐行给src_buff
- point += width * img_byte;
- //指针偏移一行
- }
- jpeg_finish_decompress(&cinfo);//解压缩完毕
- for(i = 0 ; i < LCD_HEIGHT ; i ++)
- {
- for(j = 0 ; j < LCD_WIDTH ; j ++)
- if(i <= height && j <= width)
- {
- uint32_t temp = bmp_buf[(i * width+j) * 3] << 16 |
- bmp_buf[(i * width+j) * 3 + 1] << 8 |
- bmp_buf[(i * width+j) * 3 + 2];
- framebuffer_lcd[(i+ypos)*(LCD_WIDTH)+j+xpos] = temp;
- }
- //else framebuffer_lcd[(i+ypos)*(LCD_WIDTH)+j+xpos]=0;
- }
- int fd_lcd = open(dev , O_RDWR);
- write(fd_lcd , framebuffer_lcd , LCD_WIDTH * LCD_HEIGHT * 2);
- close(fd_lcd);
- }
复制代码
值得注意的是,使用libjpeg函数要注意颜色位数,一般这个由板载的GPU芯片决定,具体可由以下函数获得GPU芯片的分辨率和显示颜色位数:
- void Get_Information_Frame_Buffer(char *dev)
- {
- struct fb_var_screeninfo vinfo;
- printf("Open framebuffer device:%sn",dev);
- int fd_lcd = open(dev,O_RDWR);
- if(fd_lcd == -1)
- {
- printf("Open framebuffer device failed.n");
- return ;
- }
- if (ioctl(fd_lcd,FBIOGET_VSCREENINFO,&vinfo))
- {
- printf("Get framebuffer device info failedn");
- return ;
- }
- close(fd_lcd);
- printf("%d %d %dn",vinfo.xres,vinfo.yres,vinfo.bits_per_pixel);
- }
复制代码
如图,可以看出板上GPU显示位数为32位,那么就要用RGB888的buffer数据源进行显示。
JPG文件显示操作非常简单,接下来介绍一下稍微难一点的操作,显示GIF图片,显示GIF图片所用的giflib库无法从apt处在线安装,必须从指定网站获得源码:
- http://giflib.sourceforge.net/gif_lib.html
复制代码
编译获得libgif.so.7.0.0,并做好两级软链接,由用户代码直接调用:
运行时使用环境变量加载.so文件:
- export LD_LIBRARY_PATH=/home/proj
复制代码
LD_LIBRARY_PATH的路径为.so文件存在的路径,此export动作可以写到应用程序的启动脚本上,也可以手动执行。
使用两个函数获得gif文件信息并循环显示:
- int GifLoadFile()
- {
- int error = 0;
- int size = 0;
- int idx = 0;
- int ret = 0;
- do
- {
- if (NULL == gEffectGifFile)
- {
- ret = -1;
- break;
- }
- gpGifFile = DGifOpenFileName(gEffectGifFile, &error);
- if (NULL == gpGifFile)
- {
- ret = -2;
- break;
- }
- if ((gpGifFile->SHeight == 0) || (gpGifFile->SWidth == 0))
- {
- ret = -3;
- break;
- }
- gpScreenBuffer = (GifRowType *)malloc(gpGifFile->SHeight * sizeof(GifRowType));
- if (NULL == gpScreenBuffer)
- {
- ret = -4;
- break;
- }
- /* Size in bytes one row */
- size = gpGifFile->SWidth * sizeof(GifPixelType);
- gpScreenBuffer[0] = (GifRowType)malloc(size);
- if(NULL == gpScreenBuffer[0])
- {
- ret = -5;
- break;
- }
- /* Set its color to BackGround */
- for (idx = 0; idx < gpGifFile->SWidth; idx++)
- {
- gpScreenBuffer[0][idx] = gpGifFile->SBackGroundColor;
- }
- /* Allocate the other rows, and set their color to background too */
- for (idx = 1; idx < gpGifFile->SHeight; idx++)
- {
- gpScreenBuffer[idx] = (GifRowType)malloc(size);
- if (NULL == gpScreenBuffer[idx])
- {
- ret = -6;
- break;
- }
- memcpy(gpScreenBuffer[idx], gpScreenBuffer[0], size);
- }
- if (0 > ret)
- {
- break;
- }
- } while (0);
- if (0 > ret)
- {
- GifFreeFile();
- }
- return ret;
- }
- void GifScreenBufferToRgb888(ColorMapObject *ColorMap, uint8_t *inRgb,
- GifRowType *ScreenBuffer, int ScreenWidth, int ScreenHeight)
- {
- GifColorType *ColorMapEntry = NULL;
- GifRowType GifRow = NULL;
- uint8_t *rgbBuf = inRgb;
- int idxH = 0;
- int idxW = 0;
- for (idxH = 0; idxH < ScreenHeight; idxH++)
- {
- GifRow = ScreenBuffer[idxH];
- rgbBuf = inRgb + idxH * ScreenWidth * 3;
- for (idxW = 0; idxW < ScreenWidth; idxW++)
- {
- ColorMapEntry = &ColorMap->Colors[GifRow[idxW]];
- *rgbBuf++ = ColorMapEntry->Red;
- *rgbBuf++ = ColorMapEntry->Green;
- *rgbBuf++ = ColorMapEntry->Blue;
- }
- }
- }
- int LCD_Show_Gif()
- {
- ColorMapObject *colorMap = NULL;
- GifByteType *extension = NULL;
- int InterlacedOffset[] = { 0, 4, 2, 1 };
- // The way Interlaced image should
- int InterlacedJumps[] = { 8, 8, 4, 2 };
- // be read - offsets and jumps...
- int extCode = 0;
- int row = 0;
- int col = 0;
- int width = 0;
- int height = 0;
- int iW = 0;
- int iH = 0;
- int ret = 0;
- do
- {
- if (DGifGetRecordType(gpGifFile, &gRecordType) == GIF_ERROR)
- {
- ret = -1;
- break;
- }
- switch (gRecordType)
- {
- case IMAGE_DESC_RECORD_TYPE:
- if (DGifGetImageDesc(gpGifFile) == GIF_ERROR)
- {
- ret = -2;
- break;
- }
- row = gpGifFile->Image.Top;
- col = gpGifFile->Image.Left;
- width = gpGifFile->Image.Width;
- height = gpGifFile->Image.Height;
- if (gpGifFile->Image.Interlace)
- {
- for (iH = 0; iH < 4; iH++)
- {
- for (iW = row + InterlacedOffset[iH];
- iW < row + height; iW += InterlacedJumps[iH])
- {
- DGifGetLine(gpGifFile, &gpScreenBuffer[iW][col], width);
- }
- }
- }
- else
- {
- for (iH = 0; iH < height; iH++)
- {
- DGifGetLine(gpGifFile, &gpScreenBuffer[row++][col], width);
- }
- }
- colorMap = (gpGifFile->Image.ColorMap ?
- gpGifFile->Image.ColorMap : gpGifFile->SColorMap);
- if (colorMap == NULL)
- {
- ret = -3;
- break;
- }
- GifScreenBufferToRgb888(colorMap, rgbBuf, gpScreenBuffer,
- gpGifFile->SWidth, gpGifFile->SHeight);
- LCD32_Show_Buffer8_Proportional_Stretch(FB_DEV , 0 , 0 , gpGifFile->SWidth , gpGifFile->SHeight , (unsigned char*)rgbBuf , 3);
- break;
- case EXTENSION_RECORD_TYPE:
- /* Skip any extension blocks in file: */
- if (DGifGetExtension(gpGifFile, &extCode, &extension) == GIF_ERROR)
- {
- ret = -4;
- break;
- }
- while (extension != NULL)
- {
- if (DGifGetExtensionNext(gpGifFile, &extension) == GIF_ERROR)
- {
- ret = -5;
- break;
- }
- }
- break;
- case TERMINATE_RECORD_TYPE:
- break;
- default:
- break;
- }
- if (0 < ret)
- {
- break;
- }
- } while (gRecordType != TERMINATE_RECORD_TYPE);
- return ret;
- }
复制代码
对libgif工具生成的buffer进行比例拉伸:
- int LCD32_Show_Buffer8_Proportional_Stretch(char *dev_name , int xpos , int ypos , int width , int height ,unsigned char frame_buffer8[] , int multi)
- {
- int fd_lcd,i,j,count;
- fd_lcd = open(dev_name,O_RDWR);
- if(fd_lcd == -1)
- {
- printf("open LCD failed!n");
- return -1;
- }
- for(i = 0 ; i < LCD_HEIGHT ; i++)
- {
- for(j = 0 ; j < LCD_WIDTH ; j++)
- {
- if(i <= height && j <= width)
- {
- if(multi == 2)
- {
- framebuffer_lcd[i * LCD_WIDTH * multi + j * multi] =
- frame_buffer8[(i * width + j) * 3 ] << 16 |
- frame_buffer8[(i * width + j) * 3 + 1] << 8 |
- frame_buffer8[(i * width + j) * 3 + 2];
- framebuffer_lcd[i * LCD_WIDTH * multi + j * multi + 1] = framebuffer_lcd[i * LCD_WIDTH * multi + j * multi];
- framebuffer_lcd[i * LCD_WIDTH * multi + LCD_WIDTH + j * multi] = framebuffer_lcd[i * LCD_WIDTH * multi + j * multi];
- framebuffer_lcd[i * LCD_WIDTH * multi + LCD_WIDTH + j * multi + 1] = framebuffer_lcd[i * LCD_WIDTH * multi + j * multi];
- }
- else if(multi == 3)
- {
- framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + j * multi + xpos] =
- frame_buffer8[(i * width + j) * 3 ] << 16 |
- frame_buffer8[(i * width + j) * 3 + 1] << 8 |
- frame_buffer8[(i * width + j) * 3 + 2];
- framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + j * multi + 1 + xpos] = framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + j * multi + xpos];
- framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + j * multi + 2 + xpos] = framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + j * multi + xpos];
- framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + LCD_WIDTH + j * multi + xpos] = framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + j * multi + xpos];
- framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + LCD_WIDTH + j * multi + 1 + xpos] = framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + j * multi + xpos];
- framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + LCD_WIDTH + j * multi + 2 + xpos] = framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + j * multi + xpos];
- framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + LCD_WIDTH * 2 + j * multi + xpos] = framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + j * multi + xpos];
- framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + LCD_WIDTH * 2 + j * multi + 1 + xpos] = framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + j * multi + xpos];
- framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + LCD_WIDTH * 2 + j * multi + 2 + xpos] = framebuffer_lcd[i * LCD_WIDTH * multi + ypos * LCD_WIDTH + j * multi + xpos];
- }
- }
- }
- }
- write(fd_lcd,framebuffer_lcd,LCD_WIDTH * LCD_HEIGHT * 4);
- close(fd_lcd);
- return 0;
- }
复制代码
演示视频稍后交由管理员上传。
0
|
|
|
|