您的位置:首页 > 移动开发 > Android开发

Android笔记---framebuffer 显示图像文件(QImage方式)

2018-01-19 18:50 176 查看
Platform: android 22
Software:
Based on Qt 5.7.0 (GCC 4.9.1 20140922 (Red Hat 4.9.1-10), 64 bit) for android

Qt Creator 4.0.2

近几日,在搅腾着怎么在16位framebuffer指定位置显示一张图片。今天,终于有点眉目,在此记录一点心得。

要在16位的framebuffer上显示图片,那么这张图片也应该是16位深度的。所以如果读到的图片数据不是16位深度的,那就需要通过RGB转换。
其间,尝试了三种方法:
1. frambuffer 显示bmp图片方式;
主要参考:http://blog.csdn.net/luxiaoxun/article/details/7622988

遇到几个问题:a. bmp读取是按照从下到上,从左到右的方式,如果要对字节进行处理,需考虑数据的顺序; b. 用上面博客中的代码测试,最后发现显示的bmp图片颜色有偏差,直接对像素写数据显示红,绿,蓝都是OK的,说明代码读取bmp数据有问题,至今没有解决。

2. framebuffer 显示jpeg图片方式;
主要参考:http://blog.csdn.net/liu0808/article/details/49818733
遇到问题:上述博客是转载的,最初出处链接已经失效,但是说明比较详细,简单而言就是通过jpeglib的库对jpeg图片进行读取,解压缩等处理。
其间,遇到最大问题就是,我要交叉编译jpeglib 的库,才能用到。下载了jpeg-9b/jpeg-9c源码包,编译的时候遇到问题,包括交叉编译器的选择、库和头文件放置的路径、怎么加入到QT中调用、在远端运行时是否需要cp库和头文件到板端,等问题。代码还是比较好理解。。。呵呵

3. 通过Qt的QImage类获取图片数据,之后对数据进行字节处理,最后显示在framebuffer上。花了一天时间搞定。主要还是因为是个菜鸟。。。

经过上面三个历程,你们可以想象一下我的痛苦。。。进入正题。。。
需掌握的知识点:

QImage类的介绍:http://doc.qt.io/archives/qt-4.8/qimage.html

QImage对图片的处理:https://www.cnblogs.com/Romi/archive/2012/12/03/2800039.html

大致的思路是:1. QImage::bits()读到图片数据;2. ARGB8888 转换到RGB565;3. 指定位置刷fb。

源码如下:

//show Image
int G2DThread::showImage(QString imagePath, unsigned int x, unsigned int y)
{
int fp = 0;
char *fbp = NULL;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
fp = open("/dev/graphics/fb1", O_RDWR);

QImage qimage;
qimage.load(imagePath);
unsigned char *data = qimage.bits();
unsigned char r, g, b;
int w = qimage.width();
int h = qimage.height();
int d = qimage.depth();

// qDebug()<<"data[0]"<<data[0]<<"data[1]"<<data[1]<<"data[2]"<<data[2]<<"data[3]"<<data[3]<<endl;
qDebug()<<"qimage depth is"<<d<<endl;

if (fp < 0)
{
qDebug()<<"Error: Can not open framebuffer device!"<<endl;
exit(1);
}

if (ioctl(fp, FBIOGET_FSCREENINFO, &finfo))
{
qDebug()<<"Error reading fixed information!!!"
b13f
<<endl;
exit(2);
}

if (ioctl(fp, FBIOGET_VSCREENINFO, &vinfo))
{
qDebug()<<"Error reading variable information!!!"<<endl;
exit(3);
}

int screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel/8;

fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fp, 0);
if ((int) fbp == -1)
{
qDebug()<<"Error: failed to map framebuffer device to memory."<<endl;
exit(4);
}
unsigned int total_len = w*h*2;
unsigned char *fb_buff=fb_buff;//notice "char" style.

fb_buff = (unsigned char *)malloc(total_len);

// for(unsigned int i=0; i<total_len/2; i++)
// {
// unsigned int j = i*2;
// fb_buff[j] = 0x00;
// fb_buff[j+1] = 0xF8;
// }

//32bits ARGB8888 to 16bits RGB565
for(unsigned int i=0; i<total_len/2;i++)
{
unsigned int j = i*4;
unsigned int k = i*2;
r = data[j+2];
g = data[j+1];
b = data[j];

fb_buff[k] = ((g & 0x1C)<<3 | (b>>3));
fb_buff[k+1] = ((r & 0xF8) | (g>>5));
}

//show on framebuffer
for(int i=0;i<h;i++)
{
int offset = w* 2;
// unsigned int x=124;
// unsigned int y=155;
unsigned int offsetLine = (y+i+fb_dev.vinfo.yoffset)*fb_dev.finfo.line_length;
unsigned int location=(x+fb_dev.vinfo.xoffset)*(fb_dev.vinfo.bits_per_pixel/8)+offsetLine;
memcpy(fb_dev.map_fb+location,fb_buff+i*offset,offset);
}

// qDebug()<<"The mem is:"<<finfo.smem_len<<endl;
// qDebug()<<"The line_length is:"<<finfo.line_length<<endl;
// qDebug()<<"The xres is:"<<vinfo.xres<<endl;
// qDebug()<<"The yres is:"<<vinfo.yres<<endl;
// qDebug()<<"The bits_per_pixel is:"<<vinfo.bits_per_pixel<<endl;
// qDebug()<<"The fb_buff[10] is:"<<fb_buff[10]<<endl;
// qDebug()<<"The fb_buff[11] is:"<<fb_buff[11]<<endl;

free(fb_buff);

munmap(fbp, screensize);

close(fp);

return 0;
}
其中的一些注释掉的代码是我用来测试的,1. 可以直接对像素字节赋值,显示单色;2. 输出一些图片和fb信息。有需要的可以试一试。
代码分析:
1. 打开fb
fp = open("/dev/graphics/fb1", O_RDWR);
/dev/graphics/fb1 是板端android的fb1的路径,有fb0和fb1,放在fb1上显示图片。

2. 获取图像数据
unsigned char *data = qimage.bits();关于QImage 的bits()用法,博客https://www.cnblogs.com/Romi/archive/2012/12/03/2800039.html中的介绍很详细:

这里要注意,采用bits()方法的到的数据data中像素的组织形式应为ARGB,但实际调试中发现,每个像素中从字节从低到高依次是BGRA,方向刚好反过来。在处理彩色图像时尤其注意。下面会解释这样排列顺序的原因。
3. AGRB8888转RGB565
//32bits ARGB8888 to 16bits RGB565
for(unsigned int i=0; i<total_len/2;i++)
{
unsigned int j = i*4;
unsigned int k = i*2;
r = data[j+2];
g = data[j+1];
b = data[j];

fb_buff[k] = ((g & 0x1C)<<3 | (b>>3));
fb_buff[k+1] = ((r & 0xF8) | (g>>5));
}这里将的比较细致:http://blog.csdn.net/lucykingljj/article/details/40422121
并附上RGB565常用颜色表,以供测试:
#define   BLACK     0x0000          黑色    0,   0,   0
#define   NAVY      0x000F          深蓝色  0,   0, 127
#define   DGREEN    0x03E0          深绿色  0,  127,  0
#define   DCYAN     0x03EF          深青色  0,  127, 127       
#define   MAROON    0x7800          深红色  127,   0,   0      
#define   PURPLE    0x780F          紫色    127,   0, 127      
#define   OLIVE     0x7BE0          橄榄绿  127, 127,   0      
#define   LGRAY     0xC618          灰白色  192, 192, 192      
#define   DGRAY     0x7BEF          深灰色  127, 127, 127      
#define   BLUE      0x001F          蓝色    0,   0, 255        
#define   GREEN     0x07E0          绿色    0, 255,   0        
#define   CYAN      0x07FF          青色    0, 255, 255        
#define   RED       0xF800          红色    255,   0,   0      
#define   MAGENTA   0xF81F          品红    255,   0, 255      
#define   YELLOW    0xFFE0          黄色    255, 255, 0        
#define   WHITE     0xFFFF          白色    255, 255, 255    
4. 刷fb
先用mmap()映射内存,后memcpy()导入数据。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: