public void ToRgba32(ref Rgba32 dest) { dest.R = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); dest.G = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); dest.B = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); dest.A = byte.MaxValue; }
public Rgba64(Argb32 source) { this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); }
public Rgba64(Bgr24 source) { this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); this.A = ushort.MaxValue; }
/// <summary> /// Creates the quantized frame. /// </summary> /// <typeparam name="TPixel">The type of the pixel.</typeparam> /// <param name="options">The options.</param> /// <param name="image">The image.</param> public static IndexedImageFrame <TPixel> CreateQuantizedFrame <TPixel>( PngEncoderOptions options, Image <TPixel> image) where TPixel : unmanaged, IPixel <TPixel> { if (options.ColorType != PngColorType.Palette) { return(null); } // Use the metadata to determine what quantization depth to use if no quantizer has been set. if (options.Quantizer is null) { byte bits = (byte)options.BitDepth; var maxColors = ColorNumerics.GetColorCountForBitDepth(bits); options.Quantizer = new WuQuantizer(new QuantizerOptions { MaxColors = maxColors }); } // Create quantized frame returning the palette and set the bit depth. using (IQuantizer <TPixel> frameQuantizer = options.Quantizer.CreatePixelSpecificQuantizer <TPixel>(image.GetConfiguration())) { ImageFrame <TPixel> frame = image.Frames.RootFrame; return(frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds())); } }
public static int GetLuminance <TPixel>(TPixel sourcePixel) where TPixel : unmanaged, IPixel <TPixel> { var vector = sourcePixel.ToVector4(); return(ColorNumerics.GetBT709Luminance(ref vector, 256)); }
public void FromL8(L8 source) { ushort rgb = ColorNumerics.UpscaleFrom8BitTo16Bit(source.PackedValue); this.R = rgb; this.G = rgb; this.B = rgb; }
public void FromLa16(La16 source) { ushort rgb = ColorNumerics.UpscaleFrom8BitTo16Bit(source.L); this.R = rgb; this.G = rgb; this.B = rgb; }
public void FromLa32(La32 source) { byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); this.R = rgb; this.G = rgb; this.B = rgb; }
public void FromL16(L16 source) { byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); this.R = rgb; this.G = rgb; this.B = rgb; }
private void RemovePixelsFromHistogram(ref Vector4 greyValuesBase, ref int histogramBase, int luminanceLevels, int length) { for (int idx = 0; idx < length; idx++) { int luminance = ColorNumerics.GetBT709Luminance(ref Unsafe.Add(ref greyValuesBase, idx), luminanceLevels); Unsafe.Add(ref histogramBase, luminance)--; } }
public void Encode_WithPngTransparentColorBehaviorClear_Works(PngColorType colorType) { // arrange var image = new Image <Rgba32>(50, 50); var encoder = new PngEncoder() { TransparentColorMode = PngTransparentColorMode.Clear, ColorType = colorType }; Rgba32 rgba32 = Color.Blue; for (int y = 0; y < image.Height; y++) { System.Span <Rgba32> rowSpan = image.GetPixelRowSpan(y); // Half of the test image should be transparent. if (y > 25) { rgba32.A = 0; } for (int x = 0; x < image.Width; x++) { rowSpan[x].FromRgba32(rgba32); } } // act using var memStream = new MemoryStream(); image.Save(memStream, encoder); // assert memStream.Position = 0; using var actual = Image.Load <Rgba32>(memStream); Rgba32 expectedColor = Color.Blue; if (colorType == PngColorType.Grayscale || colorType == PngColorType.GrayscaleWithAlpha) { var luminance = ColorNumerics.Get8BitBT709Luminance(expectedColor.R, expectedColor.G, expectedColor.B); expectedColor = new Rgba32(luminance, luminance, luminance); } for (int y = 0; y < actual.Height; y++) { System.Span <Rgba32> rowSpan = actual.GetPixelRowSpan(y); if (y > 25) { expectedColor = Color.Transparent; } for (int x = 0; x < actual.Width; x++) { Assert.Equal(expectedColor, rowSpan[x]); } } }
public void Invoke(int y, Span <Vector4> span) { Span <TPixel> rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length); PixelOperations <TPixel> .Instance.ToVector4(this.configuration, rowSpan, span, PixelConversionModifiers.Scale); ColorNumerics.Transform(span, ref Unsafe.AsRef(this.matrix)); PixelOperations <TPixel> .Instance.FromVector4Destructive(this.configuration, span, rowSpan, PixelConversionModifiers.Scale); }
public void GetBT709Luminance_WithVector4(float x, float y, float z, int luminanceLevels, int expected) { // arrange var vector = new Vector4(x, y, z, 0.0f); // act int actual = ColorNumerics.GetBT709Luminance(ref vector, luminanceLevels); // assert Assert.Equal(expected, actual); }
public void L8_FromRgba32(byte rgb) { // Arrange L8 gray = default; byte expected = ColorNumerics.Get8BitBT709Luminance(rgb, rgb, rgb); // Act gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); byte actual = gray.PackedValue; // Assert Assert.Equal(expected, actual); }
public void La16_FromRgba32(byte rgb) { // Arrange La16 gray = default; byte expected = ColorNumerics.Get8BitBT709Luminance(rgb, rgb, rgb); // Act gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); byte actual = gray.L; // Assert Assert.Equal(expected, actual); Assert.Equal(255, gray.A); }
public void L16_FromRgba32() { // Arrange L16 gray = default; const byte rgb = 128; ushort scaledRgb = ColorNumerics.UpscaleFrom8BitTo16Bit(rgb); ushort expected = ColorNumerics.Get16BitBT709Luminance(scaledRgb, scaledRgb, scaledRgb); // Act gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); ushort actual = gray.PackedValue; // Assert Assert.Equal(expected, actual); }
public OctreeQuantizer(Configuration configuration, QuantizerOptions options) { Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(options, nameof(options)); this.Configuration = configuration; this.Options = options; this.maxColors = this.Options.MaxColors; this.octree = new Octree(Numerics.Clamp(ColorNumerics.GetBitsNeededForColorDepth(this.maxColors), 1, 8)); this.paletteOwner = configuration.MemoryAllocator.Allocate <TPixel>(this.maxColors, AllocationOptions.Clean); this.palette = default; this.pixelMap = default; this.isDithering = !(this.Options.Dither is null); this.isDisposed = false; }
private void EncodeLocal <TPixel>(Image <TPixel> image, IndexedImageFrame <TPixel> quantized, Stream stream) where TPixel : unmanaged, IPixel <TPixel> { ImageFrame <TPixel> previousFrame = null; GifFrameMetadata previousMeta = null; for (int i = 0; i < image.Frames.Count; i++) { ImageFrame <TPixel> frame = image.Frames[i]; ImageFrameMetadata metadata = frame.Metadata; GifFrameMetadata frameMetadata = metadata.GetGifMetadata(); if (quantized is null) { // Allow each frame to be encoded at whatever color depth the frame designates if set. if (previousFrame != null && previousMeta.ColorTableLength != frameMetadata.ColorTableLength && frameMetadata.ColorTableLength > 0) { var options = new QuantizerOptions { Dither = this.quantizer.Options.Dither, DitherScale = this.quantizer.Options.DitherScale, MaxColors = frameMetadata.ColorTableLength }; using IQuantizer <TPixel> frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer <TPixel>(this.configuration, options); quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds()); } else { using IQuantizer <TPixel> frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer <TPixel>(this.configuration); quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds()); } } this.bitDepth = ColorNumerics.GetBitsNeededForColorDepth(quantized.Palette.Length); this.WriteGraphicalControlExtension(frameMetadata, this.GetTransparentIndex(quantized), stream); this.WriteImageDescriptor(frame, true, stream); this.WriteColorTable(quantized, stream); this.WriteImageData(quantized, stream); quantized.Dispose(); quantized = null; // So next frame can regenerate it previousFrame = frame; previousMeta = frameMetadata; } }
public void La32_ToRgba32(ushort input) { // Arrange ushort expected = ColorNumerics.DownScaleFrom16BitTo8Bit(input); var gray = new La32(input, ushort.MaxValue); // Act Rgba32 actual = default; gray.ToRgba32(ref actual); // Assert Assert.Equal(expected, actual.R); Assert.Equal(expected, actual.G); Assert.Equal(expected, actual.B); Assert.Equal(byte.MaxValue, actual.A); }
/// <summary> /// Calculates the bit depth value. /// </summary> /// <typeparam name="TPixel">The type of the pixel.</typeparam> /// <param name="options">The options.</param> /// <param name="quantizedFrame">The quantized frame.</param> public static byte CalculateBitDepth <TPixel>( PngEncoderOptions options, IndexedImageFrame <TPixel> quantizedFrame) where TPixel : unmanaged, IPixel <TPixel> { byte bitDepth; if (options.ColorType == PngColorType.Palette) { byte quantizedBits = (byte)Numerics.Clamp(ColorNumerics.GetBitsNeededForColorDepth(quantizedFrame.Palette.Length), 1, 8); byte bits = Math.Max((byte)options.BitDepth, quantizedBits); // Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk // We check again for the bit depth as the bit depth of the color palette from a given quantizer might not // be within the acceptable range. if (bits == 3) { bits = 4; } else if (bits >= 5 && bits <= 7) { bits = 8; } bitDepth = bits; } else { bitDepth = (byte)options.BitDepth; } if (Array.IndexOf(PngConstants.ColorTypes[options.ColorType.Value], bitDepth) == -1) { throw new NotSupportedException("Bit depth is not supported or not valid."); } return(bitDepth); }
public void FromRgba64(Rgba64 source) { this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); }
public void FromArgb32(Argb32 source) { this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); }
public void FromRgb24(Rgb24 source) { this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); }
/// <summary> /// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="image">The <see cref="Image{TPixel}"/> to encode from.</param> /// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param> /// <param name="cancellationToken">The token to request cancellation.</param> public void Encode <TPixel>(Image <TPixel> image, Stream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel <TPixel> { Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); ImageMetadata metadata = image.Metadata; GifMetadata gifMetadata = metadata.GetGifMetadata(); this.colorTableMode ??= gifMetadata.ColorTableMode; bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global; // Quantize the image returning a palette. IndexedImageFrame <TPixel> quantized; using (IQuantizer <TPixel> frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer <TPixel>(this.configuration)) { if (useGlobalTable) { frameQuantizer.BuildPalette(this.pixelSamplingStrategy, image); quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame, image.Bounds()); } else { quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image.Frames.RootFrame, image.Bounds()); } } // Get the number of bits. this.bitDepth = ColorNumerics.GetBitsNeededForColorDepth(quantized.Palette.Length); // Write the header. this.WriteHeader(stream); // Write the LSD. int index = this.GetTransparentIndex(quantized); this.WriteLogicalScreenDescriptor(metadata, image.Width, image.Height, index, useGlobalTable, stream); if (useGlobalTable) { this.WriteColorTable(quantized, stream); } // Write the comments. this.WriteComments(gifMetadata, stream); // Write application extension to allow additional frames. if (image.Frames.Count > 1) { this.WriteApplicationExtension(stream, gifMetadata.RepeatCount); } if (useGlobalTable) { this.EncodeGlobal(image, quantized, index, stream); } else { this.EncodeLocal(image, quantized, stream); } // Clean up. quantized.Dispose(); // TODO: Write extension etc stream.WriteByte(GifConstants.EndIntroducer); }