Chinaunix首页 | 论坛 | 博客
  • 博客访问: 737542
  • 博文数量: 124
  • 博客积分: 3156
  • 博客等级: 中校
  • 技术积分: 1584
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-02 10:29
文章分类

全部博文(124)

文章存档

2012年(3)

2011年(2)

2010年(61)

2009年(34)

2008年(24)

我的朋友

分类: LINUX

2010-08-20 23:10:36

http://wowocpp.blog.163.com/blog/static/124262780200911214567678/

http://blog.chinaunix.net/u2/84904/showart_1913883.html

apt-get install libjpeg62

编译的时候应该加上 -ljpeg

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#define        FB_DEV        "/dev/fb0"

/***************** function declaration ******************/

void            usage(char *msg);

unsigned short  RGB888toRGB565(unsigned char red,

        unsigned char green, unsigned char blue);

int             fb_open(char *fb_device);

int             fb_close(int fd);

int             fb_stat(int fd, int *width, int *height, int *depth);

void           *fb_mmap(int fd, unsigned int screensize);

int             fb_munmap(void *start, size_t length);

int             fb_pixel(void *fbmem, int width, int height,

        int x, int y, unsigned short color);

/************ function implementation ********************/

    int

main(int argc, char *argv[])

{

    /*

     * declaration for jpeg decompression

     */

    struct jpeg_decompress_struct cinfo;

    struct jpeg_error_mgr jerr;

    FILE           *infile;

    unsigned char  *buffer;

    /*

     * declaration for framebuffer device

     */

    int             fbdev;

    char           *fb_device;

    unsigned char  *fbmem;

    unsigned int    screensize;

    unsigned int    fb_width;

    unsigned int    fb_height;

    unsigned int    fb_depth;

    unsigned int    x;

    unsigned int    y;

    /*

     * check auguments

     */

    if (argc != 2) {

        usage("insuffient auguments");

        exit(-1);

    }

        /*

         * open framebuffer device

         */

        if ((fb_device = getenv("FRAMEBUFFER")) == NULL)

            fb_device = FB_DEV;

        fbdev = fb_open(fb_device);

        /*

         * get status of framebuffer device

         */

        fb_stat(fbdev, &fb_width, &fb_height, &fb_depth);

        /*

         * map framebuffer device to shared memory

         */

        screensize = fb_width * fb_height * fb_depth / 8;

        fbmem = fb_mmap(fbdev, screensize);

        /*

         * open input jpeg file

         */

        if ((infile = fopen(argv[1], "rb")) == NULL) {

            fprintf(stderr, "open %s failed\n", argv[1]);

            exit(-1);

        }

        /*

         * init jpeg decompress object error handler

         */

        cinfo.err = jpeg_std_error(&jerr);

        jpeg_create_decompress(&cinfo);

        /*

         * bind jpeg decompress object to infile

         */

        jpeg_stdio_src(&cinfo, infile);

        /*

         * read jpeg header

         */

        jpeg_read_header(&cinfo, TRUE);

        /*

         * decompress process.

         * note: after jpeg_start_decompress() is called

         * the dimension infomation will be known,

         * so allocate memory buffer for scanline immediately

         */

        jpeg_start_decompress(&cinfo);

        if ((cinfo.output_width > fb_width) ||

                (cinfo.output_height > fb_height)) {

            printf("too large JPEG file,cannot display\n");

            return (-1);

        }

        buffer = (unsigned char *) malloc(cinfo.output_width *

                cinfo.output_components);

        y = 0;

        while (cinfo.output_scanline < cinfo.output_height) {

            jpeg_read_scanlines(&cinfo, &buffer, 1);

            if (fb_depth == 16) {

                unsigned short  color;

                for (x = 0; x < cinfo.output_width; x++) {

                    color = RGB888toRGB565(buffer[x * 3],

                            buffer[x * 3 + 1], buffer[x * 3 + 2]);

                    fb_pixel(fbmem, fb_width, fb_height, x, y, color);

                }

            } else if (fb_depth == 24) {

                memcpy((unsigned char *) fbmem + y * fb_width * 3,

                        buffer, cinfo.output_width * cinfo.output_components);

            }

            y++;                                        // next scanline

        }

        /*

         * finish decompress, destroy decompress object

         */

        jpeg_finish_decompress(&cinfo);

        jpeg_destroy_decompress(&cinfo);

        /*

         * release memory buffer

         */

        free(buffer);

        /*

         * close jpeg inputing file

         */

        fclose(infile);

        /*

         * unmap framebuffer's shared memory

         */

        fb_munmap(fbmem, screensize);

        /*

         * close framebuffer device

         */

        fb_close(fbdev);

        return (0);

    }

    void

        usage(char *msg)

        {

            fprintf(stderr, "%s\n", msg);

            printf("Usage: fv some-jpeg-file.jpg\n");

        }

    /*

     * convert 24bit RGB888 to 16bit RGB565 color format

     */

    unsigned short

        RGB888toRGB565(unsigned char red, unsigned char green, unsigned char blue)

        {

            unsigned short  B = (blue >> 3) & 0x001F;

            unsigned short  G = ((green >> 2) << 5) & 0x07E0;

            unsigned short  R = ((red >> 3) << 11) & 0xF800;

            return (unsigned short) (R | G | B);

        }

    /*

     * open framebuffer device.

     * return positive file descriptor if success,

     * else return -1.

     */

    int

        fb_open(char *fb_device)

        {

            int             fd;

            if ((fd = open(fb_device, O_RDWR)) < 0) {

                perror(__func__);

                return (-1);

            }

            return (fd);

        }

    /*

     * get framebuffer's width,height,and depth.

     * return 0 if success, else return -1.

     */

    int

        fb_stat(int fd, int *width, int *height, int *depth)

        {

            struct fb_fix_screeninfo fb_finfo;

            struct fb_var_screeninfo fb_vinfo;

            if (ioctl(fd, FBIOGET_FSCREENINFO, &fb_finfo)) {

                perror(__func__);

                return (-1);

            }

            if (ioctl(fd, FBIOGET_VSCREENINFO, &fb_vinfo)) {

                perror(__func__);

                return (-1);

            }

            *width = fb_vinfo.xres;

            *height = fb_vinfo.yres;

            *depth = fb_vinfo.bits_per_pixel;

            return (0);

        }

    /*

     * map shared memory to framebuffer device.

     * return maped memory if success,

     * else return -1, as mmap dose.

     */

    void           *

        fb_mmap(int fd, unsigned int screensize)

        {

            caddr_t         fbmem;

            if ((fbmem = mmap(0, screensize, PROT_READ | PROT_WRITE,

                            MAP_SHARED, fd, 0)) == MAP_FAILED) {

                perror(__func__);

                return (void *) (-1);

            }

            return (fbmem);

        }

    /*

     * unmap map memory for framebuffer device.

     */

    int

        fb_munmap(void *start, size_t length)

        {

            return (munmap(start, length));

        }

    /*

     * close framebuffer device

     */

    int

        fb_close(int fd)

        {

            return (close(fd));

        }

    /*

     * display a pixel on the framebuffer device.

     * fbmem is the starting memory of framebuffer,

     * width and height are dimension of framebuffer,

     * x and y are the coordinates to display,

     * color is the pixel's color value.

     * return 0 if success, otherwise return -1.

     */

    int

        fb_pixel(void *fbmem, int width, int height,

                int x, int y, unsigned short color)

        {

            if ((x > width) || (y > height))

                return (-1);

            unsigned short *dst = ((unsigned short *) fbmem + y * width + x);

            *dst = color;

            return 0;

        }

 

 libjpeg介绍:

 libjpeg是一个被广泛使用的JPEG压缩/解压缩函数库,它能够读写JFIF格式的 JPEG图像文件,通常这类文件是以.jpg或者.jpeg为后缀名的。通过libjpeg库,应用程序可以每次从JPEG压缩图像中读取一个或多个扫描 线(scanline,所谓扫描线,是指由一行像素点构成的一条图像线条),而诸如颜色空间转换、降采样/增采样、颜色量化之类的工作则都由 libjpeg去完成了。

 对于彩色图像,每个像素通常用三个分量表示,即R(Red)、G(Green)、B(Blue)三个分量,每个分量用一个字节表示,因此每个分量的取值范围从0到255;对于灰度图像,每个像素通常用一个分量表示,一个分量同样由一个字节表示,取值范围从0到255。

在libjpeg中,图像数据是以扫描线的形式存放的。每一条扫描线由一行像素点构成,像素点沿着扫描线从左到右依次排列。对于彩色图像,每个分量由三个字节组成,因此这三个字节以R、G、B的顺序构成扫描线上的一个像素点。一个典型的扫描线形式如下:

       R,G,B,R,G,B,R,G,B,…

通过libjpeg解压出来的图像数据也是以扫描线的形式存放的。

在本文中,只涉及到JPEG的解压缩,因此只对libjpeg的解压过程进行说明,有关libjpeg的压缩过程和其它高级用法,请参考[3]。一般地,libjpeg的解压过程如下:

1、分配并初始化一个JPEG解压对象(本文中将JPEG解压对象命名为cinfo):

    struct jpeg_decompress_struct cinfo;

    struct jpeg_error_mgr jerr;

    ...

    cinfo.err = jpeg_std_error(&jerr);

    jpeg_create_decompress(&cinfo);

2、指定要解压缩的图像文件:

    FILE * infile;

    ...

    if ((infile = fopen(filename, "rb")) == NULL) {

        fprintf(stderr, "can't open %s\n", filename);

        exit(1);

    }

    jpeg_stdio_src(&cinfo, infile);

3、调用jpeg_read_header()获取图像信息:

    jpeg_read_header(&cinfo, TRUE);

4、这是一个可选步骤,用于设置JPEG解压缩对象cinfo的一些参数,本文可忽略;

5、调用jpeg_start_decompress()开始解压过程:

    jpeg_start_decompress(&cinfo);

调用jpeg_start_decompress()函数之后,JPEG解压缩对象cinfo中的下面这几个字段将会比较有用:

l output_width                这是图像输出的宽度

l output_height                这是图像输出的高度

l output_components              每个像素的分量数,也即字节数

这是因为在调用jpeg_start_decompress()之后往往需要为解压后的扫描 线上的所有像素点分配存储空间,这个空间的大小可以通过output_width * output_componets确定,而要读取的扫描线的总数为output_height行。

6、读取一行或者多行扫描线数据并处理,通常的代码是这样的:

       while (cinfo.output_scanline < cinfo.ouput_height) {

              jpeg_read_scanlines();

              /* deal with scanlines */

       }

对扫描线的读取是按照从上到下的顺序进行的,也就是说图像最上方的扫描线最先被jpeg_read_scanlines()读入存储空间中,紧接着是第二个扫描线,最后是图像底边的扫描线被读入存储空间中。

7、调用jpeg_finish_decompress()完成解压过程:

    jpeg_finish_decompress(&cinfo);

8、调用jpeg_destroy_decompress()释放JPEG解压对象cinfo:

    jpeg_destroy_decompress(&cinfo);

以上就是通过libjpeg函数解压JPEG压缩图像的基本过程,由于本文不涉及libjpeg的高级特性和用法,因此,上面的介绍对于说明本文中要用到的libjpeg的功能已经足够了。

另外一个需要说明地方是:由于作者所用的Framebuffer设备的颜色深度为16位,颜 色格式为5-6-5格式——即R(红色)在16bit中占据高5位,G(绿色)在16bit中占据中间6位,B(蓝色)在16bit中占据低5位;而 libjpeg解压出来的图像数据为24位RGB格式,因此必须进行转换。对于24位的RGB,每个字节表示一个颜色分量,因此转换的方式为:对于R字 节,右移3位,对于G字节,右移2位,对于B字节,右移3位,然后将右移得到的值拼接起来,就得到了16位的颜色值。在后面的程序中,将把24位的颜色称 为RGB888,而把16位颜色值称为RGB565,这种命名方式可能不太规范,不过无论如何,在本文中就这样称呼了。另外,读者可能会想到,上面这种直 接将颜色分量的低位丢弃的方式不是会导致图像细节的丢失吗?比如,对于24位颜色的R字节,假如原来低3位的值在0~7之间均匀分布,转换之后,所有这低 3位的值全部都变成了0,这就是颜色细节的丢失。为了处理这个问题,可以采用误差扩散算法或者抖动算法来完成颜色转换。上面介绍的是最简单的转换方式—— 而且事实表明,这样做得到的结果并不差。

 

    for(i=0;i<16;i+=2)

    {

        bits=ch[i/2];

        for(j=0;j<16;j+=2,bits<<=1)

            if(bits&0x80)

            {

                location1 = (x+j) * (vinfo.bits_per_pixel / 8) + (y+i)  *  finfo.line_length;

                location2 = (x+j+1) * (vinfo.bits_per_pixel / 8) + (y+i)  *  finfo.line_length;

                location3 = (x+j) * (vinfo.bits_per_pixel / 8) + (y+i+1)  *  finfo.line_length;

                location4 = (x+j+1) * (vinfo.bits_per_pixel / 8) + (y+i+1)  *  finfo.line_length;

                *(unsigned short*)(fbp + location1) =0x00ff;        /* 蓝色的色深 */        /*直接赋值来改变屏幕上某点的颜色*/

                *(unsigned short*)(fbp + location2) =0x00ff;        /* 蓝色的色深 */        /*直接赋值来改变屏幕上某点的颜色*/

                *(unsigned short*)(fbp + location3) =0x00ff;        /* 蓝色的色深 */        /*直接赋值来改变屏幕上某点的颜色*/

                *(unsigned short*)(fbp + location4) =0x00ff;        /* 蓝色的色深 */        /*直接赋值来改变屏幕上某点的颜色*/

            }

    }

阅读(2561) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~