C#实现图片按比例缩放与裁剪:自定义ImgHelper类详解

季宁
季宁
发布时间:2026-10-14| 6人浏览过
原创

在C#开发中,处理图片缩略图常需兼顾尺寸限制与原图比例。本文介绍一种基于 System.Drawing 的实现方案:通过 ImgHelper 类自动计算最佳截取区域,确保输出图片在指定宽高中完全显示且不变形,同时利用高质量渲染和JPEG压缩平衡画质与文件大小。

核心逻辑与算法思路

图片缩放的核心挑战在于如何在固定大小的画布(toWidth × toHeight)内完整展示原图。直接拉伸会导致图像变形,因此需要遵循以下逻辑:

  1. 原始适配检测:若原图尺寸小于目标尺寸,通常直接保存原图或居中放置,避免放大导致模糊。
  2. 比例计算:根据原图的宽高比,判断应以宽度还是高度为基准进行等比缩放。
  3. 区域裁剪与定位:计算出实际绘制的源矩形区域(x, y, w, h),确保在目标框内居中且无黑边或留白(除非特意设计留白)。

第1步:准备环境与支持库

首先需要引入 System.Drawing 命名空间及其相关子命名空间,这是 .NET Framework 中进行图像处理的基础。

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;

第2步:定义智能缩放主方法

AdjustPhoto 是核心处理方法,负责加载、处理并保存最终图片。该方法接收目标宽高等参数,内部通过复杂的条件判断确定最终绘制区域。

public static void AdjustPhoto(int toWidth, int toHeight, string filePath, string fromFileName, string toFileName, int maxWidth, int maxHeight)
{
    // 1. 加载原图
    Image originalImage = Image.FromFile(filePath + "/" + fromFileName);
    
    // 2. 简单情况:原图比目标小,直接保存原图,无需缩放
    if (originalImage.Width < toWidth && originalImage.Height < toHeight)
    {
        originalImage.Save(filePath + "/" + toFileName);
        originalImage.Dispose();
        return;
    }

    // 3. 复杂计算:确定截取区域的 x, y, w, h
    // ... (此处省略详细分支计算逻辑,见下方代码块) ...
}

第3步:实现比例自适应与居中算法

在 AdjustPhoto 的主体逻辑中,我们需要根据原图与目标容器的关系,决定如何“挤”入这个容器。以下是关键的比例计算部分:

  • 双方向限制模式:当 toWidth 和 toHeight 均有效时,优先满足宽度,若计算出的高度超过限制,则转而以高度为基准重新计算宽度,保证图片完全在框内。
  • 单方向限制模式:仅限制宽度或高度时,另一侧自由按比例伸缩。
// 根据图片大小获取新图片从原图片截取的区域
int x, y, w, h;
if (toHeight > 0)
{
    if (toWidth > 0)
    {
        // 同时有宽高限制
        if (originalImage.Width > toWidth && originalImage.Height > toHeight)
        {
            w = toWidth;
            h = toWidth * originalImage.Height / originalImage.Width;
            
            // 如果计算后的高度超出限制,则切换基准为高度
            if (h > toHeight)
            {
                h = toHeight;
                w = toHeight * originalImage.Width / originalImage.Height;
                x = (toWidth - w) / 2; // 水平居中
                y = 0;
            }
            else
            {
                x = 0;
                y = (toHeight - h) / 2; // 垂直居中
            }
        }
        // ... 其他分支处理仅超出一边的情况 ...
    }
    // ... 处理仅高度限制的情况 ...
}
// ... 处理仅宽度限制的情况 ...

// 创建目标Bitmap
Bitmap bm = new Bitmap(toWidth, toHeight);
Graphics g = Graphics.FromImage(bm);

// 设置高质量渲染模式
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.Clear(Color.White); // 清除背景,防止透明图层变黑

// 绘制图片:将原图的一部分(x,y,w,h)映射到整个Bitmap(0,0,toWidth,toHeight)
g.DrawImage(originalImage, new Rectangle(x, y, w, h), 0, 0, originalImage.Width, originalImage.Height, GraphicsUnit.Pixel);

第4步:应用JPEG压缩与保存

为了减小文件体积,保存时需指定 JPEG 编码器及质量参数(如80分)。

long[] quality = new long[1];
quality[0] = 80; // 设置JPEG质量为80%

EncoderParameters encoderParams = new EncoderParameters();
EncoderParameter encoderParam = new EncoderParameter(Encoder.Quality, quality);
encoderParams.Param[0] = encoderParam;

// 获取JPEG编码器信息
ImageCodecInfo jpegICI = null;
foreach (ImageCodecInfo ici in ImageCodecInfo.GetImageEncoders())
{
    if (ici.FormatDescription.Equals("JPEG"))
    {
        jpegICI = ici;
        break;
    }
}

if (jpegICI != null)
{
    bm.Save(filePath + "/" + toFileName, jpegICI, encoderParams);
}

// 释放资源
bm.Dispose();
originalImage.Dispose();
g.Dispose();

简易尺寸计算辅助方法

如果你只需要知道缩放后的宽高数值,而不需要执行绘图操作,可以使用 AdjustSize 方法。它返回一个包含宽高的字典,逻辑更直观:

public static Dictionary<string, int> AdjustSize(int spcWidth, int spcHeight, int orgWidth, int orgHeight)
{
    Dictionary<string, int> size = new Dictionary<string, int>;
    // 原图小于等于目标,不处理
    if (orgWidth <= spcWidth && orgHeight <= spcHeight)
    {
        size["Width"] = orgWidth;
        size["Height"] = orgHeight;
    }
    else
    {
        float wRatio = orgWidth / (float)spcWidth;
        float hRatio = orgHeight / (float)spcHeight;
        
        if (wRatio > hRatio)
        {
            size["Width"] = spcWidth;
            size["Height"] = (int)Math.Round(orgHeight / wRatio);
        }
        else if (wRatio < hRatio)
        {
            size["Height"] = spcHeight;
            size["Width"] = (int)Math.Round(orgWidth / hRatio);
        }
        else
        {
            size["Width"] = spcWidth;
            size["Height"] = spcHeight;
        }
    }
    return size;
}

注意事项与维护

资源释放:System.Drawing 中的对象(如 Image, Bitmap, Graphics)非托管资源较多,务必在最后调用 .Dispose(),否则在高并发场景下可能导致内存泄漏。
依赖限制:此代码依赖于服务端安装的 GDI+ 库,纯 Linux/Server Core 环境可能需要额外配置或使用 ImageSharp 等跨平台替代库。
透明度处理:代码中使用 g.Clear(Color.White) 填充白色背景。如果原图包含透明通道,此举会将透明部分变为白色,符合一般网页缩略图习惯。

以上就是C#图片按比例缩放与裁剪实现的详细内容,更多关于C#图像处理与System.Drawing应用技巧的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。