public void GetHuffmanEncodingLength_Zero() { int expected = 0; int actual = HuffmanScanEncoder.GetHuffmanEncodingLength(0); Assert.Equal(expected, actual); }
static void RunTest() { Block8x8F data = default; int expectedLessThan = 1; int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data); Assert.True(actual < expectedLessThan); }
public void GetHuffmanEncodingLength_Random(int seed) { int maxNumber = 1 << 16; var rng = new Random(seed); for (int i = 0; i < 1000; i++) { uint number = (uint)rng.Next(0, maxNumber); int expected = GetHuffmanEncodingLength_Reference(number); int actual = HuffmanScanEncoder.GetHuffmanEncodingLength(number); Assert.Equal(expected, actual); } }
/// <summary> /// Encode writes the image to the jpeg baseline format with the given options. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="image">The image to write from.</param> /// <param name="stream">The stream to write 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)); if (image.Width >= JpegConstants.MaxLength || image.Height >= JpegConstants.MaxLength) { JpegThrowHelper.ThrowDimensionsTooLarge(image.Width, image.Height); } cancellationToken.ThrowIfCancellationRequested(); this.outputStream = stream; ImageMetadata metadata = image.Metadata; JpegMetadata jpegMetadata = metadata.GetJpegMetadata(); // If the color type was not specified by the user, preserve the color type of the input image, if it's a supported color type. if (!this.colorType.HasValue && IsSupportedColorType(jpegMetadata.ColorType)) { this.colorType = jpegMetadata.ColorType; } // Compute number of components based on color type in options. int componentCount = (this.colorType == JpegColorType.Luminance) ? 1 : 3; ReadOnlySpan <byte> componentIds = this.GetComponentIds(); // TODO: Right now encoder writes both quantization tables for grayscale images - we shouldn't do that // Initialize the quantization tables. this.InitQuantizationTables(componentCount, jpegMetadata, out Block8x8F luminanceQuantTable, out Block8x8F chrominanceQuantTable); // Write the Start Of Image marker. this.WriteStartOfImage(); // Do not write APP0 marker for RGB colorspace. if (this.colorType != JpegColorType.Rgb) { this.WriteJfifApplicationHeader(metadata); } // Write Exif, ICC and IPTC profiles this.WriteProfiles(metadata); if (this.colorType == JpegColorType.Rgb) { // Write App14 marker to indicate RGB color space. this.WriteApp14Marker(); } // Write the quantization tables. this.WriteDefineQuantizationTables(ref luminanceQuantTable, ref chrominanceQuantTable); // Write the image dimensions. this.WriteStartOfFrame(image.Width, image.Height, componentCount, componentIds); // Write the Huffman tables. this.WriteDefineHuffmanTables(componentCount); // Write the scan header. this.WriteStartOfScan(componentCount, componentIds); // Write the scan compressed data. var scanEncoder = new HuffmanScanEncoder(stream); if (this.colorType == JpegColorType.Luminance) { // luminance quantization table only. scanEncoder.EncodeGrayscale(image, ref luminanceQuantTable, cancellationToken); } else { // luminance and chrominance quantization tables. switch (this.colorType) { case JpegColorType.YCbCrRatio444: case JpegColorType.Luminance: scanEncoder.Encode444(image, ref luminanceQuantTable, ref chrominanceQuantTable, cancellationToken); break; case JpegColorType.YCbCrRatio420: scanEncoder.Encode420(image, ref luminanceQuantTable, ref chrominanceQuantTable, cancellationToken); break; case JpegColorType.Rgb: scanEncoder.EncodeRgb(image, ref luminanceQuantTable, cancellationToken); break; } } // Write the End Of Image marker. this.WriteEndOfImageMarker(); stream.Flush(); }