C#縮放jpg文件的尺寸的操作方法
普通處理
以下是一個使用 System.Drawing 調(diào)整 JPG 圖像寬度為 365 像素、高度按比例自動縮放的 C# 函數(shù)。該方法適用于 .NET Framework 4.6+ 或 .NET Core/.NET 5+(需安裝 System.Drawing.Common NuGet 包)。
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
public static class ImageHelper
{
/// <summary>
/// 將 JPG 圖像寬度調(diào)整為指定像素(默認 365),高度按原比例自動計算,并保存為新文件。
/// </summary>
/// <param name="inputPath">輸入 JPG 文件路徑</param>
/// <param name="outputPath">輸出 JPG 文件路徑</param>
/// <param name="targetWidth">目標寬度,默認 365</param>
/// <param name="quality">JPEG 質(zhì)量(1-100),默認 90</param>
public static void ResizeJpgToWidth(string inputPath, string outputPath, int targetWidth = 365, int quality = 90)
{
if (string.IsNullOrEmpty(inputPath))
throw new ArgumentNullException(nameof(inputPath));
if (string.IsNullOrEmpty(outputPath))
throw new ArgumentNullException(nameof(outputPath));
if (targetWidth <= 0)
throw new ArgumentOutOfRangeException(nameof(targetWidth), "目標寬度必須大于0");
if (quality < 1 || quality > 100)
throw new ArgumentOutOfRangeException(nameof(quality), "質(zhì)量值必須在1到100之間");
using (var originalImage = Image.FromFile(inputPath))
{
// 計算等比例高度
float ratio = (float)targetWidth / originalImage.Width;
int newHeight = (int)(originalImage.Height * ratio);
// 創(chuàng)建目標位圖
using (var resizedImage = new Bitmap(targetWidth, newHeight))
{
using (var graphics = Graphics.FromImage(resizedImage))
{
// 設(shè)置高質(zhì)量縮放參數(shù)
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
// 繪制縮放后的圖像
graphics.DrawImage(originalImage, 0, 0, targetWidth, newHeight);
}
// 保存為 JPEG,可設(shè)置壓縮質(zhì)量
var encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, quality);
var jpegCodec = GetEncoder(ImageFormat.Jpeg);
if (jpegCodec != null)
{
resizedImage.Save(outputPath, jpegCodec, encoderParams);
}
else
{
// 若找不到JPEG編碼器則使用默認保存(可能質(zhì)量較低)
resizedImage.Save(outputPath, ImageFormat.Jpeg);
}
}
}
}
private static ImageCodecInfo GetEncoder(ImageFormat format)
{
var codecs = ImageCodecInfo.GetImageEncoders();
foreach (var codec in codecs)
{
if (codec.FormatID == format.Guid)
return codec;
}
return null;
}
}
使用示例
// 將 "photo.jpg" 寬度改為 365 像素,高度自動等比例,輸出為 "resized.jpg" ImageHelper.ResizeJpgToWidth(@"C:\temp\photo.jpg", @"C:\temp\resized.jpg"); // 自定義質(zhì)量(例如 80%) ImageHelper.ResizeJpgToWidth(@"C:\temp\photo.jpg", @"C:\temp\resized.jpg", quality: 80);
注意事項
環(huán)境要求:
- .NET Framework 4.6+ 可直接使用
System.Drawing。 - .NET Core / .NET 5+ 需通過 NuGet 安裝 System.Drawing.Common。
- 該方案在 Windows 上完全支持,跨平臺(Linux/macOS)需安裝
libgdiplus。
輸出格式:
即使輸入文件擴展名不是 .jpg,只要文件本身是 JPEG 格式,函數(shù)依然可以處理并輸出為 JPEG。如需嚴格校驗輸入格式,可在 Image.FromFile 后檢查 originalImage.RawFormat。
內(nèi)存管理:
使用了多個 using 塊,確保非托管資源(GDI+ 句柄)及時釋放。
性能優(yōu)化:InterpolationMode.HighQualityBicubic 提供較好的縮放質(zhì)量,但速度略慢。若對速度有更高要求,可改為 InterpolationMode.Bilinear 或 InterpolationMode.Default。
替代方案(跨平臺推薦)
如果需要在非 Windows 環(huán)境(如 Linux 容器)中運行,推薦使用 SixLabors.ImageSharp,無需依賴系統(tǒng)庫:
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
public static void ResizeJpgToWidth(string inputPath, string outputPath, int targetWidth = 365)
{
using (var image = Image.Load(inputPath))
{
image.Mutate(x => x.Resize(targetWidth, 0)); // 0 表示保持縱橫比
image.Save(outputPath);
}
}
使用 ImageSharp 更簡潔,且完全托管,無需額外配置。建議在 .NET 6+ 項目中優(yōu)先考慮。
以上函數(shù)可直接復(fù)制使用,按需調(diào)整參數(shù)即可。
需要覆蓋原文件的方法
要讓函數(shù)直接覆蓋原文件,只需在調(diào)用時將輸出路徑設(shè)為與輸入路徑相同,但需處理文件鎖問題:Image.FromFile 會一直鎖定文件,導(dǎo)致無法直接寫回原路徑。
解決方案:當(dāng)輸入和輸出路徑相同時,先將原始圖像完整讀入內(nèi)存(釋放文件鎖),再執(zhí)行縮放并保存。
以下是改造后的函數(shù),自動判斷路徑是否相同,并采用安全的內(nèi)存加載方式:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
public static class ImageHelper
{
/// <summary>
/// 將 JPG 圖像寬度調(diào)整為指定像素(默認 365),高度按原比例自動計算。
/// 若輸出路徑與輸入路徑相同,則自動覆蓋原文件(不會因文件鎖定而報錯)。
/// </summary>
/// <param name="inputPath">輸入 JPG 文件路徑</param>
/// <param name="outputPath">輸出 JPG 文件路徑(可與輸入相同)</param>
/// <param name="targetWidth">目標寬度,默認 365</param>
/// <param name="quality">JPEG 質(zhì)量(1-100),默認 90</param>
public static void ResizeJpgToWidth(string inputPath, string outputPath, int targetWidth = 365, int quality = 90)
{
if (string.IsNullOrEmpty(inputPath))
throw new ArgumentNullException(nameof(inputPath));
if (string.IsNullOrEmpty(outputPath))
throw new ArgumentNullException(nameof(outputPath));
if (targetWidth <= 0)
throw new ArgumentOutOfRangeException(nameof(targetWidth), "目標寬度必須大于0");
if (quality < 1 || quality > 100)
throw new ArgumentOutOfRangeException(nameof(quality), "質(zhì)量值必須在1到100之間");
// 判斷是否為同一物理文件(忽略大小寫,并規(guī)范化路徑)
bool isOverwrite = string.Equals(
Path.GetFullPath(inputPath),
Path.GetFullPath(outputPath),
StringComparison.OrdinalIgnoreCase);
if (isOverwrite)
{
// 覆蓋原文件:先將整個文件讀入內(nèi)存,釋放文件鎖
byte[] imageBytes = File.ReadAllBytes(inputPath);
using (var ms = new MemoryStream(imageBytes))
using (var originalImage = Image.FromStream(ms))
{
ResizeAndSave(originalImage, outputPath, targetWidth, quality);
}
}
else
{
// 不同文件:直接從文件加載(保留原有邏輯)
using (var originalImage = Image.FromFile(inputPath))
{
ResizeAndSave(originalImage, outputPath, targetWidth, quality);
}
}
}
/// <summary>
/// 縮放圖像并保存為 JPEG(內(nèi)部復(fù)用邏輯)
/// </summary>
private static void ResizeAndSave(Image originalImage, string outputPath, int targetWidth, int quality)
{
// 計算等比例高度
float ratio = (float)targetWidth / originalImage.Width;
int newHeight = (int)(originalImage.Height * ratio);
using (var resizedImage = new Bitmap(targetWidth, newHeight))
using (var graphics = Graphics.FromImage(resizedImage))
{
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.DrawImage(originalImage, 0, 0, targetWidth, newHeight);
// 設(shè)置 JPEG 質(zhì)量
var encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, quality);
var jpegCodec = GetEncoder(ImageFormat.Jpeg);
if (jpegCodec != null)
{
resizedImage.Save(outputPath, jpegCodec, encoderParams);
}
else
{
resizedImage.Save(outputPath, ImageFormat.Jpeg);
}
}
}
private static ImageCodecInfo GetEncoder(ImageFormat format)
{
var codecs = ImageCodecInfo.GetImageEncoders();
foreach (var codec in codecs)
{
if (codec.FormatID == format.Guid)
return codec;
}
return null;
}
// --- 便捷方法:直接覆蓋原文件 ---
public static void ResizeJpgToWidthAndOverwrite(string filePath, int targetWidth = 365, int quality = 90)
{
ResizeJpgToWidth(filePath, filePath, targetWidth, quality);
}
}
核心改動說明
自動檢測覆蓋場景
使用 Path.GetFullPath 規(guī)范化路徑并忽略大小寫比較,準確判斷輸入、輸出是否為同一文件。
內(nèi)存加載解除文件鎖
當(dāng)需要覆蓋原文件時,通過 File.ReadAllBytes 將圖片數(shù)據(jù)載入內(nèi)存,再用 Image.FromStream 加載,此時原文件已完全釋放,后續(xù)可安全寫入。
提取共用縮放保存邏輯
將縮放和保存代碼抽離為 ResizeAndSave 方法,避免重復(fù)代碼。
使用示例
// 直接覆蓋原文件(兩種寫法等價) ImageHelper.ResizeJpgToWidth(@"C:\photo.jpg", @"C:\photo.jpg"); // 或使用專用方法 ImageHelper.ResizeJpgToWidthAndOverwrite(@"C:\photo.jpg");
注意事項
- 格式校驗:該函數(shù)不強制檢查輸入文件是否為 JPEG,若輸入其他格式,縮放仍可執(zhí)行,但保存時會強行轉(zhuǎn)為 JPEG。如需嚴格校驗,可在
ResizeAndSave前添加if (originalImage.RawFormat.Guid != ImageFormat.Jpeg.Guid) throw ...。 - 性能:覆蓋原文件時多一次內(nèi)存拷貝,但對普通圖片影響極小。
- 跨平臺:若使用
System.Drawing.Common在非 Windows 環(huán)境運行,仍需安裝libgdiplus??缙脚_場景推薦改用 SixLabors.ImageSharp(完全托管,無文件鎖問題)。
如果需要更簡潔的跨平臺方案(無需處理文件鎖),可直接采用 ImageSharp:
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
public static void ResizeAndOverwrite(string filePath, int targetWidth = 365)
{
using (var image = Image.Load(filePath))
{
image.Mutate(x => x.Resize(targetWidth, 0));
image.Save(filePath); // ImageSharp 會自動處理覆蓋
}
}
根據(jù)項目環(huán)境選擇合適方案即可。
以上就是C#縮放jpg文件的尺寸的操作方法的詳細內(nèi)容,更多關(guān)于C#縮放jpg文件尺寸的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C# 使用相同權(quán)限調(diào)用 cmd 傳入命令的方法
本文告訴大家如何使用相同權(quán)限調(diào)用cmd并且傳入命令,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友參考下吧2018-07-07
詳解C#中多態(tài)性學(xué)習(xí)/虛方法/抽象方法和接口的用法
這篇文章主要為大家詳細介紹了C#中多態(tài)性學(xué)習(xí)、虛方法、抽象方法和接口的用法的相關(guān)知識,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下2023-03-03
解析OpenXml?Pptx的邊框虛線轉(zhuǎn)為WPF的邊框虛線問題
這篇文章主要介紹了OpenXml?Pptx的邊框虛線轉(zhuǎn)為WPF的邊框虛線,在文中用PPTX的7種直線,分別設(shè)置7種能夠設(shè)置的虛線類型,具體實例代碼跟隨小編一起看看吧2021-12-12
C#通過進程調(diào)用外部應(yīng)用的實現(xiàn)示例
本文主要介紹了C#通過進程調(diào)用外部應(yīng)用的實現(xiàn)示例,以WINFORM應(yīng)用程序為例,在C#應(yīng)用程序中調(diào)用PYTHON程序,具有一定的參考價值,感興趣的可以了解一下2025-05-05
C#用Topshelf創(chuàng)建Windows服務(wù)的步驟分享
這篇文章主要給大家介紹了關(guān)于C#如何利用Topshelf創(chuàng)建Windows服務(wù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05

