用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) ,看到显示图像文件时,都是分别调用
1
2
3load = 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
1
2
3#include <gif_lib.h> 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()中的流程是行不通了
1
2
3
4
5
6
7
8
9#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):
1
2
3
4
5
6
7
8
9
10
11
12#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("exitn"); exit(0); } #endif
代码参考了上面提到的微博,处理GIF文件的过程:
case IMAGE_DESC_RECORD_TYPE
中先读出一帧的颜色索引值,然后按照ColorMap解析成RGB像素,代码参照DumpScreen2RGBA(),注意微博中的DumpScreen2RGBA()中解析RGB的字节顺序可能是不对的。
接着是解析透明色alpha,参照DumpScreen2RGBA()修改一个:
1
2
3
4
5
6
7
8
9
10
11
12
13
14static 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
中主要处理的是透明色和延时
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19if(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,看看
1
2
3
4
5
6
7
8
9
10
11void 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的处理,那么就是它了。
没有透明色要处理的时候,把数据直接一行行的填进去:
1
2
3for(i = 0; i < yc; i++, fbptr += scr_xs * cpp, imptr += pic_xs * cpp) memcpy(fbptr, imptr, xc * cpp);
有透明色要处理的时候:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33unsigned 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<xc; x++) { int v; from = to = -1; for(v = x; v<xc; v++) { if(from == -1) { if(alphaptr[v] > 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:
1
2
3
4
5
6
7
8
9if(alphaptr[v] < 0x80) { to = v; break; }, ... if(to == -1) to = xc;
然后用图像像素数据填充from to之间的framebuffer。
想想就能知道这么处理的问题了,就是每一行有多段透明,非透明存在,造成部分数据少填充。
解决的办法也简单,按像素处理,稍微会慢一点(就代码处理的感觉上。。。):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17if(alpha) { int w ,h ; unsigned char * alphaptr; int pos; alphaptr = alpha + (yp * pic_xs + xp); printf("writing fbn"); 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动画了。
最后
以上就是专注铃铛最近收集整理的关于用fvb在Framebuffer中显示GIF动画fbv (v1.0b)、Framebuffer简介的全部内容,更多相关用fvb在Framebuffer中显示GIF动画fbv内容请搜索靠谱客的其他文章。
发表评论 取消回复