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)); }
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); }
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); }
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);
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); }
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); } }
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)); }
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); }
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); }
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)); }