/// <summary> /// Writes a 1 bit image with a color palette. The color palette has 2 entry's with 4 bytes for each entry. /// </summary> /// <typeparam name="TPixel">The type of the pixel.</typeparam> /// <param name="stream">The <see cref="Stream"/> to write to.</param> /// <param name="image"> The <see cref="ImageFrame{TPixel}"/> containing pixel data.</param> private void Write1BitColor <TPixel>(Stream stream, ImageFrame <TPixel> image) where TPixel : unmanaged, IPixel <TPixel> { using IQuantizer <TPixel> frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer <TPixel>(this.configuration, new QuantizerOptions() { MaxColors = 2 }); using IndexedImageFrame <TPixel> quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds()); using IMemoryOwner <byte> colorPaletteBuffer = this.memoryAllocator.Allocate <byte>(ColorPaletteSize1Bit, AllocationOptions.Clean); Span <byte> colorPalette = colorPaletteBuffer.GetSpan(); ReadOnlySpan <TPixel> quantizedColorPalette = quantized.Palette.Span; this.WriteColorPalette(stream, quantizedColorPalette, colorPalette); ReadOnlySpan <byte> quantizedPixelRow = quantized.DangerousGetRowSpan(0); int rowPadding = quantizedPixelRow.Length % 8 != 0 ? this.padding - 1 : this.padding; for (int y = image.Height - 1; y >= 0; y--) { quantizedPixelRow = quantized.DangerousGetRowSpan(y); int endIdx = quantizedPixelRow.Length % 8 == 0 ? quantizedPixelRow.Length : quantizedPixelRow.Length - 8; for (int i = 0; i < endIdx; i += 8) { Write1BitPalette(stream, i, i + 8, quantizedPixelRow); } if (quantizedPixelRow.Length % 8 != 0) { int startIdx = quantizedPixelRow.Length - 7; endIdx = quantizedPixelRow.Length; Write1BitPalette(stream, startIdx, endIdx, quantizedPixelRow); } for (int i = 0; i < rowPadding; i++) { stream.WriteByte(0); } } }
/// <summary> /// Writes an 4 bit color image with a color palette. The color palette has 16 entry's with 4 bytes for each entry. /// </summary> /// <typeparam name="TPixel">The type of the pixel.</typeparam> /// <param name="stream">The <see cref="Stream"/> to write to.</param> /// <param name="image"> The <see cref="ImageFrame{TPixel}"/> containing pixel data.</param> private void Write4BitColor <TPixel>(Stream stream, ImageFrame <TPixel> image) where TPixel : unmanaged, IPixel <TPixel> { using IQuantizer <TPixel> frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer <TPixel>(this.configuration, new QuantizerOptions() { MaxColors = 16 }); using IndexedImageFrame <TPixel> quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds()); using IMemoryOwner <byte> colorPaletteBuffer = this.memoryAllocator.Allocate <byte>(ColorPaletteSize4Bit, AllocationOptions.Clean); Span <byte> colorPalette = colorPaletteBuffer.GetSpan(); ReadOnlySpan <TPixel> quantizedColorPalette = quantized.Palette.Span; this.WriteColorPalette(stream, quantizedColorPalette, colorPalette); ReadOnlySpan <byte> pixelRowSpan = quantized.DangerousGetRowSpan(0); int rowPadding = pixelRowSpan.Length % 2 != 0 ? this.padding - 1 : this.padding; for (int y = image.Height - 1; y >= 0; y--) { pixelRowSpan = quantized.DangerousGetRowSpan(y); int endIdx = pixelRowSpan.Length % 2 == 0 ? pixelRowSpan.Length : pixelRowSpan.Length - 1; for (int i = 0; i < endIdx; i += 2) { stream.WriteByte((byte)((pixelRowSpan[i] << 4) | pixelRowSpan[i + 1])); } if (pixelRowSpan.Length % 2 != 0) { stream.WriteByte((byte)((pixelRowSpan[pixelRowSpan.Length - 1] << 4) | 0)); } for (int i = 0; i < rowPadding; i++) { stream.WriteByte(0); } } }
public void SinglePixelOpaque() { Configuration config = Configuration.Default; var quantizer = new WuQuantizer(new QuantizerOptions { Dither = null }); using var image = new Image <Rgba32>(config, 1, 1, Color.Black); ImageFrame <Rgba32> frame = image.Frames.RootFrame; using IQuantizer <Rgba32> frameQuantizer = quantizer.CreatePixelSpecificQuantizer <Rgba32>(config); using IndexedImageFrame <Rgba32> result = frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds()); Assert.Equal(1, result.Palette.Length); Assert.Equal(1, result.Width); Assert.Equal(1, result.Height); Assert.Equal(Color.Black, (Color)result.Palette.Span[0]); Assert.Equal(0, result.DangerousGetRowSpan(0)[0]); }
/// <summary> /// Writes an 8 bit color image with a color palette. The color palette has 256 entry's with 4 bytes for each entry. /// </summary> /// <typeparam name="TPixel">The type of the pixel.</typeparam> /// <param name="stream">The <see cref="Stream"/> to write to.</param> /// <param name="image"> The <see cref="ImageFrame{TPixel}"/> containing pixel data.</param> /// <param name="colorPalette">A byte span of size 1024 for the color palette.</param> private void Write8BitColor <TPixel>(Stream stream, ImageFrame <TPixel> image, Span <byte> colorPalette) where TPixel : unmanaged, IPixel <TPixel> { using IQuantizer <TPixel> frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer <TPixel>(this.configuration); using IndexedImageFrame <TPixel> quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds()); ReadOnlySpan <TPixel> quantizedColorPalette = quantized.Palette.Span; this.WriteColorPalette(stream, quantizedColorPalette, colorPalette); for (int y = image.Height - 1; y >= 0; y--) { ReadOnlySpan <byte> pixelSpan = quantized.DangerousGetRowSpan(y); stream.Write(pixelSpan); for (int i = 0; i < this.padding; i++) { stream.WriteByte(0); } } }