コード例 #1
0
ファイル: GorgonWICImage.cs プロジェクト: tmp7701/Gorgon
        /// <summary>
        /// Function to create a WIC bitmap from a System.Drawing.Image object.
        /// </summary>
        /// <param name="bitmap">WIC bitmap to copy to our image data.</param>
        /// <param name="filter">Filter used to scale the image.</param>
        /// <param name="ditherFlags">Flags used to dither the image.</param>
        /// <param name="buffer">Buffer for holding the image data.</param>
        /// <param name="clip">TRUE to clip the data, FALSE to scale it.</param>
        public void AddWICBitmapToImageData(WIC.Bitmap bitmap, ImageFilter filter, ImageDithering ditherFlags, GorgonImageBuffer buffer, bool clip)
        {
            Guid conversionFormat = GetGUID(buffer.Format);
            bool needsResize      = (buffer.Width != bitmap.Size.Width) || (buffer.Height != bitmap.Size.Height);

            if (conversionFormat == Guid.Empty)
            {
                throw new GorgonException(GorgonResult.FormatNotSupported,
                                          string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, buffer.Format));
            }

            // Turn off filtering if we're not resizing.
            if (!needsResize)
            {
                filter = ImageFilter.Point;
            }

            // If the pixel format of the bitmap is not the same as our
            // conversion format, then we need to convert the image.
            if (bitmap.PixelFormat != conversionFormat)
            {
                ConvertFormat(bitmap.PixelFormat, conversionFormat, (WIC.BitmapDitherType)ditherFlags, (WIC.BitmapInterpolationMode)filter, bitmap, null, 0, buffer, needsResize, clip);
            }
            else
            {
                // Just dump without converting because our formats are equal.
                if ((!needsResize) || (!ResizeBitmap(bitmap, (WIC.BitmapInterpolationMode)filter, buffer, clip)))
                {
                    bitmap.CopyPixels(buffer.PitchInformation.RowPitch, buffer.Data.BasePointer, buffer.PitchInformation.SlicePitch);
                }
            }
        }
コード例 #2
0
        /// <summary>
        /// Function to convert the image to B4G4R4A4.
        /// </summary>
        /// <param name="baseImage">The base image to convert.</param>
        /// <param name="dithering">Dithering to apply to the converstion to B8G8R8A8.</param>
        /// <returns>The updated image.</returns>
        private static IGorgonImage ConvertToB4G4R4A4(IGorgonImage baseImage, ImageDithering dithering)
        {
            // This temporary image will be used to convert to B8G8R8A8.
            IGorgonImage newImage = baseImage;

            IGorgonImageInfo destInfo = new GorgonImageInfo(baseImage.ImageType, BufferFormat.B4G4R4A4_UNorm)
            {
                Depth      = baseImage.Depth,
                Height     = baseImage.Height,
                Width      = baseImage.Width,
                ArrayCount = baseImage.ArrayCount,
                MipCount   = baseImage.MipCount
            };

            // This is our working buffer for B4G4R4A4.
            IGorgonImage destImage = new GorgonImage(destInfo);

            try
            {
                // If necessary, convert to B8G8R8A8. Otherwise, we'll just downsample directly.
                if ((newImage.Format != BufferFormat.B8G8R8A8_UNorm) &&
                    (newImage.Format != BufferFormat.R8G8B8A8_UNorm))
                {
                    newImage = baseImage.Clone();
                    ConvertToFormat(newImage, BufferFormat.B8G8R8A8_UNorm, dithering);
                }

                // The next step is to manually downsample to R4G4B4A4.
                // Because we're doing this manually, dithering won't be an option unless unless we've downsampled from a much higher bit format when converting to B8G8R8A8.
                for (int array = 0; array < newImage.ArrayCount; ++array)
                {
                    for (int mip = 0; mip < newImage.MipCount; ++mip)
                    {
                        int depthCount = newImage.GetDepthCount(mip);

                        for (int depth = 0; depth < depthCount; depth++)
                        {
                            IGorgonImageBuffer destBuffer = destImage.Buffers[mip, destInfo.ImageType == ImageType.Image3D ? depth : array];
                            IGorgonImageBuffer srcBuffer  = newImage.Buffers[mip, newImage.ImageType == ImageType.Image3D ? depth : array];

                            ConvertPixelsToB4G4R4A4(destBuffer, srcBuffer);
                        }
                    }
                }

                destImage.CopyTo(baseImage);

                return(baseImage);
            }
            finally
            {
                destImage.Dispose();

                if (newImage != baseImage)
                {
                    newImage.Dispose();
                }
            }
        }
コード例 #3
0
        /// <summary>
        /// Function to convert the pixel format of an image into another pixel format.
        /// </summary>
        /// <param name="baseImage">The image to convert.</param>
        /// <param name="format">The new pixel format for the image.</param>
        /// <param name="dithering">[Optional] Flag to indicate the type of dithering to perform when the bit depth for the <paramref name="format"/> is lower than the original bit depth.</param>
        /// <returns>A <see cref="IGorgonImage"/> containing the image data with the converted pixel format.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="baseImage"/> is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="format"/> is set to <see cref="BufferFormat.Unknown"/>.
        /// <para>-or-</para>
        /// <para>Thrown when the original format could not be converted into the desired <paramref name="format"/>.</para>
        /// </exception>
        /// <remarks>
        /// <para>
        /// Use this to convert an image format from one to another. The conversion functionality uses Windows Imaging Components (WIC) to perform the conversion.
        /// </para>
        /// <para>
        /// Because this method uses WIC, not all formats will be convertible. To determine if a format can be converted, use the <see cref="GorgonImage.CanConvertToFormat"/> method.
        /// </para>
        /// <para>
        /// For the <see cref="BufferFormat.B4G4R4A4_UNorm"/> format, Gorgon has to perform a manual conversion since that format is not supported by WIC. Because of this, the
        /// <paramref name="dithering"/> flag will be ignored when downsampling to that format.
        /// </para>
        /// </remarks>
        public static IGorgonImage ConvertToFormat(this IGorgonImage baseImage, BufferFormat format, ImageDithering dithering = ImageDithering.None)
        {
            if (baseImage == null)
            {
                throw new ArgumentNullException(nameof(baseImage));
            }

            if ((format == BufferFormat.Unknown) || (!baseImage.CanConvertToFormat(format)))
            {
                throw new ArgumentException(string.Format(Resources.GORIMG_ERR_FORMAT_NOT_SUPPORTED, format), nameof(format));
            }

            if (format == baseImage.Format)
            {
                return(baseImage);
            }

            // If we've asked for 4 bit per channel BGRA, then we have to convert the base image to B8R8G8A8,and then convert manually (no support in WIC).
            if (format == BufferFormat.B4G4R4A4_UNorm)
            {
                return(ConvertToB4G4R4A4(baseImage, dithering));
            }

            // If we're currently using B4G4R4A4, then manually convert (no support in WIC).
            if (baseImage.Format == BufferFormat.B4G4R4A4_UNorm)
            {
                return(ConvertFromB4G4R4A4(baseImage, format));
            }

            var          destInfo = new GorgonFormatInfo(format);
            WicUtilities wic      = null;

            IGorgonImage newImage = null;

            try
            {
                wic      = new WicUtilities();
                newImage = wic.ConvertToFormat(baseImage, format, dithering, baseImage.FormatInfo.IsSRgb, destInfo.IsSRgb);

                newImage.CopyTo(baseImage);

                return(baseImage);
            }
            finally
            {
                newImage?.Dispose();
                wic?.Dispose();
            }
        }
コード例 #4
0
ファイル: GorgonWICImage.cs プロジェクト: tmp7701/Gorgon
        /// <summary>
        /// Function to perform conversion/transformation of a bitmap.
        /// </summary>
        /// <param name="sourceData">WIC bitmap to transform.</param>
        /// <param name="destData">Destination data buffer.</param>
        /// <param name="rowPitch">Number of bytes per row in the image.</param>
        /// <param name="slicePitch">Number of bytes in total for the image.</param>
        /// <param name="destFormat">Destination format for transformation.</param>
        /// <param name="isSourcesRGB">TRUE if the source format is sRGB.</param>
        /// <param name="isDestsRGB">TRUE if the destination format is sRGB.</param>
        /// <param name="dither">Dithering to apply to images that get converted to a lower bit depth.</param>
        /// <param name="destRect">Rectangle containing the area to scale or clip</param>
        /// <param name="clip">TRUE to perform clipping instead of scaling.</param>
        /// <param name="scaleFilter">Filter to apply to scaled data.</param>
        public void TransformImageData(WIC.BitmapSource sourceData, IntPtr destData, int rowPitch, int slicePitch, Guid destFormat, bool isSourcesRGB, bool isDestsRGB, ImageDithering dither, Rectangle destRect, bool clip, ImageFilter scaleFilter)
        {
            WIC.BitmapSource    source        = sourceData;
            WIC.FormatConverter converter     = null;
            WIC.BitmapClipper   clipper       = null;
            WIC.BitmapScaler    scaler        = null;
            WIC.ColorContext    sourceContext = null;
            WIC.ColorContext    destContext   = null;
            WIC.ColorTransform  sRGBTransform = null;

            try
            {
                if (destFormat != Guid.Empty)
                {
                    if (sourceData.PixelFormat != destFormat)
                    {
                        converter = new WIC.FormatConverter(Factory);

                        if (!converter.CanConvert(sourceData.PixelFormat, destFormat))
                        {
                            throw new GorgonException(GorgonResult.FormatNotSupported,
                                                      string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, destFormat));
                        }

                        converter.Initialize(source, destFormat, (WIC.BitmapDitherType)dither, null, 0, WIC.BitmapPaletteType.Custom);
                        source = converter;
                    }

                    if ((isDestsRGB) ||
                        (isSourcesRGB))
                    {
                        sRGBTransform = new WIC.ColorTransform(Factory);
                        sourceContext = new WIC.ColorContext(Factory);
                        destContext   = new WIC.ColorContext(Factory);

                        sourceContext.InitializeFromExifColorSpace(isSourcesRGB ? 1 : 2);
                        destContext.InitializeFromExifColorSpace(isDestsRGB ? 1 : 2);

                        sRGBTransform.Initialize(source, sourceContext, destContext, destFormat);
                        source = sRGBTransform;
                    }
                }

                if (destRect.IsEmpty)
                {
                    source.CopyPixels(rowPitch, destData, slicePitch);
                    return;
                }

                Guid pixelFormat = source.PixelFormat;

                if (!clip)
                {
                    scaler = new WIC.BitmapScaler(Factory);
                    scaler.Initialize(source,
                                      destRect.Width,
                                      destRect.Height,
                                      (WIC.BitmapInterpolationMode)scaleFilter);
                    source = scaler;
                }
                else
                {
                    destRect.Width  = destRect.Width.Min(source.Size.Width);
                    destRect.Height = destRect.Height.Min(source.Size.Height);

                    if ((destRect.Width < source.Size.Width) ||
                        (destRect.Height < source.Size.Height))
                    {
                        clipper = new WIC.BitmapClipper(Factory);
                        clipper.Initialize(source,
                                           new DX.Rectangle(destRect.X, destRect.Y, destRect.Width, destRect.Height));
                        source     = clipper;
                        destRect.X = 0;
                        destRect.Y = 0;
                    }
                }

                // We have a change of format (probably due to the filter when scaling)... so we need to convert.
                if (source.PixelFormat != pixelFormat)
                {
                    converter = new WIC.FormatConverter(Factory);

                    if (!converter.CanConvert(source.PixelFormat, pixelFormat))
                    {
                        throw new GorgonException(GorgonResult.FormatNotSupported,
                                                  string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, pixelFormat));
                    }

                    converter.Initialize(source,
                                         pixelFormat,
                                         WIC.BitmapDitherType.None,
                                         null,
                                         0,
                                         WIC.BitmapPaletteType.Custom);
                    source = converter;
                }

                source.CopyPixels(rowPitch, destData, slicePitch);
            }
            finally
            {
                if (converter != null)
                {
                    converter.Dispose();
                }

                if (sourceContext != null)
                {
                    sourceContext.Dispose();
                }

                if (destContext != null)
                {
                    destContext.Dispose();
                }

                if (sRGBTransform != null)
                {
                    sRGBTransform.Dispose();
                }

                if (scaler != null)
                {
                    scaler.Dispose();
                }

                if (clipper != null)
                {
                    clipper.Dispose();
                }
            }
        }