XNA Texture2D.FromStream returns 颜色通道偶尔关闭 1

XNA Texture2D.FromStream returns color channels ocasionally off by 1

我目前正在将用作映射图像的 Texture2D 加载并保存到数据库中,以便稍后可以预加载它们。每个颜色通道都需要是加载后保存时的精确颜色。问题是 Texture2D.FromStream 有时 return 不正确的颜色通道 有时 相差 1 左右。这是不可接受的,因为映射的颜色如果不正确就没有用。

下面的示例提供了一种情况,当 alpha 设置为 100 时,RGB 255 变为 RGB 254。当将 alpha 设置为 1 或 255 时,它们 return 正确为 255,其他alpha 值导致与 100 相同的问题。

Texture2D tex = new Texture2D(GraphicsDevice, 20, 20, false, SurfaceFormat.Color);
Color[] data = new Color[tex.Width * tex.Height];
for (int i = 0; i < data.Length; i++) {
    data[i] = new Color(255, 255, 255, 100);
}
tex.SetData<Color>(data);
using (Stream stream = File.Open("TestAlpha.png", FileMode.OpenOrCreate)) {
    tex.SaveAsPng(stream, tex.Width, tex.Height);
    stream.Position = 0;
    tex = Texture2D.FromStream(GraphicsDevice, stream);
    tex.GetData<Color>(data);
    Console.WriteLine(data[0]); // Returns (R:254 G:254 B:254 A:100)
}

我在 Paint.NET 中查看保存的图像时确认 png 具有正确的 RGB 255,因此它只能是 Texture2D.FromStream 期间造成的。

好吧,我没有找到 Texture2D.FromStream 问题的原因,但我找到了 all-around 加载 Texture2D 的更好方法。在这种情况下,我改为从流中加载 GDI Bitmap,获取其数据,并将其传输到新创建的 Texture2D.

无论 Texture2D.FromSteam 是否可修复,我都计划使用它,但我仍然很想知道是否有人知道它发生了什么。

对于新手,请务必将 System.Drawing 作为参考,因为默认情况下 XNA 项目中不存在它。

public static unsafe Texture2D FromStream(GraphicsDevice graphicsDevice, Stream stream) {
    // Load through GDI Bitmap because it doesn't cause issues with alpha
    using (Bitmap bitmap = (Bitmap) Bitmap.FromStream(stream)) {
        // Create a texture and array to output the bitmap to
        Texture2D texture = new Texture2D(graphicsDevice,
            bitmap.Width, bitmap.Height, false, SurfaceFormat.Color);
        Color[] data = new Color[bitmap.Width * bitmap.Height];

        // Get the pixels from the bitmap
        Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
        BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly,
            PixelFormat.Format32bppArgb);

        // Write the pixels to the data buffer
        byte* ptr = (byte*) bmpData.Scan0;
        for (int i = 0; i < data.Length; i++) {
            // Go through every color and reverse red and blue channels
            data[i] = new Color(ptr[2], ptr[1], ptr[0], ptr[3]);
            ptr += 4;
        }

        bitmap.UnlockBits(bmpData);

        // Assign the data to the texture
        texture.SetData<Color>(data);

        // Fun fact: All this extra work is actually 50% faster than
        // Texture2D.FromStream! It's not only broken, but slow as well.

        return texture;
    }
}