[翻译]Asp.net生成高质量缩略图
原文:http://www.thebrainparasite.com/post/Creating-great-thumbnails-in-ASPNET.aspx
 
使用ASP.NET内置的功能创建缩略图是非常方便和容易实现的。
 
 int width = 190;
int width = 190;
 int height = 190;
int height = 190;
 Bitmap source = new Bitmap("c:\someimage.gif");
Bitmap source = new Bitmap("c:\someimage.gif");
 System.Drawing.Image thumb = source.GetThumbnailImage(width,height,null,IntPtr.Zero);
System.Drawing.Image thumb = source.GetThumbnailImage(width,height,null,IntPtr.Zero);
  (31.7k)
 (31.7k)
 
麻烦的是,它生产的缩略图质量相对较差且生成的文件过大。该方法生成的缩略图往往看起来非常污浊,或许很多情况下这对你所需要的来说已经足够好。
 
一个选择
 
我常用的一个方法是使用 System.Drawing.Graphics 库 重画图像,这实现起来非常简单,但是却有非常好的效果。下面是我用来生成缩略图的一个示例函数
 
 public static Bitmap CreateThumbnail(Bitmap source, int thumbWi, int thumbHi, bool maintainAspect)
public static Bitmap CreateThumbnail(Bitmap source, int thumbWi, int thumbHi, bool maintainAspect)
 {
        {
 // return the source image if it's smaller than the designated thumbnail
            // return the source image if it's smaller than the designated thumbnail
 if (source.Width < thumbWi && source.Height < thumbHi) return source;
            if (source.Width < thumbWi && source.Height < thumbHi) return source;

 System.Drawing.Bitmap ret = null;
            System.Drawing.Bitmap ret = null;
 try
            try
 {
            {
 int wi, hi;
                int wi, hi;

 wi = thumbWi;
                wi = thumbWi;
 hi = thumbHi;
                hi = thumbHi;

 if (maintainAspect)
                if (maintainAspect)
 {
                {
 // maintain the aspect ratio despite the thumbnail size parameters
                    // maintain the aspect ratio despite the thumbnail size parameters
 if (source.Width > source.Height)
                    if (source.Width > source.Height)
 {
                    {
 wi = thumbWi;
                        wi = thumbWi;
 hi = (int)(source.Height * ((decimal)thumbWi / source.Width));
                        hi = (int)(source.Height * ((decimal)thumbWi / source.Width));
 }
                    }
 else
                    else
 {
                    {
 hi = thumbHi;
                        hi = thumbHi;
 wi = (int)(source.Width * ((decimal)thumbHi / source.Height));
                        wi = (int)(source.Width * ((decimal)thumbHi / source.Height));
 }
                    }
 }
                }

 // original code that creates lousy thumbnails
                // original code that creates lousy thumbnails
 // System.Drawing.Image ret = source.GetThumbnailImage(wi,hi,null,IntPtr.Zero);
                // System.Drawing.Image ret = source.GetThumbnailImage(wi,hi,null,IntPtr.Zero);
 ret = new Bitmap(wi, hi);
                ret = new Bitmap(wi, hi);
 using (Graphics g = Graphics.FromImage(ret))
                using (Graphics g = Graphics.FromImage(ret))
 {
                {
 g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
 g.FillRectangle(Brushes.White, 0, 0, wi, hi);
                    g.FillRectangle(Brushes.White, 0, 0, wi, hi);
 g.DrawImage(source, 0, 0, wi, hi);
                    g.DrawImage(source, 0, 0, wi, hi);
 }
                }
 }
            }
 catch
            catch
 {
            {
 ret = null;
                ret = null;
 }
            }

 return ret;
            return ret;
 }
        }
 int width = 190;
int width = 190; int height = 190;
int height = 190; Bitmap source = new Bitmap("c:\someimage.gif");
Bitmap source = new Bitmap("c:\someimage.gif"); System.Drawing.Image thumb = source.GetThumbnailImage(width,height,null,IntPtr.Zero);
System.Drawing.Image thumb = source.GetThumbnailImage(width,height,null,IntPtr.Zero); (31.7k)
 (31.7k)麻烦的是,它生产的缩略图质量相对较差且生成的文件过大。该方法生成的缩略图往往看起来非常污浊,或许很多情况下这对你所需要的来说已经足够好。
一个选择
我常用的一个方法是使用 System.Drawing.Graphics 库 重画图像,这实现起来非常简单,但是却有非常好的效果。下面是我用来生成缩略图的一个示例函数
 public static Bitmap CreateThumbnail(Bitmap source, int thumbWi, int thumbHi, bool maintainAspect)
public static Bitmap CreateThumbnail(Bitmap source, int thumbWi, int thumbHi, bool maintainAspect) {
        { // return the source image if it's smaller than the designated thumbnail
            // return the source image if it's smaller than the designated thumbnail if (source.Width < thumbWi && source.Height < thumbHi) return source;
            if (source.Width < thumbWi && source.Height < thumbHi) return source;
 System.Drawing.Bitmap ret = null;
            System.Drawing.Bitmap ret = null; try
            try {
            { int wi, hi;
                int wi, hi;
 wi = thumbWi;
                wi = thumbWi; hi = thumbHi;
                hi = thumbHi;
 if (maintainAspect)
                if (maintainAspect) {
                { // maintain the aspect ratio despite the thumbnail size parameters
                    // maintain the aspect ratio despite the thumbnail size parameters if (source.Width > source.Height)
                    if (source.Width > source.Height) {
                    { wi = thumbWi;
                        wi = thumbWi; hi = (int)(source.Height * ((decimal)thumbWi / source.Width));
                        hi = (int)(source.Height * ((decimal)thumbWi / source.Width)); }
                    } else
                    else {
                    { hi = thumbHi;
                        hi = thumbHi; wi = (int)(source.Width * ((decimal)thumbHi / source.Height));
                        wi = (int)(source.Width * ((decimal)thumbHi / source.Height)); }
                    } }
                }
 // original code that creates lousy thumbnails
                // original code that creates lousy thumbnails // System.Drawing.Image ret = source.GetThumbnailImage(wi,hi,null,IntPtr.Zero);
                // System.Drawing.Image ret = source.GetThumbnailImage(wi,hi,null,IntPtr.Zero); ret = new Bitmap(wi, hi);
                ret = new Bitmap(wi, hi); using (Graphics g = Graphics.FromImage(ret))
                using (Graphics g = Graphics.FromImage(ret)) {
                { g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.FillRectangle(Brushes.White, 0, 0, wi, hi);
                    g.FillRectangle(Brushes.White, 0, 0, wi, hi); g.DrawImage(source, 0, 0, wi, hi);
                    g.DrawImage(source, 0, 0, wi, hi); }
                } }
            } catch
            catch {
            { ret = null;
                ret = null; }
            }
 return ret;
            return ret; }
        } (10.5k)
 (10.5k)
 
 这个函数是很方便的,因为的它的一个参数用来标识是否维在生成缩略图的时候维持图像的长宽比。这个缩略图魔法发生在下面的代码中
 
 using (Graphics g = Graphics.FromImage(ret))
                using (Graphics g = Graphics.FromImage(ret)) {
                { g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.FillRectangle(Brushes.White, 0, 0, wi, hi);
                    g.FillRectangle(Brushes.White, 0, 0, wi, hi); g.DrawImage(source, 0, 0, wi, hi);
                    g.DrawImage(source, 0, 0, wi, hi); }
                }
这个方法有点慢但是却让人难以舍弃,从下面的插图的对比可见:
我想说这是文件和图像质量都非常棒的实现,但是……
我们可以做的更好
现在我门可以混入 JPEG压缩来真正的优化结果, 我不想假装完全了解JPEG压缩的代码如何工作的,但它确实扭转了乾坤。
 
 //Configure JPEG Compression Engine
                //Configure JPEG Compression Engine System.Drawing.Imaging.EncoderParameters encoderParams = new System.Drawing.Imaging.EncoderParameters();
                System.Drawing.Imaging.EncoderParameters encoderParams = new System.Drawing.Imaging.EncoderParameters(); long[] quality = new long[1];
                long[] quality = new long[1]; quality[0] = 75;
                quality[0] = 75; System.Drawing.Imaging.EncoderParameter encoderParam = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
                System.Drawing.Imaging.EncoderParameter encoderParam = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality); encoderParams.Param[0] = encoderParam;
                encoderParams.Param[0] = encoderParam;
 System.Drawing.Imaging.ImageCodecInfo[] arrayICI = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders();
                System.Drawing.Imaging.ImageCodecInfo[] arrayICI = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); System.Drawing.Imaging.ImageCodecInfo jpegICI = null;
                System.Drawing.Imaging.ImageCodecInfo jpegICI = null; for (int x = 0; x < arrayICI.Length; x++)
                for (int x = 0; x < arrayICI.Length; x++) {
                { if (arrayICI[x].FormatDescription.Equals("JPEG"))
                    if (arrayICI[x].FormatDescription.Equals("JPEG")) {
                    { jpegICI = arrayICI[x];
                        jpegICI = arrayICI[x]; break;
                        break; }
                    } }
                }
 这段代码设置了保存经过压缩的缩略图所需的 encoderParameters 参数,quality[0] 的值设定压缩的级别,我曾经针对某些应用设置像40这么低的值也成功了,俺是当质量要求比较高的时候 ,我发现设置为75非常好。使用这段代码你能够在生成缩略图之前使用 JPEG 压缩算法,当保存的时候把 encoderParamaters 作为参数,例如:
 
 System.Drawing.Image myThumbnail = CreateThumbnail(myBitmap,Width,Height,false);
    System.Drawing.Image myThumbnail = CreateThumbnail(myBitmap,Width,Height,false);                
 //Configure JPEG Compression Engine
    //Configure JPEG Compression Engine System.Drawing.Imaging.EncoderParameters encoderParams = new System.Drawing.Imaging.EncoderParameters();
                System.Drawing.Imaging.EncoderParameters encoderParams = new System.Drawing.Imaging.EncoderParameters(); long[] quality = new long[1];
                long[] quality = new long[1]; quality[0] = 75;
                quality[0] = 75; System.Drawing.Imaging.EncoderParameter encoderParam = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
                System.Drawing.Imaging.EncoderParameter encoderParam = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality); encoderParams.Param[0] = encoderParam;
                encoderParams.Param[0] = encoderParam;
 System.Drawing.Imaging.ImageCodecInfo[] arrayICI = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders();
                System.Drawing.Imaging.ImageCodecInfo[] arrayICI = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); System.Drawing.Imaging.ImageCodecInfo jpegICI = null;
                System.Drawing.Imaging.ImageCodecInfo jpegICI = null; for (int x = 0; x < arrayICI.Length; x++)
                for (int x = 0; x < arrayICI.Length; x++) {
                { if (arrayICI[x].FormatDescription.Equals("JPEG"))
                    if (arrayICI[x].FormatDescription.Equals("JPEG")) {
                    { jpegICI = arrayICI[x];
                        jpegICI = arrayICI[x]; break;
                        break; }
                    } }
                } 
     myThumbnail.Save(Path.Combine(SavePathThumb, fileName), jpegICI, encoderParams);
    myThumbnail.Save(Path.Combine(SavePathThumb, fileName), jpegICI, encoderParams); myThumbnail.Dispose();
                myThumbnail.Dispose();
  (2.39k)
 (2.39k)
 
 2.39K 大小 看起来依然很棒
 
 结论和最后比较
 
 这是最后三张缩略图从文件大小最大到最小的效果对比
 
最大 = 31.7k
未压缩重绘 = 10.5k (67% smaller)
压缩重绘 = 2.39k (92% smaller)
难以舍弃的结果啊,缩略图生成函数和JPEG压缩的源代码 在下边 :
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号