C# GDI+;错误:透明度上的抗锯齿白色

C# GDI+;错误:透明度上的抗锯齿白色,c#,gdi+,transparent,antialiasing,C#,Gdi+,Transparent,Antialiasing,下面的代码将创建一个透明位图,然后在其上绘制一个带抗锯齿的白色椭圆 using(var background = new Bitmap(500, 500)) using (var graphics = Graphics.FromImage(background)) { graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.Clear(Color.Transparent); graphics.DrawEll

下面的代码将创建一个透明位图,然后在其上绘制一个带抗锯齿的白色椭圆

using(var background = new Bitmap(500, 500))
using (var graphics = Graphics.FromImage(background))
{
    graphics.SmoothingMode = SmoothingMode.AntiAlias;

    graphics.Clear(Color.Transparent);

    graphics.DrawEllipse(new Pen(Color.White, 50), 250, 250, 150, 150);

    background.Save("test.png", ImageFormat.Png);
 }

我发现的错误是椭圆边缘周围的抗锯齿像素具有意外的颜色。它们的RGB值为(25425)而不是(255255)。既然GDI+将透明定义为ARGB(0255255),白色定义为(255255),为什么混合后我会看到254?

在Mono(Mac OS X)中从SVG生成PNG时,我遇到了相同的问题,但由于某些原因,在Windows上没有

为了解决这个问题,我将最接近的rgb值从图形复制到了抗锯齿像素,但保留了抗锯齿alpha值

代码基于以下示例:

要作为保存方法之前的最后一步运行的代码:

var pxf = PixelFormat.Format32bppArgb;
var rect = new Rectangle(0, 0, image.Width, image.Height);
BitmapData bmpData = image.LockBits(rect, ImageLockMode.ReadWrite, pxf);

IntPtr ptr = bmpData.Scan0;

int numBytes = image.Width * image.Height * 4;
byte[] rgbValues = new byte[numBytes];
Marshal.Copy(ptr, rgbValues, 0, numBytes);

for (int argb = 0; argb < rgbValues.Length; argb += 4) {
    var a = rgbValues [argb + 3]; //A
    if(a > 0x00 && a < 0xFF) { //Antialiasing:
        //Scan for neares solid with 0 transparency:
        for (int i = 0; i < 3; i++) { //3 pixels scan seems to be enough

            var right = argb + i * 4;
            var left = argb - i * 4;
            var up = argb - i * image.Width * 4;
            var down = argb + i * image.Width * 4;

            if (right < rgbValues.Length && rgbValues [right + 3] == 0xFF) {
                rgbValues [argb+2] = rgbValues [right + 2]; //R
                rgbValues [argb+1] = rgbValues [right + 1]; //G
                rgbValues [argb] = rgbValues [right];       //B
                break;
            } else if (left > 0 && rgbValues [left + 3] == 0xFF) {
                rgbValues [argb+2] = rgbValues [left + 2];
                rgbValues [argb+1] = rgbValues [left + 1];
                rgbValues [argb] = rgbValues [left];
                break;
            } else if (up > 0 && rgbValues [up + 3] == 0xFF) {
                rgbValues [argb+2] = rgbValues [up + 2];
                rgbValues [argb+1] = rgbValues [up + 1];
                rgbValues [argb] = rgbValues [up];
                break;
            } else if (down < rgbValues.Length && rgbValues [down + 3] == 0xFF) {
                rgbValues [argb+2] = rgbValues [down + 2];
                rgbValues [argb+1] = rgbValues [down + 1];
                rgbValues [argb] = rgbValues [down];
                break;
            }
        }
        //rgbValues [argb+3] = a; //Keep old alpha.
    }
}

Marshal.Copy(rgbValues, 0, ptr, numBytes);

image.UnlockBits(bmpData);
var pxf=PixelFormat.Format32bppArgb;
var rect=新矩形(0,0,image.Width,image.Height);
BitmapData bmpData=image.LockBits(rect、ImageLockMode.ReadWrite、pxf);
IntPtr ptr=bmpData.Scan0;
int numBytes=image.Width*image.Height*4;
字节[]rgbValues=新字节[numBytes];
封送处理副本(ptr,rgb值,0,numBytes);
for(int argb=0;argb0x00&&a<0xFF){//抗锯齿:
//扫描透明度为0的近实体:
对于(inti=0;i<3;i++){//3像素的扫描似乎就足够了
var right=argb+i*4;
var left=argb-i*4;
var up=argb-i*image.Width*4;
var down=argb+i*image.Width*4;
if(right0&&RGB值[left+3]==0xFF){
RGB值[argb+2]=RGB值[left+2];
RGB值[argb+1]=RGB值[left+1];
RGB值[argb]=RGB值[左];
打破
}否则如果(向上>0&&RGB值[向上+3]==0xFF){
RGB值[argb+2]=RGB值[up+2];
RGB值[argb+1]=RGB值[up+1];
RGB值[argb]=RGB值[up];
打破
}else if(向下

`

我想这是一个精度问题……背景颜色是什么?背景颜色是彩色的。透明ARGB(0255255)。因此,我不确定精度在哪里丢失。构成特定像素的前景颜色根据其亚像素前景覆盖率混合在一起,忽略背景的影响。您要求GDI+做一些不可能的事情:渲染将在任何背景下混合的抗锯齿像素。这在设计上不起作用,只有当背景颜色与混合颜色匹配时,图像边缘才会看起来很好。最好不要尝试,使用SmoothingMode。没有,你会得到一个纯白色的边缘。代码还需要4个方向,垂直、垂直、左下和右下。这很容易实现。