<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mingbo &#187; 图片压缩</title>
	<atom:link href="http://shao.mingbo.de/tag/%e5%9b%be%e7%89%87%e5%8e%8b%e7%bc%a9/feed/" rel="self" type="application/rss+xml" />
	<link>http://shao.mingbo.de</link>
	<description>包括教育技术，编程，互联网等方面的文章及随想。</description>
	<lastBuildDate>Thu, 26 Aug 2010 02:57:15 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=abc</generator>
		<item>
		<title>六十岁的中国，二十岁的我(2)</title>
		<link>http://shao.mingbo.de/2009/10/10/ipv6-web-auto-adaptation/</link>
		<comments>http://shao.mingbo.de/2009/10/10/ipv6-web-auto-adaptation/#comments</comments>
		<pubDate>Sat, 10 Oct 2009 07:49:34 +0000</pubDate>
		<dc:creator>邵 明博</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[教育技术学]]></category>
		<category><![CDATA[ipv6]]></category>
		<category><![CDATA[图片压缩]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[网页自适应]]></category>
		<category><![CDATA[视频压缩]]></category>

		<guid isPermaLink="false">http://shao.mingbo.de/?p=110</guid>
		<description><![CDATA[这个假期的大部分时间，主要还是宅code。正如上次提到的，我的具体任务是：研制现有资源向移动学习终端系统显示模式的资源转换工具，以及相关的全套技术文档。接单之后，任务很自然的被我分解为：视频、图片和html三个处理模块。（移动学习终端方面，是用的TCL的IOpen来做测试的）。截止至7号凌晨5点16分，整个任务的基本功能全部实现。 图片处理这块，毫无疑问的，我是走了一大圈弯路。 不敢说自己是一个java程序员，但让一个学习了java的人转过头来搞c#，这无疑会带着很复杂的感情。正如Jesse在他的著作里谈的那样： Java programmers may look at C# with a mixture of trepidation, glee, and resentment. It has been suggested that C# is somehow a &#8220;rip-off&#8221; of Java. I won&#8217;t comment on the religious war between Microsoft and the &#8220;anyone but Microsoft&#8221; crowd, except to acknowledge that C# certainly learned a great deal from [...]]]></description>
			<content:encoded><![CDATA[<p>这个假期的大部分时间，主要还是宅code。正如上次提到的，我的具体任务是：<strong>研制现有资源向移动学习终端系统显示模式的资源转换工具，以及相关的全套技术文档</strong>。接单之后，任务很自然的被我分解为：视频、图片和html三个处理模块。（移动学习终端方面，是用的TCL的<a href="http://cn.engadget.com/2008/09/12/tcls-iopen-081a-no-lipstick-on-this-pig/" target="_blank">IOpen</a>来做测试的）。截止至7号凌晨5点16分，整个任务的基本功能全部实现。</p>
<p>图片处理这块，毫无疑问的，我是走了一大圈弯路。 不敢说自己是一个java程序员，但让一个学习了java的人转过头来搞c#，这无疑会带着很复杂的感情。正如Jesse在他的著作里谈的那样：</p>
<blockquote><p>Java programmers may look at C# with a mixture of trepidation, glee, and resentment. It has been suggested that C# is somehow a &#8220;rip-off&#8221; of Java. I won&#8217;t comment on the religious war between Microsoft and the &#8220;anyone but Microsoft&#8221; crowd, except to acknowledge that C# certainly learned a great deal from Java. But then Java learned a great deal from C++, which owed its syntax to C, which in turn was built on lessons learned in other languages. We all stand on the shoulders of giants.</p></blockquote>
<p>不管怎么说，凭着自己的那一点小个性，还是会想在java上小冲一把。当天接到的任务，无视老刘给出的要求，晚上就直接开始编写有关图片压缩的代码。并且，很快的取得了成效：（以下为java批量压缩图片的核心代码）</p>
<p>package imageCompress;<br />
import java.util.*;<br />
import java.io.*;<br />
import java.awt.*;<br />
import java.awt.image.BufferedImage;<br />
import com.sun.image.codec.jpeg.JPEGCodec;<br />
import com.sun.image.codec.jpeg.JPEGImageEncoder;</p>
<p>public class doCompress {</p>
<p>	private static String path;</p>
<p>	//获取压缩比例<br />
	public float getRatio(int width, int height, int maxWidth , int maxHeight)<br />
	{<br />
		float ratio=0;</p>
<p>		float widthR=(float)maxWidth/width;<br />
		float heightR=(float)maxHeight/height;</p>
<p>		if(widthR<1.0||heightR<1.0)<br />
		{<br />
			ratio=(widthR<=heightR?widthR:heightR);<br />
		}<br />
		return ratio;<br />
	}</p>
<p>	public void imgCompress(String path,String maxW, String maxH)<br />
	{<br />
		try {<br />
			imageSource iSource=new imageSource(path);<br />
			String[] imgNames=iSource.getImageNames();</p>
<p>			for(int i=0;i<imgNames.length;i++)<br title="六十岁的中国，二十岁的我(2)" alt=" 六十岁的中国，二十岁的我(2)" />
			{<br />
				Image img=javax.imageio.ImageIO.read(new File(path+"/PIC/"+imgNames[i]));;<br />
				int imgWidth=img.getWidth(null);<br />
				int imgHeight=img.getHeight(null);<br />
				float r=this.getRatio(imgWidth, imgHeight, Integer.parseInt(maxW), Integer.parseInt(maxH));</p>
<p>				imgWidth=(int)(imgWidth*r);<br />
				imgHeight=(int)(imgHeight*r);</p>
<p>				BufferedImage bimg=new BufferedImage(imgWidth,imgHeight,BufferedImage.TYPE_INT_RGB);</p>
<p>				Graphics2D g2=bimg.createGraphics();<br />
				g2.drawImage(img, 0, 0, imgWidth, imgHeight, Color.WHITE, null);<br />
				g2.dispose();</p>
<p>				FileOutputStream outputStream=new FileOutputStream(path+"/PIC/"+imgNames[i]);<br />
				JPEGImageEncoder encoder=JPEGCodec.createJPEGEncoder(outputStream);<br />
				encoder.encode(bimg);<br />
				outputStream.close();<br />
			}</p>
<p>		} catch (Exception e) {<br />
			// TODO: handle exception<br />
			e.printStackTrace();<br />
		}<br />
	}<br />
}</p>
<p>
用java写完图片模块之后，等到我再接触视频模块时才发现，如果弃用WMEncoder提供的Interface（全微软接口），几乎是不能完成任务的。原因在每一次对视频进行ReEncode的时候，视频中存在的header file全部会丢失，导致三分屏课件没有办法让视频与ppt同步，而脚本也无法对视频进行点播控制。百般无奈的开始研究<a title="wmencoder" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=5691ba02-e496-465a-bba9-b2f1182cdf24&amp;displaylang=en" target="_blank">WMEncoder</a>提供的<a href="http://www.microsoft.com/downloads/details.aspx?familyid=ACDDAAE1-93A9-4DD5-AAA2-5FB28C3BA43A&amp;displaylang=zh-cn" target="_blank">SDK</a>，开始基础的c#学习。</p>
<p><a href="http://shao.mingbo.de/wp-content/uploads/2009/10/encoder-struct.jpg"><img class="alignright size-thumbnail wp-image-112" title="encoder-struct" src="http://shao.mingbo.de/wp-content/uploads/2009/10/encoder-struct-150x150.jpg" alt="encoder struct 150x150 六十岁的中国，二十岁的我(2)" width="150" height="150" /></a>好在c#和java貌似同父异母的兄弟，语法套路很类似，再加上强大Visual Studio，用了不到3个小时，就可以上手了。呃，废话不多说，在这里想对视频压缩处理的相关核心部分做一下总结。首先是SDK，图中红线标出的即为需要用到的接口对象（点击可以查看大图）。其实对于视频操作的难点在于header file的处理。之前使用java的解决方案，我采用了一款名叫<a href="http://ffmpeg.org/documentation.html" target="_blank">ffmpeg</a>的视频开源项目代码。但处理后的视频没有办法再导入header，以至于让我的整个工作停滞了好几天。学习了sdk后，才发现WMEncBasicEdit Interface就能够较好的处理这一块的工作：</p>
<blockquote><p>The <strong>WMEncBasicEdit</strong> interface provids an Automation interface that  allows you to perform postprocessing on a Windows Media file, such as modifying  the attributes, specifying mark-in and mark-out times to change the length of  the file, adding scripts and markers, and indexing the file so that users can  use seek functions. An XML configuration file can be used to save and load  certain settings.</p></blockquote>
<p>不过，这里不得不谈到接口中的一个BUG。对于config的处理，如果视频文件过长，indexing的数目过多，则无法正常的导入header file.微软自己推出的解决方案中（Encoder Utilities-Windows Media File Editor）直接删除了最后的2个indexing.对于MS封装整个接口的做法，我是深表遗憾的。哎，下面是视频操作的核心代码：</p>
<p>using System;<br />
using System.Collections.Generic;<br />
using System.Text;<br />
using WMEncoderLib;<br />
using System.Windows.Forms;<br />
using System.IO;</p>
<p>namespace webAutoFinal<br />
{<br />
    class doVideoCompress<br />
    {</p>
<p>        public void getVideoConfige(string sourceUrl)<br />
        {<br />
            // bool flag;</p>
<p>            string vPath = sourceUrl + &#8220;\\stream.wmv&#8221;;<br />
            string cPath = sourceUrl + &#8220;\\config.xml&#8221;;<br />
            try<br />
            {<br />
                //创建后期编辑器<br />
                WMEncBasicEdit BasicEdit;<br />
                BasicEdit = new WMEncBasicEdit();</p>
<p>                //设定输入视频<br />
                BasicEdit.MediaFile = vPath;<br />
                BasicEdit.SaveConfigFile(cPath);<br />
                BasicEdit.Start();</p>
<p>            }<br />
            catch (Exception e)<br />
            {<br />
                // Console.WriteLine(e.StackTrace);<br />
                MessageBox.Show(&#8221;  public  void getVideoConfige(string sourceUrl) method has something wrong!(视频文件没找到)&#8221; + e.Message);<br />
            }</p>
<p>        }</p>
<p>        public bool compressVideo(string sourceUrl, string vParam)<br />
        {<br />
            string vPath = sourceUrl + @&#8221;\stream.wmv&#8221;;<br />
            string vPath2 = sourceUrl + @&#8221;\ostream.wmv&#8221;;<br />
            bool flag = false;</p>
<p>            try<br />
            {<br />
                //新建一个编码器<br />
                WMEncoder encoder = new WMEncoder();</p>
<p>                IWMEncSourceGroupCollection srcGroupCollection = encoder.SourceGroupCollection;<br />
                IWMEncSourceGroup srcGroup = srcGroupCollection.Add(&#8220;SG_1&#8243;);</p>
<p>                //输入选项<br />
                //添加音频源<br />
                IWMEncSource srcAudio = srcGroup.AddSource(WMENC_SOURCE_TYPE.WMENC_AUDIO);<br />
                //添加视频源<br />
                IWMEncVideoSource2 srcVideo = (IWMEncVideoSource2)srcGroup.AddSource(WMENC_SOURCE_TYPE.WMENC_VIDEO);<br />
                srcAudio.SetInput(vPath, &#8220;&#8221;, &#8220;&#8221;);<br />
                srcVideo.SetInput(vPath, &#8220;&#8221;, &#8220;&#8221;);</p>
<p>                //输出选项<br />
                IWMEncFile file = encoder.File;<br />
                file.LocalFileName = vPath2;</p>
<p>                IWMEncProfileCollection ProColl = encoder.ProfileCollection;<br />
                IWMEncProfile Pro;<br />
                for (int i = 0; i < ProColl.Count; i++)<br />
                {<br />
                    Pro = ProColl.Item(i);<br />
                    if (Pro.Name == vParam)<br />
                    {<br />
                        srcGroup.set_Profile(Pro);<br />
                        break;<br />
                    }<br />
                }</p>
<p>                //开始压缩<br />
                encoder.PrepareToEncode(true);<br />
                encoder.Start();</p>
<p>                WMENC_ENCODER_STATE iEncoderState; //定义encoder的运行状态<br />
                iEncoderState = encoder.RunState;</p>
<p>                IWMEncStatistics Stats;  //定义 统计对象<br />
                decimal lEncTime;       //定义 已编码的时长</p>
<p>                //获取视频源的时长<br />
                int lVidDuration = srcVideo.Duration / 1000;</p>
<p>                //    Console.WriteLine("****** Now ,Video-Compression Session Working ******");<br />
                while (iEncoderState != WMENC_ENCODER_STATE.WMENC_ENCODER_STOPPED)<br />
                {<br />
                    //获得当前encoder的运行状态<br />
                    iEncoderState = encoder.RunState;<br />
                    // 获得encoder的统计对象<br />
                    Stats = encoder.Statistics;<br />
                    // 获得当前已编码的市场<br />
                    lEncTime = Stats.EncodingTime * 10;</p>
<p>                    //  MessageBox.Show("Encoder starts..");<br />
                    //  Console.Write("Encoder Status: {0} % of the video has benn encodered.", Math.Round(lEncTime / lVidDuration * 100, 0));</p>
<p>                    //   System.Threading.Thread.Sleep(100);<br />
                    if ((Math.Round(lEncTime / lVidDuration * 100)) == 100)<br />
                    {<br />
                        flag = true;<br />
                        break;<br />
                    }<br />
                    // encoder.AutoStop = true;</p>
<p>                }</p>
<p>                //释放编码器内存<br />
                encoder.Stop();<br />
                while (encoder.RunState != WMENC_ENCODER_STATE.WMENC_ENCODER_STOPPED)<br />
                {<br />
                    System.Threading.Thread.Sleep(1000);<br />
                }<br />
                encoder.Reset();<br />
                encoder = null;<br />
                return flag;<br />
            }</p>
<p>            catch (Exception e)<br />
            {<br />
                //System.Console.Write(e.StackTrace);<br />
                MessageBox.Show("public bool compressVideo(string sourceUrl, string vParam) method has something wrong!\n" + e.Message);<br />
                return false;<br />
            }</p>
<p>        }</p>
<p>        public void loadVideoConfig(string sourceUrl)<br />
        {<br />
            string vPath = sourceUrl + "\\ostream.wmv";<br />
            string oPath = sourceUrl + "\\stream.wmv";<br />
            string cPath = sourceUrl + "\\config.xml";</p>
<p>            //bool flag = false;<br />
            if (System.IO.File.Exists(vPath)  &#038;&#038; System.IO.File.Exists(cPath))<br />
            {<br />
                try<br />
                {</p>
<p>                    // Create the WMEncBasicEdit object.<br />
                    WMEncBasicEdit BasicEdit;<br />
                    BasicEdit = new WMEncBasicEdit();<br />
                    BasicEdit.MediaFile = vPath;<br />
                    BasicEdit.OutputFile = oPath;<br />
                    BasicEdit.ConfigFile = cPath;</p>
<p>                    // Start the basic edit process.<br />
                    BasicEdit.Start();</p>
<p>                }<br />
                catch (Exception e)<br />
                {<br />
                    // Console.WriteLine(e.StackTrace);<br />
                    MessageBox.Show(" public void loadVideoConfig(string sourceUrl) method has something wrong!" + e.Message);<br />
                }<br />
            }<br />
            else<br />
                MessageBox.Show("some path can not find");<br />
        }</p>
<p>    }<br />
}</p>
<p>至于图片处理模块，我也用c#重写了两份批量压缩的代码。这一次的压缩不仅可以对分辨率控制，还可以对jpg压缩质量进行控制。核心代码如下：</p>
<p>using System;<br />
using System.Collections.Generic;<br />
using System.Text;<br />
using System.IO;<br />
using System.Drawing;<br />
using System.Windows.Forms;<br />
using System.Drawing.Imaging;</p>
<p>namespace webAutoFinal<br />
{<br />
    class doImageCompress<br />
    {<br />
        //获取资源包中所有图片的URL<br />
       public string[] loadDir(string fileFoldUrl)<br />
        {<br />
            string bg = fileFoldUrl + @"\skin\background.jpg";<br />
            fileFoldUrl += @"\pic\";</p>
<p>            if (System.IO.File.Exists(bg))<br />
                System.IO.File.Copy(bg, fileFoldUrl + @"\background.jpg",true);<br />
            string[] pics = null;<br />
            try<br />
            {<br />
                pics = Directory.GetFiles(fileFoldUrl, "*.jpg");<br />
            }<br />
            catch (Exception e)//未找到图片文件夹给出异常<br />
            {<br />
              //  Console.WriteLine("The source directory has something wrong!");<br />
              //  Console.WriteLine(e.StackTrace);<br />
                MessageBox.Show("doImageCompress.loadDir() Method got something wrong:"+e.Message);<br />
            }<br />
           // pics[pics.Length] = fileFoldUrl + @"\skin\background.jpg";</p>
<p>            return pics;<br />
        }</p>
<p>        //将单个图片文件转换成byte<br />
       public byte[] loadPicture(String filePath)<br />
        {<br />
            byte[] picData = null;<br />
            FileInfo fi = new FileInfo(filePath);</p>
<p>            if (fi.Exists)<br />
            {<br />
                picData = new byte[fi.Length];<br />
                FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite);<br />
                BinaryReader br = new BinaryReader(fs);<br />
                br.Read(picData, 0, Convert.ToInt32(fi.Length));<br />
                fs.Dispose();<br />
            }<br />
            else<br />
            {<br />
               // Console.WriteLine("can not find the picture!");<br />
                MessageBox.Show("doImageCompress.loadPicture() Method got something wrong: can not find the picture!");<br />
            }<br />
            return picData;<br />
        }</p>
<p>        //图片压缩<br />
       public void compressPicuture(string filePath, int width, int height)<br />
        {<br />
            try<br />
            {<br />
                byte[] picByte = this.loadPicture(filePath);<br />
                MemoryStream ms = new MemoryStream(picByte);<br />
                System.Drawing.Image img = System.Drawing.Image.FromStream(ms);<br />
                Bitmap bmp = new Bitmap(img, width, height);<br />
                bmp.Save(filePath);<br />
            }<br />
            catch (Exception e)<br />
            {<br />
                Console.WriteLine(e.StackTrace);<br />
            }<br />
        }</p>
<p>        //新压缩方法</p>
<p>        private ImageCodecInfo GetEncoder(string mimeType)<br />
{</p>
<p>    ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();</p>
<p>    foreach (ImageCodecInfo codec in codecs)<br />
    {<br />
        if (codec.MimeType == mimeType)<br />
        {<br />
            return codec;<br />
        }<br />
    }<br />
    return null;<br />
}</p>
<p>        //设置压缩级别   0--100L<br />
        public void jpgLevel(Bitmap bmp, string fileName)<br />
        {</p>
<p>            EncoderParameters ps = new EncoderParameters(1);<br />
            EncoderParameter p = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality,100L);<br />
            ps.Param[0] = p;<br />
            bmp.Save(fileName, this.GetEncoder("image/jpeg"), ps);</p>
<p>        }<br />
        //设置分辨率<br />
        public void doCompressNEW(string fileName,int width,int height)<br />
        {<br />
           // Image img = Image.FromFile(fileName);<br />
            byte[] picByte = this.loadPicture(fileName);<br />
            MemoryStream ms = new MemoryStream(picByte);<br />
            System.Drawing.Image img = System.Drawing.Image.FromStream(ms);<br />
            Bitmap bmp = new Bitmap(img, width, height);<br />
            jpgLevel(bmp,fileName);<br />
            GC.Collect();<br />
           // bmp.Dispose();<br />
        }<br />
    }<br />
}</p>
<p>其实，整个程序到这里基本上完成了，整体做下来还是比较有成就感的。接下来的工作，应该是对批量处理资源包的功能进行扩充，以及相关技术文档的整理了。<br />
<a href="http://shao.mingbo.de/wp-content/uploads/2009/10/webAutoFace.jpg"><img class="aligncenter size-full wp-image-124" title="教育资源转换工具" src="http://shao.mingbo.de/wp-content/uploads/2009/10/webAutoFace.jpg" alt="教育资源转换工具" width="558" height="243" /></a></p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2010年02月26日 -- <a href="http://shao.mingbo.de/2010/02/26/proxy-server-with-web-cache-and-http/" title="超文本转移协议与万维网高速缓存">超文本转移协议与万维网高速缓存</a></li><li>2009年10月18日 -- <a href="http://shao.mingbo.de/2009/10/18/wmencoder-batch-function-completed/" title="WMEncoder批处理功能实现">WMEncoder批处理功能实现</a></li><li>2009年09月28日 -- <a href="http://shao.mingbo.de/2009/09/28/why-not-the-same-as-others/" title="为什么我和别人不一样">为什么我和别人不一样</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://shao.mingbo.de/2009/10/10/ipv6-web-auto-adaptation/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
