用fvb在Framebuffer中显示GIF动画

用fvb在Framebuffer中显示GIF动画

  • fbv (v1.0b)、Framebuffer简介
    • fvb显示GIF为所有帧叠加的一张图像
    • 找找fvb不能正常显示GIF动画的问题
      • fbv显示图像文件的流程:
      • fbv读取GIF文件的过程:
    • 想想办法让GIF动画正常显示
      • 按照show_image()中的流程是行不通了
    • 为什么显示GIF动画过程,画面有些奇怪的小点点出现,还有残影???!!!

fbv (v1.0b)、Framebuffer简介

fbv是一个简单的图像文件显示程序,可以用来在Framebuffer中显示GIF、JPEG、PNG 和BMP文件图像。
Framebuffer,可看作显示屏像素点的抽象。

fvb显示GIF为所有帧叠加的一张图像

如果直接将下载编译后的fbv打开GIF文件,显示的是GIF文件所有帧叠加的一张图像,而非按照一帧一帧的图像显示为动画。

找找fvb不能正常显示GIF动画的问题

fbv显示图像文件的流程:

main.c中,定位到show_image(char * filename) ,看到显示图像文件时,都是分别调用

load = fh_gif_load;   
load = fh_png_load;

等把图像文件的图像解析到image
unsigned char * image = NULL;
指针中,然后再链接到 struct image i 的 rgb ,
i.rgb = image;
接下来调用了fb_display
fb_display(i.rgb, i.alpha, i.width, i.height, x_pan, y_pan, x_offs, y_offs);
进行显示,然后就退出了。。。出了。。。了

也就是说,在fbv中一个图像文件只有一次显示到framebuffer的机会。

fbv读取GIF文件的过程:

看看fh_gif_load的内容,在gif.c中。fbv解析GIF文件用的是giflib

#include 

int fh_gif_load(char *name,unsigned char *buffer, unsigned char ** alpha, int x,int y)

使用giflib解析GIF我参考的是 https://blog.csdn.net/go_to_learn/article/details/8070742 ,跟fbv里的解析略有不同。
整个解析流程就是连续读取GIF文件,处理一遍,像素索引转换为RGB存到 传入的指针 buffer里,透明色则在申请到的一段内存进行保存,并将指针存到alpha地址指针中。

想想办法让GIF动画正常显示

按照show_image()中的流程是行不通了

#ifdef FBV_SUPPORT_GIF
	if(fh_gif_id(filename))
		if(fh_gif_getsize(filename, &x_size, &y_size) == FH_ERROR_OK)
		{
			load = fh_gif_load;
			goto identified;
		}
#endif

那么加入自己的处理流程 gif_display(char * filename):

#ifdef FBV_SUPPORT_GIF
	if(fh_gif_id(filename))
		if(fh_gif_getsize(filename, &x_size, &y_size) == FH_ERROR_OK)
		{
			// load = fh_gif_load;
			// goto identified;
			gif_display(filename);
			printf("exit\n");
			exit(0);
		}
#endif

代码参考了上面提到的微博,处理GIF文件的过程:
case IMAGE_DESC_RECORD_TYPE中先读出一帧的颜色索引值,然后按照ColorMap解析成RGB像素,代码参照DumpScreen2RGBA(),注意微博中的DumpScreen2RGBA()中解析RGB的字节顺序可能是不对的。
接着是解析透明色alpha,参照DumpScreen2RGBA()修改一个:

static void GetAlpha(unsigned char * alpha_buffer , GifRowType * ScreenBuffer , int ScreenWidth, int ScreenHeight,int alphaColorIndex){
        int i, j;
        GifRowType GifRow;
        static GifColorType *ColorMapEntry;
        unsigned char *BufferP;
     
        for (i = 0; i < ScreenHeight; i++) {
            GifRow = ScreenBuffer[i];
           BufferP = alpha_buffer + i * (ScreenWidth);
           for (j = 0; j < ScreenWidth; j++) {
               	*BufferP++ = (alphaColorIndex ==GifRow[j])?0x00: 0xff;
           }
       }
}

读取完RGB ,alpha 数据后,将数据跟其他参数存到struct image im,再调用fb_display进行显示。
完成显示后继续处理下一帧。

case EXTENSION_RECORD_TYPE中主要处理的是透明色和延时

		if(extcode==0xf9) //look image transparency in graph ctr extension
		{
			if(extension[1] & 1)
			{
				//透明色获取
				transparency = extension[4];
			}else{
				transparency = -1;
			}
			if(extension[0] == 4){
				unsigned long usec;
				usec = (extension[3] << 8 | extension[2]) * 10*1000;
				//延时处理
				usleep(usec);
				printf("Delay msec %d \n",usec/1000);
			}
        }

按这么处理,理论上就可以正常显示GIF动画了。。。。吧

为什么显示GIF动画过程,画面有些奇怪的小点点出现,还有残影???!!!

为啥?我也只能靠猜,靠着printf打印信息出来判断。。。

还好,print还差个f,想到了:透明色处理可能有问题。

第一帧图像是没问题的。
如果把透明色去掉,GIF动画过程会出现越来越多的奇怪的点;残影则像是贴图错位。

来到fb_display.c,看看

void fb_display(unsigned char *rgbbuff, unsigned char * alpha, 
			int x_size, int y_size, int x_pan, int y_pan, 
			int x_offs, int y_offs){
...
    /* blit buffer 2 fb */
    fbbuff = convertRGB2FB(fh, rgbbuff, x_size * y_size, var.bits_per_pixel, &bp);
...

	blit2FB(fh, fbbuff, alpha, x_size, y_size, x_stride, var.yres_virtual, x_pan, y_pan, x_offs, y_offs + var.yoffset, bp);

...
}

看看convertRGB2FB()代码,用来将RGB数据转换为framebuff要传输的像素格式数据。

看看blit2FB()代码,把转换后的像素数据填充到framebuff中,涉及到了透明色alpha的处理,那么就是它了。

没有透明色要处理的时候,把数据直接一行行的填进去:

for(i = 0; i < yc; i++, fbptr += scr_xs * cpp, imptr += pic_xs * cpp)
			memcpy(fbptr, imptr, xc * cpp);

有透明色要处理的时候:

	 	unsigned char * alphaptr;
		int from, to, x;
		
		alphaptr = alpha + (yp	* pic_xs + xp);
		
		for(i = 0; i < yc; i++, fbptr += scr_xs * cpp, imptr += pic_xs * cpp, alphaptr += pic_xs)
		{
			for(x = 0; x 0x80) from = v;
					}
					else
					{
						if(alphaptr[v] < 0x80)
						{
							to = v;
							break;
						}
					}
				}
				if(from == -1)
					break;
					
				if(to == -1) to = xc;
				
				memcpy(fbptr + (from * cpp), imptr + (from * cpp), (to - from - 1) * cpp);
				x += to - from - 1;
			}
		}

看着有点绕,就是按行处理,每行记录不透明的起始位置 from:
if(alphaptr[v] > 0x80) from = v;
和结束位置to:

					if(alphaptr[v] < 0x80)
						{
							to = v;
							break;
						},
						...
				if(to == -1) to = xc;

然后用图像像素数据填充from to之间的framebuffer。

想想就能知道这么处理的问题了,就是每一行有多段透明,非透明存在,造成部分数据少填充。
解决的办法也简单,按像素处理,稍微会慢一点(就代码处理的感觉上。。。):

	if(alpha)
	{
		int w ,h ;
		unsigned char * alphaptr;
		int pos;
		alphaptr = alpha + (yp	* pic_xs + xp);
		printf("writing fb\n");
		for( h = 0 ; h< yc  ; h++ ,fbptr += scr_xs * cpp, imptr += pic_xs * cpp,alphaptr+=pic_xs){
			for(w = 0 ; w< xc ; w++){
				if(alphaptr[w]>0x80){
					memcpy(fbptr+w * cpp , imptr+w * cpp,cpp);
					 
				}
			}
		}
	}

好了,终于正常显示GIF动画了。

你可能感兴趣的:(linux,Lichee,Zero,fbv,gif,framebuffer)