Juan Carlos Ruiz Pacheco

How can i obtain extra information from a File using Content importer

Now i already have made a content importer for my ownfile format, that is ok because i se the importer to extract the texture Infromation from my file...

But the problem Is that i have very valuable information in my file format in addition to the texture infromation,

This is the code that i use to import the texture content from my files (jki Files):

    /// <summary>

    /// Importador de archivos JKI al XNA Content pipeline

    /// </summary>

    [ContentImporter(".jki", DisplayName = "Imagen De Multiples Frames JKI", DefaultProcessor = "Procesador para archivos JKI")]

    public class JKIImporter : ContentImporter<Texture2DContent[]>

    {

        /// <summary>

        /// Importa el contenido de un archivo JKI al content pipeline de XNA

        /// </summary>

        /// <param name="filename">Nombre del archivo a procesar</param>

        /// <param name="context">Contexto para el content importer</param>

        /// <returns>Array de texturas extraidas del archivo</returns>

        public override Texture2DContent[] Import(string filename, ContentImporterContext context)

        {

            //Decodificador del archivo JKI

            DecodificadorJKI decodificador = new DecodificadorJKI();

            //Encabezado identificador de la imagen JKI

            EncabezadoFijo encabezado;

            //Colores de mascara por cada cuadro informado por el archivo JKI

            BaseColor[] coloresMascara = new BaseColor[0];

            //Mapeador de pixeles

            PixelBitmapContent<Rgba32> pixelHelper;

            //Array de textura a retornar

            Texture2DContent[] textureContent;

            //Array de bytes paa capturar la infromacion del archivo JKI

            byte[] byteArray;

            //Imagen JKI cargada desde archivo

            ImagenJKI<Color32> imagen32 = (ImagenJKI<Color32>)decodificador.CargaImagenJKIDesdeArchivo(

                                                          filename, out encabezado, ref coloresMascara);

 

            //Inicializa el array de texturas con la cantidad de frames que existen en el archivo JKI

            textureContent = new Texture2DContent[imagen32.InformacionBase.NumCuadros];

 

            //Carga cada uno de los cuadros de archivo JKI al textureContent

            for (int i = 0; i < imagen32.InformacionBase.NumCuadros; i++)

            {

                //Inicializa un nuevo contenedor de datos de pixeles

                pixelHelper = new PixelBitmapContent<Rgba32>(imagen32.cuadrosDeImagen[ i ].Ancho, imagen32.cuadrosDeImagen[ i ].Alto);

                //Cargar la informacion de bytes para el archivo JKI Actual

                byteArray = ImagenJKI<Color32>.CuadroImagenJKIAByteArray(imagen32, (Int16)i);

                //Envia los datos de bytes al pixel helper

                pixelHelper.SetPixelData(byteArray);

                //Inicializa una nueva textura

                textureContent[ i ] = new Texture2DContent();

                //Carga la informacion de la imagen en la textura

                textureContent[ i ].Mipmaps = new MipmapChain(pixelHelper);

            }

            return textureContent;

        }

    }

 

    /// <summary>

    /// Procesador de Contenido para Archivos JKI para el content pipeline de XNA

    /// </summary>

    [ContentProcessor(DisplayName = "Procesador para archivos JKI")]

    class JKIProcessor: ContentProcessor<Texture2DContent[], Texture2DContent[]>

    {

        /// <summary>

        /// Procesa la informacion enviada por los archivos JKI

        /// </summary>

        /// <param name="input">Array de contenido de texturas 2d</param>

        /// <param name="context">ontexto para el content processor</param>

        /// <returns>Array de texturas extraidas del archivo ya procesadas</returns>

        public override Texture2DContent[] Process(Texture2DContent[] input, ContentProcessorContext context)

        {

            for (int i = 0; i < input.Length; i++)

                input[ i ] = (Texture2DContent)context.Convert<TextureContent, TextureContent>(input[ i ], "SpriteTextureProcessor");

 

            return input;

        }

    }

 

But i need the information contained into

imagen32.InformacionBase, coloresMascara

Will be returned both too, but off course this will be in the same importer and processor that i show a few lines before this.




Re: XNA Framework How can i obtain extra information from a File using Content importer?

dczraptor

i believe you can use the Tag property to store an object of any type.  And to retrieve it, you just cast the tag. I know you can use it in conjuction with a Model, but I'm not so sure about a texture.




Re: XNA Framework How can i obtain extra information from a File using Content importer?

JuanK_solocodigo

Hi,
sounds god but i didn't find any thing like this in the texture content object.




Re: XNA Framework How can i obtain extra information from a File using Content importer?

dczraptor

Hmm, yea, i just checked out the content processor/importer classes and didn't find the tag property either. The model one is under Processors.ModelMeshContent.Tag, but TextureProcessor didn't contain anything. That's weird because you can call Texture2D.Tag . Can anyone clear this up




Re: XNA Framework How can i obtain extra information from a File using Content importer?

Shawn Hargreaves - MSFT

All the design time content pipeline classes contain an OpaqueData property. This is a dictionary that you can use to hold whatever custom data you like.

For the runtime classes, a whole dictionary per object seemed like more overhead than would generally be worth it, so those have just a single Tag property instead. It is up to your custom processor to extract whatever information it thinks is useful from the input OpaqueData, and store this into a useful runtime Tag format.

Alternatively, you could attach data by inheritance (make your own class that derives from the built in one and adds more properties) or aggregation (make your own class that includes one of the built in types as one of its properties).






Re: XNA Framework How can i obtain extra information from a File using Content importer?

JuanK_solocodigo

I see, ok, this is my current simple content processor:

        /// <summary>

        /// Procesa la informacion enviada por los archivos JKI

        /// </summary>

        /// <param name="input">Array de contenido de texturas 2d</param>

        /// <param name="context">Contexto para el content processor</param>

        /// <returns>Array de texturas extraidas del archivo ya procesadas</returns>

        public override Texture2DContent[] Process(Texture2DContent[] input, ContentProcessorContext context)

        {

            for (int i = 0; i < input.Length; i++)

                input[ i ] = (Texture2DContent)context.Convert<TextureContent, TextureContent>(input[ i ], "SpriteTextureProcessor");

 

            return input;

        }

The input object has in the OpaqueData field the information that i need... but how can i  put this information in the tag property of the final Texture2D object






Re: XNA Framework How can i obtain extra information from a File using Content importer?

JuanK_solocodigo

This is my Content Importer: I need get access to the items marked with bold font:

/// <summary>

/// Importador de archivos JKI al XNA Content pipeline

/// </summary>

[ContentImporter(".jki", DisplayName = "Imagen De Multiples Frames JKI", DefaultProcessor = "Procesador para imagenes JKI")]

public class JKIImageImporter : ContentImporter<Texture2DContent[]>

{

/// <summary>

/// Importa el contenido de un archivo JKI al content pipeline de XNA

/// </summary>

/// <param name="filename">Nombre del archivo a procesar</param>

/// <param name="context">Contexto para el content importer</param>

/// <returns>Array de texturas extraidas del archivo</returns>

public override Texture2DContent[] Import(string filename, ContentImporterContext context)

{

//Decodificador del archivo JKI

DecodificadorJKI decodificador = new DecodificadorJKI();

//Encabezado identificador de la imagen JKI

EncabezadoFijo encabezado;

//Mapeador de pixeles

PixelBitmapContent<Rgba32> pixelHelper;

//Array de textura a retornar

Texture2DContent[] textureContent;

//Array de bytes paa capturar la infromacion del archivo JKI

byte[] byteArray;

//Imagen JKI cargada desde archivo

ImagenJKI<Color32> imagen32 = (ImagenJKI<Color32>)decodificador.CargaImagenJKIDesdeArchivo(

filename, out encabezado);

//Inicializa el array de texturas con la cantidad de frames que existen en el archivo JKI

textureContent = new Texture2DContent[imagen32.InformacionBase.NumCuadros];

//Carga cada uno de los cuadros de archivo JKI al textureContent

for (int i = 0; i < imagen32.InformacionBase.NumCuadros; i++)

{

//Inicializa un nuevo contenedor de datos de pixeles

pixelHelper = new PixelBitmapContent<Rgba32>(imagen32.cuadrosDeImagen[ i ].Ancho, imagen32.cuadrosDeImagen[ i ].Alto);

//Cargar la informacion de bytes para el archivo JKI Actual

byteArray = ImagenJKI<Color32>.CuadroImagenJKIAByteArray(imagen32, (Int16)i);

//Envia los datos de bytes al pixel helper

pixelHelper.SetPixelData(byteArray);

//Inicializa una nueva textura

textureContent[ i ] = new Texture2DContent();

//Carga la informacion de la imagen en la textura

textureContent[ i ].Mipmaps = new MipmapChain(pixelHelper);

textureContent[ i ].OpaqueData.Add("Prueba", 1);

textureContent[ i ].OpaqueData.Add("OffSet",new Point(imagen32.cuadrosDeImagen[ i ].Desplazamiento.X,

imagen32.cuadrosDeImagen[ i ].Desplazamiento.Y) );

textureContent[ i ].OpaqueData.Add("ShowTime",imagen32.cuadrosDeImagen[ i ].Tiempo );

textureContent[ i ].OpaqueData.Add("MaskColor", new Color(imagen32.cuadrosDeImagen[ i ].ColorMascara.Rojo,

imagen32.cuadrosDeImagen[ i ].ColorMascara.Verde,

imagen32.cuadrosDeImagen[ i ].ColorMascara.Azul,

imagen32.cuadrosDeImagen[ i ].ColorMascara.Alpha

));

/*//Guarda el desplazamiento de la imagen repsecto al origen

textureContent[ i ].offset = new Point(imagen32.cuadrosDeImagen[ i ].Desplazamiento.X,

imagen32.cuadrosDeImagen[ i ].Desplazamiento.Y);

//Guarda el tiempo de exhibicion de la imagen

textureContent[ i ].showTime = imagen32.cuadrosDeImagen[ i ].Tiempo;

//Guarda el color de mascara de la imagen

textureContent[ i ].maskColor = new Color(imagen32.cuadrosDeImagen[ i ].ColorMascara.Rojo,

imagen32.cuadrosDeImagen[ i ].ColorMascara.Verde,

imagen32.cuadrosDeImagen[ i ].ColorMascara.Azul,

imagen32.cuadrosDeImagen[ i ].ColorMascara.Alpha

);

* */

}

return textureContent;

}

}

And This is my Content Processor, but i don't know how i could put the OpaqueData into the tag element in the Texture2D Object.

/// <summary>

/// Procesador de Contenido para Archivos JKI para el content pipeline de XNA

/// </summary>

[ContentProcessor(DisplayName = "Procesador para imagenes JKI")]

class JKIImageProcessor : ContentProcessor<Texture2DContent[], Texture2DContent[]>

{

/// <summary>

/// Procesa la informacion enviada por los archivos JKI

/// </summary>

/// <param name="input">Array de contenido de texturas 2d</param>

/// <param name="context">Contexto para el content processor</param>

/// <returns>Array de texturas extraidas del archivo ya procesadas</returns>

public override Texture2DContent[] Process(Texture2DContent[] input, ContentProcessorContext context)

{

for (int i = 0; i < input.Length; i++)

{

input[ i ] = (Texture2DContent)context.Convert<TextureContent, TextureContent>(input[ i ], "SpriteTextureProcessor");

input[ i ].OpaqueData.Add("Prueba2",1);

}

return input;

}

}

Maybe i'm making something Wrong... I need to implement my content Writer and my content Reader .






Re: XNA Framework How can i obtain extra information from a File using Content importer?

Leaf.

There is no Texture2D.Tag property so you will have to find some other way of storing the extra information. One of Shawn's suggestions was to use aggregation and that sounds like a good idea for your particular case.

Roughly speaking you will need to create a new content type (e.g. JKITextureContent) that contains the Texture2DContent and your extra information (OffSet, ShowTime, etc.). Your importer will import to JKITextureContent instead of Texture2DContent and your processor will process JKITextureContent into JKITextureContent.

To save and load your JKITextureContent you will need to create ContentWriter and ContentReader classes. You will also need to create a run time type for your content (e.g. JKITexture).

This sounds like a lot but you've already done most of the work. The extra classes will be fairly small and simple.

If you wanted you could also create a processor that processes JKITextureContent into Texture2DContent (it just throws away the extra information), that way you can still load .jki textures straight into Texture2D instances, like any other texture format. Which might be useful if you dont allways need the extra information that you store in .jki files.

Cheers,
Leaf.






Re: XNA Framework How can i obtain extra information from a File using Content importer?

JuanK_solocodigo

Ok, now i understand, maybe i didn't undertstand Shawn because i don't speak english very well.

Luckily i already have the JKITextureContent, JKITexture the ContentProcess and the ContentImporter classes, but because of the unknowledge about XNA i din't want to spend a lot of time coding The reader and the writer without estay secure about if it was the correct solution. :)

Well, now i know the answer, iĄŻll be trying to make the writer and the reader this night or next night, if i have troubles i'll asking you in  the future.

Thanks to Shawn and thaks to you.






Re: XNA Framework How can i obtain extra information from a File using Content importer?

JuanK_solocodigo

doesn't work :'(

In my luch time i've trying to make the classes but don't work ...

something is wrong again, but i can't see it.

Take a look to the classes that i made for complete the necessary 'accesories':

    [ContentTypeWriter]

    public class JKIContentWriter : ContentTypeWriter<JKITexture2DContent>

    {

        protected override void Write(ContentWriter output, JKITexture2DContent value)

        {

            output.Write(value.MaskColor.R);

            output.Write(value.MaskColor.G);

            output.Write(value.MaskColor.B);

            output.Write(value.MaskColor.A);

            output.Write(value.offset.X);

            output.Write(value.offset.Y);

            output.Write(value.ShowTime);

            byte[] pixelData = value.Mipmaps[0].GetPixelData();

            output.Write(pixelData.Length);

            output.Write(pixelData);

        }

 

        public override string GetRuntimeReader(TargetPlatform targetPlatform)

        {

            return typeof(JKITexture2D).AssemblyQualifiedName;

        }

    }

 

    public class JKIContentReader : ContentTypeReader<JKITexture2D>

    {

        protected override JKITexture2D Read(ContentReader input, JKITexture2D existingInstance)

        {

             existingInstance.maskColor = new Color(input.ReadByte(),input.ReadByte(),input.ReadByte(),input.ReadByte());

            existingInstance.offset = new Point(input.ReadInt32(), input.ReadInt32());

            existingInstance.showTime = input.ReadInt32();

            int tamArray = input.ReadInt32();

            byte[] pixelData = new byte[tamArray];

            pixelData = input.ReadBytes(tamArray);

            existingInstance.SetData<byte>(pixelData);

 

            return existingInstance;

        }

    }

This was the rigth way to do that The code compile OK, but when i run the project it crash and i don't know why.

Please helpme.






Re: XNA Framework How can i obtain extra information from a File using Content importer?

Shawn Hargreaves - MSFT

I think you don't need to do so much work as that.

Using the WriteObject and ReadObject methods, you can write your Color and Point instances with one call each, and then write the Texture2DContent with just one more WriteObject call.

You don't need to bother writing out each individual field for embedded types, just WriteObject the whole thing and as long as there is a ContentTypeWriter for the type of that nested object, we'll recursively call into that other writer for you.






Re: XNA Framework How can i obtain extra information from a File using Content importer?

JuanK_solocodigo

OK Shawn, i already have a WriteObject - ReadObject Version of the assemblies, but they didn't work neither.

I believe that something very stupid is happening with my code but i can't detect it here, in my job, because my machine don't support pixel shader 1.1.

Exist any way to start XNA Graphic Device in Reference Rasterizer Mode

I was trying to do that but all the time when the Run method start XNA make the pixel Shader Valitation and don't allowme to start with reference rasterizer, at least not very easy as i spect.

 






Re: XNA Framework How can i obtain extra information from a File using Content importer?

Shawn Hargreaves - MSFT

What exactly is going wrong with the object based version Do you get an exception If so what type, and what is the exception message string





Re: XNA Framework How can i obtain extra information from a File using Content importer?

JuanK_solocodigo

The importer And processor:< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

    [ContentImporter(".jki", DisplayName = "Imagen De Multiples Frames JKI", DefaultProcessor = "Procesador para imagenes JKI")]

    public class JKIImageImporter : ContentImporter<JKITexture2DContent[]>

    {

        /// <summary>

        /// Importa el contenido de un archivo JKI al content pipeline de XNA

        /// </summary>

        /// <param name="filename">Nombre del archivo a procesar</param>

        /// <param name="context">Contexto para el content importer</param>

        /// <returns>Array de texturas extraidas del archivo</returns>

        public override JKITexture2DContent[] Import(string filename, ContentImporterContext context)

        {

            //Decodificador del archivo JKI

            DecodificadorJKI decodificador = new DecodificadorJKI();

            //Encabezado identificador de la imagen JKI

            EncabezadoFijo encabezado;

            //Mapeador de pixeles

            PixelBitmapContent<Rgba32> pixelHelper;

            //Array de textura a retornar

            JKITexture2DContent[] textureContent;

            //Array de bytes paa capturar la infromacion del archivo JKI

            byte[] byteArray;

            //Imagen JKI cargada desde archivo

            ImagenJKI<Color32> imagen32 = (ImagenJKI<Color32>)decodificador.CargaImagenJKIDesdeArchivo(

                                                          filename, out encabezado);

 

            //Inicializa el array de texturas con la cantidad de frames que existen en el archivo JKI

            textureContent = new JKITexture2DContent[imagen32.InformacionBase.NumCuadros];

 

            //Carga cada uno de los cuadros de archivo JKI al textureContent

            for (int i = 0; i < imagen32.InformacionBase.NumCuadros; i++)

            {

                //Inicializa un nuevo contenedor de datos de pixeles

                pixelHelper = new PixelBitmapContent<Rgba32>(imagen32.cuadrosDeImagen[ i ].Ancho, imagen32.cuadrosDeImagen[ i ].Alto);

                //Cargar la informacion de bytes para el archivo JKI Actual

                byteArray = ImagenJKI<Color32>.CuadroImagenJKIAByteArray(imagen32, (Int16)i);

                //Envia los datos de bytes al pixel helper

                pixelHelper.SetPixelData(byteArray);

                //Inicializa una nueva textura

                textureContent[ i ] = new JKITexture2DContent();

                //Carga la informacion de la imagen en la textura

                textureContent[ i ].Mipmaps = new MipmapChain(pixelHelper);

                //Guarda el desplazamiento de la imagen repsecto al origen

                textureContent[ i ].offset = new Point(imagen32.cuadrosDeImagen[ i ].Desplazamiento.X,

                                                     imagen32.cuadrosDeImagen[ i ].Desplazamiento.Y);

                //Guarda el tiempo de exhibicion de la imagen

                textureContent[ i ].showTime = imagen32.cuadrosDeImagen[ i ].Tiempo;

                //Guarda el color de mascara de la imagen

                textureContent[ i ].maskColor = new Color(imagen32.cuadrosDeImagen[ i ].ColorMascara.Rojo,

                                                        imagen32.cuadrosDeImagen[ i ].ColorMascara.Verde,

                                                        imagen32.cuadrosDeImagen[ i ].ColorMascara.Azul,

                                                        imagen32.cuadrosDeImagen[ i ].ColorMascara.Alpha

                                                        );

 

            }

            return textureContent;

        }

    }

    /// <summary>

    /// Procesador de Contenido para Archivos JKI para el content pipeline de XNA

    /// </summary>

    [ContentProcessor(DisplayName = "Procesador para imagenes JKI")]

    class JKIImageProcessor : ContentProcessor<JKITexture2DContent[], JKITexture2DContent[]>

    {

        /// <summary>

        /// Procesa la informacion enviada por los archivos JKI

        /// </summary>

        /// <param name="input">Array de contenido de texturas 2d</param>

        /// <param name="context">Contexto para el content processor</param>

        /// <returns>Array de texturas extraidas del archivo ya procesadas</returns>

        public override JKITexture2DContent[] Process(JKITexture2DContent[] input, ContentProcessorContext context)

        {

            for (int i = 0; i < input.Length; i++)

            {

                input[ i ] = (JKITexture2DContent)context.Convert<TextureContent,

                            TextureContent>((TextureContent)input[ i ], "SpriteTextureProcessor");

            }

 

            return input;

        }

    }

 

The Writer and Reader ( Object Version)

    [ContentTypeWriter]

    public class JKIContentWriter : ContentTypeWriter<JKITexture2DContent>

    {

        protected override void Write(ContentWriter output, JKITexture2DContent value)

        {

            byte[] pixelData = value.Mipmaps[0].GetPixelData();

            output.Write(pixelData.Length);

            output.Write(pixelData);

            output.WriteObject<Color>(value.MaskColor);

            output.WriteObject<Point>(value.Offset);

            output.Write(value.ShowTime);

        }

 

        public override string GetRuntimeReader(TargetPlatform targetPlatform)

        {

            return typeof(JKITexture2D).AssemblyQualifiedName;

        }

    }

 

    public class JKIContentReader : ContentTypeReader<JKITexture2D>

    {

        protected override JKITexture2D Read(ContentReader input, JKITexture2D existingInstance)

        {

            int tam = input.ReadInt32();

            byte[] pixelData = new byte[tam];

            pixelData = input.ReadBytes(tam);

            existingInstance.GetData<byte>(pixelData);

            existingInstance.maskColor = input.ReadObject<Color>();

            existingInstance.offset = input.ReadObject<Point>();

            existingInstance.showTime = input.ReadInt32();

            return existingInstance;

        }

 

        public JKIContentReader():base()

        {

 

        }

    }

The error Message Appears here

            if (loadAllContent)

            {

                imagenes = content.Load<JKITexture2D[]>("UF3");

 

            }

And this is the error message detail

Microsoft.Xna.Framework.Content.ContentLoadException was unhandled

  Message="Error loading \"UF3\". Cannot instantiate ContentTypeReader JKIXNAExtention.JKITexture2D, JKIXNAExtention, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null."

  Source="Microsoft.Xna.Framework"

  StackTrace:

       en Microsoft.Xna.Framework.Content.ContentTypeReaderManager.InstantiateTypeReader(String readerTypeName, ContentReader contentReader, ContentTypeReader& reader)

       en Microsoft.Xna.Framework.Content.ContentTypeReaderManager.GetTypeReader(String readerTypeName, ContentReader contentReader, List`1& newTypeReaders)

       en Microsoft.Xna.Framework.Content.ContentTypeReaderManager.ReadTypeManifest(Int32 typeCount, ContentReader contentReader)

       en Microsoft.Xna.Framework.Content.ContentReader.ReadHeader()

       en Microsoft.Xna.Framework.Content.ContentReader.ReadAsset[T]()

       en Microsoft.Xna.Framework.Content.ContentManager.Load[T](String assetName)

       en GraphicServicePrueba.Game1.LoadGraphicsContent(Boolean loadAllContent) en Game1.cs:linea 78

       en Microsoft.Xna.Framework.Game.Initialize()

       en GraphicServicePrueba.Game1.Initialize() en Game1.cs:linea 63

       en Microsoft.Xna.Framework.Game.Run()

       en GraphicServicePrueba.Program.Main(String[] args) en Program.cs:linea 16

 

I got in my house more screenshots about the error message, this information is available in this links:

http://pwp.etb.net.co/juancarlosruiz/error1.jpg

 

http://pwp.etb.net.co/juancarlosruiz/error2.jpg

 

http://pwp.etb.net.co/juancarlosruiz/errortext.txt






Re: XNA Framework How can i obtain extra information from a File using Content importer?

JuanK_solocodigo

I believe that the problem was solved.

take a look to this code in content Writer:

public override string GetRuntimeReader(TargetPlatform targetPlatform)

{

return typeof(JKITexture2D).AssemblyQualifiedName;

}

Here i would return the type of the associated Reader, so the right implementation would be:

public override string GetRuntimeReader(TargetPlatform targetPlatform)

{

return "JKIXNAExtention.JKIContentReader, JKIXNAExtention, Version=1.0.0.0, Culture=neutral";

//or

//return typeof(JKIContentReader).AssemblyQualifiedName;

}

As i said later.... something really stupid :S

this code:

return typeof(JKITexture2D).AssemblyQualifiedName;

Should be used in another overrided method:

public override string GetRuntimeType(TargetPlatform targetPlatform)

{

return typeof(JKITexture2D).AssemblyQualifiedName;

}

but i don't know if this is absolutly required.

This night i'll test the code, i hope that the code will work fine.