public void GetHuffmanEncodingLength_Zero()
        {
            int expected = 0;

            int actual = HuffmanScanEncoder.GetHuffmanEncodingLength(0);

            Assert.Equal(expected, actual);
        }
Пример #2
0
            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);
            }
        }
Пример #4
0
        /// <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();
        }