Search code examples
c#xna

How to load transparent PNG using Texture2D.FromStream


I wanted to ask how can I load Texture2D image from file (i don't want to use XNA's Content Pipeline) while preserving transparency of my image, because I want skinning in my game.

Code I have:

Initialising Texture using _cursor.Texture = _helper.LoadPicture("skin\\cursor.png");

Drawing Texture using spriteBatch.Draw(Texture, rectangle, Color.BlanchedAlmond);

public Texture2D LoadPicture(string filename) {
    FileStream setStream = File.Open(filename, FileMode.Open);
    StreamReader reader = new StreamReader(setStream);
    Texture2D NewTexture = Texture2D.FromStream(_graphicsDevice, setStream);
    setStream.Dispose();
    return NewTexture;
 }

Screenshot 1 (Result): http://prntscr.com/cxjzwu

Screenshot 2 (Expected): http://prntscr.com/cxk065


Solution

  • I've tried to recreate your problem, but it worked fine for me:

    enter image description here

    My code behind the scenes:

        #region Usings
    
    using System.IO;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    
    #endregion
    
    namespace OpacityTest
    {
        /// <summary>
        ///     This is the main type for your game
        /// </summary>
        public class Game1 : Game
        {
            private static Texture2D Tested;
            private GraphicsDeviceManager graphics;
            private SpriteBatch spriteBatch;
    
            public Game1()
            {
                graphics = new GraphicsDeviceManager(this);
                Content.RootDirectory = "Content";
            }
    
            /// <summary>
            ///     Allows the game to perform any initialization it needs to before starting to run.
            ///     This is where it can query for any required services and load any non-graphic
            ///     related content.  Calling base.Initialize will enumerate through any components
            ///     and initialize them as well.
            /// </summary>
            protected override void Initialize()
            {
                // TODO: Add your initialization logic here
    
                base.Initialize();
            }
    
            /// <summary>
            ///     LoadContent will be called once per game and is the place to load
            ///     all of your content.
            /// </summary>
            protected override void LoadContent()
            {
                // Create a new SpriteBatch, which can be used to draw textures.
                spriteBatch = new SpriteBatch(GraphicsDevice);
    
                using (var fileStream = new FileStream("test.png", FileMode.Open))
                {
                    Tested = Texture2D.FromStream(GraphicsDevice, fileStream);
                }
            }
    
            /// <summary>
            ///     UnloadContent will be called once per game and is the place to unload
            ///     all content.
            /// </summary>
            protected override void UnloadContent()
            {
                // Important!!!
                Tested.Dispose();
            }
    
            /// <summary>
            ///     Allows the game to run logic such as updating the world,
            ///     checking for collisions, gathering input, and playing audio.
            /// </summary>
            /// <param name="gameTime">Provides a snapshot of timing values.</param>
            protected override void Update(GameTime gameTime)
            {
                // Allows the game to exit
                if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                    Exit();
    
                base.Update(gameTime);
            }
    
            /// <summary>
            ///     This is called when the game should draw itself.
            /// </summary>
            /// <param name="gameTime">Provides a snapshot of timing values.</param>
            protected override void Draw(GameTime gameTime)
            {
                GraphicsDevice.Clear(Color.CornflowerBlue);
    
                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
                spriteBatch.Draw(Tested, Vector2.Zero, Color.White);
                spriteBatch.End();
    
                base.Draw(gameTime);
            }
        }
    }
    

    I'm using this texture:

    enter image description here

    and put it into my build folder.


    [Edit]

    Now I see where your problem is - the colors alpha value is set to the maximum. I have tried some things and got to the conclusion, that you have to replace this line:

            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
    

    with that line:

            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);
    

    After that I got your Content.Load result:

    enter image description here

    If you want to know more about "Premultiplied alpha" click me! :)

    There is the second texture I've used for the cursor:

    enter image description here