ovxrfl0w
ovxrfl0w

Reputation: 131

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

Upvotes: 2

Views: 2550

Answers (2)

G.Vernier
G.Vernier

Reputation: 379

You can also handle it from the loading, so you can keep your BlendState to AlphaBlend.

Here is the function I use to load my textures from file :

private Texture2D PremultiplyTexture(String FilePath, GraphicsDevice device)
{
    Texture2D texture;

    FileStream titleStream = File.OpenRead(FilePath);
    texture = Texture2D.FromStream(device, titleStream);
    titleStream.Close();
    Color[] buffer = new Color[texture.Width * texture.Height];
    texture.GetData(buffer);
    for (int i = 0; i < buffer.Length; i++)
        buffer[i] = Color.FromNonPremultiplied(buffer[i].R, buffer[i].G, buffer[i].B, buffer[i].A);
    texture.SetData(buffer);

    return texture;
}

Upvotes: 4

TheRealVira
TheRealVira

Reputation: 1614

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

Upvotes: 3

Related Questions