您可以到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]Idea [I];
                }       
        }

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相关推荐

  1. Jpeglib使用指南, 各种压缩包的压缩和解压方法, 开源社区分裂史

    http://antkillerfarm.github.io/ Jpeglib使用指南 1.问题的由来 Jpeg图片在图像处理领域已经用的相当广泛了.但在编程领域,尤其是嵌入式编程领域使用的还不是很广 ...

  2. jpeglib使用指南

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

  3. 利用libjpeg库实现jpg与bmp图片互转指南

    jpg与bmp图片互转指南 一.原理: ​ jpg与bmp图片格式都是以rgb像素为基础的,但是jpg在bmp的rgb的基础上进行了压缩.而且存储的方式是bgr,因此,在二者转换过程中需要转换对应的格 ...

  4. 超详细中文预训练模型ERNIE使用指南-源码

    作者 | 高开远,上海交通大学,自然语言处理研究方向 最近在工作上处理的都是中文语料,也尝试了一些最近放出来的预训练模型(ERNIE,BERT-CHINESE,WWM-BERT-CHINESE),比对 ...

  5. 入门指南目录页 -PaddlePaddle 飞桨 入门指南 FAQ合集-深度学习问题

    入门指南目录页 -PaddlePaddle 飞桨 入门指南 FAQ合集 GT_Zhang关注 0.1012019.08.01 18:43:34字数 1,874阅读 795 Hi,欢迎各位来自Paddl ...

  6. ASIC设计-终极指南

    ASIC设计-终极指南 ASIC Design – The Ultimate Guide ASIC设计-终极指南 ASICs代表特定于应用的集成电路,指的是针对特定应用而设计的半导体解决方案,与其他解 ...

  7. Python神经网络集成技术Guide指南

    Python神经网络集成技术Guide指南 本指南将介绍如何加载一个神经网络集成系统并从Python运行推断. 提示 所有框架的神经网络集成系统运行时接口都是相同的,因此本指南适用于所有受支持框架(包 ...

  8. 深度学习框架集成平台C++ Guide指南

    深度学习框架集成平台C++ Guide指南 这个指南详细地介绍了神经网络C++的API,并介绍了许多不同的方法来处理模型. 提示 所有框架运行时接口都是相同的,因此本指南适用于所有受支持框架(包括Te ...

  9. HTML5与CSS3权威指南之CSS3学习记录

    title: HTML5与CSS3权威指南之CSS3学习记录 toc: true date: 2018-10-14 00:06:09 学习资料--<HTML5与CSS3权威指南>(第3版) ...

最新文章

  1. 详细讲解SQL Server索引的性能问题
  2. antv图例出现分页_2020,贴地飞行的 AntV 设计
  3. 记一次死锁问题的排查和解决
  4. 验证STIL的pattern的输入输出顺序
  5. 2020年一季度中小微企业收入平均下降69.5%
  6. 基于Visual Studio2010与.NET 4.0--多显示器支持使开发效率事半功倍
  7. 【C语言】控制台窗口图形界面编程(五):文本移动
  8. 关于抠图的一些文章方法收集
  9. Android Fragment(二)
  10. 【Unity编辑器】UnityEditor多重弹出窗体与编辑器窗口层级管理
  11. 集中刷新父窗口,关闭子窗口的JS(后台)
  12. Android设置屏幕亮度的两种方式
  13. JBX IDE中文输入
  14. Arduino Leonardo教程:如何回车,特殊按键定义,DIY超便宜的键盘主控
  15. 苹果在旧设备中修复了两个 iOS 零日漏洞
  16. 小学计算机教学打字,怎么快速学拼音打字-小学生如何更快的学习拼音
  17. java 排版快捷键_Eclipse自动排版快捷键失效(转)
  18. JavaScript之Soft排序
  19. Google AIY视觉套件登陆香港!Gravitylink引力互联商城开启预售!
  20. 内网安全-流量隧道(一)不出网CS上线正反向端口转发

热门文章

  1. 航电oj:18岁生日
  2. python学习—— IPy 强大的IP地址解析模块
  3. linux 显示并替换控制字符
  4. c语言学习之可变数组
  5. 发票信息批量提取到 excel 软件 5.1
  6. UVA 208 救火车
  7. 机器学习:基于朴素贝叶斯(Naive Bayes)的分类预测
  8. 卷积神经网络算法汇总
  9. 前端显示LaTex公式
  10. 智冠尝试包月免费并行 《新绝代双骄》4日实施双轨