/// <summary> /// Function to clip a bitmap. /// </summary> /// <param name="bitmap">Bitmap to clip.</param> /// <param name="buffer">Buffer containing clipped data.</param> private void ClipBitmap(WIC.BitmapSource bitmap, GorgonImageBuffer buffer) { using (var clipper = new WIC.BitmapClipper(Factory)) { clipper.Initialize(bitmap, new DX.Rectangle(0, 0, buffer.Width < bitmap.Size.Width ? buffer.Width : bitmap.Size.Width, buffer.Height < bitmap.Size.Height ? buffer.Height : bitmap.Size.Height)); clipper.CopyPixels(buffer.PitchInformation.RowPitch, buffer.Data.BasePointer, buffer.PitchInformation.SlicePitch); } }
/// <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(); } } }
/// <summary> /// Function to convert the format of a bitmap into the format of the buffer. /// </summary> /// <param name="sourceFormat">Format to convert from.</param> /// <param name="destFormat">Format to convert into.</param> /// <param name="dithering">Dithering to apply.</param> /// <param name="filter">Filtering to apply to scaled bitmaps.</param> /// <param name="bitmap">Bitmap to convert.</param> /// <param name="bitmapPalette">Palette for the bitmap.</param> /// <param name="alphaValue">Value of pixel to consider transparent.</param> /// <param name="buffer">Buffer holding the converted data.</param> /// <param name="scale">TRUE to scale when converting, FALSE to keep at original size.</param> /// <param name="clip">TRUE to perform clipping, FALSE to keep at original size.</param> private void ConvertFormat(Guid sourceFormat, Guid destFormat, WIC.BitmapDitherType dithering, WIC.BitmapInterpolationMode filter, WIC.BitmapSource bitmap, WIC.Palette bitmapPalette, int alphaValue, GorgonImageBuffer buffer, bool scale, bool clip) { WIC.BitmapSource source = bitmap; double alphaPercent = alphaValue / 255.0; var paletteType = WIC.BitmapPaletteType.Custom; // If we have a palette, then confirm that the dithering method is valid. if (bitmapPalette != null) { // Do not apply dithering if we're using // a custom palette and request ordered dithering. switch (dithering) { case WIC.BitmapDitherType.Ordered4x4: case WIC.BitmapDitherType.Ordered8x8: case WIC.BitmapDitherType.Ordered16x16: if (bitmapPalette.TypeInfo == WIC.BitmapPaletteType.Custom) { dithering = WIC.BitmapDitherType.None; } break; } paletteType = bitmapPalette.TypeInfo; } try { // Create a scaler if need one. if ((scale) && (!clip)) { var scaler = new WIC.BitmapScaler(Factory); scaler.Initialize(bitmap, buffer.Width, buffer.Height, filter); source = scaler; } // Create a clipper if we want to clip and the image needs resizing. if ((clip) && (scale) && ((buffer.Width < bitmap.Size.Width) || (buffer.Height < bitmap.Size.Height))) { var clipper = new WIC.BitmapClipper(Factory); clipper.Initialize(bitmap, new DX.Rectangle(0, 0, buffer.Width < bitmap.Size.Width ? buffer.Width : bitmap.Size.Width, buffer.Height < bitmap.Size.Height ? buffer.Height : bitmap.Size.Height)); source = clipper; } using (var converter = new WIC.FormatConverter(Factory)) { if (!converter.CanConvert(sourceFormat, destFormat)) { throw new GorgonException(GorgonResult.FormatNotSupported, string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, buffer.Format)); } converter.Initialize(source, destFormat, dithering, bitmapPalette, alphaPercent, paletteType); if (!scale) { int rowPitch = (GetBitsPerPixel(destFormat) * bitmap.Size.Width + 7) / 8; int slicePitch = rowPitch * bitmap.Size.Height; if ((rowPitch != buffer.PitchInformation.RowPitch) || (slicePitch != buffer.PitchInformation.SlicePitch)) { throw new GorgonException(GorgonResult.CannotWrite, Resources.GORGFX_IMAGE_PITCH_TOO_SMALL); } } converter.CopyPixels(buffer.PitchInformation.RowPitch, buffer.Data.BasePointer, buffer.PitchInformation.SlicePitch); } } finally { if (source != bitmap) { source.Dispose(); } } }