Linux应用开发-libjpeg库交叉编译与使用

描述

1. 前言

在开发板上如果想要显示jpeg格式的图片,必须用到libjpeg库,不可能自己去编写jpg的解码代码。

libjpeg是一个完全用C语言编写的库,包含了被广泛使用的JPEG解码、JPEG编码和其他的JPEG功能的实现。这个库由独立JPEG工作组维护。

Linux

源码获取地址: www.ijg.org/

Linux

2. 安装编译步骤

下面介绍libjpeg库交叉编译器的详细步骤。

 ① 下载源码包,将源码包拷贝到linux系统下。比如:jpegsrc.v9b.tar.gz
 ​
 ② 解码源码包
 [root@xiaolong jpeg-9b]# tar xf jpegsrc.v9b.tar.gz 
 ​
 ③ 配置源码
 [root@xiaolong jpeg-9b]# 
 ./configure --prefix=/usr/local/lib CC=arm-linux-gcc --host=arm-linux --enable-shared --enable-static
 注意:
 /usr/local/lib 表示指定源码最终安装的路径。
 ​
 ④ 编译源码
 [root@xiaolong jpeg-9b]# make
 ​
 ⑤ 安装源码
 [root@xiaolong jpeg-9b]# make install
 ​
 安装好的目录如下:(/usr/local/lib)
 [root@xiaolong lib]# ls
 bin  include  lib  share
 ​
 文件结构:
 [root@xiaolong lib]# pwd
 /usr/local/lib
 [root@xiaolong lib]# tree ./
 ./
 ├── bin
 │   ├── cjpeg
 │   ├── djpeg
 │   ├── jpegtran
 │   ├── rdjpgcom
 │   └── wrjpgcom
 ├── include
 │   ├── jconfig.h
 │   ├── jerror.h
 │   ├── jmorecfg.h
 │   └── jpeglib.h
 ├── lib
 │   ├── libjpeg.a
 │   ├── libjpeg.la
 │   ├── libjpeg.so -> libjpeg.so.9.2.0
 │   ├── libjpeg.so.9 -> libjpeg.so.9.2.0
 │   └── libjpeg.so.9.2.0
 └── share
     └── man
         └── man1
             ├── cjpeg.1
             ├── djpeg.1
             ├── jpegtran.1
             ├── rdjpgcom.1
             └── wrjpgcom.1
 ​
 6 directories, 19 files
复制代码

3. 使用步骤

 1.将以下几个头文件拷贝到需要编译的工程目录下:
 jmorecfg.h、jpeglib.h、jerror.h、jconfig.h
 ​
 2.将以下头文件加到工程中:
 #include "jpeglib.h"
 ​
 3./将usr/local/lib目录下的生成的库文件拷贝到开发板的lib目录下。
 ​
 4.编译选择--任意一种:
 arm-linux-gcc -o app show_jpeg.c -L/usr/local/lib
 arm-linux-gcc -o app show_jpeg.c -l:libjpeg.so.9
 arm-linux-gcc show_jpeg.c -ljpeg -static -o app
 ​
 show_jpeg.c是要编译的源文件
 app 是生成的目标文件。
  -static 表示静态生成
 #include 头文件定义解压缩使用的数据结构信息。
复制代码

4. 使用案例

4.1 使用libjpg库编码-RGB数据保存为jpg图片

下面这个是利用libjpeg封装的一个方便函数,用于将传入的rgb数据压缩编码成jpg文件保存,一般用与屏幕截屏、相机拍照等地方。

 #include 
 #define JPEG_QUALITY 100 //图片质量
  
 int savejpg(uchar *pdata, char *jpg_file, int width, int height)
 {  //分别为RGB数据,要保存的jpg文件名,图片长宽
     int depth = 3;
     JSAMPROW row_pointer[1];//指向一行图像数据的指针
     struct jpeg_compress_struct cinfo;
     struct jpeg_error_mgr jerr;
     FILE *outfile;
  
     cinfo.err = jpeg_std_error(&jerr);//要首先初始化错误信息
     //* Now we can initialize the JPEG compression object.
     jpeg_create_compress(&cinfo);
  
     if ((outfile = fopen(jpg_file, "wb")) == NULL)
     {
         fprintf(stderr, "can't open %s\n", jpg_file);
         return -1;
     }
     jpeg_stdio_dest(&cinfo, outfile);
  
     cinfo.image_width = width;             //* image width and height, in pixels
     cinfo.image_height = height;
     cinfo.input_components = depth;    //* # of color components per pixel
     cinfo.in_color_space = JCS_RGB;     //* colorspace of input image
     jpeg_set_defaults(&cinfo);
  
     jpeg_set_quality(&cinfo, JPEG_QUALITY, TRUE ); //* limit to baseline-JPEG values
     jpeg_start_compress(&cinfo, TRUE);
  
     int row_stride = width * 3;
     while (cinfo.next_scanline < cinfo.image_height)
     {
             row_pointer[0] = (JSAMPROW)(pdata + cinfo.next_scanline * row_stride);//一行一行数据的传,jpeg为大端数据格式
             jpeg_write_scanlines(&cinfo, row_pointer, 1);
     }
  
     jpeg_finish_compress(&cinfo);
     jpeg_destroy_compress(&cinfo);//这几个函数都是固定流程
     fclose(outfile);
     return 0;
 }
复制代码

4.2 LCD显示jpg格式图片

下面代码利用libjpeg库解码传入的jpg文件,得到rgb数据,再绘制到LCD屏上显示。

Linux
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 ​
 // 24位色和16位色转换宏
 // by cheungmine
 #define RGB888_TO_RGB565(r,g,b)  ((WORD)(((WORD(r)<<8)&0xF800)|((WORD(g)<<3)&0x7E0)|((WORD(b) >> 3))))
 #define RGB_TO_RGB565(rgb)       ((WORD)(((((WORD)((rgb)>>3))&(0x1F))<<11)|((((WORD)((rgb)>>10))&(0x3F))<<5)|(((WORD)((rgb)>>19))&(0x1F))))
 #define RGB888_TO_RGB555(r,g,b)  ((WORD)(((WORD(r)<<7)&0x7C00)|((WORD(g)<<2)&0x3E0)|((WORD(b)>>3))))
 #define RGB_TO_RGB555(rgb)       ((WORD)(((((WORD)((rgb)>>3))&(0x1F))<<10)|((((WORD)((rgb)>>11))&(0x1F))<<5)|(((WORD)((rgb)>>19))&(0x1F))))
 #define RGB555_TO_RGB(rgb555)    ((DWORD)(((BYTE)(((rgb555)>>7)&0xF8)|((WORD)((BYTE)(((rgb555)>>2)&0xF8))<<8))|(((DWORD)(BYTE)(((rgb555)<<3)&0xF8))<<16)))
 #define RGB565_TO_RGB(rgb565)    ((DWORD)(((BYTE)((((rgb565)&0xF800)>>11)<<3)|((WORD)((BYTE)((((rgb565)&0x07E0)>>5)<<2))<<8))|(((DWORD)(BYTE)(((rgb565)&0x001F)<<3))<<16)))
 unsigned short  rgb888_to_rgb555(unsigned char red,unsigned char green,unsigned char blue);
 unsigned short  rgb888_to_rgb565(unsigned char red,unsigned char green,unsigned char blue);
                        
                                  
 /*--------------------------------------------------------------
                         JPEG图片显示
 ---------------------------------------------------------------*/
 static unsigned char *fbmem = NULL;
 static struct fb_var_screeninfo var;//定义可变参数结构体来接收驱动传过来的可变参数结构体
 static struct fb_fix_screeninfo fix;//定义固定参数结构体来接收驱动传过来的固定参
 ​
 //显示JPEG
 int show_jpeg(unsigned char *file)
 {
     struct jpeg_decompress_struct cinfo; //存放图像的数据
     struct jpeg_error_mgr jerr; //存放错误信息
     FILE           *infile;
     unsigned int *dst=fbmem;
     unsigned char  *buffer;
     unsigned int    x;
     unsigned int    y;
     /*
     * 打开图像文件
     */
     if ((infile = fopen(file, "rb")) == NULL) {
         fprintf(stderr, "open %s failed\n", file);
         exit(-1);
     }
 ​
     /*
      * init jpeg压缩对象错误处理程序
      */
     cinfo.err = jpeg_std_error(&jerr); //初始化标准错误,用来存放错误信息
     jpeg_create_decompress(&cinfo);    //创建解压缩结构信息
      
      
     /*
      * 将jpeg压缩对象绑定到infile
      */
     jpeg_stdio_src(&cinfo, infile);
 ​
     /*
      * 读jpeg头
      */
     jpeg_read_header(&cinfo, TRUE);
    
     /*
         *开始解压
         */
     jpeg_start_decompress(&cinfo);
     
     printf("JPEG高度: %d\n",cinfo.output_height);
     printf("JPEG宽度: %d\n",cinfo.output_width);
     printf("JPEG颜色位数(字节单位): %d\n",cinfo.output_components);
     
     //为一条扫描线上的像素点分配存储空间
     buffer = (unsigned char *) malloc(cinfo.output_width *cinfo.output_components);
     y = 0;
 ​
     //将图片内容显示到framebuffer上
     while (cinfo.output_scanline < cinfo.output_height) 
     {
          
          //读取一行的数据    
         jpeg_read_scanlines(&cinfo, &buffer, 1);
         
         //判断LCD屏的映射空间像素位数
         if (var.bits_per_pixel == 32) 
         {
             unsigned int  color;
             for (x = 0; x < cinfo.output_width; x++) {
                 color = buffer[x * 3 + 0] << 16  |
                         buffer[x * 3 + 1] << 8   |
                         buffer[x * 3 + 2] << 0;
                 dst = ((unsigned int *) fbmem + y * var.xres + x);
                 *dst = color;
             }
         }
         y++;                                   // 显示下一个像素点
     }
     
     /*
      * 完成解压,摧毁解压对象
      */
     jpeg_finish_decompress(&cinfo); //结束解压
     jpeg_destroy_decompress(&cinfo); //释放结构体占用的空间
 ​
     /*
      * 释放内存缓冲区
      */
     free(buffer);
 ​
     /*
      * 释放内存缓冲区
      */
     fclose(infile);
     return 0;
 }
 ​
 /*映射LCD显示的内存空间*/
 unsigned char * fmem(unsigned char *fbname)
 {
     int fb;
     unsigned char *mem;
     fb = open(fbname,2);
     if(fb<0)
     {
         printf("open fbdev is error!!!\n");
         return NULL;
     }
     ioctl(fb,FBIOGET_VSCREENINFO,&var);//获取固定参数结构体放在var结构体中
     ioctl(fb,FBIOGET_FSCREENINFO,&fix);//获取固定参数,存放在fix结构体中
     mem = (unsigned char *)mmap(NULL,fix.smem_len,PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
     if(mem == (unsigned char *)-1)
     {
         printf("fbmmap is error!!!\n");
         munmap(mem,fix.smem_len);
         return NULL;
     }
     return mem;
 }
 ​
 ​
 int main (int argc,char** argv) //./a.out /dev/fb0 xxx.bmp
 {
     int fb ,i=4;
     char key;
     unsigned char * bmpmem;
     if(argc!=3)
     {
         printf("Usage: ./%s  \n",argv[0]);
         return -1;
     }
     fbmem =  fmem(argv[1]);        //将缓冲设备映射到内存进行写入 
     memset(fbmem,0x00,fix.smem_len);//清屏函数 往映射的地址填充fix.sem_len大小的0xff颜色进去
     show_jpeg(argv[2]);           //程序运行时显示主界面
     return 0;
 }

  审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分