Skip to content

Instantly share code, notes, and snippets.

@dinowang
Last active December 20, 2015 13:48
Show Gist options
  • Select an option

  • Save dinowang/6141186 to your computer and use it in GitHub Desktop.

Select an option

Save dinowang/6141186 to your computer and use it in GitHub Desktop.
A Simple Aggregated C# Image Process API with Fluent Interface
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace HexDigits.Drawing
{
public enum Side { Width, Height }
public class ImageProcess : IDisposable
{
#region Static
/// <summary>
/// 以 空白畫布 建構圖片處理
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns></returns>
public static ImageProcess Handle(int width, int height)
{
return new ImageProcess(new Bitmap(width, height));
}
/// <summary>
/// 以 Bitmap 建構圖片處理
/// </summary>
/// <param name="bitmap"></param>
/// <returns></returns>
public static ImageProcess Handle(Bitmap bitmap)
{
return new ImageProcess(bitmap);
}
/// <summary>
/// 以 Stream 建構圖片處理
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
public static ImageProcess Handle(Stream stream)
{
var bitmap = Image.FromStream(stream) as Bitmap;
return new ImageProcess(bitmap);
}
/// <summary>
/// 以 路徑檔名 建構圖片處理
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public static ImageProcess Handle(string filePath)
{
if (!File.Exists(filePath))
{
throw new InvalidOperationException("filePath");
}
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
return Handle(stream);
}
}
/// <summary>
/// 儲存 Bitmap 到 Stream, 可借品質參數控制圖片品質
/// </summary>
/// <param name="bitmap"></param>
/// <param name="stream"></param>
/// <param name="format"></param>
/// <param name="quality"></param>
public static void SaveAsQualityFactor(Bitmap bitmap, Stream stream, ImageFormat format = null, long? quality = null)
{
if (format == null)
{
format = ImageFormat.Jpeg;
}
if (quality.HasValue)
{
var codec = ImageCodecInfo
.GetImageEncoders()
.FirstOrDefault(x => x.FormatDescription.Equals(format.ToString(), StringComparison.CurrentCultureIgnoreCase));
if (codec != null)
{
//Set the parameters for defining the quality of the thumbnail... here it is set to 100%
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality.Value);
bitmap.Save(stream, codec, encoderParameters);
}
else
{
bitmap.Save(stream, format);
}
}
else
{
bitmap.Save(stream, format);
}
}
#endregion
#region Private members
private Action<Graphics> _graphicSetup = null;
private IDictionary<string, Bitmap> _store;
private Bitmap _bitmap = null;
public Bitmap Bitmap
{
get { return _bitmap; }
private set
{
if (_bitmap != null)
{
_bitmap.Dispose();
}
_bitmap = value;
}
}
public ImageFormat OutputFormat { get; private set; }
public long? OutputQuality { get; private set; }
#endregion
#region Private methods
protected void StandardGraphicsInit(Graphics graphics)
{
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
}
#endregion
/// <summary>
/// 唯一建構子
/// </summary>
/// <param name="bitmap"></param>
private ImageProcess(Bitmap bitmap)
{
Bitmap = bitmap;
OutputFormat = ImageFormat.Jpeg;
OutputQuality = null;
_graphicSetup = StandardGraphicsInit;
_store = new Dictionary<string, Bitmap>();
}
/// <summary>
/// 回收
/// </summary>
public void Dispose()
{
Bitmap = null;
foreach (var key in _store.Keys)
{
_store[key].Dispose();
_store[key] = null;
}
_store = null;
}
/// <summary>
/// 暫存
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public ImageProcess Store(string name)
{
_store[name] = Bitmap.Clone() as Bitmap;
return this;
}
/// <summary>
/// 提取
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public ImageProcess Fetch(string name)
{
Bitmap = _store[name];
return this;
}
/// <summary>
/// Setup
/// </summary>
/// <param name="g"></param>
/// <returns></returns>
public ImageProcess Setup(Action<Graphics> g = null)
{
_graphicSetup = g;
return this;
}
/// <summary>
/// 設定輸出格式
/// </summary>
/// <param name="format"></param>
/// <returns></returns>
public ImageProcess Format(ImageFormat format)
{
OutputFormat = format;
return this;
}
/// <summary>
/// 設定輸出品質
/// </summary>
/// <param name="quality"></param>
/// <returns></returns>
public ImageProcess Quality(long? quality)
{
OutputQuality = quality;
return this;
}
/// <summary>
/// 取得尺寸
/// </summary>
/// <param name="size"></param>
/// <returns></returns>
public ImageProcess Size(out Size size)
{
size = new Size(Bitmap.Width, Bitmap.Height);
return this;
}
/// <summary>
/// 取得尺寸
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public ImageProcess Size(Action<Size> action)
{
var size = new Size(Bitmap.Width, Bitmap.Height);
action(size);
return this;
}
/// <summary>
/// 裁切
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns></returns>
public ImageProcess Crop(int x, int y, int width, int height)
{
var destination = new Bitmap(width, height);
using (var graphics = Graphics.FromImage(destination))
{
_graphicSetup(graphics);
graphics.DrawImage(Bitmap,
new Rectangle(0, 0, width, height),
new Rectangle(x, y, width, height),
GraphicsUnit.Pixel);
}
Bitmap = destination;
return this;
}
/// <summary>
/// 變更大小
/// </summary>
/// <param name="length"></param>
/// <param name="baseSide"></param>
/// <returns></returns>
public ImageProcess Resize(int length, Side baseSide = Side.Width)
{
var w = length;
var h = length;
double ratio = 0L;
switch (baseSide)
{
case Side.Width:
ratio = w / (double)Bitmap.Width;
h = (int)Math.Round(Bitmap.Height * ratio);
break;
case Side.Height:
ratio = h / (double)Bitmap.Height;
w = (int)Math.Round(Bitmap.Width * ratio);
break;
}
return Resize(w, h);
}
/// <summary>
/// 變更大小
/// </summary>
/// <param name="percent">0 ~ 1</param>
/// <param name="baseSide"></param>
/// <returns></returns>
public ImageProcess Resize(double percent, Side baseSide = Side.Width)
{
var w = Bitmap.Width;
var h = Bitmap.Height;
double ratio = 0L;
switch (baseSide)
{
case Side.Width:
w = (int)Math.Round(w * percent);
ratio = w / (double)Bitmap.Width;
h = (int)Math.Round(h * ratio);
break;
case Side.Height:
h = (int)Math.Round(h * percent);
ratio = h / (double)Bitmap.Height;
w = (int)Math.Round(w * ratio);
break;
}
return Resize(w, h);
}
/// <summary>
/// 變更大小
/// </summary>
/// <param name="size"></param>
/// <returns></returns>
public ImageProcess Resize(Size size)
{
return Resize(size.Width, size.Height);
}
/// <summary>
/// 變更大小
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns></returns>
public ImageProcess Resize(int width, int height)
{
// 寬度縮放比
var ws = (float)width / Bitmap.Width;
// 高度縮放比
var hs = (float)height / Bitmap.Height;
// 最佳縮放比
var ss = Math.Min(1, Math.Max(ws, hs));
// Destination
var destination = new Bitmap(width, height);
using (var graphics = Graphics.FromImage(destination))
{
_graphicSetup(graphics);
//graphics.FillRectangle(Brushes.White, 0, 0, width, height);
// 最適圖寬
var _w = Bitmap.Width * ss;
// 最適圖高
var _h = Bitmap.Height * ss;
// 擺放位置
float x = 0;
// 擺放位置
float y = 0;
if (true)
{
// 置中
x = -(_w - (float)width) / 2;
y = -(_h - (float)height) / 2;
}
graphics.DrawImage(Bitmap, x, y, _w, _h);
}
Bitmap = destination;
return this;
}
/// <summary>
/// 透通
/// </summary>
/// <param name="opacity"></param>
/// <returns></returns>
public ImageProcess Opacity(double opacity)
{
var destination = new Bitmap(Bitmap.Width, Bitmap.Height);
using (var graphics = Graphics.FromImage(destination))
{
_graphicSetup(graphics);
//create a color matrix object
var matrix = new ColorMatrix();
//set the opacity
matrix.Matrix33 = (float)opacity;
//create some image attributes
var attributes = new ImageAttributes();
//set the color(opacity) of the image
attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
var rectangle = new Rectangle(0, 0, Bitmap.Width, Bitmap.Height);
graphics.DrawImage(Bitmap, rectangle, 0, 0, Bitmap.Width, Bitmap.Height, GraphicsUnit.Pixel, attributes);
}
Bitmap = destination;
return this;
}
/// <summary>
/// 圖章
/// </summary>
/// <param name="filePath"></param>
/// <param name="stampPlacer"></param>
/// <returns></returns>
public ImageProcess Overlay(string filePath, Func<Size, Size, Point> stampPlacer)
{
return Overlay(ImageProcess.Handle(filePath), stampPlacer);
}
/// <summary>
/// 圖章
/// </summary>
/// <param name="process"></param>
/// <param name="stampPlacer"></param>
/// <returns></returns>
public ImageProcess Overlay(ImageProcess process, Func<Size, Size, Point> stampPlacer)
{
var stamp = process.Bitmap;
return Overlay(stamp, stampPlacer);
}
/// <summary>
/// 圖章
/// </summary>
/// <param name="stamp"></param>
/// <param name="stampPlacer"></param>
/// <returns></returns>
public ImageProcess Overlay(Bitmap stamp, Func<Size, Size, Point> stampPlacer)
{
var destination = new Bitmap(Bitmap.Width, Bitmap.Height);
using (var graphics = Graphics.FromImage(destination))
{
_graphicSetup(graphics);
graphics.DrawImage(Bitmap, 0, 0);
var point = stampPlacer(new Size(Bitmap.Width, Bitmap.Height),
new Size(stamp.Width, stamp.Height));
graphics.DrawImage(stamp, point);
}
Bitmap = destination;
return this;
}
/// <summary>
/// 灰階
/// </summary>
/// <returns></returns>
public ImageProcess GrayScale()
{
var destination = new Bitmap(Bitmap.Width, Bitmap.Height);
using (var graphics = Graphics.FromImage(destination))
{
_graphicSetup(graphics);
//create the grayscale ColorMatrix
var colorMatrix = new ColorMatrix(new float[][]
{
new float[] { .3f, .3f, .3f, 0, 0 },
new float[] { .59f, .59f, .59f, 0, 0 },
new float[] { .11f, .11f, .11f, 0, 0 },
new float[] { 0, 0, 0, 1, 0 },
new float[] { 0, 0, 0, 0, 1 }
});
//create some image attributes
var attributes = new ImageAttributes();
//set the color matrix attribute
attributes.SetColorMatrix(colorMatrix);
var rectangle = new Rectangle(0, 0, Bitmap.Width, Bitmap.Height);
graphics.DrawImage(Bitmap, rectangle, 0, 0, Bitmap.Width, Bitmap.Height, GraphicsUnit.Pixel, attributes);
}
Bitmap = destination;
return this;
}
/// <summary>
/// 自由繪圖
/// </summary>
/// <param name="g"></param>
/// <returns></returns>
public ImageProcess Draw(Action<Graphics, Size> g)
{
var destination = new Bitmap(Bitmap.Width, Bitmap.Height);
using (var graphics = Graphics.FromImage(destination))
{
_graphicSetup(graphics);
g(graphics, new Size(Bitmap.Width, Bitmap.Height));
}
Bitmap = destination;
return this;
}
/// <summary>
/// 存檔
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public ImageProcess Save(string filePath)
{
using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite))
{
return Save(stream);
}
}
/// <summary>
/// 存檔
/// </summary>
/// <param name="stream"></param>
/// <param name="rewind"></param>
/// <returns></returns>
public ImageProcess Save(Stream stream, bool rewind = false)
{
SaveAsQualityFactor(Bitmap, stream, OutputFormat, OutputQuality);
if (rewind)
{
stream.Seek(0, SeekOrigin.Begin);
}
return this;
}
/// <summary>
/// Delegate
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public ImageProcess TakeStream(Action<Stream> action)
{
using (var stream = new MemoryStream())
{
Save(stream, rewind: true);
action(stream);
}
return this;
}
/// <summary>
/// Delegate
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public ImageProcess TakeBitmap(Action<Bitmap> action)
{
action(Bitmap);
return this;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment