Texture2D.SaveAsPng implementation

I’ve implemented my own SaveAsPng function to be used on Windows (with OpenTK) without much difficulty or third party libraries. I was wondering why this code is not part of MonoGame. It works fine for me. Am I missing something here?

public static class Texture2DExtensions
    {
        /// <summary>
        /// The BGR to RGB color matrix used to switch the blue and red colors from an image
        /// </summary>
        private static ColorMatrix _BgrToRgbColorMatrix = new ColorMatrix(new float[][]
        {
            new float[] {0, 0, 1, 0, 0},
            new float[] {0, 1, 0, 0, 0},
            new float[] {1, 0, 0, 0, 0},
            new float[] {0, 0, 0, 1, 0},
            new float[] {0, 0, 0, 0, 1}
        });

        /// <summary>
        /// My SaveAsPng function.
        /// </summary>
        /// <param name="stream">The stream to write the png to.</param>
        /// <param name="width">The width.</param>
        /// <param name="height">The height.</param>
        public static void MySaveAsPng(this Texture2D thisTexture2D, Stream stream, int width, int height)
        {
            var pixelData = new byte[thisTexture2D.Width * thisTexture2D.Height * GraphicsExtensions.Size(thisTexture2D.Format)];
            thisTexture2D.GetData(pixelData);
            Bitmap bitmap = new Bitmap(thisTexture2D.Width, thisTexture2D.Height, PixelFormat.Format32bppArgb);
            BitmapData bmData = bitmap.LockBits(new Rectangle(0, 0, thisTexture2D.Width, thisTexture2D.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
            Marshal.Copy(pixelData, 0, bmData.Scan0, 4 * thisTexture2D.Width * thisTexture2D.Height);
            bitmap.UnlockBits(bmData);

            // Switch from BGR encoding to RGB
            using (ImageAttributes ia = new ImageAttributes())
            {
                ia.SetColorMatrix(_BgrToRgbColorMatrix);
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    g.DrawImage(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height), 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, ia);
                }
            }

            bitmap.Save(stream, ImageFormat.Png);
        }

    }

I believe this is primarily due to Monogame’s goals. Up until now, they have been trying to fully reimplement XNA, of which this is not a part. Also, (this may be wrong) your code relies on Gdi+, which is not available on the iOS version of Xamarin, so adding it would be platform specific.

Additionally, saving a texture as a PNG is a rather ‘niche’ usage, as most people upload textures from a disk. Out of curiosity, how do you typically use that code and how often?

Texture2D.SaveAsPng is part of XNA. MonoGame has implemented it with a bunch of #ifdefs for WINDOWS_STOREAPP and MONOMAC. For all other OS’es (including Windows) it throws a NotImplemented Exception.

Although I suspect that most people would use it for printscreen-like functionality (e.g. generating a printscreen to be used for savegames, so a preview can be shown), I’m using it for a Debug-GUI that is able to show all loaded resources (and is able to replace them on-the-fly without recompiling projects).

Because no one has contributed it.

MonoGame is an all volunteer project with zero full time developers. Unless someone makes the effort to implement something and submit it… it just doesn’t appear in the code base.

What would be great is for you to contribute the code to the project.

https://github.com/mono/MonoGame/blob/develop/CONTRIBUTING.md