367 lines
12 KiB
C#
367 lines
12 KiB
C#
|
||
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;
|
||
}
|
||
}
|
||
}
|