C# 使用 GDI+ 畫圖

来源:https://www.cnblogs.com/dandelion-drq/archive/2018/04/01/8687262.html
-Advertisement-
Play Games

最近做一個微信公眾號服務,有一些簡單的圖片處理功能。主要就是用戶在頁面操作,前端做一些立刻顯示的效果,然後提交保存時後端真正修改原圖。 我們的後端是 ,也就是 語言了, 本身處理圖片還是比較方便的,使用 就好,只需要添加 引用,不需要任何第三方庫。於是最近也用到一些比較常用的 圖片處理方法,就整理一 ...


最近做一個微信公眾號服務,有一些簡單的圖片處理功能。主要就是用戶在頁面操作,前端做一些立刻顯示的效果,然後提交保存時後端真正修改原圖。
我們的後端是 ASP.NET,也就是 C# 語言了,C# 本身處理圖片還是比較方便的,使用 GDI+ 就好,只需要添加 System.Drawing 引用,不需要任何第三方庫。於是最近也用到一些比較常用的 GDI+ 圖片處理方法,就整理一下做個記錄了。

這個題目大概會寫幾篇文章,第一篇先簡單介紹一下 GDI+ 的常用對象,以及一些使用時候的註意事項,後面會挑一些項目中做過的比較有用的處理過程來介紹一下。

廢話不多說,開始進入正題。


需要用到的類

使用 GDI+ 畫圖會用到的幾個常用的類有:GraphicsBitmapImage
其中 Graphics 是畫板。這個類包含了許多畫圖的方法,包括畫圖片(DrawImage),畫線(DrawLine),畫圓(DrawEllipse、FillEllipse),寫字(DrawString)等等。簡單說使用這個類可以完成我們需要的大部分工作。

生成一個 Graphics 對象需要用到 Image 或者 Bitmap
PS: Winform 下可以直接從窗體或控制項的事件中引用 Graphics 對象。
比如:

private void Form1_Paint(object sender, PaintEventArgs e)
{
    Graphics g = e.Graphics; // 創建畫板,這裡的畫板是由Form提供的.
}

不過本文討論的是其他場景,比如 ASP.NET MVC,或單純的控制台程式。這些時候是沒有控制項的,所以要用其他方法。

我一般用以下方法:

//
// 摘要:
//     從指定的 System.Drawing.Image 創建新的 System.Drawing.Graphics。
//
// 參數:
//   image:
//     從中創建新 System.Drawing.Graphics 的 System.Drawing.Image。
//
// 返回結果:
//     此方法為指定的 System.Drawing.Image 返回一個新的 System.Drawing.Graphics。
//
// 異常:
//   T:System.ArgumentNullException:
//     image 為 null。
//
//   T:System.Exception:
//     image 具有索引像素格式,或者格式未定義。
public static Graphics FromImage(Image image);

其中的參數可以傳入 ImageBitmap,因為 Bitmap 是繼承自 Image 的。


如何創建畫板

  • 如果是要對原圖進行處理,比如旋轉圖片,添加文字等,可以直接通過原圖片獲得畫板對象。

    Image img = Image.FromFile(imgPath);
    Graphics graphics = Graphics.FromImage(img);
  • 如果是要畫一個新的圖,可以通過要保存的圖片寬、高生成畫板。

    Bitmap bmp = new Bitmap(width, height);
    Graphics graph = Graphics.FromImage(bmp);

    PS: Graphics 本身是沒有提供構造函數來直接生成的。所以我們可以先創建一個需要保存圖片大小的 Bitmap 點陣圖對象,然後再獲得畫板對象。


如何保存畫好的圖片

通過調用 img.Save(savePath) 或者 bmp.Save(savePath) 即可保存對象。
PS: BitmapSave 方法是直接繼承自 Image 的。


GDI+ 的坐標系

GDI+ 的坐標系是個二維坐標系,不過又有點不一樣,它的原點是在左上角的。如下圖:


使用 GDI+ 的一些註意事項

這裡我忍不住要先吐槽一下,GDI+ 的報錯信息不太友好啊。經常只是返回一個“GDI+ 中發生一般性錯誤。”,不能快速地根據這個錯誤提示定位問題。比如說沒有釋放圖片資源時想再次訪問資源會報這個錯誤,想要保存圖片的文件夾不存在時也是提示這個錯誤。看不出來區別……

1. 保存到相同路徑的文件時要先釋放圖片資源,否則會報錯(GDI+中發生一般性錯誤)

Image img = Image.FromFile(imgPath);
Bitmap bmp = new Bitmap(img);
Graphics graphics = Graphics.FromImage(bmp);
... // 對圖片進行一些處理
img.Dispose(); // 釋放原圖資源
bmp.Save(imgPath); // 保存到原圖
graphics.Dispose(); // 圖片處理過程完成,剩餘資源全部釋放
bmp.Dispose();

2. 使用完的資源記得要釋放。可以用 try..catch..finally 或者 using 的方式,這樣即使遇到代碼運行報錯也能及時釋放資源,更加保險。

  • try..catch...finally:把釋放資源的代碼寫到 finally 代碼段里。

    Image img = Image.FromFile(imgPath);
    Bitmap bmp = new Bitmap(img);
    Graphics graphics = Graphics.FromImage(bmp);
    try
    {
       //  ...
    }
    catch (System.Exception ex)
    {
    throw ex;
    }
    finally
    {
    graphics.Dispose();
    bmp.Dispose();
    img.Dispose();
    }
  • using:使用 using 語句創建的資源會在離開 using 代碼段時自動釋放該資源。

    /// <summary>
    /// 縮放圖像
    /// </summary>
    /// <param name="originalImagePath">原圖路徑</param>
    /// <param name="destWidth">目標圖寬度</param>
    /// <param name="destHeight">目標圖高度</param>
    /// <returns></returns>
    public Bitmap GetThumbnail(string originalImagePath, int destWidth, int destHeight)
    {
    using (Image imgSource = Image.FromFile(originalImagePath))
    {
        return GetThumbnail(imgSource, destWidth, destHeight);
    }
    }

3. 要保存圖片的文件夾一定要是已經存在的,否則會報錯(GDI+中發生一般性錯誤)

eg:假設圖片要保存到 D:\test\output.png

string directory = @"D:\test\";
string fileName = "output.png";

// 檢查文件夾是否存在,不存在則先創建
if (!Directory.Exists(directory))
{
    Directory.CreateDirectory(directory);
}

bmp.Save(directory + fileName);

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、Redis的安裝 xshell連上伺服器,依次輸入以下代碼: 如果不巧發生以下截圖中的錯誤: 說明未安裝gcc,如果是centos系統,輸入:yum install gcc安裝gcc即可,然後再次輸入make執行。 輸入make後,很不幸,再次發生如下截圖錯誤: 推測是因為編譯庫的問題。 將ma ...
  • 第二章、線性表 一、線性表的順序表示和實現 1、線性表中第i個數據元素ai的存儲位置: LOC(ai)=LOC(a1)+(i-1)*l l為每個元素需占用l個單元 2、有上式可知,線性表的順序結構是一種隨機存取的存儲結構,但其缺點為插入和刪除比較困難。 3、線性表的數據結構表示為: // 線性表的動 ...
  • 前言 從今天開始進入Java基礎的複習,可能一個星期會有一篇的,我寫博文的未必都是正確的~如果有寫錯的地方請大家多多包涵並指正~ 今天要複習的是泛型,泛型在Java中也是個很重要的知識點,本文主要講解基礎的概念,並不是高深的知識,如果基礎好的同學可以當複習看看~ 一、什麼是泛型? Java泛型設計原 ...
  • 將數據處理移植到STM32上,採用串口的DMA接收模式,註意的是DMA_MODE採用Circular,DMA_BufferSize>(8*512+36=4132)(小包8個位元組,每秒512個,完整的大包36個位元組) 代碼如下: //////////////////////////////////// ...
  • 概述 New UWP Community Toolkit V2.2.0 的版本發佈日誌中提到了 RadialGauge 的調整,本篇我們結合代碼詳細講解 RadialGauge 的實現。 RadialGauge 是一種徑向儀錶盤控制項,使用圓盤面上的指針來顯示一定範圍的值,這種顯示和交互方式,讓數據可 ...
  • 在14,15年間帶領幾個不同的團隊,交付了幾個項目,在這個過程中,雖然幾個項目的業務不一樣,但是很多應用程式架構基礎性的功能卻是大同小異,例如認證、授權、請求驗證、異常處理、DTO、日誌、審計、定時任務、調度、多語言、應用配置管理等等這些功能。但是由於項目受限於進度、資源、團隊成員的背景,在當時卻難 ...
  • 1.業務場景 生產車間中使用的條碼掃描,往往一把掃描槍需要掃描不同的條碼來處理不同的業務邏輯,比如,掃描投入料工位條碼、掃描投入料條碼、掃描產出工裝條碼等,每種類型的條碼位數是不一樣,因此通過條碼長度來進行業務區分。 2.初步設計 面對此場景,能夠想到的最簡單的設計就是使用if...else if. ...
  • 概述 UWP Community Toolkit 中有一個圓形的進度條控制項 - RadialProgressBar,本篇我們結合代碼詳細講解 RadialProgressBar 的實現。 RadialProgressBar 是一種圓形的進度條控制項,進度值用圓形中的填充色的角度來表示,進度增長,填充色 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...