Exemple #1
0
        /// <summary>
        /// Function to retrieve palette information for indexed images.
        /// </summary>
        /// <param name="wic">The WIC interface.</param>
        /// <param name="bitmap">The bitmap to derive the palette from (only used when encoding).</param>
        /// <returns>
        /// A tuple containing the palette data, alpha percentage and the type of palette.
        /// </returns>
        internal override Tuple <Palette, double, BitmapPaletteType> GetPaletteInfo(GorgonWICImage wic, Bitmap bitmap)
        {
            Palette palette;

            if (Palette.Count == 0)
            {
                // If decoding, just return the default, otherwise we'll need to generate from the frame.
                if (bitmap == null)
                {
                    return(base.GetPaletteInfo(wic, null));
                }

                palette = new Palette(wic.Factory);
                palette.Initialize(bitmap, 256, true);

                return(new Tuple <Palette, double, BitmapPaletteType>(palette, AlphaThresholdPercent, BitmapPaletteType.Custom));
            }

            // Generate from our custom palette.
            var paletteColors = new DX.Color4[256];
            int size          = paletteColors.Length.Min(Palette.Count);

            for (int i = 0; i < size; i++)
            {
                paletteColors[i] = Palette[i].SharpDXColor4;
            }

            palette = new Palette(wic.Factory);
            palette.Initialize(paletteColors);

            return(new Tuple <Palette, double, BitmapPaletteType>(palette, AlphaThresholdPercent, BitmapPaletteType.Custom));
        }
        /// <summary>
        /// Function to create 2D Gorgon image data from a single System.Drawing.Image.
        /// </summary>
        /// <param name="wic">Windows Imaging Component interface to use.</param>
        /// <param name="image">An image to convert.</param>
        /// <param name="options">Options for conversion.</param>
        /// <returns>The converted image data.</returns>
        public static GorgonImageData Create2DImageDataFromImage(GorgonWICImage wic, Image image, GorgonGDIOptions options)
        {
            if (options.Format == BufferFormat.Unknown)
            {
                options.Format = GetBufferFormat(image.PixelFormat);
            }

            if (options.Format == BufferFormat.Unknown)
            {
                throw new GorgonException(GorgonResult.FormatNotSupported,
                                          string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, image.PixelFormat));
            }

            if (options.Width < 1)
            {
                options.Width = image.Width;
            }

            if (options.Height < 1)
            {
                options.Height = image.Height;
            }

            // Specify 0 to generate a full mip chain.
            options.MipCount = options.MipCount < 1
                                                   ? GorgonImageData.GetMaxMipCount(options.Width, options.Height)
                                                   : options.MipCount.Min(GorgonImageData.GetMaxMipCount(options.Width, options.Height));

            // Create our settings.
            var settings = new GorgonTexture2DSettings
            {
                Width      = options.Width,
                Height     = options.Height,
                MipCount   = options.MipCount,
                ArrayCount = 1,
                Format     = options.Format,
                AllowUnorderedAccessViews = options.AllowUnorderedAccess,
                ShaderViewFormat          = options.ViewFormat,
                Usage = options.Usage
            };

            // Create our image data.
            var data = new GorgonImageData(settings);

            // Using the image, convert to a WIC bitmap object.
            using (Bitmap bitmap = wic.CreateWICImageFromImage(image))
            {
                for (int mipLevel = 0; mipLevel < options.MipCount; mipLevel++)
                {
                    var buffer = data.Buffers[mipLevel];
                    wic.AddWICBitmapToImageData(bitmap, options.Filter, options.Dither, buffer, options.UseClipping);
                }
            }

            return(data);
        }
Exemple #3
0
 /// <summary>
 /// Function to retrieve meta data from the image.
 /// </summary>
 /// <param name="wic">WIC interface.</param>
 /// <param name="decoder">Decoder for the image.</param>
 /// <param name="frame">Frame in the image to decode.</param>
 /// <param name="bestFormatMatch">The best match for the pixel format.</param>
 /// <returns>Settings for the new image.</returns>
 internal IImageSettings ReadMetaData(GorgonWICImage wic, BitmapDecoder decoder, BitmapFrameDecode frame, out Guid bestFormatMatch)
 {
     return(new GorgonTexture2DSettings
     {
         Width = frame.Size.Width,
         Height = frame.Size.Height,
         MipCount = 1,
         ArrayCount = (CodecUseAllFrames && SupportsMultipleFrames) ? decoder.FrameCount : 1,
         Format = wic.FindBestFormat(frame.PixelFormat, DecodeFlags, out bestFormatMatch)
     });
 }
Exemple #4
0
        /// <summary>
        /// Function to read the data from a frame.
        /// </summary>
        /// <param name="wic">WIC interface.</param>
        /// <param name="data">Image data to populate.</param>
        /// <param name="srcFormat">Source image format.</param>
        /// <param name="convertFormat">Conversion format.</param>
        /// <param name="frame">Frame containing the image data.</param>
        private void ReadFrame(GorgonWICImage wic, GorgonImageData data, Guid srcFormat, Guid convertFormat, BitmapFrameDecode frame)
        {
            var buffer = data.Buffers[0];

            // We don't need to convert, so just leave.
            if ((convertFormat == Guid.Empty) || (srcFormat == convertFormat))
            {
                frame.CopyPixels(buffer.PitchInformation.RowPitch, buffer.Data.BasePointer, buffer.PitchInformation.SlicePitch);
                return;
            }

            // Perform conversion.
            using (var converter = new FormatConverter(wic.Factory))
            {
                bool isIndexed = ((frame.PixelFormat == PixelFormat.Format8bppIndexed) ||
                                  (frame.PixelFormat == PixelFormat.Format4bppIndexed) ||
                                  (frame.PixelFormat == PixelFormat.Format2bppIndexed) ||
                                  (frame.PixelFormat == PixelFormat.Format1bppIndexed));
                Tuple <Palette, double, BitmapPaletteType> paletteInfo = null;

                try
                {
                    // If the pixel format is indexed, then retrieve a palette.
                    if (isIndexed)
                    {
                        paletteInfo = GetPaletteInfo(wic, null);
                    }

                    // If we've defined a palette for an indexed image, then copy it to a bitmap and set its palette.
                    if ((paletteInfo != null) && (paletteInfo.Item1 != null))
                    {
                        using (var tempBitmap = new Bitmap(wic.Factory, frame, BitmapCreateCacheOption.CacheOnDemand))
                        {
                            tempBitmap.Palette = paletteInfo.Item1;
                            converter.Initialize(tempBitmap, convertFormat, (BitmapDitherType)Dithering, paletteInfo.Item1, paletteInfo.Item2, paletteInfo.Item3);
                            converter.CopyPixels(buffer.PitchInformation.RowPitch, buffer.Data.BasePointer, buffer.PitchInformation.SlicePitch);
                        }

                        return;
                    }

                    // Only apply palettes to indexed image data.
                    converter.Initialize(frame, convertFormat, (BitmapDitherType)Dithering, null, 0.0, BitmapPaletteType.Custom);
                    converter.CopyPixels(buffer.PitchInformation.RowPitch, buffer.Data.BasePointer, buffer.PitchInformation.SlicePitch);
                }
                finally
                {
                    if ((paletteInfo != null) && (paletteInfo.Item1 != null))
                    {
                        paletteInfo.Item1.Dispose();
                    }
                }
            }
        }
        /// <summary>
        /// Function to create an array of System.Drawing.Images from an image data object.
        /// </summary>
        /// <param name="imageData">Image data to process.</param>
        /// <returns>A list of GDI+ images.</returns>
        public static Image[] CreateGDIImagesFromImageData(GorgonImageData imageData)
        {
            PixelFormat?format = GetPixelFormat(imageData.Settings.Format);

            Bitmap[] bitmaps = null;
            Image[]  images;

            if (format == null)
            {
                format = GetPixelFormat(imageData.Settings.Format);

                if (format == null)
                {
                    throw new GorgonException(GorgonResult.FormatNotSupported,
                                              string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, imageData.Settings.Format));
                }
            }

            using (var wic = new GorgonWICImage())
            {
                try
                {
                    bitmaps = wic.CreateWICBitmapsFromImageData(imageData);
                    images  = new Image[bitmaps.Length];

                    for (int i = 0; i < bitmaps.Length; i++)
                    {
                        images[i] = wic.CreateGDIImageFromWICBitmap(bitmaps[i], format.Value);
                    }
                }
                finally
                {
                    // Clean up.
                    if (bitmaps != null)
                    {
                        foreach (var bitmap in bitmaps)
                        {
                            bitmap.Dispose();
                        }
                    }
                }
            }

            return(images);
        }
Exemple #6
0
        /// <summary>
        /// Function to perform any post processing on image data.
        /// </summary>
        internal void PostProcess(GorgonImageData data)
        {
            IImageSettings destSettings = data.Settings.Clone();
            int            width        = Width > 0 ? Width : data.Settings.Width;
            int            height       = Height > 0 ? Height : data.Settings.Height;
            int            mipCount     = MipCount > 0 ? MipCount : data.Settings.MipCount;
            BufferFormat   format       = (Format != BufferFormat.Unknown) ? Format : data.Settings.Format;
            Rectangle      newSize      = Rectangle.Empty;
            int            mipStart     = 0;
            var            sourceInfo   = GorgonBufferFormatInfo.GetInfo(data.Settings.Format);
            var            destInfo     = GorgonBufferFormatInfo.GetInfo(format);

            // First, confirm whether we can perform format conversions.
            using (var wic = new GorgonWICImage())
            {
                Guid srcPixelFormat  = wic.GetGUID(data.Settings.Format);
                Guid destPixelFormat = wic.GetGUID(format);

                // Do nothing if we can't do anything with the source format.
                if (srcPixelFormat == Guid.Empty)
                {
                    return;
                }

                // Cancel conversion if we're using the same format.
                if (srcPixelFormat == destPixelFormat)
                {
                    destPixelFormat = Guid.Empty;
                }

                // Get the new size.
                if ((width != data.Settings.Width) || (height != data.Settings.Height))
                {
                    newSize = new Rectangle(0, 0, width, height);
                }

                // Set up destination buffer settings.
                destSettings.Format   = format;
                destSettings.Width    = width;
                destSettings.Height   = height;
                destSettings.MipCount = mipCount;

                // Ensure we don't go over the maximum.
                int maxMips = GorgonImageData.GetMaxMipCount(destSettings);

                if (mipCount > maxMips)
                {
                    mipCount = maxMips;
                }

                // Nothing's going to happen here, so leave.
                if ((destPixelFormat == Guid.Empty) && (newSize == Rectangle.Empty) && (mipCount == 1))
                {
                    return;
                }

                // Create our worker buffer.
                GorgonImageData destData;
                using (destData = new GorgonImageData(destSettings))
                {
                    // The first step is to convert and resize our images:
                    if ((destPixelFormat != Guid.Empty) || (newSize != Rectangle.Empty))
                    {
                        for (int array = 0; array < destSettings.ArrayCount; array++)
                        {
                            // We're not going to copy mip levels at this point, that will come in the next step.
                            for (int depth = 0; depth < destSettings.Depth; depth++)
                            {
                                // Get our source/destination buffers.
                                var sourceBuffer = data.Buffers[0, data.Settings.ImageType == ImageType.Image3D ? depth : array];
                                var destBuffer   = destData.Buffers[0, data.Settings.ImageType == ImageType.Image3D ? depth : array];

                                var dataRect = new DataRectangle(sourceBuffer.Data.BasePointer, sourceBuffer.PitchInformation.RowPitch);

                                // Create a temporary WIC bitmap to work with.
                                using (var bitmap = new Bitmap(wic.Factory, sourceBuffer.Width, sourceBuffer.Height, srcPixelFormat, dataRect, sourceBuffer.PitchInformation.SlicePitch))
                                {
                                    wic.TransformImageData(bitmap,
                                                           destBuffer.Data.BasePointer,
                                                           destBuffer.PitchInformation.RowPitch,
                                                           destBuffer.PitchInformation.SlicePitch,
                                                           destPixelFormat,
                                                           sourceInfo.IssRGB,
                                                           destInfo.IssRGB,
                                                           Dithering,
                                                           newSize,
                                                           Clip,
                                                           Filter);
                                }
                            }
                        }

                        // Adjust the mip map starting point.
                        mipStart = 1;
                    }

                    // Next, we need to build mip maps.
                    if (destSettings.MipCount > 1)
                    {
                        // The first step is to convert and resize our images:
                        for (int array = 0; array < destSettings.ArrayCount; array++)
                        {
                            int mipDepth = destSettings.Depth;

                            for (int mip = mipStart; mip < destSettings.MipCount; mip++)
                            {
                                // We're not going to copy mip levels at this point, that will come in the next step.
                                for (int depth = 0; depth < mipDepth; depth++)
                                {
                                    // Get our source/destination buffers.
                                    var sourceBuffer = destData.Buffers[0, data.Settings.ImageType == ImageType.Image3D ? (destSettings.Depth / mipDepth) * depth : array];
                                    var destBuffer   = destData.Buffers[mip, data.Settings.ImageType == ImageType.Image3D ? depth : array];

                                    var dataRect = new DataRectangle(sourceBuffer.Data.BasePointer, sourceBuffer.PitchInformation.RowPitch);

                                    // Create a temporary WIC bitmap to work with.
                                    using (var bitmap = new Bitmap(wic.Factory, sourceBuffer.Width, sourceBuffer.Height, srcPixelFormat, dataRect, sourceBuffer.PitchInformation.SlicePitch))
                                    {
                                        wic.TransformImageData(bitmap, destBuffer.Data.BasePointer, destBuffer.PitchInformation.RowPitch, destBuffer.PitchInformation.SlicePitch,
                                                               Guid.Empty, false, false, ImageDithering.None, new Rectangle(0, 0, destBuffer.Width, destBuffer.Height), false, Filter);
                                    }
                                }

                                if (mipDepth > 1)
                                {
                                    mipDepth >>= 1;
                                }
                            }
                        }
                    }

                    // Update our data.
                    data.TakeOwnership(destData);
                }
            }
        }
        /// <summary>
        /// Function to create a 3D Gorgon image data from multiple System.Drawing.Images.
        /// </summary>
        /// <param name="wic">Windows Imaging Component interface to use.</param>
        /// <param name="images">Images to convert.</param>
        /// <param name="options">Conversion options.</param>
        /// <returns>The converted image data.</returns>
        public static GorgonImageData Create3DImageDataFromImages(GorgonWICImage wic, IList <Image> images, GorgonGDIOptions options)
        {
            if (options.Format == BufferFormat.Unknown)
            {
                options.Format = GetBufferFormat(images[0].PixelFormat);
            }

            if (options.Format == BufferFormat.Unknown)
            {
                throw new GorgonException(GorgonResult.FormatNotSupported,
                                          string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, images[0].PixelFormat));
            }

            if (images.Any(item => item.PixelFormat != images[0].PixelFormat))
            {
                throw new GorgonException(GorgonResult.CannotCreate,
                                          string.Format(Resources.GORGFX_IMAGE_MUST_BE_SAME_FORMAT, images[0].PixelFormat));
            }

            if (options.Width <= 0)
            {
                options.Width = images[0].Width;
            }

            if (options.Height <= 0)
            {
                options.Height = images[0].Height;
            }

            if (options.Depth < 1)
            {
                options.Depth = 1;
            }

            options.MipCount = options.MipCount < 1
                                                   ? 1
                                                   : options.MipCount.Min(GorgonImageData.GetMaxMipCount(options.Width, options.Height,
                                                                                                         options.Depth));

            // Set the depth to the number of images if there are no mip-maps.
            if ((images.Count > 1) && (options.MipCount == 1))
            {
                options.Depth = images.Count;
            }

            // Create our settings.
            var settings = new GorgonTexture3DSettings
            {
                Width    = options.Width,
                Height   = options.Height,
                Depth    = options.Depth,
                MipCount = options.MipCount,
                Format   = options.Format,
                AllowUnorderedAccessViews = options.AllowUnorderedAccess,
                ShaderViewFormat          = options.ViewFormat,
                Usage = options.Usage
            };

            // Only volume textures that are size to a power of 2 can have mip maps.
            if ((!settings.IsPowerOfTwo) && (options.MipCount > 1))
            {
                throw new GorgonException(GorgonResult.CannotCreate, Resources.GORGFX_IMAGE_VOLUME_NOT_POWER_OF_TWO);
            }

            // Create our image data.
            var data = new GorgonImageData(settings);

            int depthMip   = options.Depth;
            int imageIndex = 0;

            for (int mipLevel = 0; mipLevel < data.Settings.MipCount; mipLevel++)
            {
                if (imageIndex >= images.Count)
                {
                    data.Dispose();
                    throw new GorgonException(GorgonResult.CannotCreate, Resources.GORGFX_IMAGE_VOLUME_MIPCOUNT_DEPTHCOUNT_TOO_LARGE);
                }

                for (int depth = 0; depth < depthMip; depth++)
                {
                    var image = images[imageIndex + depth];

                    // Skip NULL images.
                    if (image == null)
                    {
                        continue;
                    }

                    // Using the image, convert to a WIC bitmap object.
                    using (var bitmap = wic.CreateWICImageFromImage(image))
                    {
                        var buffer = data.Buffers[mipLevel, depth];
                        wic.AddWICBitmapToImageData(bitmap, options.Filter, options.Dither, buffer, options.UseClipping);
                    }
                }

                imageIndex += depthMip;

                // Decrease depth based on mip level.
                if (depthMip > 1)
                {
                    depthMip >>= 1;
                }
            }

            return(data);
        }
        /// <summary>
        /// Function to create 2D Gorgon image data from multiple single System.Drawing.Images.
        /// </summary>
        /// <param name="wic">Windows Imaging Component interface to use.</param>
        /// <param name="images">Images to convert.</param>
        /// <param name="options">Options for conversion.</param>
        /// <returns>The converted image data.</returns>
        public static GorgonImageData Create2DImageDataFromImages(GorgonWICImage wic, IList <Image> images, GorgonGDIOptions options)
        {
            if (options.Format == BufferFormat.Unknown)
            {
                options.Format = GetBufferFormat(images[0].PixelFormat);
            }

            if (options.Format == BufferFormat.Unknown)
            {
                throw new GorgonException(GorgonResult.FormatNotSupported,
                                          string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, images[0].PixelFormat));
            }

            if (images.Any(item => item.PixelFormat != images[0].PixelFormat))
            {
                throw new GorgonException(GorgonResult.CannotCreate,
                                          string.Format(Resources.GORGFX_IMAGE_MUST_BE_SAME_FORMAT, images[0].PixelFormat));
            }

            if (options.Width < 1)
            {
                options.Width = images[0].Width;
            }

            if (options.Height < 1)
            {
                options.Height = images[0].Height;
            }

            if (options.ArrayCount < 1)
            {
                options.ArrayCount = 1;
            }

            options.MipCount = options.MipCount < 1
                                                   ? 1
                                                   : options.MipCount.Min(GorgonImageData.GetMaxMipCount(options.Width, options.Height));

            // Create our settings.
            var settings = new GorgonTexture2DSettings
            {
                Width      = options.Width,
                Height     = options.Height,
                MipCount   = options.MipCount,
                ArrayCount = options.ArrayCount,
                Format     = options.Format,
                AllowUnorderedAccessViews = options.AllowUnorderedAccess,
                ShaderViewFormat          = options.ViewFormat,
                Usage = options.Usage
            };

            if ((options.ArrayCount * options.MipCount) > images.Count)
            {
                throw new GorgonException(GorgonResult.CannotCreate, Resources.GORGFX_IMAGE_MIPCOUNT_ARRAYCOUNT_TOO_LARGE);
            }

            // Create our image data.
            var data = new GorgonImageData(settings);

            for (int array = 0; array < data.Settings.ArrayCount; array++)
            {
                for (int mipLevel = 0; mipLevel < data.Settings.MipCount; mipLevel++)
                {
                    var image = images[array * data.Settings.MipCount + mipLevel];

                    if (image == null)
                    {
                        continue;
                    }

                    // Using the image, convert to a WIC bitmap object.
                    using (var bitmap = wic.CreateWICImageFromImage(image))
                    {
                        var buffer = data.Buffers[mipLevel, array];

                        wic.AddWICBitmapToImageData(bitmap, options.Filter, options.Dither, buffer, options.UseClipping);
                    }
                }
            }

            return(data);
        }
Exemple #9
0
        /// <summary>
        /// Function to determine if this codec can read the file or not.
        /// </summary>
        /// <param name="stream">Stream used to read the file information.</param>
        /// <returns>
        /// TRUE if the codec can read the file, FALSE if not.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">Thrown when the <paramref name="stream"/> parameter is NULL (Nothing in VB.Net).</exception>
        /// <exception cref="System.IO.IOException">Thrown when the stream is write-only.
        /// <para>-or-</para>
        /// <para>Thrown when the stream cannot perform seek operations.</para>
        /// </exception>
        public override bool IsReadable(Stream stream)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            if (!stream.CanRead)
            {
                throw new IOException(Resources.GORGFX_STREAM_READ_ONLY);
            }

            if (!stream.CanSeek)
            {
                throw new IOException(Resources.GORGFX_STREAM_EOF);
            }

            long position = stream.Position;

            try
            {
                // Get our WIC interface.
                // Wrap the stream so WIC doesn't mess up the position.
                var wrapperStream = new GorgonStreamWrapper(stream);

                using (var wic = new GorgonWICImage())
                {
                    using (var decoder = new BitmapDecoder(wic.Factory, SupportedFormat))
                    {
                        using (var wicStream = new WICStream(wic.Factory, wrapperStream))
                        {
                            try
                            {
                                decoder.Initialize(wicStream, DecodeOptions.CacheOnDemand);
                            }
                            catch (SharpDXException)
                            {
                                return(false);
                            }

                            // Only load supported WIC formats.
                            if (SupportedFormat != decoder.ContainerFormat)
                            {
                                return(false);
                            }

                            using (var frame = decoder.GetFrame(0))
                            {
                                Guid bestFormat;
                                var  settings = ReadMetaData(wic, decoder, frame, out bestFormat);

                                return(settings.Format != BufferFormat.Unknown);
                            }
                        }
                    }
                }
            }
            finally
            {
                stream.Position = position;
            }
        }
Exemple #10
0
        /// <summary>
        /// Function to read file meta data.
        /// </summary>
        /// <param name="stream">Stream used to read the metadata.</param>
        /// <returns>
        /// The image meta data as a <see cref="GorgonLibrary.Graphics.IImageSettings">IImageSettings</see> value.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">Thrown when the <paramref name="stream"/> parameter is NULL (Nothing in VB.Net).</exception>
        /// <exception cref="System.IO.IOException">Thrown when the stream is write-only.
        /// <para>-or-</para>
        /// <para>Thrown when the stream cannot perform seek operations.</para>
        /// </exception>
        /// <exception cref="System.IO.EndOfStreamException">Thrown when an attempt to read beyond the end of the stream is made.</exception>
        public override IImageSettings GetMetaData(Stream stream)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            if (!stream.CanRead)
            {
                throw new IOException(Resources.GORGFX_STREAM_WRITE_ONLY);
            }

            if (!stream.CanSeek)
            {
                throw new IOException(Resources.GORGFX_STREAM_NO_SEEK);
            }

            long position = stream.Position;

            try
            {
                // Wrap the stream so WIC doesn't mess up the position.
                var wrapperStream = new GorgonStreamWrapper(stream);

                // Get our WIC interface.
                using (var wic = new GorgonWICImage())
                {
                    using (var decoder = new BitmapDecoder(wic.Factory, SupportedFormat))
                    {
                        using (var wicStream = new WICStream(wic.Factory, wrapperStream))
                        {
                            try
                            {
                                decoder.Initialize(wicStream, DecodeOptions.CacheOnDemand);
                            }
                            catch (SharpDXException)
                            {
                                throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_ENCODER, Codec));
                            }

                            using (var frame = decoder.GetFrame(0))
                            {
                                Guid bestFormat;
                                var  settings = ReadMetaData(wic, decoder, frame, out bestFormat);

                                if (settings.Format == BufferFormat.Unknown)
                                {
                                    throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, settings.Format));
                                }

                                return(settings);
                            }
                        }
                    }
                }
            }
            finally
            {
                stream.Position = position;
            }
        }
Exemple #11
0
        /// <summary>
        /// Function to persist image data to a stream.
        /// </summary>
        /// <param name="imageData"><see cref="GorgonLibrary.Graphics.GorgonImageData">Gorgon image data</see> to persist.</param>
        /// <param name="stream">Stream that will contain the data.</param>
        protected internal override void SaveToStream(GorgonImageData imageData, Stream stream)
        {
            int frameCount = 1;

            // Wrap the stream so WIC doesn't mess up the position.
            using (var wrapperStream = new GorgonStreamWrapper(stream))
            {
                using (var wic = new GorgonWICImage())
                {
                    // Find a compatible format.
                    Guid targetFormat = wic.GetGUID(imageData.Settings.Format);

                    if (targetFormat == Guid.Empty)
                    {
                        throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, imageData.Settings.Format));
                    }

                    Guid actualFormat = targetFormat;

                    using (var encoder = new BitmapEncoder(wic.Factory, SupportedFormat))
                    {
                        try
                        {
                            encoder.Initialize(wrapperStream);
                            AddCustomMetaData(encoder, null, 0, imageData.Settings, null);
                        }
                        catch (SharpDXException)
                        {
                            // Repackage this exception to keep in line with our API.
                            throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_ENCODER, Codec));
                        }

                        using (var encoderInfo = encoder.EncoderInfo)
                        {
                            if ((imageData.Settings.ArrayCount > 1) && (CodecUseAllFrames) && (encoderInfo.IsMultiframeSupported))
                            {
                                frameCount = imageData.Settings.ArrayCount;
                            }

                            for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                            {
                                using (var frame = new BitmapFrameEncode(encoder))
                                {
                                    var buffer = imageData.Buffers[0, frameIndex];

                                    frame.Initialize();
                                    frame.SetSize(buffer.Width, buffer.Height);
                                    frame.SetResolution(72, 72);
                                    frame.SetPixelFormat(ref actualFormat);

                                    SetFrameOptions(frame);

                                    // If the image encoder doesn't like the format we've chosen, then we'll need to convert to
                                    // the best format for the codec.
                                    if (targetFormat != actualFormat)
                                    {
                                        var rect = new DataRectangle(buffer.Data.BasePointer, buffer.PitchInformation.RowPitch);
                                        using (var bitmap = new Bitmap(wic.Factory, buffer.Width, buffer.Height, targetFormat, rect))
                                        {
                                            // If we're using a codec that supports 8 bit indexed data, then get the palette info.
                                            var paletteInfo = GetPaletteInfo(wic, bitmap);

                                            if (paletteInfo == null)
                                            {
                                                throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_ENCODER, Codec));
                                            }

                                            try
                                            {
                                                using (var converter = new FormatConverter(wic.Factory))
                                                {
                                                    converter.Initialize(bitmap, actualFormat, (BitmapDitherType)Dithering, paletteInfo.Item1, paletteInfo.Item2, paletteInfo.Item3);
                                                    if (paletteInfo.Item1 != null)
                                                    {
                                                        frame.Palette = paletteInfo.Item1;
                                                    }

                                                    AddCustomMetaData(encoder, frame, frameIndex, imageData.Settings, (paletteInfo.Item1 != null) ? paletteInfo.Item1.Colors : null);
                                                    frame.WriteSource(converter);
                                                }
                                            }
                                            finally
                                            {
                                                if (paletteInfo.Item1 != null)
                                                {
                                                    paletteInfo.Item1.Dispose();
                                                }
                                            }
                                        }
                                    }
                                    else
                                    {
                                        // No conversion was needed, just dump as-is.
                                        AddCustomMetaData(encoder, frame, frameIndex, imageData.Settings, null);
                                        frame.WritePixels(buffer.Height, buffer.Data.BasePointer, buffer.PitchInformation.RowPitch, buffer.PitchInformation.SlicePitch);
                                    }

                                    frame.Commit();
                                }
                            }
                        }

                        encoder.Commit();
                    }
                }
            }
        }
Exemple #12
0
        /// <summary>
        /// Function to load an image from a stream.
        /// </summary>
        /// <param name="stream">Stream containing the data to load.</param>
        /// <param name="size">Size of the data to read, in bytes.</param>
        /// <returns>
        /// The image data that was in the stream.
        /// </returns>
        protected internal override GorgonImageData LoadFromStream(GorgonDataStream stream, int size)
        {
            GorgonImageData result = null;

            // Get our WIC interface.
            var wrapperStream = new GorgonStreamWrapper(stream);

            using (var wic = new GorgonWICImage())
            {
                using (var decoder = new BitmapDecoder(wic.Factory, SupportedFormat))
                {
                    using (var wicStream = new WICStream(wic.Factory, wrapperStream))
                    {
                        try
                        {
                            decoder.Initialize(wicStream, DecodeOptions.CacheOnDemand);
                        }
                        catch (SharpDXException)
                        {
                            // Repackage this exception to keep in line with our API.
                            throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                        }

                        using (var frame = decoder.GetFrame(0))
                        {
                            Guid bestFormat;
                            var  settings = ReadMetaData(wic, decoder, frame, out bestFormat);

                            if (settings.Format == BufferFormat.Unknown)
                            {
                                throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, settings.Format));
                            }

                            // Create our image data.
                            try
                            {
                                _actualArrayCount = settings.ArrayCount;
                                if (ArrayCount > 0)
                                {
                                    settings.ArrayCount = ArrayCount;
                                }

                                result = new GorgonImageData(settings);

                                if ((settings.ArrayCount > 1) && (_actualArrayCount > 1))
                                {
                                    ReadFrames(wic, result, decoder);
                                }
                                else
                                {
                                    ReadFrame(wic, result, frame.PixelFormat, bestFormat, frame);
                                }

                                // If we've not read the full length of the data (WIC seems to ignore the CRC on the IEND chunk for PNG files for example),
                                // then we need to move the pointer up by however many bytes we've missed.
                                if (wrapperStream.Position < size)
                                {
                                    wrapperStream.Position = size;
                                }
                            }
                            catch
                            {
                                // If we run into a problem, dump the memory buffer.
                                if (result != null)
                                {
                                    result.Dispose();
                                }

                                throw;
                            }
                        }
                    }
                }
            }

            return(result);
        }
Exemple #13
0
 /// <summary>
 /// Function to retrieve palette information for indexed images.
 /// </summary>
 /// <param name="wic">The WIC interface.</param>
 /// <param name="bitmap">The bitmap to derive the palette from (only used when encoding).</param>
 /// <returns>A tuple containing the palette data, alpha percentage and the type of palette.  NULL if we're encoding and we want to generate the palette from the frame.</returns>
 internal virtual Tuple <Palette, double, BitmapPaletteType> GetPaletteInfo(GorgonWICImage wic, Bitmap bitmap)
 {
     return(new Tuple <Palette, double, BitmapPaletteType>(null, 0, BitmapPaletteType.Custom));
 }
Exemple #14
0
        /// <summary>
        /// Function to read multiple frames from a decoder that supports multiple frames.
        /// </summary>
        /// <param name="wic">WIC interface.</param>
        /// <param name="data">Image data to populate.</param>
        /// <param name="decoder">Decoder for the image.</param>
        private void ReadFrames(GorgonWICImage wic, GorgonImageData data, BitmapDecoder decoder)
        {
            Guid bestPixelFormat = wic.GetGUID(data.Settings.Format);

            // Find the best fit pixel format.
            if (bestPixelFormat == Guid.Empty)
            {
                throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, data.Settings.Format));
            }

            // Use the image array as the frames.
            int arrayCount = _actualArrayCount.Min(data.Settings.ArrayCount);

            for (int array = 0; array < arrayCount; array++)
            {
                var buffer = data.Buffers[0, array];

                // Get the frame data.
                using (var frame = decoder.GetFrame(array))
                {
                    IntPtr bufferPointer = buffer.Data.BasePointer;
                    Guid   frameFormat   = frame.PixelFormat;
                    int    frameWidth    = frame.Size.Width;
                    int    frameHeight   = frame.Size.Height;
                    var    frameOffset   = GetFrameOffset(frame);

                    // Calculate the pointer offset if we have an offset from the frame.  Only offset if we're clipping the image though.
                    if (((frameOffset.Y != 0) || (frameOffset.X != 0)) && (Clip))
                    {
                        bufferPointer = buffer.Data.BasePointer + (frameOffset.Y * buffer.PitchInformation.RowPitch) + (frameOffset.X * (buffer.PitchInformation.RowPitch / buffer.Width));
                    }

                    // Confirm that we actually need to perform clipping.
                    bool needsSizeAdjust = (frameWidth + frameOffset.X > data.Settings.Width) || (frameHeight + frameOffset.Y > data.Settings.Height);

                    // If the formats match, then we don't need to do conversion.
                    if (bestPixelFormat == frameFormat)
                    {
                        // If the width and height are the same then we can just do a straight copy into the buffer.
                        if (((frameWidth == data.Settings.Width) && (frameHeight == data.Settings.Height)) || ((!needsSizeAdjust) && (Clip)))
                        {
                            frame.CopyPixels(buffer.PitchInformation.RowPitch, bufferPointer, buffer.PitchInformation.SlicePitch);

                            continue;
                        }

                        // We need to scale the image up/down to the size of our image data.
                        if (!Clip)
                        {
                            using (var scaler = new BitmapScaler(wic.Factory))
                            {
                                scaler.Initialize(frame, data.Settings.Width, data.Settings.Height, (BitmapInterpolationMode)Filter);
                                scaler.CopyPixels(buffer.PitchInformation.RowPitch, bufferPointer, buffer.PitchInformation.SlicePitch);
                            }
                            continue;
                        }

                        using (var clipper = new BitmapClipper(wic.Factory))
                        {
                            clipper.Initialize(frame, new Rectangle(0, 0, data.Settings.Width, data.Settings.Height));
                            clipper.CopyPixels(buffer.PitchInformation.RowPitch, bufferPointer, buffer.PitchInformation.SlicePitch);
                        }

                        continue;
                    }

                    // Poop.  We need to convert this image.
                    using (var converter = new FormatConverter(wic.Factory))
                    {
                        converter.Initialize(frame,
                                             bestPixelFormat,
                                             (BitmapDitherType)Dithering,
                                             null,
                                             0.0,
                                             BitmapPaletteType.Custom);

                        if (((frameWidth == data.Settings.Width) && (frameHeight == data.Settings.Height)) ||
                            ((!needsSizeAdjust) && (Clip)))
                        {
                            converter.CopyPixels(buffer.PitchInformation.RowPitch,
                                                 bufferPointer,
                                                 buffer.PitchInformation.SlicePitch);
                            continue;
                        }

                        // And we need to scale the image.
                        if (!Clip)
                        {
                            using (var scaler = new BitmapScaler(wic.Factory))
                            {
                                scaler.Initialize(converter,
                                                  data.Settings.Width,
                                                  data.Settings.Height,
                                                  (BitmapInterpolationMode)Filter);
                                scaler.CopyPixels(buffer.PitchInformation.RowPitch,
                                                  bufferPointer,
                                                  buffer.PitchInformation.SlicePitch);
                            }

                            continue;
                        }

                        using (var clipper = new BitmapClipper(wic.Factory))
                        {
                            clipper.Initialize(frame,
                                               new Rectangle(0, 0, data.Settings.Width, data.Settings.Height));
                            clipper.CopyPixels(buffer.PitchInformation.RowPitch,
                                               bufferPointer,
                                               buffer.PitchInformation.SlicePitch);
                        }
                    }
                }
            }
        }
Exemple #15
0
        /// <summary>
        /// Function to retrieve a list of frame delays for each frame in an animated GIF.
        /// </summary>
        /// <param name="stream">Stream containing the animated GIF.</param>
        /// <returns>
        /// An array of frame delays (1/100th of a second), or an empty array if the image is not an animated GIF.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">Thrown when the <paramref name="stream"/> parameter is NULL (Nothing in VB.Net).</exception>
        /// <exception cref="System.IO.IOException">Thrown when the stream parameter is write-only.
        /// <para>-or-</para>
        /// <para>The data in the stream could not be decoded as GIF file.</para>
        /// <para>-or-</para>
        /// <para>The stream cannot perform seek operations.</para>
        /// </exception>
        /// <exception cref="System.IO.EndOfStreamException">Thrown when an attempt to read beyond the end of the stream is made.</exception>
        public ushort[] GetFrameDelays(Stream stream)
        {
            var result = new ushort[0];

            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            if (!stream.CanRead)
            {
                throw new IOException(Resources.GORGFX_STREAM_WRITE_ONLY);
            }

            if (!stream.CanSeek)
            {
                throw new IOException(Resources.GORGFX_STREAM_NO_SEEK);
            }

            if (!UseAllFrames)
            {
                return(result);
            }

            long position = stream.Position;

            try
            {
                var wrapperStream = new GorgonStreamWrapper(stream);

                // Get our WIC interface.
                using (var wic = new GorgonWICImage())
                {
                    using (var decoder = new BitmapDecoder(wic.Factory, SupportedFormat))
                    {
                        using (var wicStream = new WICStream(wic.Factory, wrapperStream))
                        {
                            try
                            {
                                decoder.Initialize(wicStream, DecodeOptions.CacheOnDemand);
                            }
                            catch (DX.SharpDXException)
                            {
                                // Repackage the exception to keep in line with our API defintion.
                                throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                            }

                            if (decoder.FrameCount < 2)
                            {
                                return(result);
                            }

                            result = new ushort[decoder.FrameCount];

                            for (int frame = 0; frame < result.Length; frame++)
                            {
                                using (var frameImage = decoder.GetFrame(frame))
                                {
                                    // Check to see if we can actually read this thing.
                                    if (frame == 0)
                                    {
                                        Guid           temp;
                                        IImageSettings settings = ReadMetaData(wic, decoder, frameImage, out temp);

                                        if (settings.Format == BufferFormat.Unknown)
                                        {
                                            throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, settings.Format));
                                        }
                                    }

                                    using (var reader = frameImage.MetadataQueryReader)
                                    {
                                        var metaData = reader.GetMetadataByName("/grctlext/Delay");

                                        if (metaData != null)
                                        {
                                            result[frame] = (ushort)metaData;
                                        }
                                        else
                                        {
                                            result[frame] = 0;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            finally
            {
                stream.Position = position;
            }

            return(result);
        }