private static IReadWriteBitmapData?DoLoadBitmapData(IAsyncContext context, Stream stream) { context.Progress?.New(DrawingOperation.Loading, 1000); var reader = new BinaryReader(stream); if (reader.ReadInt32() != magicNumber) { throw new ArgumentException(Res.ImagingNotBitmapDataStream, nameof(stream)); } var size = new Size(reader.ReadInt32(), reader.ReadInt32()); var pixelFormat = (PixelFormat)reader.ReadInt32(); Color32 backColor = Color32.FromArgb(reader.ReadInt32()); byte alphaThreshold = reader.ReadByte(); Palette?palette = null; int paletteLength = reader.ReadInt32(); if (paletteLength > 0) { var entries = new Color32[paletteLength]; for (int i = 0; i < paletteLength; i++) { entries[i] = Color32.FromArgb(reader.ReadInt32()); } palette = new Palette(entries, backColor, alphaThreshold); } context.Progress?.SetProgressValue((int)(stream.Position * 1000 / stream.Length)); if (context.IsCancellationRequested) { return(null); } IBitmapDataInternal result = CreateManagedBitmapData(size, pixelFormat, backColor, alphaThreshold, palette); int bpp = pixelFormat.ToBitsPerPixel(); bool canceled = false; try { IBitmapDataRowInternal row = result.DoGetRow(0); for (int y = 0; y < result.Height; y++) { if (canceled = context.IsCancellationRequested) { return(null); } switch (bpp) { case 32: for (int x = 0; x < result.Width; x++) { row.DoWriteRaw(x, reader.ReadInt32()); } break; case 16: for (int x = 0; x < result.Width; x++) { row.DoWriteRaw(x, reader.ReadInt16()); } break; case 64: for (int x = 0; x < result.Width; x++) { row.DoWriteRaw(x, reader.ReadInt64()); } break; default: for (int x = 0; x < result.RowSize; x++) { row.DoWriteRaw(x, reader.ReadByte()); } break; } row.MoveNextRow(); context.Progress?.SetProgressValue((int)(stream.Position * 1000 / stream.Length)); } return((canceled = context.IsCancellationRequested) ? null : result); } finally { if (canceled) { result.Dispose(); } } }
public OptimizedPaletteQuantizerSession(OptimizedPaletteQuantizer quantizer, IReadableBitmapData source, IAsyncContext context) { this.quantizer = quantizer; Palette = InitializePalette(source, context); }
internal Palette(Palette palette, Color32 backColor, byte alphaThreshold) : this(palette.Entries, backColor, alphaThreshold, palette.customGetNearestColorIndex) { }
/// <summary> /// Creates a managed <see cref="IBitmapDataInternal"/> with the specified <paramref name="size"/> and <paramref name="pixelFormat"/>. /// </summary> internal static IBitmapDataInternal CreateManagedBitmapData(Size size, PixelFormat pixelFormat = PixelFormat.Format32bppArgb, Color32 backColor = default, byte alphaThreshold = 128, Palette palette = null) { if (pixelFormat.IsIndexed() && palette != null) { int maxColors = 1 << pixelFormat.ToBitsPerPixel(); if (palette.Count > maxColors) { throw new ArgumentException(Res.ImagingPaletteTooLarge(maxColors, pixelFormat), nameof(palette)); } } Debug.Assert(palette == null || backColor.ToOpaque() == palette.BackColor && alphaThreshold == palette.AlphaThreshold); switch (pixelFormat) { case PixelFormat.Format32bppArgb: return(new ManagedBitmapData <Color32, ManagedBitmapDataRow32Argb>(size, pixelFormat)); case PixelFormat.Format32bppPArgb: return(new ManagedBitmapData <Color32, ManagedBitmapDataRow32PArgb>(size, pixelFormat)); case PixelFormat.Format32bppRgb: return(new ManagedBitmapData <Color32, ManagedBitmapDataRow32Rgb>(size, pixelFormat, backColor, alphaThreshold)); case PixelFormat.Format24bppRgb: return(new ManagedBitmapData <Color24, ManagedBitmapDataRow24Rgb>(size, pixelFormat, backColor, alphaThreshold)); case PixelFormat.Format8bppIndexed: return(new ManagedBitmapData <byte, ManagedBitmapDataRow8I>(size, pixelFormat, backColor, alphaThreshold, palette)); case PixelFormat.Format4bppIndexed: return(new ManagedBitmapData <byte, ManagedBitmapDataRow4I>(size, pixelFormat, backColor, alphaThreshold, palette)); case PixelFormat.Format1bppIndexed: return(new ManagedBitmapData <byte, ManagedBitmapDataRow1I>(size, pixelFormat, backColor, alphaThreshold, palette)); case PixelFormat.Format64bppArgb: return(new ManagedBitmapData <Color64, ManagedBitmapDataRow64Argb>(size, pixelFormat)); case PixelFormat.Format64bppPArgb: return(new ManagedBitmapData <Color64, ManagedBitmapDataRow64PArgb>(size, pixelFormat)); case PixelFormat.Format48bppRgb: return(new ManagedBitmapData <Color48, ManagedBitmapDataRow48Rgb>(size, pixelFormat, backColor, alphaThreshold)); case PixelFormat.Format16bppRgb565: return(new ManagedBitmapData <Color16Rgb565, ManagedBitmapDataRow16Rgb565>(size, pixelFormat, backColor, alphaThreshold)); case PixelFormat.Format16bppRgb555: return(new ManagedBitmapData <Color16Rgb555, ManagedBitmapDataRow16Rgb555>(size, pixelFormat, backColor, alphaThreshold)); case PixelFormat.Format16bppArgb1555: return(new ManagedBitmapData <Color16Argb1555, ManagedBitmapDataRow16Argb1555>(size, pixelFormat, backColor, alphaThreshold)); case PixelFormat.Format16bppGrayScale: return(new ManagedBitmapData <Color16Gray, ManagedBitmapDataRow16Gray>(size, pixelFormat, backColor, alphaThreshold)); default: throw new ArgumentOutOfRangeException(nameof(pixelFormat), Res.PixelFormatInvalid(pixelFormat)); } }
internal static IBitmapDataInternal CreateBitmapData(Bitmap bitmap, ImageLockMode lockMode, Color32 backColor = default, byte alphaThreshold = 128, Palette palette = null) { if (bitmap == null) { throw new ArgumentNullException(nameof(bitmap), PublicResources.ArgumentNull); } if (!lockMode.IsDefined()) { throw new ArgumentOutOfRangeException(nameof(lockMode), PublicResources.EnumOutOfRange(lockMode)); } Debug.Assert(palette == null || backColor.ToOpaque() == palette.BackColor && alphaThreshold == palette.AlphaThreshold); var pixelFormat = bitmap.PixelFormat; switch (pixelFormat) { case PixelFormat.Format32bppArgb: return(new NativeBitmapData <NativeBitmapDataRow32Argb>(bitmap, pixelFormat, lockMode)); case PixelFormat.Format32bppPArgb: return(new NativeBitmapData <NativeBitmapDataRow32PArgb>(bitmap, pixelFormat, lockMode)); case PixelFormat.Format32bppRgb: return(new NativeBitmapData <NativeBitmapDataRow32Rgb>(bitmap, pixelFormat, lockMode, backColor, alphaThreshold)); case PixelFormat.Format24bppRgb: return(new NativeBitmapData <NativeBitmapDataRow24Rgb>(bitmap, pixelFormat, lockMode, backColor, alphaThreshold)); case PixelFormat.Format8bppIndexed: return(new NativeBitmapData <NativeBitmapDataRow8I>(bitmap, pixelFormat, lockMode, backColor, alphaThreshold, palette)); case PixelFormat.Format4bppIndexed: return(new NativeBitmapData <NativeBitmapDataRow4I>(bitmap, pixelFormat, lockMode, backColor, alphaThreshold, palette)); case PixelFormat.Format1bppIndexed: return(new NativeBitmapData <NativeBitmapDataRow1I>(bitmap, pixelFormat, lockMode, backColor, alphaThreshold, palette)); case PixelFormat.Format64bppArgb: return(new NativeBitmapData <NativeBitmapDataRow64Argb>(bitmap, pixelFormat, lockMode)); case PixelFormat.Format64bppPArgb: return(new NativeBitmapData <NativeBitmapDataRow64PArgb>(bitmap, pixelFormat, lockMode)); case PixelFormat.Format48bppRgb: return(new NativeBitmapData <NativeBitmapDataRow48Rgb>(bitmap, pixelFormat, lockMode, backColor, alphaThreshold)); case PixelFormat.Format16bppRgb565: return(OSUtils.IsWindows ? (NativeBitmapDataBase) new NativeBitmapData <NativeBitmapDataRow16Rgb565>(bitmap, pixelFormat, lockMode, backColor, alphaThreshold) : new NativeBitmapData <NativeBitmapDataRow16Rgb565Via24Bpp>(bitmap, PixelFormat.Format24bppRgb, lockMode, backColor, alphaThreshold)); case PixelFormat.Format16bppRgb555: return(OSUtils.IsWindows ? (NativeBitmapDataBase) new NativeBitmapData <NativeBitmapDataRow16Rgb555>(bitmap, pixelFormat, lockMode, backColor, alphaThreshold) : new NativeBitmapData <NativeBitmapDataRow16Rgb555Via24Bpp>(bitmap, PixelFormat.Format24bppRgb, lockMode, backColor, alphaThreshold)); case PixelFormat.Format16bppArgb1555: return(new NativeBitmapData <NativeBitmapDataRow16Argb1555>(bitmap, pixelFormat, lockMode, backColor, alphaThreshold)); case PixelFormat.Format16bppGrayScale: return(new NativeBitmapData <NativeBitmapDataRow16Gray>(bitmap, pixelFormat, lockMode, backColor, alphaThreshold)); default: throw new InvalidOperationException(Res.InternalError($"Unexpected pixel format {pixelFormat}")); } }
/// <summary> /// Creates a managed <see cref="IReadWriteBitmapData"/> with the specified <paramref name="size"/>, <paramref name="pixelFormat"/> and <paramref name="palette"/>. /// <br/>See the <strong>Remarks</strong> section for details. /// </summary> /// <exception cref="ArgumentOutOfRangeException"><paramref name="size"/> or <paramref name="pixelFormat"/> has an invalid value.</exception> /// <exception cref="ArgumentException"><paramref name="palette"/> contains too many colors for the indexed format specified by <paramref name="pixelFormat"/>.</exception> /// <param name="size">The size of the bitmap data to create.</param> /// <param name="pixelFormat">The desired pixel format of the bitmap data to create.</param> /// <param name="palette">If <paramref name="pixelFormat"/> specifies an indexed format, then specifies the desired <see cref="IBitmapData.Palette"/> of the returned <see cref="IReadWriteBitmapData"/> instance. /// It determines also the <see cref="IBitmapData.BackColor"/> and <see cref="IBitmapData.AlphaThreshold"/> properties of the result.</param> /// <returns>A managed <see cref="IReadWriteBitmapData"/> with the specified <paramref name="size"/>, <paramref name="pixelFormat"/> and <paramref name="palette"/>.</returns> /// <remarks> /// <para>All possible <see cref="PixelFormat"/>s are supported, regardless of the native <see cref="Bitmap"/> support of the current operating system. /// <note>When <paramref name="pixelFormat"/> specifies a wide-color format (48/64 bit or 16 bit grayscale), then the returned instance will use the full 16-bit range of the color channels. /// This means a different raw content to Windows' wide-color <see cref="Bitmap"/> instances, which use 13-bit channels. But this difference is transparent in most cases /// unless we access actual raw content by the <see cref="IReadableBitmapDataRow.ReadRaw{T}">ReadRaw</see> and <see cref="IWritableBitmapDataRow.WriteRaw{T}">WriteRaw</see> methods.</note></para> /// <para>If <paramref name="palette"/> is not specified, then a default palette will be used for indexed formats, and a default <see cref="IBitmapData.BackColor"/> and <see cref="IBitmapData.AlphaThreshold"/> /// value will be used.</para> /// <note type="tip"> /// <list type="bullet"> /// <item>You can use the <see cref="BitmapDataExtensions.ToBitmap">ToBitmap</see> extension method to convert the created <see cref="IReadWriteBitmapData"/> to a <see cref="Bitmap"/> instance.</item> /// <item>To create an <see cref="IReadWriteBitmapData"/> instance from a native <see cref="Bitmap"/> use the <see cref="BitmapExtensions.GetReadWriteBitmapData">GetReadWriteBitmapData</see> extension method.</item> /// </list></note> /// </remarks> /// <seealso cref="CreateBitmapData(Size, PixelFormat, Color32, byte)"/> /// <seealso cref="BitmapDataExtensions.ToBitmap"/> /// <seealso cref="BitmapExtensions.GetReadableBitmapData"/> /// <seealso cref="BitmapExtensions.GetWritableBitmapData"/> /// <seealso cref="BitmapExtensions.GetReadWriteBitmapData"/> public static IReadWriteBitmapData CreateBitmapData(Size size, PixelFormat pixelFormat, Palette palette) { if (size.Width < 1 || size.Height < 1) { throw new ArgumentOutOfRangeException(nameof(size), PublicResources.ArgumentOutOfRange); } if (!pixelFormat.IsValidFormat()) { throw new ArgumentOutOfRangeException(nameof(pixelFormat), Res.PixelFormatInvalid(pixelFormat)); } return(CreateManagedBitmapData(size, pixelFormat, palette?.BackColor ?? default, palette?.AlphaThreshold ?? 128, palette)); }
internal ManagedBitmapData(Size size, PixelFormat pixelFormat, Color32 backColor = default, byte alphaThreshold = 0, Palette palette = null) { Debug.Assert(size.Width > 0 && size.Height > 0, "Non-empty size expected"); Debug.Assert(pixelFormat.IsValidFormat(), "Valid format expected"); Debug.Assert(!pixelFormat.IsIndexed() || typeof(TColor) == typeof(byte), "For indexed pixel formats byte elements are expected"); BackColor = pixelFormat.HasMultiLevelAlpha() ? default : backColor.ToOpaque(); AlphaThreshold = alphaThreshold; PixelFormat = pixelFormat; Width = size.Width; // Unlike native bitmaps our stride have 1 byte alignment so Stride = (Width * bpp + 7) / 8) int bpp = pixelFormat.ToBitsPerPixel(); int byteWidth = pixelFormat.GetByteWidth(size.Width); RowSize = byteWidth; Buffer = new Array2D <TColor>(size.Height, bpp <= 8 ? byteWidth : size.Width); if (!pixelFormat.IsIndexed()) { return; } if (palette != null) { Debug.Assert(palette.Entries.Length <= (1 << bpp), "Too many colors"); Palette = palette; return; } // if there was no palette specified we use a default one Palette = pixelFormat switch { PixelFormat.Format8bppIndexed => Palette.SystemDefault8BppPalette(backColor, alphaThreshold), PixelFormat.Format4bppIndexed => Palette.SystemDefault4BppPalette(backColor), _ => Palette.SystemDefault1BppPalette(backColor) }; }