/// <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); }
/// <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); }
/// <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(); } } }