﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Carlward blog-文章分类-VC++</title><link>http://www.cppblog.com/carlward/category/12433.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 11 Jan 2010 10:38:04 GMT</lastBuildDate><pubDate>Mon, 11 Jan 2010 10:38:04 GMT</pubDate><ttl>60</ttl><item><title>（转帖）jpeglib使用指南</title><link>http://www.cppblog.com/carlward/articles/104493.html</link><dc:creator>Carlward</dc:creator><author>Carlward</author><pubDate>Wed, 30 Dec 2009 14:27:00 GMT</pubDate><guid>http://www.cppblog.com/carlward/articles/104493.html</guid><wfw:comment>http://www.cppblog.com/carlward/comments/104493.html</wfw:comment><comments>http://www.cppblog.com/carlward/articles/104493.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/carlward/comments/commentRss/104493.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/carlward/services/trackbacks/104493.html</trackback:ping><description><![CDATA[<a href="http://blog.csdn.net/achellies/archive/2009/06/03/4238056.aspx">http://blog.csdn.net/achellies/archive/2009/06/03/4238056.aspx</a><br><br>
<p>您可以到<a href="http://www.ijg.org/"><u><font color=#810081>www.ijg.org</font></u></a>网站下载libjpeg的源码， IJG JPEG Library就是jpeg压缩库，是以源码的形式提供给软件开发人员的，当然在软件包里也有编译好的库文件，我们这里就只用到其中的libjpeg.lib，jconfig.h，jmorecfg.h，jpeglib.h这几个文件，下面我就介绍一下怎样在自己的程序里嵌入图像压缩功能。</p>
<p>　　一、建立编译环境</p>
<p>　　所谓建立编译环境，其实非常简单，就是把上面提到的４个文件拷贝到你的项目文件夹下，把libjpeg.lib添加到你的项目中，然后在你完成压缩功能的那个文件里加入#include "jpeglib.h"，需要注意的是，libjpeg.lib是用c语言开发的，如果要用在你的C++程序里，需要用到extern "C"，如下：</p>
<p>// TestLibjpeg.cpp : Defines the entry point for the console application.<br>//</p>
<p>#include "stdafx.h"<br>#include "memory.h"<br>extern "C" {<br>&nbsp;#include "jpeglib.h"<br>}</p>
<p>　　二、压缩步骤</p>
<p>　　１、申请并初始化jpeg压缩对象，同时要指定错误处理器</p>
<p>&nbsp;struct jpeg_compress_struct jcs;</p>
<p>&nbsp;// 声明错误处理器，并赋值给jcs.err域<br>&nbsp; struct jpeg_error_mgr jem;<br>&nbsp; jcs.err = jpeg_std_error(&amp;jem);</p>
<p>&nbsp; jpeg_create_compress(&amp;jcs);</p>
<p>　　２、指定压缩后的图像所存放的目标文件，注意，目标文件应以二进制模式打开</p>
<p>&nbsp;f=fopen("03.jpg","wb");<br>&nbsp; if (f==NULL) <br>&nbsp; {<br>&nbsp;&nbsp;&nbsp; delete [] data;<br>&nbsp;&nbsp;&nbsp; delete [] pDataConv;<br>&nbsp;&nbsp;&nbsp; return 0;<br>&nbsp; }<br>&nbsp; jpeg_stdio_dest(&amp;jcs, f);</p>
<p>　　３、设置压缩参数，主要参数有图像宽、高、色彩通道数（１：索引图像，３：其他），色彩空间（JCS_GRAYSCALE表示灰度图，JCS_RGB表示彩色图像），压缩质量等，如下：</p>
<p>&nbsp; jcs.image_width = nWidth;&nbsp;&nbsp;&nbsp; // 为图的宽和高，单位为像素 <br>&nbsp; jcs.image_height = nHeight;<br>&nbsp; jcs.input_components = 1;&nbsp;&nbsp; // 在此为1,表示灰度图， 如果是彩色位图，则为3 <br>&nbsp; jcs.in_color_space = JCS_GRAYSCALE; //JCS_GRAYSCALE表示灰度图，JCS_RGB表示彩色图像 </p>
<p>&nbsp; jpeg_set_defaults(&amp;jcs); <br>&nbsp;jpeg_set_quality (&amp;jcs, 80, true);</p>
<p>需要注意的是，jpeg_set_defaults函数一定要等设置好图像宽、高、色彩通道数计色彩空间四个参数后才能调用，因为这个函数要用到这四个值，调用jpeg_set_defaults函数后，jpeglib库采用默认的设置对图像进行压缩，如果需要改变设置，如压缩质量，调用这个函数后，可以调用其它设置函数，如jpeg_set_quality函数。其实图像压缩时有好多参数可以设置，但大部分我们都用不着设置，只需调用jpeg_set_defaults函数值为默认值即可。</p>
<p>　　４、上面的工作准备完成后，就可以压缩了，压缩过程非常简单，首先调用jpeg_start_compress，然后可以对每一行进行压缩，也可以对若干行进行压缩，甚至可以对整个的图像进行一次压缩，压缩完成后，记得要调用jpeg_finish_compress函数，如下：</p>
<p>&nbsp; jpeg_start_compress(&amp;jcs, TRUE);</p>
<p>&nbsp; JSAMPROW row_pointer[1];&nbsp;&nbsp; // 一行位图<br>&nbsp; int row_stride;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 每一行的字节数 </p>
<p>&nbsp; row_stride = jcs.image_width;&nbsp; // 如果不是索引图,此处需要乘以3</p>
<p>&nbsp; // 对每一行进行压缩<br>&nbsp; while (jcs.next_scanline &lt; jcs.image_height) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; row_pointer[0] = &amp; pDataConv[jcs.next_scanline * row_stride];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jpeg_write_scanlines(&amp;jcs, row_pointer, 1);<br>&nbsp; }</p>
<p>&nbsp; jpeg_finish_compress(&amp;jcs);</p>
<p>　　５、最后就是释放压缩工作过程中所申请的资源了，主要就是jpeg压缩对象，由于在本例中我是直接用的局部变量，所以只需调用jpeg_destroy_compress这个函数即可，如下：</p>
<p>&nbsp;jpeg_destroy_compress(&amp;jcs);</p>
<p>　　三、解压缩步骤<br>　　解压缩步骤与压缩步骤非常相似，只是解压缩对象为jpeg_decompress_struct类型，步骤如下：<br>　　1、声明并初始化解压缩对象，同时制定错误信息管理器<br>&nbsp;struct jpeg_decompress_struct cinfo;<br>&nbsp;struct jpeg_error_mgr jerr;</p>
<p>&nbsp;cinfo.err = jpeg_std_error(&amp;jerr);<br>&nbsp;jpeg_create_decompress(&amp;cinfo);<br>　　2、打开jpg图像文件，并指定为解压缩对象的源文件<br>&nbsp;FILE *f = fopen(strSourceFileName,"rb");<br>&nbsp;if (f==NULL)<br>&nbsp;{<br>&nbsp; printf("Open file error!\n");<br>&nbsp; return;<br>&nbsp;}<br>&nbsp;// <br>&nbsp;jpeg_stdio_src(&amp;cinfo, f);<br>　　3、读取图像信息<br>&nbsp;jpeg_read_header(&amp;cinfo, TRUE);<br>　　4、根据图像信息申请一个图像缓冲区<br>&nbsp;data = new BYTE cinfo.image_width*cinfo.image_height*cinfo.num_components];<br>　　5、开始解压缩<br>&nbsp;jpeg_start_decompress(&amp;cinfo);</p>
<p>&nbsp;JSAMPROW row_pointer[1];<br>&nbsp;while (cinfo.output_scanline &lt; cinfo.output_height)<br>&nbsp;{<br>&nbsp; row_pointer[0] = &amp;data[(cinfo.output_height - cinfo.output_scanline-1)*cinfo.image_width*cinfo.num_components];<br>&nbsp; jpeg_read_scanlines(&amp;cinfo,row_pointer ,<br>&nbsp;&nbsp;&nbsp;&nbsp; 1);<br>&nbsp;}<br>&nbsp;jpeg_finish_decompress(&amp;cinfo);<br>　　6、释放资源<br>&nbsp;jpeg_destroy_decompress(&amp;cinfo);</p>
<p>&nbsp;fclose(f);</p>
<p>　　好了，利用IJG JPEG Library进行图像压缩就介绍到这里，希望对大家有所帮助，实例代码已经实现了图像的压缩和解压缩的全部功能</p>
<h3><span id=_ctl1__ctl0_ForumName>Embedded VC</span></h3>
<h3>Jpeg图像处理程序和代码(使用Indepedent JPEG Group的JpegLib)</h3>
<p>用Independent JPEG Group发行的JpegLib进行Jpeg图像的读取与保存。<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;这里只加了一个简单的处理示例——负片。其他的处理可以用与这个类似的方法，有了处理的算法对像素数据进行操作。或者加上鼠标事件的处理来完成绘画功能等等，这里主要是对JPEG文件进行操作的部分。<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;注意：程序中的CTScreenBuffer并未使用，原因是使用它加载后有段内存没有释放，加上BMP数据本来就比较好处理，所以自己写一段，将BMP数据加上头信息就可以CreateDIBSection了。<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;保存的默认质量Q=85，大家在使用时可以按照要求改变。</p>
<h3>详细的使用方法以及JpegLib库</h3>
<hr>
<p><span class=inlineLink onclick="function onclick()&#13;&#10;{&#13;&#10;window.open('/ccs/user/Profile.aspx?UserID=2628')&#13;&#10;}">MacintoshM</span> 2006-05-14, 11:38 <br><span style="FONT-SIZE: 12px">详细的使用方法：<br><br>1.系统需求<br>&nbsp;&nbsp;Microsoft eMbedded Visual C++ 4.0 + Pocket PC 2003 SDK<br>&nbsp;&nbsp;Pocket PC的JpegLib库(在本帖的附件中)<br>2.背景<br>&nbsp;&nbsp;Jpeg库的由以下两个文件配置:jconfig.h和jmorecfg.h。一般使用时是不需要改变jmorecfg.h的，但这样可能在Pocket PC中运行时遇到问题，所以这里还是对jmorecfg.h进行了修改。下面将讨论这个修改，以使这个库在Pocket PC上正常使用。不过这里能够下载的附件已经做好了这个修改。<br><br>3.将JpegLib引入Pocket PC<br>&nbsp;&nbsp;jmorecfg.h文件含有与Embedded Visual Studio冲突的定义.需要做以下修改: <br><br>(1)代码: <br><br>#ifndef XMD_H&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br>typedef long INT32;<br>#endif<br><br><br>改为: <br><br>#if !defined(XMD_H) &amp;&amp; !defined(_BASETSD_H_)<br>typedef long INT32;<br>#endif<br><br><br>(2)代码: <br><br>#ifdef NEED_FAR_POINTERS<br>#define FAR&nbsp;&nbsp;far<br>#else<br>#define FAR<br>#endif<br><br><br>用下面的ifdef代替<br><br>#ifndef FAR<br>....<br>#endif<br><br>4.使用JpegLib加载Jpeg图片<br>&nbsp;&nbsp;在前面的附件的程序中，已经有这个程序的框架，这里不再赘述。只讲主要的部分。<br>&nbsp;&nbsp;(1)加载Jpeg图片的函数：<br>&nbsp;&nbsp;void CImageView::LoadImage(const CString &amp;strFileName)<br>{<br>&nbsp; &nbsp; &nbsp; &nbsp; FILE * pFile;<br>&nbsp; &nbsp; &nbsp; &nbsp; struct jpeg_error_mgr jerr;<br>&nbsp; &nbsp; &nbsp; &nbsp; struct jpeg_decompress_struct cinfo;<br>&nbsp; &nbsp; &nbsp; &nbsp; int i,start;<br>&nbsp; &nbsp; &nbsp; &nbsp; start=0;<br>&nbsp; &nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; if ((pFile = _tfopen(strFileName, _T("rb"<img alt="" src="http://bbs.pdafans.com/images/smilies/wink.gif" align=absMiddle border=0>)) == NULL) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CString strError;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; strError.Format(_T("无法打开文件 '%s'"<img alt="" src="http://bbs.pdafans.com/images/smilies/wink.gif" align=absMiddle border=0>, strFileName);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AfxMessageBox(strError);<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; cinfo.err = jpeg_std_error(&amp;jerr);<br>&nbsp; &nbsp; &nbsp; &nbsp; jpeg_create_decompress(&amp;cinfo);<br>&nbsp; &nbsp; &nbsp; &nbsp; jpeg_stdio_src(&amp;cinfo, pFile);<br>&nbsp; &nbsp; &nbsp; &nbsp; jpeg_read_header(&amp;cinfo, TRUE);<br>&nbsp; &nbsp; &nbsp; &nbsp; jpeg_start_decompress(&amp;cinfo);<br>&nbsp; &nbsp; &nbsp; &nbsp; nRowSize = cinfo.output_width * cinfo.output_components;<br>&nbsp; &nbsp; &nbsp; &nbsp; Width=cinfo.output_width;<br>&nbsp; &nbsp; &nbsp; &nbsp; Height=cinfo.output_height;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; if(bmpLoaded)<br>&nbsp; &nbsp; &nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delete bmpBuffer;<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; bmpBuffer=new BYTE[(Height+1)*Width*3]; //这里多申请一行，是因为在模拟器执行时，会出现无法加载的错误，但在机器上正常<br><br>&nbsp; &nbsp; &nbsp; &nbsp; bmpLoaded=TRUE;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; pBuffer = (*cinfo.mem-&gt;alloc_sarray)<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ((j_common_ptr) &amp;cinfo, JPOOL_IMAGE, nRowSize, 1);<br>&nbsp; &nbsp; &nbsp; &nbsp; while(cinfo.output_scanline &lt; cinfo.output_height) <br>&nbsp; &nbsp; &nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jpeg_read_scanlines(&amp;cinfo, pBuffer, 1);<br><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; start=nRowSize*cinfo.output_scanline;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(i=0;i&lt;nRowSize;i++)<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bmpBuffer[start+i]=pBuffer[0]<img alt="Idea [I]" src="http://writeblog.csdn.net/ccs/emoticons/emotion-55.gif">;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; }<br><br>&nbsp; &nbsp; &nbsp; &nbsp; CreateBitmap();<br>&nbsp; &nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; jpeg_finish_decompress(&amp;cinfo);<br>&nbsp; &nbsp; &nbsp; &nbsp; jpeg_destroy_decompress(&amp;cinfo);<br>&nbsp; &nbsp; &nbsp; &nbsp; fclose(pFile);<br><br>}<br><br>&nbsp; &nbsp; (2)将加载后的像素数据建立一个HBITMAP对象的函数<br>&nbsp; &nbsp; 注意这里没有使用CSTScreenBuffer,因为在我实验时，用这个函数加载后，内存资源没有释放，这样每加载一幅图或做一次处理，就会多消耗几兆内存,Pocket PC内存很快就会被耗尽。所以这里将像素数据加上头信息就可以CreateDIBSection了。<br>&nbsp; &nbsp; void CImageView::CreateBitmap()<br>{<br>&nbsp; &nbsp; &nbsp; &nbsp; int m_nCorrectedWidth,m_nWidth,m_nHeight;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; m_nCorrectedWidth = ( ( Width + 3 ) / 4 ) * 4;<br>&nbsp; &nbsp; &nbsp; &nbsp; m_nWidth = Width;<br>&nbsp; &nbsp; &nbsp; &nbsp; m_nHeight = Height;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; DIBINFO&nbsp;&nbsp;dibInfo;<br>&nbsp; &nbsp; &nbsp; &nbsp; BGRColor *m_pBuffer;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biBitCount = 24;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biClrImportant = 0;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biClrUsed = 0;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biCompression = 0;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biHeight = m_nHeight;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biPlanes = 1;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biSize = 40;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biSizeImage = m_nCorrectedWidth*m_nHeight*3;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biWidth = m_nCorrectedWidth;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biXPelsPerMeter = 3780;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biYPelsPerMeter = 3780;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiColors[0].rgbBlue = 0;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiColors[0].rgbGreen = 0;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiColors[0].rgbRed = 0;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiColors[0].rgbReserved = 0;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; HDC hDC = ::GetDC(NULL);<br><br>&nbsp; &nbsp; &nbsp; &nbsp; if(m_hBitmap)<br>&nbsp; &nbsp; &nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; :<img alt="" src="http://bbs.pdafans.com/images/smilies/biggrin.gif" align=absMiddle border=0>eleteObject(m_hBitmap);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_hBitmap=0;<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; m_hBitmap = CreateDIBSection(hDC, (const BITMAPINFO*)dibInfo, DIB_RGB_COLORS, (void**)&amp;m_pBuffer, NULL, 0);<br>&nbsp; &nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; ::ReleaseDC(NULL,hDC);<br><br>&nbsp; &nbsp; &nbsp; &nbsp; int nPosition = 0;<br>&nbsp; &nbsp; &nbsp; &nbsp; int nDataPosition = 0;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; for (int y=0; y&lt;Height; y++) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nPosition = m_nCorrectedWidth*(m_nHeight-y-1);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nDataPosition = Width*3*y;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (int x=0; x&lt;Width; x++) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_pBuffer[nPosition].m_R = bmpBuffer[nDataPosition++];<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_pBuffer[nPosition].m_G = bmpBuffer[nDataPosition++];<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_pBuffer[nPosition].m_B = bmpBuffer[nDataPosition++];<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nPosition++;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br><br>}<br>&nbsp; &nbsp; (3)在绘画函数中，这里是OnDraw()，加入如下代码：<br>&nbsp; &nbsp; if (m_hBitmap) <br>&nbsp; &nbsp; &nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;CDC memDc;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; VERIFY(memDc.CreateCompatibleDC(&amp;dc));<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;HBITMAP hOldBitmap = (HBITMAP)::SelectObject(memDc.GetSafeHdc(), m_hBitmap);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; VERIFY(dc.BitBlt(-LeftTop.x, -LeftTop.y, Width, Height, &amp;memDc, 0, 0, SRCCOPY));<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;::SelectObject(memDc.GetSafeHdc(), hOldBitmap);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; VERIFY( memDc.DeleteDC() );<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br><br>5.使用JpegLib库保存Jpeg图片<br>&nbsp; &nbsp; 这里是一种实现方法：<br>&nbsp; &nbsp;void CImageView::SaveImage(const CString &amp;strFileName)<br>{&nbsp; &nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; int nQuality=85; //保存质量Q值为85<br><br>&nbsp; &nbsp; &nbsp; &nbsp; if(!::WriteRGBBytesIntoJpegFile(strFileName,Width,Height,nQuality,bmpBuffer))<br>&nbsp; &nbsp; &nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ::AfxMessageBox(GetJpegWriterError());<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>}<br><br>其他的更详细内容的看例程中的其他消息处理函数就可以了。</span> </p>
<p>1.问题的由来<br>&nbsp;&nbsp;&nbsp; Jpeg图片在图像处理领域已经用的相当广泛了。但在编程领域，尤其是嵌入式编程领域使用的还不是很广。主要的原因是Jpeg的数据结构和算法远较bmp复杂，非图像算法的专业人士，通常是无法理解这些的。（我有个同事，他曾经花了半个月，研究过Jpeg的原理，还为此在team内部举办了一个讲座，讲了足足有一个小时，令众人对之仰慕万分，但他却说，仅得皮毛，未得要害。从此我对Jpeg的原理近而远之。）<br>&nbsp;&nbsp;&nbsp; 近来，因工作需要，要在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下部署，将来还打算推广到其他的平台，因此这种方案显然是不太好的。<br>&nbsp;&nbsp;&nbsp; 这时我想到了JpegLib。JpegLib是Independent JPEG Group——一个非Jpeg官方组织推出的Jpeg库。这是个开源免费的库，支持多种平台和编译器，你可以在<a href="http://www.ijg.org/" target=_blank><span style="COLOR: #96b0af"><u>www.ijg.org</u></span></a>中获得它的最新版本。在PC上它的效率比不了intel的Jpeg库，因为后者进行了汇编优化。但在wince上应该和系统库的效率相当。事实上如果查看系统的版权信息的话，Microsoft在wince中也使用了这个库。RISC的芯片也基本没有汇编优化的问题。<br>&nbsp;&nbsp;&nbsp; 网上的中文资料以以下两篇文章最为详尽。<br>&nbsp;&nbsp;&nbsp; <a href="http://mobile.winfans.net/ccs/forums/516/PrintPost.aspx" target=_blank><span style="COLOR: #96b0af"><u>http://mobile.winfans.net/ccs/forums/516/PrintPost.aspx</u></span></a> （文献A）<br>&nbsp;&nbsp;&nbsp; <a href="http://blog.csdn.net/zhao3728/archive/2007/08/22/1754877.aspx" target=_blank><span style="COLOR: #96b0af"><u>http://blog.csdn.net/zhao3728/archive/2007/08/22/1754877.aspx</u></span></a> （文献B）<br>&nbsp;&nbsp;&nbsp; 所以我的这篇文章主要作为补遗之用。<br><br>2.编译JpegLib库<br>&nbsp;&nbsp;&nbsp; 文献A和B都是使用现成的JpegLib库，这样的库只在特定的平台下才能用，完全体现不出JpegLib的优势。所以掌握编译JpegLib库的方法，是很有必要的。<br>&nbsp;&nbsp;&nbsp; JpegLib库源代码的组成<br>&nbsp;&nbsp;&nbsp; 1）makefile。JpegLib库中有很多文件名为makefile的文件。它的后缀名表示它所用于的平台或用途。随便打开一个，就可以看到JpegLib库源代码的组成。<br>&nbsp;&nbsp;&nbsp; 2）makefile中LIBSOURCES变量所代表的文件是JpegLib的核心算法部分。<br>&nbsp;&nbsp;&nbsp; 3）makefile中SYSDEPSOURCES变量所代表的文件是JpegLib中负责内存分配的部分。这部分是系统相关的，所以根据需要选用一个就行了。<br>&nbsp;&nbsp;&nbsp; 4）makefile中APPSOURCES变量所代表的文件是JpegLib中提供诸如命令行压缩Jpeg之类的功能的部分，实际上就是一些小工具。不过在编译JpegLib库时，不要将之添加到工程中。<br>&nbsp;&nbsp;&nbsp; 5）makefile中INCLUDES变量所代表的文件是源代码中用到的头文件。不是所有的头文件都被核心算法部分使用到，因此有些头文件在编译JpegLib库时，是不必要的，当然将之添加到工程中也不会出错。<br>&nbsp;&nbsp;&nbsp; 6）makefile中DOCS变量所代表的文件是一些文档、测试用例之类的东西。其中最有用的是example.c，文献A和B的示例最重要的部分，就来自这里。<br>&nbsp;&nbsp;&nbsp; 7）jconfig。JpegLib库中还有很多和makefile类似的jconfig，这是针对不同平台的类型声明。在使用时，应根据需要，将适当的jconfig文件的后缀名改为h。<br>&nbsp;&nbsp;&nbsp; 以上这些内容更详细的说明见JpegLib库的文档，以及<br>&nbsp;&nbsp;&nbsp; <a href="http://blog.csdn.net/axlrosek/archive/2007/03/29/1545496.aspx" target=_blank><span style="COLOR: #96b0af"><u>http://blog.csdn.net/axlrosek/archive/2007/03/29/1545496.aspx</u></span></a><br>&nbsp;&nbsp;&nbsp; VC:不同版本的VC、EVC都差不多，参照文献A的步骤修改相关文件，然后新建一个空工程，然后打开JpegLib中的makefile.vc文件,将2）和3）、5）、7）中的文件添加到工程中。将生成文件的类型定为lib就行了。此外，还需要针对调用的情况选择适当的运行时库，否则可能会出LNK2005错误。<br><br>3.使用JpegLib库<br>&nbsp;&nbsp;&nbsp; JpegLib库的使用参照文献A和B，以及example.c就可以了。但文献A的示例是有问题的。<br>&nbsp;&nbsp;&nbsp; bmpBuffer[start+i]=pBuffer[0];<br>应改为<br>&nbsp;&nbsp;&nbsp; bmpBuffer[start+i]=pBuffer[0][i];<br>&nbsp;&nbsp;&nbsp; jpeg_read_scanlines(&amp;cinfo, pBuffer, 1)执行之后，<span style="FONT-WEIGHT: bold">扫描线的内容被放到pBuffer[0]，而不是pBuffer中</span>，用memcpy将扫描线的内容转移到其他的缓冲区就行了，无需用循环语句。<br><br>4.流输入的Jpeg的处理<br>&nbsp;&nbsp;&nbsp; 上面的示例处理的都是从文件读入的Jpeg，在现实中，还存在流输入的Jpeg。在很多PC游戏中，程序的数据都被集中起来放入一个大文件之中，最典型的当属暴雪的mpq文件。当这些文件被读入内存时，就形成了字节流形式的文件。将之存为临时文件，然后再用之前的方法，显然是笨方法。这时可以采用jpeg_arr_src函数来替换jpeg_stdio_src函数。<br>&nbsp;&nbsp;&nbsp; 这一点还可以参考以下文档，不过该文针对的好像是旧版本，使用时要注意。<br>&nbsp;&nbsp;&nbsp; <a href="http://blog.china.com/u/060803/5544/200608/15355.html" target=_blank><span style="COLOR: #96b0af"><u>http://blog.china.com/u/060803/5544/200608/15355.html</u></span></a></p>
<img src ="http://www.cppblog.com/carlward/aggbug/104493.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/carlward/" target="_blank">Carlward</a> 2009-12-30 22:27 <a href="http://www.cppblog.com/carlward/articles/104493.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（转帖）C语言转义符</title><link>http://www.cppblog.com/carlward/articles/103442.html</link><dc:creator>Carlward</dc:creator><author>Carlward</author><pubDate>Fri, 18 Dec 2009 02:28:00 GMT</pubDate><guid>http://www.cppblog.com/carlward/articles/103442.html</guid><wfw:comment>http://www.cppblog.com/carlward/comments/103442.html</wfw:comment><comments>http://www.cppblog.com/carlward/articles/103442.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/carlward/comments/commentRss/103442.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/carlward/services/trackbacks/103442.html</trackback:ping><description><![CDATA[<a href="http://hi.baidu.com/firesnoby/blog/item/391cd8ef33245537acafd5bb.html">http://hi.baidu.com/firesnoby/blog/item/391cd8ef33245537acafd5bb.html</a><br><br>转义字符是C语言中表示字符的一种特殊形式。通常使用转义字符表示ASCII码字符集中不可打印的控制字符和特定功能的字符，如用于表示字符常量的单撇号 （ '），用于表示字符串常量的双撇号（ "）和反斜杠（ \）等。转义字符用反斜杠\后面跟一个字符或一个八进制或十六进制数表示。 <br><br>转义字符 意义 ASCII码值(十进制) <br>\a 响铃(BEL) 007 <br>\b 退格(BS) 008 <br>\f 换页(FF) 012 <br>\n 换行(LF) 010 <br>\r 回车(CR) 013 <br>\t 水平制表(HT) 009 <br>\v 垂直制表(VT) 011 <br>\\ 反斜杠 092 <br>\? 问号字符 063 <br>\' 单引号字符 039 <br>\" 双引号字符 034 <br>\0 空字符(NULL) 000 <br>\ddd 任意字符 三位八进制 <br>\xhh 任意字符 二位十六进制 <br><br><br>字符常量中使用单引号和反斜杠以及字符常量中使用双引号和反斜杠时，都必须使用转义字符表示，即在这些字符前加上反斜杠。 <br>在C程序中使用转义字符\ d d d或者\ x h h可以方便灵活地表示任意字符。\ d d d为斜杠后面跟三位八进制数，该三位八进制数的值即为对应的八进制A S C I I码值。\ x后面跟两位十六进制数，该两位十六进制数为对应字符的十六进制A S C I I码值。 <br><br>使用转义字符时需要注意以下问题： <br>1) 转义字符中只能使用小写字母，每个转义字符只能看作一个字符。 <br>2) \v 垂直制表和\f 换页符对屏幕没有任何影响，但会影响打印机执行响应操作。 <br>3) 在C程序中，使用不可打印字符时，通常用转义字符表示<br>
<img src ="http://www.cppblog.com/carlward/aggbug/103442.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/carlward/" target="_blank">Carlward</a> 2009-12-18 10:28 <a href="http://www.cppblog.com/carlward/articles/103442.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（转帖）vs2008 90天试用版激活</title><link>http://www.cppblog.com/carlward/articles/102205.html</link><dc:creator>Carlward</dc:creator><author>Carlward</author><pubDate>Sat, 28 Nov 2009 17:15:00 GMT</pubDate><guid>http://www.cppblog.com/carlward/articles/102205.html</guid><wfw:comment>http://www.cppblog.com/carlward/comments/102205.html</wfw:comment><comments>http://www.cppblog.com/carlward/articles/102205.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/carlward/comments/commentRss/102205.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/carlward/services/trackbacks/102205.html</trackback:ping><description><![CDATA[在&#8220;控制面板&#8221;中启动&#8220;添加删除程序&#8221;， 选中Vs2008，点击&#8220;更改、删除&#8221;， 在出现的维护模式对话框中， 选择第三个输入序列号,输入 PYHYP-WXB3B-B2CCM-V9DX9-VDY8T
<img src ="http://www.cppblog.com/carlward/aggbug/102205.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/carlward/" target="_blank">Carlward</a> 2009-11-29 01:15 <a href="http://www.cppblog.com/carlward/articles/102205.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>