using System;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Diagnostics;
namespace ImageCompressor
{
///
/// 单张JPG的压缩运算
///
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;
}
///
/// 设定压缩质量
///
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
///
/// 储存Bitmap到JPG文件。
/// 之后释放 writeBitmap
///
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;
}
}
///
/// 打开一个Image文件,返回Bytes
///
///
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
///
/// 储存Bitmap到JPG文件。
///
///
///
///
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();
}
}
///
/// 打开一个Image文件
///
///
///
///
///
///
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();
}
}
///
/// 将图片压缩,不释放Image
///
///
///
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;
}
}
}