.NETのSystem.DrawingAPIを介して操作しているPNG画像があります。透明な領域が大きいので、透明な領域を白い塗りつぶしに置き換えて、画像に透明な領域がないようにします。画像編集プログラムでは十分に簡単です...しかし、これまでのところ、C#でこれを行うことはできませんでした。
誰かが私にいくつかのポインタを与えることができますか?
.NETのSystem.DrawingAPIを介して操作しているPNG画像があります。透明な領域が大きいので、透明な領域を白い塗りつぶしに置き換えて、画像に透明な領域がないようにします。画像編集プログラムでは十分に簡単です...しかし、これまでのところ、C#でこれを行うことはできませんでした。
誰かが私にいくつかのポインタを与えることができますか?
透明なピクセルを検出する方法がわかりません。Alphaが0の場合は完全に透明で、255の場合は不透明です。Alpha == 0またはAlpha!=255のどちらをチェックする必要があるかわかりません。あなたがそれを試して、私に役立つであろうフィードバックを与えることができれば。
MSDNから
alphaコンポーネントは、色の透明度を指定します。0は完全に透明で、255は完全に不透明です。同様に、255のA値は不透明な色を表します。1から254までのA値は、半透明の色を表します。Aが255に近づくと、色はより不透明になります。
void Foo(Bitmap image)
{
for (int y = 0; y < image.Height; ++y)
{
for (int x = 0; x < image.Width; ++x)
{
// not very sure about the condition.
if (image.GetPixel(x, y).A != 255)
{
image.SetPixel(x,y,Color.White);
}
}
}
}
私の例:
public void FillPngWhite(Bitmap bmp)
{
if (bmp.PixelFormat != PixelFormat.Format32bppArgb)
throw new ApplicationException("Not supported PNG image!");
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbaValues = new byte[bytes];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbaValues, 0, bytes);
// array consists of values RGBARGBARGBA
for (int counter = 0; counter < rgbaValues.Length; counter += 4)
{
double t = rgbaValues[counter + 3]/255.0; // transparency of pixel between 0 .. 1 , easier to do math with this
double rt = 1 - t; // inverted value of transparency
// C = C * t + W * (1-t) // alpha transparency for your case C-color, W-white (255)
// same for each color
rgbaValues[counter] = (byte) (rgbaValues[counter]*t + 255*rt); // R color
rgbaValues[counter + 1] = (byte)(rgbaValues[counter + 1] * t + 255 * rt); // G color
rgbaValues[counter + 2] = (byte)(rgbaValues[counter + 2] * t + 255 * rt); // B color
rgbaValues[counter + 3] = 255; // A = 255 => no transparency
}
// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(rgbaValues, 0, ptr, bytes);
// Unlock the bits.
bmp.UnlockBits(bmpData);
}
これは別の理由です:
LockBits
代わりGetPixel
に使用しSetPixel
ます。それははるかに高速ですが、理解するのは少し難しいです。これは、 MSDNから少し変更された例です。
あなたの質問へのコメントで言ったように、私は本当のアプラの価値を考慮に入れています。これにより、50%の透明度(128)の黒が黒ではなく灰色のように見えます。この理由は、「グラフィックエディタでアルファを白に置き換える」ためです。白で塗りつぶされた画像の下に新しいレイヤーを作成し、両方のレイヤーを平坦化することを想像します。この例でも同じ効果があります。
ビットマップオブジェクトへのハンドルを取得したら、次のようにします。
Bitmap yourImage = HOWEVER YOU LOAD YOUR IMAGE;
int width = YOUR IMAGE WIDTH;
int height = YOUR IMAGE HEIGHT;
Color c;
Color white = new Color(255,255,255,255)
for(int w = 0; w < width; w++)
for(int h = 0; h < height; h++)
{
c = yourImage.GetPixel(w,h);
yourImage.SetPixel(w,h, ((((short)(c.A)) & 0x00FF) <= 0)? white:c); //replace 0 here with some higher tolerance if needed
}
これは問題を単純化しすぎている可能性がありますが、フォームまたは他のすぐに利用できるコントロール上にある場合は、画像を上に配置する前に背景を白く塗るだけで済みます。