承接以前的元件系列,這個元件系列旨在介紹.NET相關的元件,讓大家可以在項目中有一個更好的選擇,社群對于第三方插件的介紹還是比較少的,很多博文的内容主要還是介紹一些簡單的操作(很多人都說部落格園現在是“hello world”的水準,博文品質在下降,對于這一說法,我覺得這個說法有些過頭了,可能一些博文的确寫的比較初級,但是很多博文的深入還是比較大,隻是很少受人關注),這個元件系列主要在介紹一些功能的元件,附帶該元件的核心對象介紹。
元件的介紹絕對不是一篇文章可以叙述完的,因為一個元件是經過開發者很長周期的開發,絕不是我這裡一篇簡單的博文就可以介紹完畢的,元件介紹的系列,一般會沿襲着元件背景介紹、元件使用介紹、核心對象介紹等等内容。如果對元件感興趣,可以深入的了解和學習。
廢話少說,進入正題。
我們在項目中很多時候都會對檔案進行處理,例如檔案的上傳下載下傳等等。其中對圖檔的實時操作也會較多,在這裡介紹一款用C#編寫的輕量級庫的集合,它允許你使用.NET 4.5+來動态地處理圖像的元件,那就是ImageProcessor,用于圖像的即時處理的.NET庫。(組織的開源項目組,會經過第一個項目的磨合後,第二項目會開發一個.NET Core元件)
一.ImageProcessor元件概述
ImageProcessor是用C#編寫的輕量級庫的集合,它允許你使用.NET 4.5+來動态地處理圖像,包括兩個主庫ImageProcessor(用于桌面和應用程式使用)ImageProcessor.Web(ASP.NET建構的動态圖像處理擴充),該元件快速,可擴充,易于使用,捆綁了一些很強大的功能,而且是完全開源。該元件有兩個部分,我們今天将主要講解ImageProcessor部分的内容,如果對另外一個感興趣,可以自行了解。
ImageProcessor.Web向項目添加了一個可配置的HttpModule,允許對圖像檔案進行即時處理。該子產品還提供了一個基于檔案和浏覽器的緩存,可以處理數百萬的圖像,增加處理輸出和節省寶貴的伺服器記憶體。該元件的功能方法包括:調整大小,旋轉,圓角,翻轉,裁剪,水印,過濾器,飽和度,亮度,對比度,品質,格式,小插曲,高斯模糊,高斯銳化和透明度。
ImageProcessor.Web的目前版本是4.8.2,可以下載下傳源碼和DLL檔案(本人建議最好下載下傳源碼,好處就不在這裡贅述)。
ImageProcessor.Web是ImageProcessor的Web擴充,允許開發人員使用Url API的查詢字元串參數作為指令執行圖像操作。此過程的輸出是高度優化的網絡,以確定web項目較高的性能。安裝ImageProcessor.Web時,預設情況下,Web.config中添加配置節點,如下節點。
<add name="ImageProcessorModule" type="ImageProcessor.Web.HttpModules.ImageProcessingModule, ImageProcessor.Web" /></httpModules>
這允許庫ImageProcessingModule攔截本地圖像處理請求。ImageProcessor.Web是高度可配置的。可以将其他配置檔案添加到解決方案中,以便從多個來源檢索,處理和緩存圖像。對于該元件的配置設定可以檢視文檔。
二.ImageProcessor元件操作概述
介紹了元件的相關資訊,在這裡介紹一下該元件的操作執行個體。ImageFactory類提供了對給定圖像執行各種操作功能的方法。它經過精心設計以防止在以高性能方式處理圖像時通常發生的各種記憶體洩漏。這使其可以安全地在桌面和Web環境中使用。ImageFactory自動檢測給定圖像的正确檔案類型,并且該類的API是流暢的,這允許您輕松地連結方法以提供所需的輸出。例如,以下代碼加載,調整大小,設定新格式并儲存包含圖像資訊的MemoryStream。

public static void Image(string file)
{
if (string.IsNullOrEmpty(file))
{
throw new ArgumentNullException(file);
}
byte[] photoBytes = System.IO.File.ReadAllBytes(file);
// 檢測格式
ISupportedImageFormat format = new JpegFormat { Quality = 70 };
Size size = new Size(150, 0);
using (MemoryStream inStream = new MemoryStream(photoBytes))
{
using (MemoryStream outStream = new MemoryStream())
{
// 使用重載初始化ImageFactory以保留EXIF中繼資料。
using (ImageFactory imageFactory = new ImageFactory(true))
{
// 加載,調整大小,設定格式和品質并儲存圖像。
imageFactory.Load(inStream)
.Resize(size)
.Format(format)
.Save(outStream);
//對擷取的imageFactory對象進行對應的操作
}
//對擷取的資料流進行操作
}
}

對于圖檔的操作,具體有較多的操作方式,具體的方法有如下的方法:
方法名稱 | 方法操作說明 |
Reset | 将目前圖像重置為其原始加載狀态 |
Alpha | 更改目前圖像的不透明度 |
AutoRotate | 執行自動旋轉以確定反映EXIF定義的旋轉最終圖像 |
BitDepth | 改變目前圖像的位深度 |
Brightness | 更改目前圖像的亮度 |
BackgroundColor | 更改目前圖像的背景顔色 |
Constrain | 限制目前圖像,調整其大小以适合給定的尺寸,同時保持其縱橫比 |
Contrast | 更改目前圖像的對比度 |
Crop | 将目前圖像裁剪到給定的位置和大小 |
DetectEdges | 檢測目前圖像中的邊緣 |
Resolution | 設定圖像的分辨率 |
EntropyCrop | 将圖像修剪到最大熵的區域 |
Filter | 将過濾器應用于目前圖像 |
Flip | 水準或垂直翻轉目前圖像 |
Gamma | 調整給定圖像的灰階(光強度)分量 |
GaussianBlur | 使用高斯核心模糊目前圖像 |
Hue | 改變目前圖像的色調,改變整體顔色 |
Halftone | 将目前圖像轉換為該圖像的CMYK半色調表示 |
Quality | 改變目前圖像的輸出品質 |
ReplaceColor | 替換目前圖像中的顔色 |
Resize | 将目前圖像調整為給定尺寸 |
Rotate | 将目前圖像旋轉給定角度 |
以上隻是列出了一些主要的操作方法,還有其他的方法這裡就不再介紹,有興趣可以自己取實踐。下面就介紹一下一些核心對象。
三.ImageProcessor核心對象解析
解析來我們具體了解一下核心的方法和屬性,看看源碼還是有好處。
1.ImageFactory.Load()

public ImageFactory Load(string imagePath)
{
FileInfo fileInfo = new FileInfo(imagePath);
if (fileInfo.Exists)
{
this.ImagePath = imagePath;
using (FileStream fileStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
{
ISupportedImageFormat format = FormatUtilities.GetFormat(fileStream);
if (format == null)
{
throw new ImageFormatException("Input stream is not a supported format.");
}
MemoryStream memoryStream = new MemoryStream();
fileStream.CopyTo(memoryStream);
memoryStream.Position = 0;
this.Image = format.Load(memoryStream);
this.CurrentBitDepth = Image.GetPixelFormatSize(this.Image.PixelFormat);
this.InputStream = memoryStream;
format.Quality = DefaultQuality;
format.IsIndexed = FormatUtilities.IsIndexed(this.Image);
this.backupFormat = format;
this.CurrentImageFormat = format;
foreach (PropertyItem propertyItem in this.Image.PropertyItems)
{
this.ExifPropertyItems[propertyItem.Id] = propertyItem;
}
this.backupExifPropertyItems = this.ExifPropertyItems;
IAnimatedImageFormat imageFormat = this.CurrentImageFormat as IAnimatedImageFormat;
if (imageFormat != null)
{
imageFormat.AnimationProcessMode = this.AnimationProcessMode;
}
Image formatted = this.Image.Copy(this.AnimationProcessMode);
this.Image.Dispose();
this.Image = formatted;
this.ShouldProcess = true;
}
}
else
{
throw new FileNotFoundException(imagePath);
}
return this;
}

該方法用來加載要處理的圖像的方法, 始終首先調用此方法。該方法具有4個重載版本,分别接收的參數為string,byte[],Image,Stream。FormatUtilities.GetFormat(fileStream)方法從給定流擷取正确的ISupportedImageFormat。在對圖檔的資料流進行操作時,首先會複制圖檔的流資料。format.Load(memoryStream)将我們的映像設定為記憶體流值。圖檔資料流進行一個操作後,會調用Image.Copy(this.AnimationProcessMode)確定圖像是最有效的格式。
2.ImageFactoryExtensions.AutoProcess()

internal static ImageFactory AutoProcess(this ImageFactory factory, IWebGraphicsProcessor[] graphicsProcessors)
{
if (factory.ShouldProcess)
{
foreach (IWebGraphicsProcessor graphicsProcessor in graphicsProcessors)
{
factory.CurrentImageFormat.ApplyProcessor(graphicsProcessor.Processor.ProcessImage, factory);
IDisposable disposable = graphicsProcessor.Processor.DynamicParameter as IDisposable;
disposable?.Dispose();
}
}
return factory;
}

ImageFactoryExtensions類是ImageFactory類的擴充類,主要是擴充Web項目。AutoProcess()方法基于添加到圖像路徑的任何查詢字元串參數,自動處理圖像檔案。graphicsProcessors參數表示要應用的圖形處理器陣列。graphicsProcessor.Processor.DynamicParameter as IDisposable打開動态參數并處理任何需要它的類型。
3.ImageProcessingModule.SetHeaders()

public static void SetHeaders(HttpContext context, int maxDays)
{
object responseTypeObject = context.Items[CachedResponseTypeKey];
object dependencyFileObject = context.Items[CachedResponseFileDependency];
string responseType = responseTypeObject as string;
string[] dependencyFiles = dependencyFileObject as string[];
SetHeaders(context, responseType, dependencyFiles, maxDays);
}

在Web擴充中,ImageProcessingModule類比較重要,處理Web應用程式中的任何圖像請求。SetHeaders()方法使浏覽器和伺服器将輸出儲存在其緩存中,進而提高性能。該方法接受兩個參數,context表示請求的http消息對象,HttpContext對象對内在伺服器對象的引用。maxDays參數表示将圖檔存儲在浏覽器緩存中的最長天數。
四.總結
說句實話,這位作者的編碼風格是喜歡的,代碼簡介明了,沒有那麼多裝逼的寫法,不會為了使用一些寫法,而去改變代碼的可讀性。對于這個元件系列,我會近可能的寫一些,大家可以借此了解一些元件,需要深入了解和使用的,可以自己檢視源碼,進行對應的擴充。寫完這篇,已經淩晨兩點了,為自己點個贊,無論寫的怎樣,覺得自己還是盡心了。