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()导入数据。
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()导入数据。
相关文章推荐
- Android从文件读取图像显示的效率问题
- Android中的基础----在按钮上显示图像的方式
- Android从文件读取图像显示的效率问题
- 图像处理笔记(1): bmp文件结构处理与显示
- opencv3编程入门学习笔记-----图像的载入、显示和输出到文件
- android开发仿照第三方app打开方式,如何将你的app显示在打开列表,并且将文件复制到你的app应用内
- android:scaleType="matrix"布局文件加载图片时候的显示方式
- android:scaleType="matrix"布局文件加载图片时候的显示方式
- Android开发笔记(一百四十)Word文件的读取与显示
- 读入图像文件并显示【C#图像处理学习笔记】
- android 解析并显示dicom文件的数据和图像
- 详谈Android从文件读取图像显示的效率问题
- android:scaleType="matrix"布局文件载入图片时候的显示方式
- android:scaleType="matrix"布局文件加载图片时候的显示方式
- hadoop学习笔记之以标准输出方式显示hadoop文件
- Android开发使用XML文件定义ImageView的在selected为true和false状态下显示不同的图像
- android:scaleType="matrix"布局文件加载图片时候的显示方式
- Android项目笔记二:用户自定义保存路径+文件列表显示+权限显示
- 图像编程学习笔记1——bmp文件结构处理与显示
- 图像编程学习笔记1——bmp文件结构处理与显示