小程序建议图片大小限制在200kb以内,故而需要将图片的大小无损压缩到200kb以内。

用C#写了下代码实现图片的压缩(你可以设置需要压缩的图片的大小)

 1. 前端代码 Index.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="WebApplication5.Index" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <table>
                <tr>
                    <td>原始图片:</td>
                    <td>
                        <asp:Image ID="Image1" runat="server" />
                    </td>
                </tr>
                <tr>
                    <td>压缩图片:</td>
                    <td>
                        <asp:Image ID="Image2" runat="server" />
                    </td>
                </tr>
            </table>
        </div>
        
    </form>
</body>
</html>

2. 后端代码 Index.aspx.cs

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace WebApplication5
{
    public partial class Index : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                string sourceFileName = "details_01.png";
                Image1.ImageUrl = sourceFileName;
                string sourcePath = Server.MapPath("~/") + sourceFileName;//图片原路径
                //获取后缀
                string extname = Path.GetExtension(sourcePath);//获取文件的拓展名称
                string newFileName = Guid.NewGuid().ToString().Substring(0, 6) + extname;
                string newPath = Server.MapPath("~/") + newFileName;

                CompressImage(sourcePath, newPath);

                Image2.ImageUrl = newFileName;
            }
        }

        /// <summary>
        /// 无损压缩图片(默认为 不超过200kb)
        /// </summary>
        /// <param name="sourceFile">原图片地址</param>
        /// <param name="newFile">压缩后保存图片地址</param>
        /// <param name="size">压缩后图片的最大大小 默认为 不超过200kb</param>
        /// <returns></returns>
        public void CompressImage(string sourceFile, string newFile, int size = 200)
        {
            //设置大小偏差幅度 1kb
            const long nearlyLen = 1024;

            //如果是第一次调用,原始图像的大小小于要压缩的大小,则直接复制文件,并且返回true
            FileInfo firstFileInfo = new FileInfo(sourceFile);
            long sourceLen = firstFileInfo.Length; //原始大小
            long targetLen = size * 1024; //压缩后大小
            if (sourceLen <= targetLen)
            {
                firstFileInfo.CopyTo(newFile);
            }
            else
            {
                //获取目标大小最低值
                var exitLen = targetLen - nearlyLen;

                using (System.Drawing.Image iSource = System.Drawing.Image.FromFile(sourceFile))
                {
                    ImageFormat sourceFormat = iSource.RawFormat; //图片格式
                    int sourceHeight = iSource.Height;
                    int sourceWidth = iSource.Width;
                    int sW = 0, sH = 0;
                    //按比例缩放
                    Size tem_size = new Size(sourceWidth, sourceHeight);
                    if (tem_size.Width > sourceHeight || tem_size.Width > sourceWidth)
                    {
                        if ((tem_size.Width * sourceHeight) > (tem_size.Width * sourceWidth))
                        {
                            sW = sourceWidth; sH = (sourceWidth * tem_size.Height) / tem_size.Width;
                        }
                        else
                        {
                            sH = sourceHeight;
                            sW = (tem_size.Width * sourceHeight) / tem_size.Height;
                        }
                    }
                    else
                    {
                        sW = tem_size.Width;
                        sH = tem_size.Height;
                    }
                    using (Bitmap ob = new Bitmap(sourceWidth, sourceHeight))
                    {
                        using (Graphics g = Graphics.FromImage(ob))
                        {
                            g.Clear(Color.WhiteSmoke);
                            g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                            g.DrawImage(iSource, new Rectangle((sourceWidth - sW) / 2, (sourceHeight - sH) / 2, sW, sH), 0, 0, iSource.Width, iSource.Height, GraphicsUnit.Pixel);
                        }
                        
                        //获取编码器信息
                        var format = ImageFormat.Jpeg;
                        ImageCodecInfo formatInfo = GetEncoder(format);
                        if (formatInfo != null)
                        {
                            //以下代码为保存图片时,设置压缩质量
                            var parms = new EncoderParameters(1);
                            //初始化质量压缩参数 压缩质量(数字越小压缩率越高)1-100
                            var quality = (long)Math.Floor(100.00 * targetLen / sourceLen);

                            //使用二分法进行查找 最接近的质量参数
                            long startQuality = quality;
                            long endQuality = 100;

                            using (var ms = new MemoryStream())
                            {
                                while (true)
                                {
                                    parms.Param[0] = new EncoderParameter(Encoder.Quality, quality);

                                    ms.SetLength(0);
                                    ms.Position = 0;
                                    ob.Save(ms, formatInfo, parms);

                                    long newImageLen = ms.Length;
                                    //若压缩后大小低于目标大小,则满足条件退出
                                    if (newImageLen >= exitLen && newImageLen <= targetLen)
                                    {
                                        break;
                                    }
                                    else
                                    {
                                        //区间相等无需再次计算
                                        if (startQuality >= endQuality)
                                        {
                                            break;
                                        }
                                        else
                                        {
                                            if (newImageLen < exitLen) //压缩过小,起始质量右移
                                            {
                                                startQuality = quality;
                                            }
                                            else //压缩过大 终止质量左移
                                            {
                                                endQuality = quality;
                                            }

                                            //重新设置质量参数 如果计算出来的质量没有发生变化,则终止查找。这样是为了避免重复计算情况{start:16,end:18} 和 {start:16,endQuality:17}
                                            long newQuality = (startQuality + endQuality) / 2;
                                            if (newQuality == quality)
                                            {
                                                break;
                                            }
                                            else
                                            {
                                                quality = newQuality;
                                            }
                                        }
                                    }
                                }
                            }
                            ob.Save(newFile, formatInfo, parms);//dFile是压缩后的新路径
                        }
                        else
                        {
                            ob.Save(newFile, sourceFormat);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 获取编码器信息
        /// </summary>
        /// <param name="format"></param>
        /// <returns></returns>
        private ImageCodecInfo GetEncoder(ImageFormat format)
        {
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
            foreach (ImageCodecInfo codec in codecs)
            {
                if (codec.FormatID == format.Guid)
                {
                    return codec;
                }
            }
            return null;
        }
    }
}

运行项目既可以看到压缩后的图片。

代码经过运行测试。

posted on 2024-09-19 15:29  £冷☆月№  阅读(45)  评论(0编辑  收藏  举报