Exemple #1
0
        public void DumpErrors(string title)
        {
            int error = Il.ilGetError();

            while (error != 0)
            {
                Console.WriteLine(title + ": Error #" + error + " Message: " + Ilu.iluErrorString(error));
                error = Il.ilGetError();
            }
        }
        public static bool ReshapeToPowersOf2AndSave(Stream input, int size, string outputFileName)
        {
            InitializeIL();
            InitializeILU();

            // load the image
            ImageData data = new ImageData();
            int       imageID;

            // create and bind a new image
            Il.ilGenImages(1, out imageID);
            Il.ilBindImage(imageID);
            // create a temp buffer and copy the stream into it
            byte[] buffer = new byte[size];
            int    bytesRead = 0, byteOffset = 0, bytes = buffer.Length;

            do
            {
                bytesRead   = input.Read(buffer, byteOffset, bytes);
                bytes      -= bytesRead;
                byteOffset += bytesRead;
            } while (bytes > 0 && bytesRead > 0);

            Il.ilLoadL(Il.IL_TYPE_UNKNOWN, buffer, buffer.Length);
            // check errors
            int ilError = Il.ilGetError();

            if (ilError != Il.IL_NO_ERROR)
            {
                throw new AxiomException("Error while loading image data: '{0}'", Ilu.iluErrorString(ilError));
            }
            // determine dimensions & compute powers-of-2 reshape if needed
            int width     = Il.ilGetInteger(Il.IL_IMAGE_WIDTH);
            int height    = Il.ilGetInteger(Il.IL_IMAGE_HEIGHT);
            int newWidth  = (int)Math.Pow(2, Math.Floor(Math.Log(width, 2)));
            int newHeight = (int)Math.Pow(2, Math.Floor(Math.Log(height, 2)));

            if (width != newWidth || height != newHeight)
            {
                // reshape
                // set the scale function filter & scale
                Ilu.iluImageParameter(Ilu.ILU_FILTER, Ilu.ILU_BILINEAR); // .ILU_SCALE_BSPLINE);
                Ilu.iluScale(newWidth, newHeight, 1);
            }
            // save
            Il.ilSetInteger(Il.IL_JPG_QUALITY, 50);
            Il.ilSaveImage(outputFileName);
            // drop image
            Il.ilDeleteImages(1, ref imageID);
            return(true);
        }
Exemple #3
0
        public Image(string filename)
        {
            // create and bind a new image
            Il.ilGenImages(1, out imageID);
            Il.ilBindImage(imageID);

            // load the data into DevIL
            Il.ilLoadImage(filename);

            // check for an error
            int ilError = Il.ilGetError();

            if (ilError != Il.IL_NO_ERROR)
            {
                throw new Exception(string.Format("Error while decoding image data: '{0}'", Ilu.iluErrorString(ilError)));
            }

            format        = Il.ilGetInteger(Il.IL_IMAGE_FORMAT);
            bytesPerPixel = Math.Max(Il.ilGetInteger(Il.IL_IMAGE_BPC),
                                     Il.ilGetInteger(Il.IL_IMAGE_BYTES_PER_PIXEL));

            width  = Il.ilGetInteger(Il.IL_IMAGE_WIDTH);
            height = Il.ilGetInteger(Il.IL_IMAGE_HEIGHT);
            depth  = Il.ilGetInteger(Il.IL_IMAGE_DEPTH);
            stride = bytesPerPixel * width;

            // get the decoded data
            IntPtr ptr = Il.ilGetData();

            // copy the data into the byte array
            pBuffer = (byte *)ptr;
        }
Exemple #4
0
        public TaoImage(string filename)
        {
            FileStream s = new FileStream(filename, FileMode.Open);

            int imageID;

            // create and bind a new image
            Il.ilGenImages(1, out imageID);
            Il.ilBindImage(imageID);

            // create a temp buffer and write the stream into it
            byte[] tmpBuffer = new byte[s.Length];
            s.Read(tmpBuffer, 0, tmpBuffer.Length);

            // load the data into DevIL
            Il.ilLoadL(Il.IL_PNG, tmpBuffer, tmpBuffer.Length);

            // check for an error
            int ilError = Il.ilGetError();

            if (ilError != Il.IL_NO_ERROR)
            {
                throw new Exception(string.Format("Error while decoding image data: '{0}'", Ilu.iluErrorString(ilError)));
            }

            // flip the image so that the mosaics produced match what L3DT produces
            Ilu.iluFlipImage();

            format        = Il.ilGetInteger(Il.IL_IMAGE_FORMAT);
            bytesPerPixel = Math.Max(Il.ilGetInteger(Il.IL_IMAGE_BPC),
                                     Il.ilGetInteger(Il.IL_IMAGE_BYTES_PER_PIXEL));

            Width  = Il.ilGetInteger(Il.IL_IMAGE_WIDTH);
            Height = Il.ilGetInteger(Il.IL_IMAGE_HEIGHT);
            depth  = Il.ilGetInteger(Il.IL_IMAGE_DEPTH);

            // get the decoded data
            buffer = new byte[Width * Height * bytesPerPixel];
            IntPtr ptr = Il.ilGetData();

            // copy the data into the byte array
            unsafe
            {
                byte *pBuffer = (byte *)ptr;
                for (int i = 0; i < buffer.Length; i++)
                {
                    buffer[i] = pBuffer[i];
                }
            }

            // we won't be needing this anymore
            Il.ilDeleteImages(1, ref imageID);
        }
Exemple #5
0
        public override Codec.DecodeResult Decode(Stream input)
        {
            var imgData = new ImageData();
            var output  = new MemoryStream();

            int imageID;
            int imageFormat, bytesPerPixel;

            // create and bind a new image
            Il.ilGenImages(1, out imageID);
            Il.ilBindImage(imageID);

            // create a temp buffer and write the stream into it
            var buffer = new byte[input.Length];

            input.Read(buffer, 0, buffer.Length);

            // Put it right side up
            Il.ilEnable(Il.IL_ORIGIN_SET);
            Il.ilSetInteger(Il.IL_ORIGIN_MODE, Il.IL_ORIGIN_UPPER_LEFT);

            // Keep DXTC(compressed) data if present
            Il.ilSetInteger(Il.IL_KEEP_DXTC_DATA, Il.IL_TRUE);

            // load the data into DevIL
            Il.ilLoadL(this._ilType, buffer, buffer.Length);

            // check for an error
            var ilError = Il.ilGetError();

            if (ilError != Il.IL_NO_ERROR)
            {
                throw new AxiomException("Error while decoding image data: '{0}'", Ilu.iluErrorString(ilError));
            }

            imageFormat = Il.ilGetInteger(Il.IL_IMAGE_FORMAT);
            var imageType = Il.ilGetInteger(Il.IL_IMAGE_TYPE);

            // Convert image if imageType is incompatible with us (double or long)
            if (imageType != Il.IL_BYTE && imageType != Il.IL_UNSIGNED_BYTE && imageType != Il.IL_FLOAT &&
                imageType != Il.IL_UNSIGNED_SHORT && imageType != Il.IL_SHORT)
            {
                Il.ilConvertImage(imageFormat, Il.IL_FLOAT);
                imageType = Il.IL_FLOAT;
            }

            // Converted paletted images
            if (imageFormat == Il.IL_COLOR_INDEX)
            {
                Il.ilConvertImage(Il.IL_BGRA, Il.IL_UNSIGNED_BYTE);
                imageFormat = Il.IL_BGRA;
                imageType   = Il.IL_UNSIGNED_BYTE;
            }

            // populate the image data
            bytesPerPixel = Il.ilGetInteger(Il.IL_IMAGE_BYTES_PER_PIXEL);

            imgData.format     = ILUtil.Convert(imageFormat, imageType);
            imgData.width      = Il.ilGetInteger(Il.IL_IMAGE_WIDTH);
            imgData.height     = Il.ilGetInteger(Il.IL_IMAGE_HEIGHT);
            imgData.depth      = Il.ilGetInteger(Il.IL_IMAGE_DEPTH);
            imgData.numMipMaps = Il.ilGetInteger(Il.IL_NUM_MIPMAPS);

            if (imgData.format == PixelFormat.Unknown)
            {
                throw new AxiomException("Unsupported devil format ImageFormat={0} ImageType={1}", imageFormat, imageType);
            }

            // Check for cubemap
            var numFaces = Il.ilGetInteger(Il.IL_NUM_IMAGES) + 1;

            if (numFaces == 6)
            {
                imgData.flags |= ImageFlags.CubeMap;
            }
            else
            {
                numFaces = 1;                 // Support only 1 or 6 face images for now
            }

            // Keep DXT data (if present at all and the GPU supports it)
            var dxtFormat = Il.ilGetInteger(Il.IL_DXTC_DATA_FORMAT);

            if (dxtFormat != Il.IL_DXT_NO_COMP &&
                Root.Instance.RenderSystem.Capabilities.HasCapability(Axiom.Graphics.Capabilities.TextureCompressionDXT))
            {
                imgData.format = ILUtil.Convert(dxtFormat, imageType);
                imgData.flags |= ImageFlags.Compressed;

                // Validate that this devil version loads DXT mipmaps
                if (imgData.numMipMaps > 0)
                {
                    Il.ilBindImage(imageID);
                    Il.ilActiveMipmap(1);
                    if ((uint)Il.ilGetInteger(Il.IL_DXTC_DATA_FORMAT) != dxtFormat)
                    {
                        imgData.numMipMaps = 0;
                        LogManager.Instance.Write(
                            "Warning: Custom mipmaps for compressed image were ignored because they are not loaded by this DevIL version.");
                    }
                }
            }

            // Calculate total size from number of mipmaps, faces and size
            imgData.size = Image.CalculateSize(imgData.numMipMaps, numFaces, imgData.width, imgData.height, imgData.depth,
                                               imgData.format);

            // get the decoded data
            BufferBase BufferHandle;

            // Dimensions of current mipmap
            var width  = imgData.width;
            var height = imgData.height;
            var depth  = imgData.depth;

            // Transfer data
            for (var mip = 0; mip <= imgData.numMipMaps; ++mip)
            {
                for (var i = 0; i < numFaces; ++i)
                {
                    Il.ilBindImage(imageID);
                    if (numFaces > 1)
                    {
                        Il.ilActiveImage(i);
                    }
                    if (imgData.numMipMaps > 0)
                    {
                        Il.ilActiveMipmap(mip);
                    }

                    // Size of this face
                    var imageSize = PixelUtil.GetMemorySize(width, height, depth, imgData.format);
                    buffer = new byte[imageSize];

                    if ((imgData.flags & ImageFlags.Compressed) != 0)
                    {
                        // Compare DXT size returned by DevIL with our idea of the compressed size
                        if (imageSize == Il.ilGetDXTCData(IntPtr.Zero, 0, dxtFormat))
                        {
                            // Retrieve data from DevIL
                            using (BufferHandle = BufferBase.Wrap(buffer))
                            {
                                Il.ilGetDXTCData(BufferHandle.Pin(), imageSize, dxtFormat);
                                BufferHandle.UnPin();
                            }
                        }
                        else
                        {
                            LogManager.Instance.Write("Warning: compressed image size mismatch, devilsize={0} oursize={1}",
                                                      Il.ilGetDXTCData(IntPtr.Zero, 0, dxtFormat), imageSize);
                        }
                    }
                    else
                    {
                        // Retrieve data from DevIL
                        using (BufferHandle = BufferBase.Wrap(buffer))
                        {
                            var dst = new PixelBox(width, height, depth, imgData.format, BufferHandle);
                            ILUtil.ConvertFromIL(dst);
                        }
                    }

                    // write the decoded data to the output stream
                    output.Write(buffer, 0, buffer.Length);
                }

                // Next mip
                if (width != 1)
                {
                    width /= 2;
                }

                if (height != 1)
                {
                    height /= 2;
                }

                if (depth != 1)
                {
                    depth /= 2;
                }
            }

            // Restore IL state
            Il.ilDisable(Il.IL_ORIGIN_SET);
            Il.ilDisable(Il.IL_FORMAT_SET);

            Il.ilDeleteImages(1, ref imageID);

            return(new DecodeResult(output, imgData));
        }
Exemple #6
0
        public override void EncodeToFile(Stream input, string outFileName, Codec.CodecData codecData)
        {
            int imageID;

            // create and bind a new image
            Il.ilGenImages(1, out imageID);
            Il.ilBindImage(imageID);

            var buffer = new byte[input.Length];

            input.Read(buffer, 0, buffer.Length);

            var imgData = (ImageData)codecData;

            PixelBox src;

            using (var bufHandle = BufferBase.Wrap(buffer))
            {
                src = new PixelBox(imgData.width, imgData.height, imgData.depth, imgData.format, bufHandle);
            }

            try
            {
                // Convert image from Axiom to current IL image
                ILUtil.ConvertToIL(src);
            }
            catch (Exception ex)
            {
                LogManager.Instance.Write("IL Failed image conversion :", ex.Message);
            }

            // flip the image
            Ilu.iluFlipImage();

            // save the image to file
            Il.ilSaveImage(outFileName);

            var error = Il.ilGetError();

            if (error != Il.IL_NO_ERROR)
            {
                LogManager.Instance.Write("IL Error, could not save file: {0} : {1}", outFileName, Ilu.iluErrorString(error));
            }

            Il.ilDeleteImages(1, ref imageID);
        }
Exemple #7
0
        // create the texture and call the callback
        public void Notify()
        {
            Debug.Assert(Done);

            bool loaded = false;

            // need these in the callback for scaling images into picture frames (friendworld)
            int initialWidth  = 0;
            int initialHeight = 0;

            try
            {
                if (sourceBuffer != null)
                {
                    int imageID;

                    // create and bind a new image
                    Il.ilGenImages(1, out imageID);
                    Il.ilBindImage(imageID);

                    // Put it right side up
                    Il.ilEnable(Il.IL_ORIGIN_SET);
                    Il.ilSetInteger(Il.IL_ORIGIN_MODE, Il.IL_ORIGIN_UPPER_LEFT);

                    // Keep DXTC(compressed) data if present
                    Il.ilSetInteger(Il.IL_KEEP_DXTC_DATA, Il.IL_TRUE);

                    // load the data into DevIL
                    Il.ilLoadL(this.ilImageType, sourceBuffer, sourceBuffer.Length);

                    // check for an error
                    int ilError = Il.ilGetError();

                    if (ilError != Il.IL_NO_ERROR)
                    {
                        log.ErrorFormat("TextureFetcher: Error while decoding image data: '{0}'", Ilu.iluErrorString(ilError));
                        throw new Exception("TextureFetcher: Error while decoding image data: " + Ilu.iluErrorString(ilError));
                    }

                    int ilFormat  = Il.ilGetInteger(Il.IL_IMAGE_FORMAT);
                    int imageType = Il.ilGetInteger(Il.IL_IMAGE_TYPE);

                    // force conversion to 24-bit RGB image
                    if ((imageType != Il.IL_BYTE && imageType != Il.IL_UNSIGNED_BYTE) || ilFormat != Il.IL_BGR)
                    {
                        ilFormat  = Il.IL_BGR;
                        imageType = Il.IL_UNSIGNED_BYTE;

                        Il.ilConvertImage(ilFormat, imageType);
                    }

                    PixelFormat format     = PixelFormat.R8G8B8;
                    int         width      = Il.ilGetInteger(Il.IL_IMAGE_WIDTH);
                    int         height     = Il.ilGetInteger(Il.IL_IMAGE_HEIGHT);
                    int         depth      = Il.ilGetInteger(Il.IL_IMAGE_DEPTH);
                    int         numMipMaps = Il.ilGetInteger(Il.IL_NUM_MIPMAPS) + 1;
                    int         numFaces   = Il.ilGetInteger(Il.IL_NUM_IMAGES) + 1;

                    initialWidth  = width;
                    initialHeight = height;

                    if (numFaces > 1 || numMipMaps > 1)
                    {
                        log.WarnFormat("TextureFetcher: ignoring extra faces or mipmaps: faces={0}: mipmaps={1}", numFaces, numMipMaps);
                    }

                    if (destHeight == 0)
                    {
                        destHeight = height;
                    }
                    if (destWidth == 0)
                    {
                        destWidth = width;
                    }

                    int scaleX;
                    int scaleY;
                    int topFill    = 0;
                    int bottomFill = 0;
                    int leftFill   = 0;
                    int rightFill  = 0;

                    if (keepAspect)
                    {
                        float scaleWidthFactor  = (float)width / (float)destWidth;
                        float scaleHeightFactor = (float)height / (float)destHeight;
                        if (scaleWidthFactor > scaleHeightFactor)
                        {
                            scaleX     = destWidth;
                            scaleY     = (int)(height / scaleWidthFactor);
                            topFill    = (destHeight - scaleY) / 2;
                            bottomFill = destHeight - scaleY - topFill;
                        }
                        else
                        {
                            scaleX    = (int)(width / scaleHeightFactor);
                            scaleY    = destHeight;
                            leftFill  = (destWidth - scaleX) / 2;
                            rightFill = destWidth - scaleX - leftFill;
                        }
                    }
                    else
                    {
                        scaleX = destWidth;
                        scaleY = destWidth;
                    }

                    // scale the image
                    if ((scaleX != width) || (scaleY != height))
                    {
                        DoScale(scaleX, scaleY);

                        width  = scaleX;
                        height = scaleY;
                    }

                    int imageSize = PixelUtil.GetMemorySize(destWidth, destHeight, depth, format);

                    // set up buffer for the decoded data
                    byte[] buffer = new byte[imageSize];

                    byte fillRed   = (byte)(fillColor.r * 255.0);
                    byte fillGreen = (byte)(fillColor.g * 255.0);
                    byte fillBlue  = (byte)(fillColor.b * 255.0);

                    if (keepAspect)
                    {
                        // fill top
                        for (int y = 0; y < topFill; y++)
                        {
                            int offset = y * destWidth * 3;
                            for (int x = 0; x < destWidth; x++)
                            {
                                buffer[offset++] = fillBlue;
                                buffer[offset++] = fillGreen;
                                buffer[offset++] = fillRed;
                            }
                        }

                        // copy the data
                        IntPtr srcPtr    = Il.ilGetData();
                        int    srcOffset = 0;
                        unsafe
                        {
                            byte *srcBytes = (byte *)srcPtr.ToPointer();

                            for (int y = topFill; y < topFill + height; y++)
                            {
                                int offset = y * destWidth * 3;
                                for (int x = 0; x < leftFill; x++)
                                {
                                    buffer[offset++] = fillBlue;
                                    buffer[offset++] = fillGreen;
                                    buffer[offset++] = fillRed;
                                }

                                for (int x = 0; x < width; x++)
                                {
                                    buffer[offset++] = srcBytes[srcOffset++];
                                    buffer[offset++] = srcBytes[srcOffset++];
                                    buffer[offset++] = srcBytes[srcOffset++];
                                }

                                for (int x = 0; x < rightFill; x++)
                                {
                                    buffer[offset++] = fillBlue;
                                    buffer[offset++] = fillGreen;
                                    buffer[offset++] = fillRed;
                                }
                            }
                        }

                        // fill bottom
                        for (int y = topFill + height; y < destHeight; y++)
                        {
                            int offset = y * destWidth * 3;
                            for (int x = 0; x < destWidth; x++)
                            {
                                buffer[offset++] = fillBlue;
                                buffer[offset++] = fillGreen;
                                buffer[offset++] = fillRed;
                            }
                        }
                    }
                    else
                    {
                        // copy the data
                        IntPtr srcPtr = Il.ilGetData();
                        unsafe
                        {
                            byte *srcBytes = (byte *)srcPtr.ToPointer();
                            for (int i = 0; i < imageSize; i++)
                            {
                                buffer[i] = srcBytes[i];
                            }
                        }
                    }

                    // Restore IL state
                    Il.ilDisable(Il.IL_ORIGIN_SET);
                    Il.ilDisable(Il.IL_FORMAT_SET);

                    // we won't be needing this anymore
                    Il.ilDeleteImages(1, ref imageID);

                    Image resultImage = Image.FromDynamicImage(buffer, destWidth, destHeight, depth, format);

                    TextureManager.Instance.LoadImage(textureName, resultImage);
                    loaded = true;
                    resultImage.Dispose();
                }
            }
            catch (Exception ex)
            {
                LogUtil.LogUtil.ExceptionLog.ErrorFormat("TextureFetcher: exception while decoding image: {0}", ex);
            }
            finally
            {
                doneHandler(textureName, initialWidth, initialHeight, loaded);
            }
            return;
        }
        public override object Decode(Stream input, Stream output, params object[] args)
        {
            ImageData data = new ImageData();

            int imageID;
            int format, bytesPerPixel, imageType;

            // create and bind a new image
            Il.ilGenImages(1, out imageID);
            Il.ilBindImage(imageID);

            // Put it right side up
            Il.ilEnable(Il.IL_ORIGIN_SET);
            Il.ilSetInteger(Il.IL_ORIGIN_MODE, Il.IL_ORIGIN_UPPER_LEFT);

            // Keep DXTC(compressed) data if present
            Il.ilSetInteger(Il.IL_KEEP_DXTC_DATA, Il.IL_TRUE);

            // create a temp buffer and write the stream into it
            byte[] buffer = new byte[input.Length];
            input.Read(buffer, 0, buffer.Length);

            // load the data into DevIL
            Il.ilLoadL(this.ILType, buffer, buffer.Length);

            // check for an error
            int ilError = Il.ilGetError();

            if (ilError != Il.IL_NO_ERROR)
            {
                throw new AxiomException("Error while decoding image data: '{0}'", Ilu.iluErrorString(ilError));
            }

            format    = Il.ilGetInteger(Il.IL_IMAGE_FORMAT);
            imageType = Il.ilGetInteger(Il.IL_IMAGE_TYPE);
            //bytesPerPixel = Math.Max(Il.ilGetInteger(Il.IL_IMAGE_BPC),
            //                         Il.ilGetInteger(Il.IL_IMAGE_BYTES_PER_PIXEL));

            // Convert image if ImageType is incompatible with us (double or long)
            if (imageType != Il.IL_BYTE && imageType != Il.IL_UNSIGNED_BYTE &&
                imageType != Il.IL_FLOAT &&
                imageType != Il.IL_UNSIGNED_SHORT && imageType != Il.IL_SHORT)
            {
                Il.ilConvertImage(format, Il.IL_FLOAT);
                imageType = Il.IL_FLOAT;
            }
            // Converted paletted images
            if (format == Il.IL_COLOUR_INDEX)
            {
                Il.ilConvertImage(Il.IL_BGRA, Il.IL_UNSIGNED_BYTE);
                format    = Il.IL_BGRA;
                imageType = Il.IL_UNSIGNED_BYTE;
            }

            bytesPerPixel = Il.ilGetInteger(Il.IL_IMAGE_BYTES_PER_PIXEL);

            // populate the image data
            data.format     = ILUtil.ConvertFromILFormat(format, imageType);
            data.width      = Il.ilGetInteger(Il.IL_IMAGE_WIDTH);
            data.height     = Il.ilGetInteger(Il.IL_IMAGE_HEIGHT);
            data.depth      = Il.ilGetInteger(Il.IL_IMAGE_DEPTH);
            data.numMipMaps = Il.ilGetInteger(Il.IL_NUM_MIPMAPS);
            data.flags      = 0;

            if (data.format == PixelFormat.Unknown)
            {
                Il.ilDeleteImages(1, ref imageID);
                throw new AxiomException("Unsupported DevIL format: ImageFormat = {0:x} ImageType = {1:x}", format, imageType);
            }

            // Check for cubemap
            // int cubeflags = Il.ilGetInteger(Il.IL_IMAGE_CUBEFLAGS);
            int numFaces = Il.ilGetInteger(Il.IL_NUM_IMAGES) + 1;

            if (numFaces == 6)
            {
                data.flags |= ImageFlags.CubeMap;
            }
            else
            {
                numFaces = 1; // Support only 1 or 6 face images for now
            }
            // Keep DXT data (if present at all and the GPU supports it)
            int dxtFormat = Il.ilGetInteger(Il.IL_DXTC_DATA_FORMAT);

            if (dxtFormat != Il.IL_DXT_NO_COMP &&
                Root.Instance.RenderSystem.Caps.CheckCap(Axiom.Graphics.Capabilities.TextureCompressionDXT))
            {
                data.format = ILUtil.ConvertFromILFormat(dxtFormat, imageType);
                data.flags |= ImageFlags.Compressed;

                // Validate that this devil version saves DXT mipmaps
                if (data.numMipMaps > 0)
                {
                    Il.ilBindImage(imageID);
                    Il.ilActiveMipmap(1);
                    if (Il.ilGetInteger(Il.IL_DXTC_DATA_FORMAT) != dxtFormat)
                    {
                        data.numMipMaps = 0;
                        LogManager.Instance.Write("Warning: Custom mipmaps for compressed image were ignored because they are not loaded by this DevIL version");
                    }
                }
            }

            // Calculate total size from number of mipmaps, faces and size
            data.size = Image.CalculateSize(data.numMipMaps, numFaces,
                                            data.width, data.height,
                                            data.depth, data.format);

            // set up buffer for the decoded data
            buffer = new byte[data.size];
            // Pin the buffer, so we can use our PixelBox methods on it
            GCHandle bufGCHandle = new GCHandle();

            bufGCHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
            IntPtr bufPtr = bufGCHandle.AddrOfPinnedObject();

            int offset = 0;

            // Dimensions of current mipmap
            int width  = data.width;
            int height = data.height;
            int depth  = data.depth;

            // Transfer data
            for (int mip = 0; mip <= data.numMipMaps; ++mip)
            {
                for (int i = 0; i < numFaces; ++i)
                {
                    Il.ilBindImage(imageID);
                    if (numFaces > 1)
                    {
                        Il.ilActiveImage(i);
                    }
                    if (data.numMipMaps > 0)
                    {
                        Il.ilActiveMipmap(mip);
                    }
                    /// Size of this face
                    int imageSize = PixelUtil.GetMemorySize(width, height, depth, data.format);
                    if ((data.flags & ImageFlags.Compressed) != 0)
                    {
                        // Compare DXT size returned by DevIL with our idea of the compressed size
                        if (imageSize == Il.ilGetDXTCData(IntPtr.Zero, 0, dxtFormat))
                        {
                            // Retrieve data from DevIL
                            byte[] tmpBuffer = new byte[imageSize];
                            Il.ilGetDXTCData(tmpBuffer, imageSize, dxtFormat);
                            // Copy the data into our output buffer
                            Array.Copy(tmpBuffer, 0, buffer, offset, tmpBuffer.Length);
                        }
                        else
                        {
                            LogManager.Instance.Write("Warning: compressed image size mismatch, devilsize={0} oursize={1}",
                                                      Il.ilGetDXTCData(IntPtr.Zero, 0, dxtFormat), imageSize);
                        }
                    }
                    else
                    {
                        /// Retrieve data from DevIL
                        PixelBox dst = new PixelBox(width, height, depth, data.format, bufPtr);
                        dst.Offset = offset;
                        ILUtil.ToAxiom(dst);
                    }
                    offset += imageSize;
                }

                /// Next mip
                if (width != 1)
                {
                    width /= 2;
                }
                if (height != 1)
                {
                    height /= 2;
                }
                if (depth != 1)
                {
                    depth /= 2;
                }
            }

            // Restore IL state
            Il.ilDisable(Il.IL_ORIGIN_SET);
            Il.ilDisable(Il.IL_FORMAT_SET);

            // we won't be needing this anymore
            Il.ilDeleteImages(1, ref imageID);

            output.Write(buffer, 0, buffer.Length);


            // Free the buffer we allocated for the conversion.
            // I used bufPtr to store my data while I converted it.
            // I need to free it here.  This invalidates bufPtr.
            // My data has already been copied to output.
            if (bufGCHandle.IsAllocated)
            {
                bufGCHandle.Free();
            }

            return(data);
        }