Пример #1
0
        public static JpegQuantizationTable ScaleByQuality(JpegQuantizationTable quantizationTable, int quality)
        {
            if (quantizationTable.IsEmpty)
            {
                throw new ArgumentException("Quantization table is not initialized.", nameof(quantizationTable));
            }
            if ((uint)quality > 100)
            {
                throw new ArgumentOutOfRangeException(nameof(quality));
            }

            int scale = quality < 50 ? 5000 / quality : 200 - (quality * 2);

            ReadOnlySpan <ushort> source = quantizationTable.Elements;

            ushort[] elements = new ushort[64];
            for (int i = 0; i < elements.Length; i++)
            {
                int x = source[i];
                x           = ((x * scale) + 50) / 100;
                elements[i] = (ushort)JpegMathHelper.Clamp(x, 1, 255);
            }

            return(new JpegQuantizationTable(quantizationTable.ElementPrecision, quantizationTable.Identifier, elements));
        }
Пример #2
0
        public bool TryEstimateQuality(out float quality)
        {
            if (_quantizationTables is null)
            {
                quality = 0;
                return(false);
            }

            // Luminance
            JpegQuantizationTable quantizationTable = GetQuantizationTable(0);

            if (quantizationTable.IsEmpty)
            {
                quality = 0;
                return(false);
            }
            quality = EstimateQuality(quantizationTable, JpegStandardQuantizationTable.GetLuminanceTable(0, 0), out _);

            // Chrominance
            quantizationTable = GetQuantizationTable(1);
            if (!quantizationTable.IsEmpty)
            {
                float quality2 = EstimateQuality(quantizationTable, JpegStandardQuantizationTable.GetChrominanceTable(0, 0), out _);
                quality = Math.Min(quality, quality2);
            }

            quality = JpegMathHelper.Clamp(quality, 0f, 100f);
            return(true);
        }
Пример #3
0
        public void SetQuantizationTable(JpegQuantizationTable table)
        {
            if (table.IsEmpty)
            {
                throw new ArgumentException("Quantization table is not initialized.", nameof(table));
            }
            if (table.ElementPrecision != 0)
            {
                throw new InvalidOperationException("Only baseline JPEG is supported.");
            }

            List <JpegQuantizationTable>?tables = _quantizationTables;

            if (tables is null)
            {
                _quantizationTables = tables = new List <JpegQuantizationTable>(2);
            }

            for (int i = 0; i < tables.Count; i++)
            {
                if (tables[i].Identifier == table.Identifier)
                {
                    tables[i] = table;
                    return;
                }
            }

            tables.Add(table);
        }
Пример #4
0
        private static float EstimateQuality(JpegQuantizationTable quantizationTable, JpegQuantizationTable standardTable, out float dVariance)
        {
            Debug.Assert(!quantizationTable.IsEmpty);
            Debug.Assert(!standardTable.IsEmpty);

            bool   allOnes        = true;
            double dSumPercent    = 0;
            double dSumPercentSqr = 0;

            ref ushort elementRef  = ref MemoryMarshal.GetReference(quantizationTable.Elements);
Пример #5
0
        public static bool TryParse(byte precision, byte identifier, ReadOnlySequence <byte> buffer, out JpegQuantizationTable quantizationTable, ref int bytesConsumed)
        {
            if (buffer.IsSingleSegment)
            {
                return(TryParse(precision, identifier, buffer.First.Span, out quantizationTable, ref bytesConsumed));
            }

            ushort[]    elements;
            Span <byte> local = stackalloc byte[128];

            if (precision == 0)
            {
                if (buffer.Length < 64)
                {
                    quantizationTable = default;
                    return(false);
                }

                buffer.Slice(0, 64).CopyTo(local);

                elements = new ushort[64];
                for (int i = 0; i < 64; i++)
                {
                    elements[i] = local[i];
                }
                bytesConsumed += 64;
            }
            else if (precision == 1)
            {
                if (buffer.Length < 128)
                {
                    quantizationTable = default;
                    return(false);
                }

                buffer.Slice(0, 128).CopyTo(local);

                elements = new ushort[64];
                for (int i = 0; i < 64; i++)
                {
                    elements[i] = (ushort)(local[2 * i] << 8 | local[2 * i + 1]);
                }
                bytesConsumed += 128;
            }
            else
            {
                quantizationTable = default;
                return(false);
            }

            quantizationTable = new JpegQuantizationTable(precision, identifier, elements);
            return(true);
        }
Пример #6
0
 private void ProcessDefineQuantizationTable(ReadOnlySequence <byte> segment, int currentOffset)
 {
     while (!segment.IsEmpty)
     {
         if (!JpegQuantizationTable.TryParse(segment, out JpegQuantizationTable quantizationTable, out int bytesConsumed))
         {
             ThrowInvalidDataException(currentOffset, "Failed to parse quantization table.");
             return;
         }
         segment        = segment.Slice(bytesConsumed);
         currentOffset += bytesConsumed;
         SetQuantizationTable(quantizationTable);
     }
 }
Пример #7
0
        public static bool TryParse(ReadOnlySpan <byte> buffer, out JpegQuantizationTable quantizationTable, out int bytesConsumed)
        {
            bytesConsumed = 0;
            if (buffer.IsEmpty)
            {
                quantizationTable = default;
                return(false);
            }

            byte b = buffer[0];

            bytesConsumed++;

            return(TryParse((byte)(b >> 4), (byte)(b & 0xf), buffer.Slice(1), out quantizationTable, ref bytesConsumed));
        }
Пример #8
0
        internal void SetQuantizationTable(JpegQuantizationTable table)
        {
            List <JpegQuantizationTable>?list = _quantizationTables;

            if (list is null)
            {
                list = _quantizationTables = new List <JpegQuantizationTable>(2);
            }
            for (int i = 0; i < list.Count; i++)
            {
                JpegQuantizationTable item = list[i];
                if (item.Identifier == table.Identifier)
                {
                    list[i] = table;
                    return;
                }
            }
            list.Add(table);
        }
Пример #9
0
        public static bool TryParse(byte precision, byte identifier, ReadOnlySpan <byte> buffer, out JpegQuantizationTable quantizationTable, ref int bytesConsumed)
        {
            ushort[] elements;
            if (precision == 0)
            {
                if (buffer.Length < 64)
                {
                    quantizationTable = default;
                    return(false);
                }

                elements = new ushort[64];
                for (int i = 0; i < 64; i++)
                {
                    elements[i] = buffer[i];
                }
                bytesConsumed += 64;
            }
            else if (precision == 1)
            {
                if (buffer.Length < 128)
                {
                    quantizationTable = default;
                    return(false);
                }

                elements = new ushort[64];
                for (int i = 0; i < 64; i++)
                {
                    elements[i] = (ushort)(buffer[2 * i] << 8 | buffer[2 * i + 1]);
                }
                bytesConsumed += 128;
            }
            else
            {
                quantizationTable = default;
                return(false);
            }

            quantizationTable = new JpegQuantizationTable(precision, identifier, elements);
            return(true);
        }
Пример #10
0
        public static bool TryParse(ReadOnlySequence <byte> buffer, out JpegQuantizationTable quantizationTable, out int bytesConsumed)
        {
            if (buffer.IsSingleSegment)
            {
                return(TryParse(buffer.First.Span, out quantizationTable, out bytesConsumed));
            }

            bytesConsumed = 0;
            if (buffer.IsEmpty)
            {
                quantizationTable = default;
                return(false);
            }

            byte b = buffer.First.Span[0];

            bytesConsumed++;

            return(TryParse((byte)(b >> 4), (byte)(b & 0xf), buffer.Slice(1), out quantizationTable, ref bytesConsumed));
        }