Beispiel #1
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    imageData = null;
            TGAConversionFlags flags;

            if (DirectAccess.SizeOf <TGAHeader>() > size)
            {
                throw new EndOfStreamException(Resources.GORGFX_STREAM_EOF);
            }

            // Read the header information.
            IImageSettings settings = ReadHeader(stream, out flags);

            if (ArrayCount > 1)
            {
                settings.ArrayCount = ArrayCount;
            }

            try
            {
                // Create our image data structure.
                imageData = new GorgonImageData(settings);

                // Copy the data from the stream to the buffer.
                CopyImageData(stream, imageData, flags);
            }
            catch
            {
                // Clean up any memory allocated if we can't copy the image.
                if (imageData != null)
                {
                    imageData.Dispose();
                }

                throw;
            }

            return(imageData);
        }
Beispiel #2
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);
        }
        /// <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);
        }
Beispiel #4
0
        /// <summary>
        /// Function to clip the sprite region from the texture.
        /// </summary>
        /// <param name="texture">Texture containing the image data to clip.</param>
        /// <returns>A rectangle for the sprite.  Or an empty rectangle if no sprite was selected.</returns>
        public unsafe Rectangle Clip(GorgonTexture2D texture)
        {
            GorgonImageData imageData = null;

            try
            {
                // Constrain our mouse to the texture.
                _startPoint.X = _startPoint.X.Max(0).Min(texture.Settings.Width - 1);
                _startPoint.Y = _startPoint.Y.Max(0).Min(texture.Settings.Height - 1);

                imageData = GorgonImageData.CreateFromTexture(texture);

                _stride        = imageData.Buffers[0].PitchInformation.RowPitch;
                _format        = imageData.Settings.Format;
                _bytesPerPixel = GorgonBufferFormatInfo.GetInfo(_format).SizeInBytes;
                _textureWidth  = imageData.Settings.Width;

                // Get a pointer to the buffer.
                byte *bytePtr = (byte *)imageData.UnsafePointer;

                if (IsMaskValue(bytePtr, _startPoint.X, _startPoint.Y))
                {
                    return(Rectangle.Empty);
                }

                Queue <ClipSpan> clipSpans = new Queue <ClipSpan>();

                _pixels = new bool[imageData.Settings.Width * imageData.Settings.Height];

                int left   = _startPoint.X;
                int top    = _startPoint.Y;
                int right  = left;
                int bottom = top;

                // Get the initial span from our starting point and add it to our queue.
                ClipSpan span = GetSpan(bytePtr, left, top);
                clipSpans.Enqueue(span);

                while (clipSpans.Count > 0)
                {
                    // Take the span off the queue.
                    span = clipSpans.Dequeue();

                    // Find the next vertical span above and below the current span.
                    int west  = span.Start;
                    int east  = span.End;
                    int north = span.Y - 1;
                    int south = span.Y + 1;

                    // Check each pixel between the start and end of the upper and lower spans.
                    for (int x = west; x <= east; ++x)
                    {
                        int pixelindex = _textureWidth * north + x;

                        if ((span.Y > 0) && (!IsMaskValue(bytePtr, x, north)) && (!_pixels[pixelindex]))
                        {
                            clipSpans.Enqueue(GetSpan(bytePtr, x, north));
                        }

                        pixelindex = _textureWidth * south + x;

                        if ((span.Y >= imageData.Settings.Height - 1) || (IsMaskValue(bytePtr, x, south)) || (_pixels[pixelindex]))
                        {
                            continue;
                        }

                        clipSpans.Enqueue(GetSpan(bytePtr, x, south));
                    }

                    // Update the boundaries.
                    left   = west.Min(left);
                    right  = (east + 1).Max(right);
                    top    = (north + 1).Min(top);
                    bottom = south.Max(bottom);
                }

                return(Rectangle.FromLTRB(left, top, right, bottom));
            }
            finally
            {
                if (imageData != null)
                {
                    imageData.Dispose();
                }
            }
        }