jpeg解碼庫使用實例

jpeg庫下載地址:
    http://www.ijg.org/

交叉編譯三部曲:
    A ./configure --host=arm-linux-gcc --prefix=/home/flying/jpeg-install
    B  make
    C  make install
jpeg庫是解壓jpeg/jpg圖片或將圖片壓縮爲jpeg/jpg格式所用到的庫,使用起來比較簡單!

jpeg/jpg解碼過程:

    1. 創建jpeg對象和錯誤處理對象
        struct jpeg_decompress_struct cinfo;
        struct jpeg_error_mgr         jerr; 

    2. 將錯誤處理對象綁定到jpeg對象上
        EXTERN(struct jpeg_error_mgr *) jpeg_std_error
        JPP((struct jpeg_error_mgr * err));

    3. 初始化jpeg對象
        #define jpeg_create_compress(cinfo) \
    jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \
                        (size_t) sizeof(struct jpeg_compress_struct))

    4. 指定解壓數據源(有兩種方式)
        a. EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo, const unsigned char * inbuffer, unsigned long insize));
            參數一: jpeg對象地址
            參數二: 儲存jpeg數據源緩衝區
            參數三: 緩衝區數據源大小

        b. EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile));
            參數一: jpeg對象地址
            參數二: 要解壓的jpeg圖片的文件指針

    5. 填充cinfo對象的缺省信息,常見的可用信息包括圖像的
       寬:       cinfo.image_width,
       高:       cinfo.image_height,
       色彩空間:  cinfo.jpeg_color_space,
       顏色通道數: cinfo.num_components等。
       EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo,
                                  boolean require_image));

    6. 爲解壓設定參數**(依情況而定)**
        比如解壓的圖片與原圖的縮放比例爲1/2,這可以設置參數
        cinfo.scale_num   = 1
        cinfo.scale_denom = 2

    7. 開始解壓
        EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo));

    在完成解壓縮操作後,會將解壓後的圖像信息填充至cinfo結構中。比如,輸出圖
    像寬度cinfo.output_width,輸出圖像高度cinfo.output_height,每個像
    素中的顏色通道數cinfo.output_components(比如灰度爲1,全綵色爲3)
    等。
    一般情況下,這些參數是在jpeg_start_decompress後才被填充到cinfo中
    的,如果希望在調用jpeg_start_decompress之前就獲得這些參數,可以通過
    調用jpeg_calc_output_dimensions()的方法來實現。


    8. 取數據
        解壓出來的數據是按照行取出的,從左到右,從上到下的順序,每個像
        素對應的各顏色或灰度通道數據是依次存儲,24位RGB圖解壓後的顏色
        通道排序是R,G,B,R,G,B......

        我們可以使用此函數取出循環取出數據:
        extern JDIMENSION jpeg_read_scanlines(j_decompress_ptr, JSAMPARRAY,
                      JDIMENSION);
            參數二: 一般來說就是unsigned char *,表示保存數據的緩衝區
            參數三: 表示要讀取的行數

    9. 解壓完畢釋放資源
        boolean jpeg_finish_decompress(j_decompress_ptr cinfo);

        後續不需要使用jpeg對象:
        void jpeg_destroy_decompress(j_decompress_ptr cinfo);

        如果在後續還需使用jpeg對象,則使用:
        void jpeg_abort_decompress(j_decompress_ptr cinfo);
實例:
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdbool.h>


#include "jpeglib.h"
#include "my_err.h"



struct image_info
{
    int width;
    int height;
    int pixel_size;
};

//將圖片顯示到LCD屏幕上,最後兩個參數指定顯示的原點座標
void write_jpeg_to_lcd(unsigned char *lcdmem, unsigned char *rgb_buffer
                        , struct fb_var_screeninfo *vinfo, struct image_info *image_info
                        , size_t xoffset, size_t yoffset)
{
    assert(lcdmem);
    assert(rgb_buffer);
    assert(vinfo);
    assert(image_info); 

    int x, y;

    size_t r_offset = vinfo->red.offset / 8;
    size_t g_offset = vinfo->green.offset / 8;
    size_t b_offset = vinfo->blue.offset / 8;

    for (y = 0; (y < vinfo->yres - yoffset) && (y < image_info->height); ++y) {

        for (x = 0; (x < vinfo->xres - xoffset) && (x < image_info->width); ++x) {

            size_t image_offset     =   (x * image_info->pixel_size) + (image_info->width * image_info->pixel_size * y);
            size_t lcd_offset       =   ((x + xoffset) * vinfo->bits_per_pixel / 8) + ((y + yoffset) * vinfo->xres * vinfo->bits_per_pixel /8);

            memcpy(lcdmem + lcd_offset + r_offset, rgb_buffer + image_offset, 1);
            memcpy(lcdmem + lcd_offset + g_offset, rgb_buffer + image_offset + 1, 1);
            memcpy(lcdmem + lcd_offset + b_offset, rgb_buffer + image_offset + 2, 1);
        }
    }
}

void read_image_from_file(int fd, unsigned char *jpeg_buffer, size_t image_size)
{
    assert(jpeg_buffer);

    int nread = 0;

    while (image_size > 0) {
        nread = read(fd, jpeg_buffer, image_size);
        if (nread < 0) {
            if (EINTR == errno) {
                continue;
            } else {
                err_sys("read error");
            }
        }

        image_size -= nread;
        jpeg_buffer += nread;
    }
}


int main(int argc, char **argv)
{
    if (2 != argc) {
        err_quit("Usage: %s <*.jpeg/jpg>\n", argv[1]);
    }

    int image_fd;
    if ((image_fd = open(argv[1], O_RDONLY)) < 0) {
        err_sys("open error");
    }

    struct stat sbuf;
    if (fstat(image_fd, &sbuf) < 0) {
        err_sys("stat error");
    }

    unsigned char *jpeg_buffer = calloc(1, sbuf.st_size);
    read_image_from_file(image_fd, jpeg_buffer, sbuf.st_size);


    struct jpeg_decompress_struct   cinfo;
    struct jpeg_error_mgr           jerr;

    cinfo.err   =   jpeg_std_error(&jerr);
    jpeg_create_decompress(&cinfo);

    jpeg_mem_src(&cinfo, jpeg_buffer, sbuf.st_size);

    if (JPEG_HEADER_OK != jpeg_read_header(&cinfo, true)) {
        err_sys("read head error");
    }

    jpeg_start_decompress(&cinfo);


    struct image_info *image_info   =   calloc(1, sizeof(struct image_info));
    if (image_info == NULL) {
        err_sys("calloc error for image_info");
    }

    image_info->width       =   cinfo.output_width;
    image_info->height      =   cinfo.output_height;
    image_info->pixel_size  =   cinfo.output_components;

    int row_stride  =   image_info->width * image_info->pixel_size;
    size_t rgb_size =   row_stride * image_info->height;

    unsigned char *rgb_buffer = calloc(1, rgb_size);
    if (rgb_buffer == NULL) {
        err_sys("rgb_buffer error");
    }

    //循環讀取解壓後的數據,cinfo.output_scanline表示當前讀取的行數
    while (cinfo.output_scanline < image_info->height) {
        unsigned char *buffer_array[1];
        buffer_array[0] =   rgb_buffer + cinfo.output_scanline * row_stride;
        jpeg_read_scanlines(&cinfo, buffer_array, 1);
    }


    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    free(jpeg_buffer);


    int lcd_fd;
    if ((lcd_fd = open("/dev/fb0", O_RDWR)) < 0 ) {
        err_sys("open error");
    }   

    struct fb_var_screeninfo vinfo;
    ioctl(lcd_fd, FBIOGET_VSCREENINFO, &vinfo);

    size_t mem_size =   vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
    unsigned char *lcdmem   =   mmap(0, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd, 0);
    if (lcdmem == MAP_FAILED) {
        err_sys("mmap error");
    }

    write_jpeg_to_lcd(lcdmem, rgb_buffer, &vinfo, image_info, 100, 100);

    free(rgb_buffer);
    munmap(lcdmem, mem_size);
    close(lcd_fd);
    close(image_fd);

    return EXIT_SUCCESS;
}
參考博客:
    http://blog.csdn.net/xipiaoyouzi/article/details/53257720
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章