Skip to content

Commit

Permalink
Optomize for Data slices.
Browse files Browse the repository at this point in the history
  • Loading branch information
juliusfriedman committed Oct 21, 2024
1 parent 54487dd commit cff5cbe
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 66 deletions.
21 changes: 12 additions & 9 deletions Codecs/Image/Jpeg/JpegImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public static JpegImage FromStream(Stream stream)
case Jpeg.Markers.StartOfDifferentialProgressiveArithmeticFrame:
case Jpeg.Markers.StartOfProgressiveArithmeticFrame:
case Jpeg.Markers.StartOfProgressiveHuffmanFrame:
case Jpeg.Markers.HeirarchicalProgression:
case Jpeg.Markers.HeirarchicalProgression:
switch (marker.FunctionCode)
{
case Jpeg.Markers.StartOfDifferentialProgressiveHuffmanFrame:
Expand All @@ -70,15 +70,15 @@ public static JpegImage FromStream(Stream stream)

StartOfFrame tag;

if(marker.FunctionCode == Jpeg.Markers.HeirarchicalProgression)
if (marker.FunctionCode == Jpeg.Markers.HeirarchicalProgression)
{
tag = new HeirarchicalProgression(marker);
}
else
{
tag = new StartOfFrame(marker);
}

int bitDepth = Binary.Clamp(Binary.BitsPerByte, Binary.BitsPerInteger, tag.P);
height = tag.Y;
width = tag.X;
Expand Down Expand Up @@ -110,7 +110,7 @@ public static JpegImage FromStream(Stream stream)
var mediaComponent = new JpegComponent((byte)quantizationTableNumber, (byte)componentId, bitsPerComponent);

mediaComponents[componentIndex] = mediaComponent;

remains -= frameComponent.Count;
}

Expand All @@ -127,12 +127,12 @@ public static JpegImage FromStream(Stream stream)
if (read < dataSegment.Count)
dataSegment = dataSegment.Slice(0, read);
break;
}
}
case Jpeg.Markers.AppFirst:
case Jpeg.Markers.AppLast:
var app = new App(marker);

if(app.MajorVersion >= 1 && app.MinorVersion >= 2)
if (app.MajorVersion >= 1 && app.MinorVersion >= 2)
{
var appExtension = new AppExtension(app);
thumbnailData = appExtension.ThumbnailData;
Expand Down Expand Up @@ -185,7 +185,7 @@ public void Save(Stream stream)

markerBuffer.Remove(Jpeg.Markers.QuantizationTable);

foreach(var marker in markerBuffer.Values.Where(markerBuffer => Jpeg.Markers.IsApplicationMarker(markerBuffer.FunctionCode)))
foreach (var marker in markerBuffer.Values.Where(markerBuffer => Jpeg.Markers.IsApplicationMarker(markerBuffer.FunctionCode)))
{
WriteMarker(stream, marker);

Expand Down Expand Up @@ -222,8 +222,11 @@ public void Save(Stream stream)
// Write the image data
stream.Write(Data.Array, Data.Offset, Data.Count);

// Write the EOI marker
WriteEmptyMarker(stream, Jpeg.Markers.EndOfInformation);
if (Data[Data.Count - 1] != Jpeg.Markers.EndOfInformation)
{
// Write the EOI marker
WriteEmptyMarker(stream, Jpeg.Markers.EndOfInformation);
}
}

private void WriteStartOfFrame(byte functionCode, Stream stream)
Expand Down
5 changes: 3 additions & 2 deletions Codecs/Image/Jpeg/JpegUnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,10 @@ private static void DumpMarker(Marker marker)
}
else
{
Console.Write(BitConverter.ToString(marker.Data.Array, marker.Data.Offset, Math.Min(16, marker.Data.Count)));
using var slice = marker.Data;
Console.Write(BitConverter.ToString(slice.Array, slice.Offset, Math.Min(16, slice.Count)));
}
if (marker.Data.Count > 16)
if (marker.DataLength > 16)
Console.WriteLine(" ...");
else
Console.WriteLine();
Expand Down
2 changes: 2 additions & 0 deletions Codecs/Image/Jpeg/Marker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public int Length

public int MarkerLength => DataLength + 2;

public int DataOffset => Offset + PrefixBytes + LengthBytes;

public MemorySegment Data => Count > PrefixBytes + LengthBytes ? this.Slice(PrefixBytes + LengthBytes) : Empty;

public bool IsEmpty => DataLength == 0;
Expand Down
111 changes: 92 additions & 19 deletions Codecs/Image/Jpeg/Markers/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,44 @@ public class App : Marker

public string Identifier
{
get => Encoding.UTF8.GetString(Data.Array, Data.Offset, 5);
set => Encoding.UTF8.GetBytes(value, 0, 5, Data.Array, Data.Offset);
get
{
using var slice = Data;
return Encoding.UTF8.GetString(slice.Array, slice.Offset, 5);
}
set
{
using var slice = Data;
Encoding.UTF8.GetBytes(value, 0, 5, slice.Array, slice.Offset);
}
}

public byte MajorVersion
{
get => Data[6];
set => Data[6] = value;
get
{
using var slice = Data;
return slice[6];
}
set
{
using var slice = Data;
slice[6] = value;
}
}

public byte MinorVersion
{
get => Data[7];
set => Data[7] = value;
get
{
using var slice = Data;
return slice[7];
}
set
{
using var slice = Data;
slice[7] = value;
}
}

public Version Version
Expand All @@ -39,44 +63,93 @@ public Version Version

public int DensityUnits
{
get => Data[8];
set => Data[8] = (byte)value;
get
{
using var slice = Data;
return slice[8];
}
set
{
using var slice = Data;
slice[8] = (byte)value;
}
}

public int XDensity
{
get => Binary.Read16(Data.Array, Data.Offset + 9, Binary.IsLittleEndian);
set => Binary.Write16(Data.Array, Data.Offset + 9, Binary.IsLittleEndian, (ushort)value);
get
{
using var slice = Data;
return Binary.Read16(slice.Array, slice.Offset + 9, Binary.IsLittleEndian);
}
set
{
using var slice = Data;
Binary.Write16(slice.Array, slice.Offset + 9, Binary.IsLittleEndian, (ushort)value);
}
}

public int YDensity
{
get => Binary.Read16(Data.Array, Data.Offset + 11, Binary.IsLittleEndian);
set => Binary.Write16(Data.Array, Data.Offset + 11, Binary.IsLittleEndian, (ushort)value);
get
{
using var slice = Data;
return Binary.Read16(slice.Array, slice.Offset + 11, Binary.IsLittleEndian);
}
set
{
using var slice = Data;
Binary.Write16(slice.Array, slice.Offset + 11, Binary.IsLittleEndian, (ushort)value);
}
}

public int XThumbnail
{
get => Data[12];
set => Data[12] = (byte)value;
get
{
using var slice = Data;
return slice[12];
}
set
{
using var slice = Data;
slice[12] = (byte)value;
}
}

public int YThumbnail
{
get => Data[13];
set => Data[13] = (byte)value;
get
{
using var slice = Data;
return slice[13];
}
set
{
using var slice = Data;
slice[13] = (byte)value;
}
}

public MemorySegment ThumbnailData
{
get => Data.Slice(14);
set => value.CopyTo(Data.Array, Data.Offset + 14);
get
{
using var slice = Data;
return slice.Slice(14);
}
set
{
using var slice = Data;
value.CopyTo(slice);
}
}

public App(byte functionCode, MemorySegment data)
: base(functionCode, Length + data.Count)
{
data.CopyTo(Data.Array, Data.Offset + 14);
using var slice = Data;
data.CopyTo(slice);
}

public App(Marker marker) : base(marker)
Expand Down
10 changes: 5 additions & 5 deletions Codecs/Image/Jpeg/Markers/AppExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ public AppExtension(MemorySegment data)

public string Identifier
{
get => Encoding.UTF8.GetString(Data.Array, Data.Offset, 5);
set => Encoding.UTF8.GetBytes(value, 0, 5, Data.Array, Data.Offset);
get => Encoding.UTF8.GetString(Array, DataOffset, 5);
set => Encoding.UTF8.GetBytes(value, 0, 5, Array, DataOffset);
}

public int ThumbnailFormat
{
get => Data[6];
set => Data[6] = (byte)value;
get => Array[DataOffset + 6];
set => Array[DataOffset + 6] = (byte)value;
}

public ThumbnailFormatType ThumbnailFormatType
Expand All @@ -40,7 +40,7 @@ public ThumbnailFormatType ThumbnailFormatType

public MemorySegment ThumbnailData
{
get => Data.Slice(DataLength > 0 ? 6 : 0);
get => this.Slice(DataOffset + DataLength > 0 ? Length : 0);
set
{
using var slice = ThumbnailData;
Expand Down
8 changes: 4 additions & 4 deletions Codecs/Image/Jpeg/Markers/Exp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ public int Eh
{
get
{
var bitOffset = Binary.BytesToBits(Data.Offset);
var bitOffset = Binary.BytesToBits(DataOffset);
return (int)this.ReadBits(bitOffset, Binary.Four, Binary.BitOrder.MostSignificant);
}
set
{
var bitOffset = Binary.BytesToBits(Data.Offset);
var bitOffset = Binary.BytesToBits(DataOffset);
this.WriteBits(ref bitOffset, Binary.Four, value, Binary.BitOrder.MostSignificant);
}
}
Expand All @@ -25,12 +25,12 @@ public int Ev
{
get
{
var bitOffset = Binary.BytesToBits(Data.Offset) + Binary.Four;
var bitOffset = Binary.BytesToBits(DataOffset) + Binary.Four;
return (int)this.ReadBits(bitOffset, Binary.Four, Binary.BitOrder.MostSignificant);
}
set
{
var bitOffset = Binary.BytesToBits(Data.Offset) + Binary.Four;
var bitOffset = Binary.BytesToBits(DataOffset) + Binary.Four;
this.WriteBits(ref bitOffset, Binary.Four, value, Binary.BitOrder.MostSignificant);
}
}
Expand Down
4 changes: 2 additions & 2 deletions Codecs/Image/Jpeg/Markers/NumberOfLines.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ public class NumberOfLines : Marker
/// </summary>
public int Nl
{
get => Binary.Read16(Array, Data.Offset + 2, Binary.IsLittleEndian);
set => Binary.Write16(Array, Data.Offset + 2, Binary.IsLittleEndian, (ushort)value);
get => Binary.Read16(Array, DataOffset + 2, Binary.IsLittleEndian);
set => Binary.Write16(Array, DataOffset + 2, Binary.IsLittleEndian, (ushort)value);
}

public NumberOfLines(byte functionCode, int numberOfLines)
Expand Down
21 changes: 10 additions & 11 deletions Codecs/Image/Jpeg/Markers/StartOfFrame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,35 @@ public class StartOfFrame : Marker
/// </summary>
public int P
{
get => Data[0];
set => Data[0] = (byte)value;
get => Array[DataOffset];
set => Array[DataOffset] = (byte)value;
}

/// <summary>
/// Number of lines – Specifies the maximum number of lines in the source image
/// </summary>
public int Y
{
get => Binary.ReadU16(Array, Data.Offset + 1, Binary.IsLittleEndian);
set => Binary.Write16(Array, Data.Offset + 1, Binary.IsLittleEndian, (ushort)value);
get => Binary.ReadU16(Array, DataOffset + 1, Binary.IsLittleEndian);
set => Binary.Write16(Array, DataOffset + 1, Binary.IsLittleEndian, (ushort)value);
}

/// <summary>
/// Number of samples per line – Specifies the maximum number of samples per line in the source image
/// </summary>
public int X
{
get => Binary.ReadU16(Array, Data.Offset + 3, Binary.IsLittleEndian);
set => Binary.Write16(Array, Data.Offset + 3, Binary.IsLittleEndian, (ushort)value);
get => Binary.ReadU16(Array, DataOffset + 3, Binary.IsLittleEndian);
set => Binary.Write16(Array, DataOffset + 3, Binary.IsLittleEndian, (ushort)value);
}

/// <summary>
/// Number of <see cref="FrameComponent"/>s components in frame
/// </summary>
public int Nf
{
get => Binary.ReadU8(Data.Array, Data.Offset + 5, Binary.IsBigEndian);
set => Binary.Write8(Data.Array, Data.Offset + 5, Binary.IsBigEndian, (byte)value);
get => Binary.ReadU8(Array, DataOffset + 5, Binary.IsBigEndian);
set => Binary.Write8(Array, DataOffset + 5, Binary.IsBigEndian, (byte)value);
}

/// <summary>
Expand All @@ -58,13 +58,12 @@ public int Nf
get
{
var offset = Length + index * FrameComponent.Length;
using var slice = Data.Slice(offset, FrameComponent.Length);
return new FrameComponent(slice);
return new FrameComponent(this.Slice(DataOffset + offset, FrameComponent.Length));
}
set
{
var offset = Length + index * FrameComponent.Length;
using var slice = Data.Slice(offset, FrameComponent.Length);
using var slice = this.Slice(DataOffset + offset, FrameComponent.Length);
value.CopyTo(slice);
}
}
Expand Down
Loading

0 comments on commit cff5cbe

Please sign in to comment.