Linux下GIF库移植与运用

Posted DS小龙哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux下GIF库移植与运用相关的知识,希望对你有一定的参考价值。

一、开发环境介绍

开发板:友善之臂Tiny4412

LCD型号: S702 、分辨率: 800*480

Linux内核版本: Linux 3.5

交叉编译器: arm-linux-gcc 4.5.1

二、GIF文件格式简单介绍

生活中常用图片格式有BMP、PNG、JPG、GIF等。BMP图片的显示很简单,可以直接从图片文件里读取RGB数据进行显示.。PNG格式图片显示,直接调用libpng库里的接口函数解码显示;JPG格式图片也一样,调用libjpeg库的接口函数完成解码即可得到原始RGB数据完成显示;如果要在LCD屏上显示GIF图片,那么也是调用giflib库的接口函数完成解码显示。

在解码jpeg图片和png图片的时候我们不需要对jpeg和png文件格式有了解就可以解码了(了解jpeg和png当然更好),但是在使用giflib解码gif的时候,我们必须要对gif文件有很简单的了解。

gif文件中可以存放一帧或者多帧图像数据,并且可以存放图像控制信息,因此可以存储动画图片,gif文件由文件头开头,文件尾结尾,中间是一些连续的数据块(block)。这些数据块又分为图像数据块和扩展数据块(extension),图像数据块可以理解成存放一帧的图像数据。扩展数据块存放的是一些辅助信息,比如指示怎样显示图像数据等等。

gif文件中的图像基于调色板的,因此一张gif文件中的图像最多只能有255中颜色,因此gif文件只能存储比较简单的图像。gif文件中有两种调色板 ——全局调色板和图像局部调色板。当一帧图像有局部调色板时,则以局部调色板来解码该帧图像,如果该帧图像没有局部调色板则用全局调色板来解码该图像。

更详细的信息可以查阅giflib的文档中的gif89.txt文件,或者在网络搜索相关的信息。

三、移植giflib库到嵌入式Linux平台

giflib库下载地址: http://www.linuxfromscratch.org/blfs/view/svn/general/giflib.html​​

Linux下GIF库移植与运用_libgif

编译过程:

[wbyq@wbyq work]$ tar xvf /mnt/hgfs/linux-share-dir/giflib-5.2.1.tar.gz​
[wbyq@wbyq work]$ cd giflib-5.2.1/
[wbyq@wbyq giflib-5.2.1]$ make CC=arm-linux-gcc​
[wbyq@wbyq giflib-5.2.1]$ make PREFIX=$PWD/_install install​
[wbyq@wbyq giflib-5.2.1]$ tree _install/
_install/
├── bin​
├── gif2rgb​
├── gifbuild​
├── gifclrmp​
├── giffix​
├── giftext​
└── giftool​
├── include​
└── gif_lib.h​
├── lib​
├── libgif.a​
├── libgif.so -> libgif.so.7
├── libgif.so.7 -> libgif.so.7.2.0
└── libgif.so.7.2.0
└── share​
└── man​
└── man1​
├── gif2rgb.1
├── gifbg.1
├── gifbuild.1
├── gifclrmp.1
├── gifcolor.1
├── gifecho.1
├── giffix.1
├── gifhisto.1
├── gifinto.1
├── giflib.1
├── giftext.1
├── giftool.1
└── gifwedge.1

6 directories, 24 files​
[wbyq@wbyq giflib-5.2.1]$​

编译完成之后,将头文件和库文件拷贝一份到交叉编译器的路径下,方便程序编译时直接可以找到头文件和库文件;当前,也可以在程序编译的时候在编译器后面指定gif使用的头文件和库文件也可以。再将动态库文件拷贝一份到目标开发板的lib目录下,方便程序在开发板上运行时能找到对应的库。

[wbyq@wbyq _install]$ pwd​
/home/wbyq/work/giflib-5.2.1/_install​

[wbyq@wbyq _install]$ ls​
bin include lib share​

[wbyq@wbyq _install]$ sudo cp include/* /home/wbyq/work/arm-linux-gcc/opt/FriendlyARM/toolschain/4.5.1/arm-none-linux-gnueabi/sys-root/usr/include/ -rf​

[wbyq@wbyq _install]$ sudo cp lib/* /home/wbyq/work/arm-linux-gcc/opt/FriendlyARM/toolschain/4.5.1/arm-none-linux-gnueabi/sys-root/usr/lib/ -rf​

[wbyq@wbyq _install]$ cp lib/* /home/wbyq/work/rootfs/lib/

Linux下GIF库移植与运用_libgif_02


四、示例代码

#include <stdio.h>​
#include <sys/types.h>​
#include <sys/stat.h>​
#include <fcntl.h>​
#include <sys/ioctl.h>​
#include <linux/fb.h>​
#include <sys/ioctl.h>​
#include <sys/mman.h>​
#include <string.h>​
#include <sys/types.h>​
#include <sys/stat.h>​
#include <unistd.h>​
#include <stdlib.h>​
#include <gif_lib.h>​
struct fb_var_screeninfo var; //可变参数​
struct fb_fix_screeninfo fix; //固定参数​
unsigned char *fb_mem=NULL; //LCD屏的首地址​

/*
函数功能: 画点
*/
void LCD_WritePoint(int x,int y,int color)

unsigned int *lcd=(unsigned int *)(fb_mem+y*var.xres*var.bits_per_pixel/8+x*var.bits_per_pixel/8);
*lcd=color; //颜色赋值​


//帧缓冲显示​
void FrameBufferDraw(int x,int y,int image_w,int image_h,unsigned char *rgbBuf)

int w,h;
unsigned char r,g,b;
unsigned int c;
/*将图像数据显示在LCD屏幕上*/
unsigned char *rgb_p=rgbBuf;
for(h=0;h<image_h;h++)

for(w=0;w<image_w;w++)

b=*rgb_p++;
g=*rgb_p++;
r=*rgb_p++;
c=r<<16|g<<8|b<<0;
LCD_WritePoint(w+x,h+y,c); /*绘制像素点到LCD屏*/




//颜色转换​
void GifBufferToRgb888(ColorMapObject *ColorMap, unsigned char *inRgb,GifRowType *Buffer, int w, int h)

GifColorType *ColorMapEntry = NULL;
GifRowType GifRow = NULL;
unsigned char *rgbBuf = inRgb;
int idxH = 0;
int idxW = 0;

for (idxH = 0; idxH < h; idxH++)

GifRow = Buffer[idxH];
rgbBuf = inRgb + idxH * w * 3;

for(idxW = 0; idxW < w; idxW++)

ColorMapEntry = &ColorMap->Colors[GifRow[idxW]];
*rgbBuf++ = ColorMapEntry->Blue;
*rgbBuf++ = ColorMapEntry->Green;
*rgbBuf++ = ColorMapEntry->Red;




//显示GIF图像​
int LCD_DisplayGIF(int x,int y,unsigned char *file)

int error=0;
int size;
int i;
GifRowType *Buffer;
GifFileType *fp;
/*1. 打开图片文件*/
fp=DGifOpenFileName(file,&error);
if(fp==NULL)return -1;
printf("GIF图片尺寸:%dx%d\\n",fp->SWidth,fp->SHeight);

/*2. 内存空间申请、初始化*/
Buffer=(GifRowType*)malloc(fp->SHeight*sizeof(GifRowType));

/*一行字节大小*/
size = fp->SWidth*sizeof(GifPixelType);
Buffer[0]=(GifRowType)malloc(size);

/*将其颜色设置为BackGround*/
for(i=0;i<fp->SWidth;i++)

Buffer[0][i]=fp->SBackGroundColor;


/*分配其他行,并将它们的颜色也设置为背景 */
for(i=1;i<fp->SHeight;i++)

Buffer[i]=(GifRowType)malloc(size);
memcpy(Buffer[i],Buffer[0],size);


/*3. 显示图片*/
ColorMapObject *colorMap=NULL;
GifByteType *extensinotallow=NULL;
GifRecordType gRecordType=UNDEFINED_RECORD_TYPE;

int InterlacedOffset[]=0,4,2,1; // The way Interlaced image should​
int InterlacedJumps[]=8,8,4,2; // be read - offsets and jumps...​
unsigned char rgbBuf[800 * 480]=0;

int extCode = 0;
int row = 0;
int col = 0;
int width = 0;
int height = 0;
int iW = 0;
int iH = 0;
do​

if(DGifGetRecordType(fp,&gRecordType)==GIF_ERROR)break;

switch(gRecordType)

case IMAGE_DESC_RECORD_TYPE:
if(DGifGetImageDesc(fp)==GIF_ERROR)break;

row=fp->Image.Top;
col=fp->Image.Left;
width=fp->Image.Width;
height=fp->Image.Height;

if(fp->Image.Interlace)

for(iH=0;iH<4;iH++)

for(iW=row+InterlacedOffset[iH];iW<row+height;iW+=InterlacedJumps[iH])

DGifGetLine(fp,&Buffer[iW][col],width);



else​

for(iH=0;iH<height;iH++)

DGifGetLine(fp,&Buffer[row++][col],width);



colorMap=(fp->Image.ColorMap?fp->Image.ColorMap:fp->SColorMap);
if(colorMap==NULL)

break;


GifBufferToRgb888(colorMap,rgbBuf,Buffer,fp->SWidth,fp->SHeight);
//将图像显示在LCD屏上​
FrameBufferDraw(x,y,fp->SWidth,fp->SHeight,rgbBuf);
//帧间隔时间​
usleep(1000*50);
break;

case EXTENSION_RECORD_TYPE:
/* 跳过文件中的所有扩展块*/
if(DGifGetExtension(fp,&extCode,&extension)==GIF_ERROR)break;

while(extension!=NULL)

if(DGifGetExtensionNext(fp, &extension) == GIF_ERROR)break;

break;

case TERMINATE_RECORD_TYPE:
break;

default:
break;

while(gRecordType!=TERMINATE_RECORD_TYPE);

/*4. 释放空间*/
for(i =0;i<fp->SHeight;i++)

free(Buffer[i]);

free(Buffer);
DGifCloseFile(fp,&error);
return 0;


int main(int argc,char **argv)

if(argc!=2)

printf("./app <GIF图片文件>\\n");
return 0;


int fd=open("/dev/fb0",O_RDWR);
if(fd<0)

perror("设备文件打开失败");
return 0;


/*1. 获取LCD屏的可变形参*/
ioctl(fd,FBIOGET_VSCREENINFO,&var);
printf("分辨率:%d*%d\\n",var.xres,var.yres);
printf("像素点位数:%d\\n",var.bits_per_pixel);

/*2. 获取LCD屏的固定形参*/
ioctl(fd,FBIOGET_FSCREENINFO,&fix);
printf("映射的长度:%d\\n",fix.smem_len);
printf("一行的字节数:%d\\n",fix.line_length);

/*3. 映射LCD缓冲区地址到进程空间*/
fb_mem=mmap(NULL,fix.smem_len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(fb_mem==NULL)

perror("空间映射失败!\\n");
return 0;


/*4. 控制显示屏*/
memset(fb_mem,0xFFFFFF,fix.smem_len); //将屏幕清屏为白色​

while(1)

printf("GIF图片显示状态:%d\\n",LCD_DisplayGIF(100,100,argv[1]));


munmap(fb_mem,fix.smem_len);
close(fd);
return 0;

五、编译Makefile代码

all:
arm-linux-gcc lcd_app.c -o app -lgif​
cp app /home/wbyq/project​
rm app -f​

六、运行效果图

Linux下GIF库移植与运用_libgif_03

Linux下GIF库移植与运用_libgif_04


Linux下GIF库移植与运用_libgif_05

Linux下GIF库移植与运用_libgif_06


Linux下GIF库移植与运用_libgif_07

Linux下GIF库移植与运用_libgif_08



Linux下GIF库移植与运用_libgif_09

Linux下GIF库移植与运用_libgif_10



Linux下GIF库移植与运用_libgif_11

Linux下GIF库移植与运用_libgif_12


Linux下GIF库移植与运用_libgif_13

以上是关于Linux下GIF库移植与运用的主要内容,如果未能解决你的问题,请参考以下文章

Linux应用开发:嵌入式Linux下矢量字体运用

Linux下libpng库的运用

glog日志库移植Android平台

linux-2.26 移植mplayer 功能

紧急求助,关于arm版本下QWT库移植出现的错误

嵌入式Linux下MP4视频录制库MP4V2移植和简单介绍