簡體   English   中英

C#中的高效圖像處理

[英]Efficient image manipulation in C#

我正在使用System.Drawing類從用戶上傳的照片生成縮略圖和水印圖像。 用戶還可以在上傳原件后使用jCrop裁剪圖像。 我從其他人手中接過了這個代碼,我正在尋求簡化和優化它(它在高流量網站上使用)。

前一個人有靜態方法,它接收位圖作為參數並返回一個,在內部分配和處理Graphics對象。 我的理解是Bitmap實例包含內存中的整個圖像,而Graphics基本上是繪制操作的隊列,並且它是冪等的。

該過程目前的工作原理如下:

  • 接收圖像並將其存儲在臨時文件中。
  • 接收裁剪坐標。
  • 將原始位圖加載到內存中。
  • 應用裁剪,從原始位圖創建新位圖。
  • 做一些瘋狂的亮度調整新的位圖,也許(?)返回一個新的位圖(我寧願不觸摸這個;指針算術豐富!),讓我們稱之為A.
  • 從結果中創建另一個位圖,應用水印(讓我們稱之為B1)
  • 從A創建一個175x175縮略圖位圖。
  • 從A創建一個45x45縮略圖位圖。

這似乎是很多內存分配; 我的問題是:重寫部分代碼並重用Graphics實例是否是一個好主意,實際上是創建了一個管道? 實際上,我只需要內存中的1個圖像(原始上傳),而其余圖像可以直接寫入磁盤。 所有生成的圖像都需要裁剪和亮度轉換,以及該版本獨有的單個轉換,有效地創建了一個操作樹。

任何想法或想法?

哦,我應該提一下,這是我第一次真正使用.NET,所以如果我說的話似乎很混亂,請耐心等待我並給我一些提示。

這個過程似乎很合理。 每個圖像在保存到磁盤之前必須存在於內存中 - 因此縮略圖的每個版本都將首先在內存中。 確保其有效工作的關鍵是Dispose Your Graphics和Bitmap對象。 最簡單的方法是使用using語句。

using( Bitmap b = new Bitmap( 175, 175 ) )
using( Graphics g = Graphics.FromBitmap( b ) )
{
   ...
}

重用Graphics對象可能不會帶來顯着的性能提升。

底層GDI代碼簡單為您在RAM(內存DC)中加載的位圖創建設備上下文。

操作的瓶頸似乎是從磁盤加載映像。

為什么要從磁盤重新加載映像? 如果它已經在RAM中的字節數組中,它應該在上傳時 - 您可以在字節數組上創建一個內存流,然后從該內存流創建一個位圖。

換句話說,將它保存到磁盤,但不要重新加載它,只需從RAM上操作它。

此外,您不需要創建新的位圖來應用水印(取決於它是如何完成的)。

您應該對操作進行概述,以了解它需要改進的地方(或者即使需要改進)。

我不久前完成了一個類似的項目並做了一些實際測試,看看如果我重用Graphics對象而不是為每個圖像啟動一個新對象,是否存在性能上的差異。 就我而言,我正在研究大量圖像的穩定流(在“批量”中> 10,000)。 我發現通過重用Graphics對象,我確實獲得了輕微的性能提升。

我還發現,通過在Graphics對象中使用GraphicsContainers可以輕松地將不同的狀態交換到對象中,因為它用於執行各種操作。 (具體來說,我必須在每張圖像上應用裁剪並繪制一些文字和一個方框(矩形)。)我不知道這對你需要做什么是否有意義。 您可能希望查看Graphics對象中的BeginContainer和EndContainer方法。

就我而言,差異很小。 我不知道你的實現是否會有或多或少的改進。 但是,由於重寫代碼會產生成本,因此您可能需要考慮完成當前設計並在重寫之前進行一些性能測試。 只是一個想法。

您可能會發現一些有用的鏈接:

使用嵌套圖形容器
GraphicsContainer類

我只是隨便把它扔出去,但如果你想快速“指導”處理圖像的最佳實踐,請查看Paint.NET項目。 有關進行圖像處理的免費高性能工具,請查看AForge.NET

AForge的好處是允許您在不創建新位圖的情況下執行大量這些步驟。 如果這是一個網站,我幾乎可以保證你正在使用的代碼將成為應用程序的性能瓶頸。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM