Example #1
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;
            }
        }
Example #2
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;
            }
        }
Example #3
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);
        }
Example #4
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();
                    }
                }
            }
        }
Example #5
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);
        }