Files
ImageCompressor/Compressor/JPGCompressor.cs
2026-02-02 21:56:45 +08:00

367 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Diagnostics;
namespace ImageCompressor
{
/// <summary>
/// 单张JPG的压缩运算
/// </summary>
class JPGCompressor
{
int compressLevel;
int MaxWidth;
int MaxHeight;
long Quality;
ImageCodecInfo jpegEncoder;
EncoderParameters jpeParameters;
public JPGCompressor(int compressLevel, int maxWidth,int maxHeight)
{
CompressLevel= compressLevel;
MaxWidth = maxWidth;
MaxHeight = maxHeight;
}
/// <summary>
/// 设定压缩质量
/// </summary>
public int CompressLevel
{
get { return compressLevel; }
private set
{
compressLevel = value;
Quality = compressLevel * 5 + 50; //(50-100)
if (!SetJpegCompressor()) throw new Exception("Cannot Create JPG Comporessor");
}
}
public static int CompressionLevelToMaxWidth(int level)
{
return Math.Max((int)(1920 * (level * 0.2)), 480);//480-3840
}
public static int CompressionLevelToMaxHeight(int level)
{
return Math.Max((int)(1080 * (level * 0.2)), 360);//360-2160
}
#region CompressBytes
/// <summary>
/// 储存Bitmap到JPG文件。
/// 之后释放 writeBitmap
/// </summary>
public bool SaveCompressBytes(byte[] saveBytes, FileInfo saveFile, out string errorMessage)
{
errorMessage = null;
if (saveFile.Exists)
{
if (saveFile.IsReadOnly)
{
errorMessage = Localize.Get("Save file is ReadOnly. ");
return false;
}
}
else
{
DirectoryInfo directory = saveFile.Directory;
if (!directory.Exists)
{
try
{
directory.Create();
}
catch
{
errorMessage = Localize.Get("Cannot create save folder. ");
return false;
}
}
}
try
{
File.WriteAllBytes(saveFile.FullName, saveBytes);
return true;
}
catch (Exception ex)
{
if (ex is IOException)
{
errorMessage = Localize.Get("Save file is occupied. ");
return false;
}
errorMessage = Localize.Get("Save file error at ")+$"{ex.Message}";
return false;
}
}
/// <summary>
/// 打开一个Image文件,返回Bytes
/// </summary>
/// <returns></returns>
public byte[] ReadFileToBytes(FileInfo readFile, out string errorMessage)
{
errorMessage = null;
if (!readFile.Exists)
{
errorMessage = Localize.Get("Read file not exist. ");
return null;
}
if(readFile.Length > 1024 * 1024 * 256)
{
errorMessage = Localize.Get("Read image larger than 256 MB");
return null;
}
try
{
return File.ReadAllBytes(readFile.FullName);
}
catch (Exception ex)
{
errorMessage = Localize.Get("Read file error at ") + $"{ex.Message}";
return null;
}
}
public byte[] CompressBytes(byte[] readBytes, out string errorMessage)
{
MemoryStream memoryStream = null;
MemoryStream saveMemoryStream = null;
Bitmap rawBit = null;
Graphics graphics = null;
Bitmap newBit = null;
errorMessage = null;
try
{
memoryStream = new MemoryStream(readBytes, false);
saveMemoryStream = new MemoryStream();
rawBit = new Bitmap(memoryStream);
memoryStream.Close();
memoryStream.Dispose();
double percentW = (double)MaxWidth / rawBit.Width;
double percentH = (double)MaxHeight / rawBit.Height;
double percent = Math.Min(percentW, percentH);
percent = Math.Min(1, percent);
if (percent < 1 || compressLevel < 10)
{
int newW = (int)(percent * rawBit.Width);
int newH = (int)(percent * rawBit.Height);
newBit = new Bitmap(newW, newH);
graphics = Graphics.FromImage(newBit);
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
graphics.DrawImage(rawBit, 0, 0, newW, newH);
graphics.Dispose();
rawBit.Dispose();
newBit.Save(saveMemoryStream, jpegEncoder, jpeParameters);
newBit.Dispose();
}
else
{
//Level为10则直接储存JPG
rawBit.Save(saveMemoryStream, jpegEncoder, jpeParameters);
}
int length = (int)saveMemoryStream.Length;
saveMemoryStream.Position = 0;
byte[] savedBytes = new byte[length];
saveMemoryStream.Read(savedBytes, 0, length);
saveMemoryStream.Close();
saveMemoryStream.Dispose();
return savedBytes;
}
catch (Exception ex)
{
errorMessage = Localize.Get("Save file error at ")+$"{ex.Message}";
return null;
}
finally
{
memoryStream?.Close();
memoryStream?.Dispose();
saveMemoryStream?.Close();
saveMemoryStream?.Dispose();
rawBit?.Dispose();
newBit?.Dispose();
graphics?.Dispose();
}
}
#endregion
#region CompressBitmap
/// <summary>
/// 储存Bitmap到JPG文件。
/// </summary>
/// <param name="bitmap"></param>
/// <param name="savePath"></param>
/// <param name="savedSizeInKB"></param>
public bool SaveCompressBitmap(Bitmap bitmap, FileInfo saveFile, out long savedSizeInKB, out string errorMessage)
{
savedSizeInKB = 0;
errorMessage = null;
if (saveFile.Exists)
{
if (saveFile.IsReadOnly)
{
errorMessage = Localize.Get("Save file is ReadOnly. ");
return false;
}
}
else
{
DirectoryInfo directory = saveFile.Directory;
if (!directory.Exists)
{
try
{
directory.Create();
}
catch
{
errorMessage = Localize.Get("Cannot create save folder. ");
return false;
}
}
}
FileStream stream = null;
try
{
stream = saveFile.Open(FileMode.Create, FileAccess.Write, FileShare.None);
bitmap.Save(stream, jpegEncoder, jpeParameters);
savedSizeInKB = stream.Length / 1024;
return true;
}
catch (Exception ex)
{
if (ex is IOException)
{
errorMessage = Localize.Get("Save file is occupied. ");
return false;
}
errorMessage = Localize.Get("Save file error at ") + $"{ex.Message}";
return false;
}
finally
{
stream?.Close();
stream?.Dispose();
}
}
/// <summary>
/// 打开一个Image文件
/// </summary>
/// <param name="readFile"></param>
/// <param name="image"></param>
/// <param name="readSizeInKB"></param>
/// <param name="errorMessage"></param>
/// <returns></returns>
public bool ReadFileToImage(FileInfo readFile, out Bitmap image, out long readSizeInKB, out string errorMessage)
{
image = null;
readSizeInKB = 0;
errorMessage = null;
if (!readFile.Exists)
{
errorMessage = Localize.Get("Read file not exist. ");
return false;
}
FileStream stream = null;
try
{
stream = readFile.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
Image im = Image.FromStream(stream);
image = new Bitmap(im);
im.Dispose();
readSizeInKB = stream.Length / 1024;
return true;
}
catch (Exception ex)
{
readSizeInKB = readFile.Length / 1024;
errorMessage = Localize.Get("Save file error at ") + $"{ex.Message}";
return false;
}
finally
{
stream?.Close();
stream?.Dispose();
}
}
/// <summary>
/// 将图片压缩不释放Image
/// </summary>
/// <param name="raw"></param>
/// <returns></returns>
public Bitmap CompressImgToBitmap(Bitmap raw)
{
double percentW = (double)MaxWidth / raw.Width;
double percentH = (double)MaxHeight / raw.Height;
double percent = Math.Min(percentW, percentH);
percent = Math.Min(1, percent);
if (percent < 1 || compressLevel < 10)
{
int newW = (int)(percent * raw.Width);
int newH = (int)(percent * raw.Height);
Bitmap newBit = new Bitmap(newW, newH);
using (Graphics g = Graphics.FromImage(newBit))
{
//g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
g.DrawImage(raw, 0, 0, newW, newH);
return newBit;
}
}
else
{
Bitmap bitmap = new Bitmap(raw);
return bitmap;
}
}
#endregion
bool SetJpegCompressor()
{
var temp = ImageCodecInfo.GetImageDecoders();
jpegEncoder = temp.FirstOrDefault(x => x.MimeType == "image/jpeg");
if (jpegEncoder == null) return false;
System.Drawing.Imaging.Encoder encoder = System.Drawing.Imaging.Encoder.Quality;
jpeParameters = new EncoderParameters(1);
EncoderParameter parameter = new EncoderParameter(encoder, Quality);
jpeParameters.Param[0] = parameter;
return true;
}
}
}