2013-04-11 2 views
1

Следующий код создаст прозрачную растровую карту, а затем нарисует на ней белый эллипс с сглаживанием.GDI + Ошибка: Anti-Aliasing White On Transparency

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 (254,254,254) вместо (255,255,255). Поскольку GDI + определяет прозрачность как ARGB (0,255,255,255) и белый как (255,255,255,255), почему я вижу 254 после смешивания?

+0

я себе его прецизионный вопрос ... Что цвет фона? – Sayse

+0

Цвет фона Цвет. Прозрачный ARGB (0,255,255,255). Поэтому я не уверен, где точность теряется. – Zach

+0

Цвета переднего плана, составляющие конкретный пиксель, смешиваются в соответствии с их субпиксельным охватом переднего плана, игнорируя вклад фона. http://www.w3.org/Conferences/WWW4/Papers/53/gq-trans.html – Sayse

ответ

0

У меня была такая же проблема, когда я сгенерировал PNG из SVG в Mono (Mac OS X), но по какой-то причине не в Windows.

Чтобы исправить это, я скопировал ближайшие значения rgb с рисунка на пиксели сглаживания, но изменил значение antialias-alpha.

код основан на примере из: https://msdn.microsoft.com/en-us/library/ms229672(v=vs.90).aspx

код для запуска, как последний шаг перед тем, сохранить метод:

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); 

`

+0

Код также понадобится еще 4 направления, вверх, вертикально, вниз и прямо. Это легко реализовать. – oddbear