首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET 使用 GDI+ 動態轉換圖片顏色:灰階與偽彩色互轉完整實作

     編輯:ASP.NET 基礎

前言

專案需求:使用者上傳圖片後,需提供「灰階」與「原彩色」切換預覽,且不儲存多份檔案。利用 System.Drawing (GDI+) 對每像素操作,即可即時轉換。本文提供完整可用的 update_pixelColor 方法與核心演算法解析。

完整程式碼實作

#region 圖片顏色轉換
/// 
/// 將圖片轉為灰階或還原為偽彩色(單通道映射)
/// 
/// 圖片實體完整路徑
/// true=轉灰階,false=轉偽彩色(紅色通道主導)
public void UpdatePixelColor(string filePath, bool toGray)
{
    using (Bitmap bmp = new Bitmap(Bitmap.FromFile(filePath)))
    {
        int pixelValue;
        for (int y = 0; y < bmp.Height; y++)
        {
            for (int x = 0; x < bmp.Width; x++)
            {
                Color original = bmp.GetPixel(x, y);
                if (toGray)
                    pixelValue = GetGrayValue(original);
                else
                    pixelValue = GetPseudoColorValue(original);
                
                // 灰階:R=G=B=同一值;偽彩色:此處示範同值(可擴展為調色盤映射)
                bmp.SetPixel(x, y, Color.FromArgb(pixelValue, pixelValue, pixelValue));
            }
        }
        bmp.Save(filePath); // 覆蓋原檔,生產建議另存新檔
    }
}

/// 
/// 標準灰階公式:Y = 0.299R + 0.587G + 0.114B
/// 整數運算優化:(R*19595 + G*38469 + B*7472) >> 16
/// 
private int GetGrayValue(Color c)
{
    return (c.R * 19595 + c.G * 38469 + c.B * 7472) >> 16;
}

/// 
/// 偽彩色示範:此處同灰階公式,實務可映射至調色盤
/// 
private int GetPseudoColorValue(Color c)
{
    // 範例:單純取紅通道或自訂映射
    return (c.R * 19595 + c.G * 38469 + c.B * 7472) >> 16;
}
#endregion

核心演算法解析

1. 灰階公式由來

人眼對綠最敏感、紅次之、藍最低。ITU-R BT.601 標準亮度公式:

Y = 0.299 × R + 0.587 × G + 0.114 × B

為避免浮點運算,乘以 65536 (2^16) 整數化:

  • 0.299 × 65536 ≈ 19595
  • 0.587 × 65536 ≈ 38469
  • 0.114 × 65536 ≈ 7472

計算後右移 16 位(>> 16)即除以 65536,得到 0~255 灰階值。

2. GetPixel/SetPixel 效能警示

GetPixel/SetPixel 每次呼叫都會鎖定/解鎖位圖記憶體,**極慢**(百萬像素需數秒)。實務必須使用 LockBits 直接操作記憶體:

public unsafe void FastGrayScale(string filePath)
{
    using (Bitmap bmp = new Bitmap(filePath))
    {
        var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
        var bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
        
        int stride = bmpData.Stride;
        byte* ptr = (byte*)bmpData.Scan0;
        
        for (int y = 0; y < bmp.Height; y++)
        {
            byte* row = ptr + y * stride;
            for (int x = 0; x < bmp.Width; x++)
            {
                int b = row[x * 3];
                int g = row[x * 3 + 1];
                int r = row[x * 3 + 2];
                int gray = (r * 19595 + g * 38469 + b * 7472) >> 16;
                row[x * 3] = row[x * 3 + 1] = row[x * 3 + 2] = (byte)gray;
            }
        }
        bmp.UnlockBits(bmpData);
        bmp.Save(filePath);
    }
}

效能差異: 1000x1000 圖片,GetPixel 約 2.5 秒,LockBits 約 30ms(快 80 倍)。

3. 偽彩色擴展:調色盤映射

若需將灰階映射為「鐵紅、深藍、綠」等偽彩色,可建立 256 色調色盤陣列:

Color[] palette = new Color[256];
for (int i = 0; i < 256; i++)
{
    // 範例:藍->青->綠->黃->紅 熱力圖漸層
    if (i < 64) palette[i] = Color.FromArgb(0, i * 4, 255);
    else if (i < 128) palette[i] = Color.FromArgb(0, 255, 255 - (i - 64) * 4);
    else if (i < 192) palette[i] = Color.FromArgb((i - 128) * 4, 255, 0);
    else palette[i] = Color.FromArgb(255, 255 - (i - 192) * 4, 0);
}

// LockBits 內使用:
// int gray = ...;
// row[x*3] = palette[gray].B;
// row[x*3+1] = palette[gray].G;
// row[x*3+2] = palette[gray].R;

部署與安全注意事項

  1. GDI+ 記憶體洩漏:大量處理圖片時,Bitmap 需嚴格 using 或 Dispose(),否則導致程序記憶體暴漲。
  2. 伺服器權限:IIS 應用程式池身分需具備檔案讀寫權限。
  3. 併發處理:GDI+ 非執行緒安全,高併發建議使用影像處理佇列(如 Hangfire)串行處理,或改用 ImageSharp、SkiaSharp 等跨平台純管理庫。
  4. 原始檔保留:範例直接覆蓋原檔,生產環境**務必**備份原圖或另存新檔(如 _gray.jpg)。

總結

本文提供從簡單 GetPixel 版本到高效能 LockBits 版本的完整灰階/偽彩色轉換實作。理解亮度公式整數化原理與記憶體鎖定技巧,是 .NET 影像處理的核心基礎。現代專案建議優先採用 ImageSharp 等無非受控相依的庫,避開 GDI+ 部署坑點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved