From a98c717072b461e89cbc1ec7dd8b97b40399fd94 Mon Sep 17 00:00:00 2001 From: Julius Friedman Date: Mon, 21 Oct 2024 20:08:19 -0400 Subject: [PATCH] More jpeg work. --- Codecs/Image/Jpeg/Classes/FrameComponent.cs | 15 +++++++ Codecs/Image/Jpeg/JpegComponent.cs | 34 ++++++++++++-- Codecs/Image/Jpeg/JpegImage.cs | 49 +++++++++++++-------- Codecs/Image/Jpeg/Markers/StartOfScan.cs | 25 +++++------ 4 files changed, 87 insertions(+), 36 deletions(-) diff --git a/Codecs/Image/Jpeg/Classes/FrameComponent.cs b/Codecs/Image/Jpeg/Classes/FrameComponent.cs index 5863f300..5a29010d 100644 --- a/Codecs/Image/Jpeg/Classes/FrameComponent.cs +++ b/Codecs/Image/Jpeg/Classes/FrameComponent.cs @@ -9,11 +9,18 @@ public class FrameComponent : MemorySegment /// public const int Length = 3; + /// + /// Ci + /// public int ComponentIdentifier { get => Array[Offset]; set => Array[Offset] = (byte)value; } + + /// + /// Hi + /// public int HorizontalSamplingFactor { get @@ -28,6 +35,9 @@ public int HorizontalSamplingFactor } } + /// + /// Vi + /// public int VerticalSamplingFactor { get @@ -41,11 +51,16 @@ public int VerticalSamplingFactor this.WriteBits(bitoffset, Binary.Four, value, Binary.BitOrder.MostSignificant); } } + + /// + /// Tqi + /// public int QuantizationTableDestinationSelector { get => Count > 3 ? Array[Offset + 3] : 0; set => Array[Offset + 3] = (byte)value; } + public FrameComponent(MemorySegment other) : base(other) { diff --git a/Codecs/Image/Jpeg/JpegComponent.cs b/Codecs/Image/Jpeg/JpegComponent.cs index 6715c0a7..f4fef905 100644 --- a/Codecs/Image/Jpeg/JpegComponent.cs +++ b/Codecs/Image/Jpeg/JpegComponent.cs @@ -4,12 +4,40 @@ namespace Codec.Jpeg; public class JpegComponent : MediaComponent { - public readonly byte QuantizationTableNumber; + /// + /// Quantization table destination selector + /// + public byte Tqi; + /// + /// DC Entropy encoding table destination selector + /// + public byte Tdj; + + /// + /// AC Entropy coding table desintation selector. + /// + public byte Taj; + + /// + /// Not yet useful. + /// + public byte Reserved; + + /// + /// + /// + /// + /// + /// public JpegComponent(byte quantizationTableNumber, byte id, int size) : base(id, size) - => QuantizationTableNumber = quantizationTableNumber; + => Tqi = quantizationTableNumber; + /// + /// + /// + /// public override int GetHashCode() - => System.HashCode.Combine(base.GetHashCode(), QuantizationTableNumber); + => System.HashCode.Combine(base.GetHashCode(), Tqi, Tdj, Taj); } diff --git a/Codecs/Image/Jpeg/JpegImage.cs b/Codecs/Image/Jpeg/JpegImage.cs index 497106f3..f0924729 100644 --- a/Codecs/Image/Jpeg/JpegImage.cs +++ b/Codecs/Image/Jpeg/JpegImage.cs @@ -35,7 +35,7 @@ public static JpegImage FromStream(Stream stream) MemorySegment dataSegment = default; MemorySegment thumbnailData = default; bool progressive = false; - ConcurrentThesaurus markers = new ConcurrentThesaurus(); + ConcurrentThesaurus markers = new ConcurrentThesaurus(); foreach (var marker in JpegCodec.ReadMarkers(stream)) { //Handle the marker to decode. @@ -91,7 +91,7 @@ public static JpegImage FromStream(Stream stream) if (bitsPerComponent == 0) bitsPerComponent = Binary.BitsPerByte; - MediaComponent[] mediaComponents = new MediaComponent[numberOfComponents]; + JpegComponent[] mediaComponents = new JpegComponent[numberOfComponents]; int[] widths = new int[numberOfComponents]; int[] heights = new int[numberOfComponents]; @@ -118,9 +118,21 @@ public static JpegImage FromStream(Stream stream) imageFormat = new ImageFormat(Binary.ByteOrder.Little, DataLayout.Planar, mediaComponents); imageFormat.HorizontalSamplingFactors = widths; imageFormat.VerticalSamplingFactors = heights; + tag.Dispose(); + tag = null; continue; case Jpeg.Markers.StartOfScan: { + using var sos = new StartOfScan(marker); + + for(int ns = sos.Ns, i = 0; i < ns; ++i) + { + using var scanComponentSelector = sos[i]; + var jpegComponent = imageFormat.GetComponentById(scanComponentSelector.Csj) as JpegComponent ?? imageFormat.Components[i] as JpegComponent; + jpegComponent.Tdj = scanComponentSelector.Tdj; + jpegComponent.Taj = scanComponentSelector.Taj; + } + var dataSegmentSize = CalculateSize(imageFormat, width, height); dataSegment = new MemorySegment(Math.Abs(dataSegmentSize)); var read = stream.Read(dataSegment.Array, dataSegment.Offset, dataSegment.Count); @@ -130,21 +142,22 @@ public static JpegImage FromStream(Stream stream) } case Jpeg.Markers.AppFirst: case Jpeg.Markers.AppLast: - var app = new App(marker); - - if (app.MajorVersion >= 1 && app.MinorVersion >= 2) { - var appExtension = new AppExtension(app); - thumbnailData = appExtension.ThumbnailData; + using var app = new App(marker); + + if (app.MajorVersion >= 1 && app.MinorVersion >= 2) + { + using var appExtension = new AppExtension(app); + thumbnailData = appExtension.ThumbnailData; + } + else + { + thumbnailData = app.ThumbnailData; + imageFormat = ImageFormat.RGB(8); + width = app.XThumbnail; + height = app.YThumbnail; + } } - else - { - thumbnailData = app.ThumbnailData; - imageFormat = ImageFormat.RGB(8); - width = app.XThumbnail; - height = app.YThumbnail; - } - goto default; case Jpeg.Markers.StartOfInformation: case Jpeg.Markers.EndOfInformation: @@ -242,7 +255,7 @@ private void WriteStartOfFrame(byte functionCode, Stream stream) if (imageComponent is JpegComponent jpegComponent) { - var frameComponent = new FrameComponent(jpegComponent.Id, ImageFormat.HorizontalSamplingFactors[i], ImageFormat.VerticalSamplingFactors[i], jpegComponent.QuantizationTableNumber); + var frameComponent = new FrameComponent(jpegComponent.Id, ImageFormat.HorizontalSamplingFactors[i], ImageFormat.VerticalSamplingFactors[i], jpegComponent.Tqi); sof[i] = frameComponent; } else @@ -272,8 +285,8 @@ private void WriteStartOfScan(Stream stream) { var componentSelector = new ScanComponentSelector(); componentSelector.Csj = jpegComponent.Id; - componentSelector.Tdj = jpegComponent.Id; - componentSelector.Taj = jpegComponent.Id; + componentSelector.Tdj = jpegComponent.Tdj; + componentSelector.Taj = jpegComponent.Taj; sos[i] = componentSelector; } else diff --git a/Codecs/Image/Jpeg/Markers/StartOfScan.cs b/Codecs/Image/Jpeg/Markers/StartOfScan.cs index 847bacb9..4d00242a 100644 --- a/Codecs/Image/Jpeg/Markers/StartOfScan.cs +++ b/Codecs/Image/Jpeg/Markers/StartOfScan.cs @@ -62,9 +62,8 @@ public IEnumerable Components } set { - var offset = 1 + index * ScanComponentSelector.Length; - using var slice = this.Slice(DataOffset + offset, ScanComponentSelector.Length); - value.CopyTo(slice); + var offset = DataOffset + 1 + index * ScanComponentSelector.Length; + value.CopyTo(Array, offset); } } @@ -109,15 +108,13 @@ public int Ah { get { - var bitOffset = Binary.BytesToBits(1 + Ns * ScanComponentSelector.Length + 1 + 1); - using var slice = Data; - return (int)slice.ReadBits(ref bitOffset, Binary.Four, Binary.BitOrder.MostSignificant); + var bitOffset = Binary.BytesToBits(DataOffset + 1 + Ns * ScanComponentSelector.Length + 1 + 1); + return (int)this.ReadBits(ref bitOffset, Binary.Four, Binary.BitOrder.MostSignificant); } set { - var bitOffset = Binary.BytesToBits(1 + Ns * ScanComponentSelector.Length + 1 + 1); - using var slice = Data; - slice.WriteBits(ref bitOffset, Binary.Four, value, Binary.BitOrder.MostSignificant); + var bitOffset = Binary.BytesToBits(DataOffset + 1 + Ns * ScanComponentSelector.Length + 1 + 1); + this.WriteBits(ref bitOffset, Binary.Four, value, Binary.BitOrder.MostSignificant); } } @@ -128,15 +125,13 @@ public int Al { get { - var bitOffset = Binary.BytesToBits(1 + Ns * ScanComponentSelector.Length + 1 + 1) + Binary.Four; - using var slice = Data; - return (int)slice.ReadBits(ref bitOffset, Binary.Four, Binary.BitOrder.MostSignificant); + var bitOffset = Binary.BytesToBits(DataOffset + 1 + Ns * ScanComponentSelector.Length + 1 + 1) + Binary.Four; + return (int)this.ReadBits(ref bitOffset, Binary.Four, Binary.BitOrder.MostSignificant); } set { - var bitOffset = Binary.BytesToBits(1 + Ns * ScanComponentSelector.Length + 1 + 1) + Binary.Four; - using var slice = Data; - slice.WriteBits(ref bitOffset, Binary.Four, value, Binary.BitOrder.MostSignificant); + var bitOffset = Binary.BytesToBits(DataOffset + 1 + Ns * ScanComponentSelector.Length + 1 + 1) + Binary.Four; + this.WriteBits(ref bitOffset, Binary.Four, value, Binary.BitOrder.MostSignificant); } } }