You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中使用Graphics.DrawImage()处理含Alpha通道图像时像素值异常

问题原因与精确复制方案

核心问题

GDI+的Graphics.DrawImage默认会对带Alpha通道的图像做预乘Alpha处理——自动把RGB通道值和Alpha通道值相乘后写入目标,哪怕你设置了CompositingMode.SourceCopy也没用。另外默认的颜色校正、平滑优化也会篡改原始像素值,导致复制结果不符合预期。

解决方案1:调整Graphics参数+使用ImageAttributes强制精确复制

修改你的绘制代码,禁用所有可能的图像优化,并通过ImageAttributes告诉GDI+直接复制原始通道数据:

using (Graphics g = Graphics.FromImage(bmpDestDrawImage))
{
    g.CompositingMode = CompositingMode.SourceCopy;
    g.TextRenderingHint = TextRenderingHint.SingleBitPerPixel;
    
    // 禁用所有会修改像素的优化选项
    g.SmoothingMode = SmoothingMode.None;
    g.InterpolationMode = InterpolationMode.NearestNeighbor;
    g.PixelOffsetMode = PixelOffsetMode.None;
    g.CompositingQuality = CompositingQuality.HighSpeed;
    g.Clear(Color.Transparent); // 确保目标画布初始状态正确

    // 创建ImageAttributes,强制不做任何颜色转换
    using (ImageAttributes attributes = new ImageAttributes())
    {
        // 恒等颜色矩阵:完全保留原始RGB/A值
        ColorMatrix identityMatrix = new ColorMatrix(
            new float[][]
            {
                new float[] {1, 0, 0, 0, 0},
                new float[] {0, 1, 0, 0, 0},
                new float[] {0, 0, 1, 0, 0},
                new float[] {0, 0, 0, 1, 0},
                new float[] {0, 0, 0, 0, 1}
            });
        attributes.SetColorMatrix(identityMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

        // 执行精确绘制
        g.DrawImage(bmp, 
            new Rectangle(0, 0, bitmapSize, bitmapSize), 
            0, 0, bitmapSize, bitmapSize, 
            GraphicsUnit.Pixel, 
            attributes);
    }
}

解决方案2:直接内存复制(更高效精确)

如果不需要缩放、旋转等绘制操作,直接通过LockBits复制像素内存是最可靠的方式,完全绕过GDI+的绘制逻辑:

// 替代DrawImage的直接像素复制方案
Rectangle rect = new Rectangle(0, 0, bitmapSize, bitmapSize);
BitmapData srcData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
BitmapData destData = bmpDestDrawImage.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

int byteCount = Math.Abs(srcData.Stride) * bitmapSize;
byte[] pixelBuffer = new byte[byteCount];

// 从源图像读取像素数据
System.Runtime.InteropServices.Marshal.Copy(srcData.Scan0, pixelBuffer, 0, byteCount);
// 写入目标图像
System.Runtime.InteropServices.Marshal.Copy(pixelBuffer, 0, destData.Scan0, byteCount);

// 解锁内存
bmp.UnlockBits(srcData);
bmpDestDrawImage.UnlockBits(destData);

内容的提问来源于stack exchange,提问作者Fux

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 05:17:33