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