您可以到http://www.ijg.org/网站下载libjpeg的源码, IJG JPEG Library就是jpeg压缩库,是以源码的形式提供给软件开发人员的,当然在软件包里也有编译好的库文件,我们这里就只用到其中的libjpeg.lib,jconfig.h,jmorecfg.h,jpeglib.h这几个文件,下面我就介绍一下怎样在自己的程序里嵌入图像压缩功能。

  一、建立编译环境

  所谓建立编译环境,其实非常简单,就是把上面提到的4个文件拷贝到你的项目文件夹下,把libjpeg.lib添加到你的项目中,然后在你完成压缩功能的那个文件里加入#include "jpeglib.h",需要注意的是,libjpeg.lib是用c语言开发的,如果要用在你的C++程序里,需要用到extern "C",如下:

// TestLibjpeg.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "memory.h"
extern "C" {
 #include "jpeglib.h"
}

  二、压缩步骤

  1、申请并初始化jpeg压缩对象,同时要指定错误处理器

struct jpeg_compress_struct jcs;

// 声明错误处理器,并赋值给jcs.err域
  struct jpeg_error_mgr jem;
  jcs.err = jpeg_std_error(&jem);

jpeg_create_compress(&jcs);

  2、指定压缩后的图像所存放的目标文件,注意,目标文件应以二进制模式打开

f=fopen("03.jpg","wb");
  if (f==NULL) 
  {
    delete [] data;
    delete [] pDataConv;
    return 0;
  }
  jpeg_stdio_dest(&jcs, f);

  3、设置压缩参数,主要参数有图像宽、高、色彩通道数(1:索引图像,3:其他),色彩空间(JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像),压缩质量等,如下:

jcs.image_width = nWidth;    // 为图的宽和高,单位为像素 
  jcs.image_height = nHeight;
  jcs.input_components = 1;   // 在此为1,表示灰度图, 如果是彩色位图,则为3 
  jcs.in_color_space = JCS_GRAYSCALE; //JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像

jpeg_set_defaults(&jcs); 
 jpeg_set_quality (&jcs, 80, true);

需要注意的是,jpeg_set_defaults函数一定要等设置好图像宽、高、色彩通道数计色彩空间四个参数后才能调用,因为这个函数要用到这四个值,调用jpeg_set_defaults函数后,jpeglib库采用默认的设置对图像进行压缩,如果需要改变设置,如压缩质量,调用这个函数后,可以调用其它设置函数,如jpeg_set_quality函数。其实图像压缩时有好多参数可以设置,但大部分我们都用不着设置,只需调用jpeg_set_defaults函数值为默认值即可。

  4、上面的工作准备完成后,就可以压缩了,压缩过程非常简单,首先调用jpeg_start_compress,然后可以对每一行进行压缩,也可以对若干行进行压缩,甚至可以对整个的图像进行一次压缩,压缩完成后,记得要调用jpeg_finish_compress函数,如下:

jpeg_start_compress(&jcs, TRUE);

JSAMPROW row_pointer[1];   // 一行位图
  int row_stride;      // 每一行的字节数

row_stride = jcs.image_width;  // 如果不是索引图,此处需要乘以3

// 对每一行进行压缩
  while (jcs.next_scanline < jcs.image_height) {
       row_pointer[0] = & pDataConv[jcs.next_scanline * row_stride];
       jpeg_write_scanlines(&jcs, row_pointer, 1);
  }

jpeg_finish_compress(&jcs);

  5、最后就是释放压缩工作过程中所申请的资源了,主要就是jpeg压缩对象,由于在本例中我是直接用的局部变量,所以只需调用jpeg_destroy_compress这个函数即可,如下:

jpeg_destroy_compress(&jcs);

  三、解压缩步骤
  解压缩步骤与压缩步骤非常相似,只是解压缩对象为jpeg_decompress_struct类型,步骤如下:
  1、声明并初始化解压缩对象,同时制定错误信息管理器
 struct jpeg_decompress_struct cinfo;
 struct jpeg_error_mgr jerr;

cinfo.err = jpeg_std_error(&jerr);
 jpeg_create_decompress(&cinfo);
  2、打开jpg图像文件,并指定为解压缩对象的源文件
 FILE *f = fopen(strSourceFileName,"rb");
 if (f==NULL)
 {
  printf("Open file error!\n");
  return;
 }
 // 
 jpeg_stdio_src(&cinfo, f);
  3、读取图像信息
 jpeg_read_header(&cinfo, TRUE);
  4、根据图像信息申请一个图像缓冲区
 data = new BYTE cinfo.image_width*cinfo.image_height*cinfo.num_components];
  5、开始解压缩
 jpeg_start_decompress(&cinfo);

JSAMPROW row_pointer[1];
 while (cinfo.output_scanline < cinfo.output_height)
 {
  row_pointer[0] = &data[(cinfo.output_height - cinfo.output_scanline-1)*cinfo.image_width*cinfo.num_components];
  jpeg_read_scanlines(&cinfo,row_pointer ,
     1);
 }
 jpeg_finish_decompress(&cinfo);
  6、释放资源
 jpeg_destroy_decompress(&cinfo);

fclose(f);

  好了,利用IJG JPEG Library进行图像压缩就介绍到这里,希望对大家有所帮助,实例代码已经实现了图像的压缩和解压缩的全部功能

Embedded VC

Jpeg图像处理程序和代码(使用Indepedent JPEG Group的JpegLib)

用Independent JPEG Group发行的JpegLib进行Jpeg图像的读取与保存。
        这里只加了一个简单的处理示例——负片。其他的处理可以用与这个类似的方法,有了处理的算法对像素数据进行操作。或者加上鼠标事件的处理来完成绘画功能等等,这里主要是对JPEG文件进行操作的部分。
        注意:程序中的CTScreenBuffer并未使用,原因是使用它加载后有段内存没有释放,加上BMP数据本来就比较好处理,所以自己写一段,将BMP数据加上头信息就可以CreateDIBSection了。
        保存的默认质量Q=85,大家在使用时可以按照要求改变。

详细的使用方法以及JpegLib库


MacintoshM 2006-05-14, 11:38 
详细的使用方法:

1.系统需求
  Microsoft eMbedded Visual C++ 4.0 + Pocket PC 2003 SDK
  Pocket PC的JpegLib库(在本帖的附件中)
2.背景
  Jpeg库的由以下两个文件配置:jconfig.h和jmorecfg.h。一般使用时是不需要改变jmorecfg.h的,但这样可能在Pocket PC中运行时遇到问题,所以这里还是对jmorecfg.h进行了修改。下面将讨论这个修改,以使这个库在Pocket PC上正常使用。不过这里能够下载的附件已经做好了这个修改。

3.将JpegLib引入Pocket PC
  jmorecfg.h文件含有与Embedded Visual Studio冲突的定义.需要做以下修改:

(1)代码:

#ifndef XMD_H                        
typedef long INT32;
#endif

改为:

#if !defined(XMD_H) && !defined(_BASETSD_H_)
typedef long INT32;
#endif

(2)代码:

#ifdef NEED_FAR_POINTERS
#define FAR  far
#else
#define FAR
#endif

用下面的ifdef代替

#ifndef FAR
....
#endif

4.使用JpegLib加载Jpeg图片
  在前面的附件的程序中,已经有这个程序的框架,这里不再赘述。只讲主要的部分。
  (1)加载Jpeg图片的函数:
  void CImageView::LoadImage(const CString &strFileName)
{
        FILE * pFile;
        struct jpeg_error_mgr jerr;
        struct jpeg_decompress_struct cinfo;
        int i,start;
        start=0;
        
        if ((pFile = _tfopen(strFileName, _T("rb")) == NULL) {
                CString strError;
                strError.Format(_T("无法打开文件 '%s'", strFileName);
                AfxMessageBox(strError);
        }
        
        cinfo.err = jpeg_std_error(&jerr);
        jpeg_create_decompress(&cinfo);
        jpeg_stdio_src(&cinfo, pFile);
        jpeg_read_header(&cinfo, TRUE);
        jpeg_start_decompress(&cinfo);
        nRowSize = cinfo.output_width * cinfo.output_components;
        Width=cinfo.output_width;
        Height=cinfo.output_height;

if(bmpLoaded)
        {
                delete bmpBuffer;
        }
        bmpBuffer=new BYTE[(Height+1)*Width*3]; //这里多申请一行,是因为在模拟器执行时,会出现无法加载的错误,但在机器上正常

bmpLoaded=TRUE;

pBuffer = (*cinfo.mem->alloc_sarray)
                ((j_common_ptr) &cinfo, JPOOL_IMAGE, nRowSize, 1);
        while(cinfo.output_scanline < cinfo.output_height) 
        {
                jpeg_read_scanlines(&cinfo, pBuffer, 1);

start=nRowSize*cinfo.output_scanline;
                for(i=0;i<nRowSize;i++)
                {
                        bmpBuffer[start+i]=pBuffer[0];
                }        
        }

CreateBitmap();
        
        jpeg_finish_decompress(&cinfo);
        jpeg_destroy_decompress(&cinfo);
        fclose(pFile);

}

(2)将加载后的像素数据建立一个HBITMAP对象的函数
    注意这里没有使用CSTScreenBuffer,因为在我实验时,用这个函数加载后,内存资源没有释放,这样每加载一幅图或做一次处理,就会多消耗几兆内存,Pocket PC内存很快就会被耗尽。所以这里将像素数据加上头信息就可以CreateDIBSection了。
    void CImageView::CreateBitmap()
{
        int m_nCorrectedWidth,m_nWidth,m_nHeight;

m_nCorrectedWidth = ( ( Width + 3 ) / 4 ) * 4;
        m_nWidth = Width;
        m_nHeight = Height;

DIBINFO  dibInfo;
        BGRColor *m_pBuffer;

dibInfo.bmiHeader.biBitCount = 24;
        dibInfo.bmiHeader.biClrImportant = 0;
        dibInfo.bmiHeader.biClrUsed = 0;
        dibInfo.bmiHeader.biCompression = 0;
        dibInfo.bmiHeader.biHeight = m_nHeight;
        dibInfo.bmiHeader.biPlanes = 1;
        dibInfo.bmiHeader.biSize = 40;
        dibInfo.bmiHeader.biSizeImage = m_nCorrectedWidth*m_nHeight*3;
        dibInfo.bmiHeader.biWidth = m_nCorrectedWidth;
        dibInfo.bmiHeader.biXPelsPerMeter = 3780;
        dibInfo.bmiHeader.biYPelsPerMeter = 3780;
        dibInfo.bmiColors[0].rgbBlue = 0;
        dibInfo.bmiColors[0].rgbGreen = 0;
        dibInfo.bmiColors[0].rgbRed = 0;
        dibInfo.bmiColors[0].rgbReserved = 0;

HDC hDC = ::GetDC(NULL);

if(m_hBitmap)
        {
                :eleteObject(m_hBitmap);
                m_hBitmap=0;
        }
        m_hBitmap = CreateDIBSection(hDC, (const BITMAPINFO*)dibInfo, DIB_RGB_COLORS, (void**)&m_pBuffer, NULL, 0);
        
        ::ReleaseDC(NULL,hDC);

int nPosition = 0;
        int nDataPosition = 0;

for (int y=0; y<Height; y++) {
                nPosition = m_nCorrectedWidth*(m_nHeight-y-1);
                nDataPosition = Width*3*y;
                for (int x=0; x<Width; x++) {
                        m_pBuffer[nPosition].m_R = bmpBuffer[nDataPosition++];
                        m_pBuffer[nPosition].m_G = bmpBuffer[nDataPosition++];
                        m_pBuffer[nPosition].m_B = bmpBuffer[nDataPosition++];
                        nPosition++;
                }
        }

}
    (3)在绘画函数中,这里是OnDraw(),加入如下代码:
    if (m_hBitmap) 
        {
            CDC memDc;
                VERIFY(memDc.CreateCompatibleDC(&dc));
            HBITMAP hOldBitmap = (HBITMAP)::SelectObject(memDc.GetSafeHdc(), m_hBitmap);
                VERIFY(dc.BitBlt(-LeftTop.x, -LeftTop.y, Width, Height, &memDc, 0, 0, SRCCOPY));
            ::SelectObject(memDc.GetSafeHdc(), hOldBitmap);
                VERIFY( memDc.DeleteDC() );
        }

5.使用JpegLib库保存Jpeg图片
    这里是一种实现方法:
   void CImageView::SaveImage(const CString &strFileName)
{        
        int nQuality=85; //保存质量Q值为85

if(!::WriteRGBBytesIntoJpegFile(strFileName,Width,Height,nQuality,bmpBuffer))
        {
                ::AfxMessageBox(GetJpegWriterError());
        }
}

其他的更详细内容的看例程中的其他消息处理函数就可以了。

1.问题的由来
    Jpeg图片在图像处理领域已经用的相当广泛了。但在编程领域,尤其是嵌入式编程领域使用的还不是很广。主要的原因是Jpeg的数据结构和算法远较bmp复杂,非图像算法的专业人士,通常是无法理解这些的。(我有个同事,他曾经花了半个月,研究过Jpeg的原理,还为此在team内部举办了一个讲座,讲了足足有一个小时,令众人对之仰慕万分,但他却说,仅得皮毛,未得要害。从此我对Jpeg的原理近而远之。)
    近来,因工作需要,要在wince平台下,为程序添加Jpeg支持。一般来说,此类问题最容易的解决方案是使用OS提供的相关库,毕竟现在不支持Jpeg的OS几乎没有。但在wince下这里出了个问题。目前绝大多数的wince设备是wince 4.X或5.X的,不过碰巧在图像处理这块,5.X和4.X的方法是不一样的。4.X提供的方法在IMGDECMP.DLL中,而5.X提供的方法在Imaging.DLL中,而且不止是链接库不同,库的接口也是完全两样的。因此,如果软件采用OS提供的相关库的话,在这里就要准备两套接口,非常的麻烦。况且,我们的软件不仅要在wince下部署,将来还打算推广到其他的平台,因此这种方案显然是不太好的。
    这时我想到了JpegLib。JpegLib是Independent JPEG Group——一个非Jpeg官方组织推出的Jpeg库。这是个开源免费的库,支持多种平台和编译器,你可以在www.ijg.org中获得它的最新版本。在PC上它的效率比不了intel的Jpeg库,因为后者进行了汇编优化。但在wince上应该和系统库的效率相当。事实上如果查看系统的版权信息的话,Microsoft在wince中也使用了这个库。RISC的芯片也基本没有汇编优化的问题。
    网上的中文资料以以下两篇文章最为详尽。
    http://mobile.winfans.net/ccs/forums/516/PrintPost.aspx (文献A)
    http://blog.csdn.net/zhao3728/archive/2007/08/22/1754877.aspx (文献B)
    所以我的这篇文章主要作为补遗之用。

2.编译JpegLib库
    文献A和B都是使用现成的JpegLib库,这样的库只在特定的平台下才能用,完全体现不出JpegLib的优势。所以掌握编译JpegLib库的方法,是很有必要的。
    JpegLib库源代码的组成
    1)makefile。JpegLib库中有很多文件名为makefile的文件。它的后缀名表示它所用于的平台或用途。随便打开一个,就可以看到JpegLib库源代码的组成。
    2)makefile中LIBSOURCES变量所代表的文件是JpegLib的核心算法部分。
    3)makefile中SYSDEPSOURCES变量所代表的文件是JpegLib中负责内存分配的部分。这部分是系统相关的,所以根据需要选用一个就行了。
    4)makefile中APPSOURCES变量所代表的文件是JpegLib中提供诸如命令行压缩Jpeg之类的功能的部分,实际上就是一些小工具。不过在编译JpegLib库时,不要将之添加到工程中。
    5)makefile中INCLUDES变量所代表的文件是源代码中用到的头文件。不是所有的头文件都被核心算法部分使用到,因此有些头文件在编译JpegLib库时,是不必要的,当然将之添加到工程中也不会出错。
    6)makefile中DOCS变量所代表的文件是一些文档、测试用例之类的东西。其中最有用的是example.c,文献A和B的示例最重要的部分,就来自这里。
    7)jconfig。JpegLib库中还有很多和makefile类似的jconfig,这是针对不同平台的类型声明。在使用时,应根据需要,将适当的jconfig文件的后缀名改为h。
    以上这些内容更详细的说明见JpegLib库的文档,以及
    http://blog.csdn.net/axlrosek/archive/2007/03/29/1545496.aspx
    VC:不同版本的VC、EVC都差不多,参照文献A的步骤修改相关文件,然后新建一个空工程,然后打开JpegLib中的makefile.vc文件,将2)和3)、5)、7)中的文件添加到工程中。将生成文件的类型定为lib就行了。此外,还需要针对调用的情况选择适当的运行时库,否则可能会出LNK2005错误。

3.使用JpegLib库
    JpegLib库的使用参照文献A和B,以及example.c就可以了。但文献A的示例是有问题的。
    bmpBuffer[start+i]=pBuffer[0];
应改为
    bmpBuffer[start+i]=pBuffer[0][i];
    jpeg_read_scanlines(&cinfo, pBuffer, 1)执行之后,扫描线的内容被放到pBuffer[0],而不是pBuffer中,用memcpy将扫描线的内容转移到其他的缓冲区就行了,无需用循环语句。

4.流输入的Jpeg的处理
    上面的示例处理的都是从文件读入的Jpeg,在现实中,还存在流输入的Jpeg。在很多PC游戏中,程序的数据都被集中起来放入一个大文件之中,最典型的当属暴雪的mpq文件。当这些文件被读入内存时,就形成了字节流形式的文件。将之存为临时文件,然后再用之前的方法,显然是笨方法。这时可以采用jpeg_arr_src函数来替换jpeg_stdio_src函数。
    这一点还可以参考以下文档,不过该文针对的好像是旧版本,使用时要注意。
    http://blog.china.com/u/060803/5544/200608/15355.html

jpeglib使用指南的更多相关文章

  1. 【Linux开发】jpeglib使用指南

    您可以到www.ijg.org网站下载libjpeg的源码, IJG JPEG Library就是jpeg压缩库,是以源码的形式提供给软件开发人员的,当然在软件包里也有编译好的库文件,我们这里就只用到 ...

  2. JavaScript权威指南 - 函数

    函数本身就是一段JavaScript代码,定义一次但可能被调用任意次.如果函数挂载在一个对象上,作为对象的一个属性,通常这种函数被称作对象的方法.用于初始化一个新创建的对象的函数被称作构造函数. 相对 ...

  3. UE4新手之编程指南

    虚幻引擎4为程序员提供了两套工具集,可共同使用来加速开发的工作流程. 新的游戏类.Slate和Canvas用户接口元素以及编辑器功能可以使用C++语言来编写,并且在使用Visual Studio 或 ...

  4. JavaScript权威指南 - 对象

    JavaScript对象可以看作是属性的无序集合,每个属性就是一个键值对,可增可删. JavaScript中的所有事物都是对象:字符串.数字.数组.日期,等等. JavaScript对象除了可以保持自 ...

  5. JavaScript权威指南 - 数组

    JavaScript数组是一种特殊类型的对象. JavaScript数组元素可以为任意类型,最大容纳232-1个元素. JavaScript数组是动态的,有新元素添加时,自动更新length属性. J ...

  6. const extern static 终极指南

    const extern static 终极指南 不管是从事哪种语言的开发工作,const extern static 这三个关键字的用法和原理都是我们必须明白的.本文将对此做出非常详细的讲解. co ...

  7. Atitit.研发管理软件公司的软资产列表指南

    Atitit.研发管理软件公司的软资产列表指南 1. Isv模型下的软资产1 2. 实现层面implet1 3. 规范spec层1 4. 法则定律等val层的总结2 1. Isv模型下的软资产 Sof ...

  8. HA 高可用软件系统保养指南

    又过了一年 618,六月是公司一年一度的大促月,一般提前一个月各系统就会减少需求和功能的开发,转而更多去关注系统可用性.稳定性和管控性等方面的非功能需求.大促前的准备工作一般叫作「备战」,可以把线上运 ...

  9. 第六代智能英特尔® 酷睿™ 处理器图形 API 开发人员指南

    欢迎查看第六代智能英特尔® 酷睿™ 处理器图形 API 开发人员指南,该处理器可为开发人员和最终用户提供领先的 CPU 和图形性能增强.各种新特性和功能以及显著提高的性能. 本指南旨在帮助软件开发人员 ...

随机推荐

  1. python中import和from...import...的区别

    python中import和from...import...的区别: 只用import时,如import xx,引入的xx是模块名,而不是模块内具体的类.函数.变量等成员,使用该模块的成员时需写成xx ...

  2. Flatten Binary Tree to Linked List

    Flatten a binary tree to a fake "linked list" in pre-order traversal. Here we use the righ ...

  3. 【leetcode】Palindrome Partitioning

    Palindrome Partitioning Given a string s, partition s such that every substring of the partition is ...

  4. c++ const总结

    [本文链接] http://www.cnblogs.com/hellogiser/p/cplusplus-const-summay.html 看到const 关键字,C++程序员首先想到的可能是con ...

  5. Java for LeetCode 200 Number of Islands

    Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surro ...

  6. python 将pdf分页后插入至word中

    所用技术 1. python编程基础 2. 使用pyPdf 3. 使用python操作word 4. 正则表达式的使用 5. windows的bat编程 下面是一个pyPdf库使用的示例: from ...

  7. July 28th, Week 31st Thursday, 2016

    Time is a bird flying into eternity. 时间是一只永远在飞翔的鸟儿. Time waits for nobody. Vitality shows in not onl ...

  8. WPF控件委托

    this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate { //要执行的代码 });

  9. ServletContext与ServletConfig的详解及区别

    转自http://hi.baidu.com/huaxuelili/item/1704a03dbb5cd7f22784f4c6 一.ServletContext详解ServletContext是serv ...

  10. cocos2dx游戏开发——微信打飞机学习笔记(五)——BackgroundLayer的搭建

    一.创建文件~ 文件名:BackgroundLayer.h BackgroundLayer.cpp 架构就跟前面的一样,我就直接进入正题 啦,而且github有完整代码,欢迎下载~ 二.创建滚动的背景 ...