Linux应用--libjpeg用于在7寸ARGB屏显示jpg图像

本文介绍了如何修改一个原本适用于RGB565屏幕的JPEG图像显示程序,以适应ARGB8888的7寸屏幕。关键在于理解ARGB与RGB565的区别,调整内存分配、数据转换和缓冲区大小。在数据转换过程中,需要交换R和B的位置,并添加透明度通道。最终,通过示例代码展示了完整的转换过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        原子的教学中,用到的是4.3寸,RGB565的屏幕,而我手上的是ARGB888的7寸屏幕,这个libjpeg的应用程序肯定是需要改的。

        对于显示屏,就简单的讲一下。RGB565,意思是说,在显存中每个像素点,是由RGB三色表示,R占5位,G占6位,B占5位,而ARGB,多的这个A代表透明度,所以说要显示图片,就把原图每个像素点属性,按顺序在显示屏上表示出来就行。

        改程序有几个点要注意的,首先是分配显存与缓冲区的大小。

        我们ARGB888屏幕,每个像素点是占4*8=32位,是RGB565的两倍。

jpeg_line_buf = malloc(cinfo.output_components * cinfo.output_width*4/3);
fb_line_buf = malloc(cinfo.output_components * width*4/3);

        这个components是原图的色彩通道数,是3,我们显示屏多了一个属性透明度,所以要改成4。

valid_bytes = min_w * bpp / 8;//一行的有效字节数 表示真正写入到LCD显存的一行数据的大小

        bpp,就是内核从驱动、设备树中读出的显示屏的位深度,也就是32位,这样就可以算出我们写一行到底要写多少个字节。

while (cinfo.output_scanline < min_h) {

        jpeg_read_scanlines(&cinfo, &jpeg_line_buf, 1);//每次读取一行数据

        for (i = 0; i < min_w-1; i += 1)
        {
            fb_line_buf[4*i+2] = jpeg_line_buf[3*i];
            fb_line_buf[4*i+1] = jpeg_line_buf[3*i+1];
            fb_line_buf[4*i] = jpeg_line_buf[3*i+2];
            fb_line_buf[4*i+3] = 0x00;
        }

        memcpy(screen_base, fb_line_buf, valid_bytes);
        screen_base += line_length; //+line_length  定位到LCD下一行显存地址的起点
    }

        最重要的就是这里了,数据转换,jpeg_line_buf中包含了libjpeg解析图像得到的数据,这是BGR888格式保存的,所以我们要交换R和B的位置,每隔4个,我们的fb_line_buf,也就是我们实际写的缓冲,就要多写一个字节的透明度。

 

        最后实现的效果就是这样了。

        完整代码献上

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <jpeglib.h>

static int width;                       //LCD X分辨率
static int height;                      //LCD Y分辨率
static unsigned char *screen_base = NULL;        //映射后的显存基地址
static unsigned int line_length;       //LCD一行的长度(字节为单位)
static unsigned int bpp;    //像素深度bpp

static int show_jpeg_image(const char *path)
{
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;
    FILE *jpeg_file = NULL;
    unsigned char *jpeg_line_buf = NULL;     //行缓冲区:用于存储从jpeg文件中解压出来的一行图像数据
    unsigned char *fb_line_buf = NULL; //行缓冲区:用于存储写入到LCD显存的一行数据
    unsigned int min_h, min_w;
    unsigned int valid_bytes;   // 1 byte = 8 bit
    int i;int j=0;

    //绑定默认错误处理函数
    cinfo.err = jpeg_std_error(&jerr);

    //打开.jpeg/.jpg图像文件
    jpeg_file = fopen(path, "r");   //只读方式打开
    if (NULL == jpeg_file) {
        perror("fopen error");
        return -1;
    }

    //创建JPEG解码对象
    jpeg_create_decompress(&cinfo);

    //指定图像文件
    jpeg_stdio_src(&cinfo, jpeg_file);

    //读取图像信息
    jpeg_read_header(&cinfo, TRUE);
    printf("原始jpeg图像大小: %d*%d,颜色通道数: %d\n", cinfo.image_width, cinfo.image_height,cinfo.num_components);

    //设置解码参数
    cinfo.out_color_space = JCS_RGB;//默认就是JCS_RGB

    //开始解码图像
    jpeg_start_decompress(&cinfo);
    printf("输出jpeg图像大小: %d*%d,jpeg图像颜色通道数: %d\n", cinfo.output_width, cinfo.output_height, cinfo.output_components);

    //为缓冲区分配内存空间
    jpeg_line_buf = malloc(cinfo.output_components * cinfo.output_width*4/3);
    fb_line_buf = malloc(cinfo.output_components * width*4/3);
    printf("width: %d\n", width);
    //判断图像和LCD屏那个的分辨率更低
    if (cinfo.output_width > width)
        min_w = width;
    else
        min_w = cinfo.output_width;

    if (cinfo.output_height > height)
        min_h = height;
    else
        min_h = cinfo.output_height;

    //读取数据
    valid_bytes = min_w * bpp / 8;//一行的有效字节数 表示真正写入到LCD显存的一行数据的大小
    printf("bpp=%d\n", bpp);
    while (cinfo.output_scanline < min_h) {

        jpeg_read_scanlines(&cinfo, &jpeg_line_buf, 1);//每次读取一行数据

        for (i = 0; i < min_w-1; i += 1)
        {
            fb_line_buf[4*i+2] = jpeg_line_buf[3*i];
            fb_line_buf[4*i+1] = jpeg_line_buf[3*i+1];
            fb_line_buf[4*i] = jpeg_line_buf[3*i+2];
            fb_line_buf[4*i+3] = 0x00;
        }

        memcpy(screen_base, fb_line_buf, valid_bytes);
        screen_base += line_length; //+line_length  定位到LCD下一行显存地址的起点
    }

    //解码完成
    jpeg_finish_decompress(&cinfo); //完成解码
    jpeg_destroy_decompress(&cinfo);//销毁JPEG解码对象、释放资源

    //关闭文件、释放内存
    fclose(jpeg_file);
    free(fb_line_buf);
    free(jpeg_line_buf);
    return 0;
}

int main(int argc, char *argv[])
{
    struct fb_var_screeninfo fb_var;
    unsigned int screen_size;
    int fd;

    /* 传参校验 */
    if (2 != argc) {
        fprintf(stderr, "usage: %s <jpeg_file>\n", argv[0]);
        exit(-1);
    }

    /* 打开framebuffer设备 */
    if (0 > (fd = open("/dev/fb0", O_RDWR))) {
        perror("open error");
        exit(EXIT_FAILURE);
    }

    /* 获取参数信息 */
    ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);

    bpp = fb_var.bits_per_pixel;
    width = fb_var.xres;
    height = fb_var.yres;
    line_length = width * bpp / 8;
    screen_size = line_length * height;

    /* 将显示缓冲区映射到进程地址空间 */
    screen_base = mmap(NULL, screen_size, PROT_WRITE, MAP_SHARED, fd, 0);
    if (MAP_FAILED == (void *)screen_base) {
        perror("mmap error");
        close(fd);
        exit(EXIT_FAILURE);
    }

    /* 显示JPEG图片 */
    memset(screen_base, 0xFF, screen_size);
    show_jpeg_image(argv[1]);

    /* 退出 */
    munmap(screen_base, screen_size);  //取消映射
    close(fd);  //关闭文件
    exit(EXIT_SUCCESS);    //退出进程
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值