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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sunny_hu92/article/details/79109571

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!!!"<<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中的介绍很详细:

unsigned char*data=img->bits();//获取图像像素字节数据的首地址
这里要注意,采用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()导入数据。



猜你喜欢

转载自blog.csdn.net/sunny_hu92/article/details/79109571