Skip to content

Commit

Permalink
Enable all JpegLSDecoderTest unit tests (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
vbaderks authored Aug 14, 2024
1 parent ceda501 commit d772a8f
Show file tree
Hide file tree
Showing 17 changed files with 584 additions and 523 deletions.
1 change: 1 addition & 0 deletions CharLSDotNet.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CheckNamespace/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ParameterOnlyUsedForPreconditionCheck_002ELocal/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=FF/@EntryIndexedValue">FF</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HP/@EntryIndexedValue">HP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LS/@EntryIndexedValue">LS</s:String>
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ This project is considered work in progress and NOT ready for general use. The f
* [X] Encode 16 bit images, interleave mode: sample
* [X] Encode\Decode 16 bit images HP color transformation
* [X] Encode\Decode 4 component images
* [ ] Support for SPIFF Header
* [X] Support for SPIFF Header
* [ ] General code clean-up
* [ ] Good code coverage
* [ ] Performance tuning
Expand Down
12 changes: 11 additions & 1 deletion src/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,20 @@ public enum ErrorCode
RestartMarkerNotFound = 26,

/// <summary>
/// TODO
/// This error is returned when an event handler threw an exception.
/// </summary>
CallbackFailed = 27,

/// <summary>
/// This error is returned when the End of Image (EOI) marker could not be found.
/// </summary>
EndOfImageMarkerNotFound = 28,

/// <summary>
/// This error is returned when the SPIFF header is invalid.
/// </summary>
InvalidSpiffHeader = 29,

/// <summary>
/// The argument for the width parameter is outside the range [1, 2147483647].
/// </summary>
Expand Down
96 changes: 70 additions & 26 deletions src/JpegLSDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace CharLS.Managed;
public sealed class JpegLSDecoder
{
private FrameInfo? _frameInfo;
private readonly JpegStreamReader _reader = new();
private readonly JpegStreamReader _reader;

private enum State
{
Expand All @@ -25,26 +25,37 @@ private enum State

private State _state = State.Initial;

/// <summary>
/// Occurs when a comment (COM segment) is read.
/// </summary>
public event EventHandler<CommentEventArgs>? Comment
{
add { _reader.Comment += value; }
remove { _reader.Comment -= value; }
}

/// <summary>
/// Initializes a new instance of the <see cref="JpegLSDecoder"/> class.
/// </summary>
public JpegLSDecoder()
{
_reader = new JpegStreamReader(this);
}

/// <summary>
/// Initializes a new instance of the <see cref="JpegLSDecoder"/> class.
/// </summary>
/// <param name="source">The buffer containing the encoded data.</param>
/// <param name="readHeader">When true the header from the JPEG-LS stream is parsed.</param>
/// <param name="readHeader">When true the header from the JPEG-LS stream is read parsed.</param>
/// <param name="tryReadSpiffHeader">When true the SPIFF header from the JPEG-LS stream is read and parsed.</param>
/// <exception cref="InvalidDataException">Thrown when the JPEG-LS stream is not valid.</exception>
public JpegLSDecoder(ReadOnlyMemory<byte> source, bool readHeader = true)
public JpegLSDecoder(ReadOnlyMemory<byte> source, bool readHeader = true, bool tryReadSpiffHeader = true)
: this()
{
Source = source;
if (readHeader)
{
ReadHeader();
ReadHeader(tryReadSpiffHeader);
}
}

Expand Down Expand Up @@ -86,7 +97,7 @@ public ReadOnlyMemory<byte> Source
/// <value>
/// The frame information of the parsed JPEG-LS image.
/// </value>
/// <exception cref="InvalidOperationException">Thrown when this property is used before <see cref="ReadHeader()"/>.</exception>
/// <exception cref="InvalidOperationException">Thrown when this property is used before <see cref="ReadHeader(bool)"/>.</exception>
public FrameInfo FrameInfo => _reader.FrameInfo ?? throw new InvalidOperationException("Incorrect state. ReadHeader has not called.");

/// <summary>
Expand All @@ -98,7 +109,7 @@ public ReadOnlyMemory<byte> Source
/// <value>
/// The near lossless parameter. A value of 0 means that the image is lossless encoded.
/// </value>
/// <exception cref="InvalidOperationException">Thrown when this property is used before <see cref="ReadHeader()"/>.</exception>
/// <exception cref="InvalidOperationException">Thrown when this property is used before <see cref="ReadHeader(bool)"/>.</exception>
public int NearLossless
{
get
Expand All @@ -115,7 +126,7 @@ public int NearLossless
/// Property should be obtained after calling <see cref="ReadHeader"/>".
/// </remarks>
/// <returns>The result of the operation: success or a failure code.</returns>
/// <exception cref="InvalidOperationException">Thrown when this property is used before <see cref="ReadHeader()"/>.</exception>
/// <exception cref="InvalidOperationException">Thrown when this property is used before <see cref="ReadHeader(bool)"/>.</exception>
public InterleaveMode InterleaveMode
{
get
Expand All @@ -131,7 +142,7 @@ public InterleaveMode InterleaveMode
/// <value>
/// The preset coding parameters.
/// </value>
/// <exception cref="InvalidOperationException">Thrown when this property is used before <see cref="ReadHeader()"/>.</exception>
/// <exception cref="InvalidOperationException">Thrown when this property is used before <see cref="ReadHeader(bool)"/>.</exception>
public JpegLSPresetCodingParameters PresetCodingParameters
{
get
Expand All @@ -158,7 +169,7 @@ public ColorTransformation ColorTransformation
/// <param name="stride">The stride to use; byte count to the next pixel row. Pass 0 for the default.</param>
/// <returns>The size of the destination buffer in bytes.</returns>
/// <exception cref="OverflowException">When the required destination size doesn't fit in an int.</exception>
/// <exception cref="InvalidOperationException">Thrown when this method is called before <see cref="ReadHeader()"/>.</exception>
/// <exception cref="InvalidOperationException">Thrown when this method is called before <see cref="ReadHeader(bool)"/>.</exception>
public int GetDestinationSize(int stride = 0)
{
if (_state < State.HeaderRead)
Expand All @@ -185,22 +196,63 @@ public int GetDestinationSize(int stride = 0)
}
}

/// <summary>
/// Reads the SPIFF (Still Picture Interchange File Format) header.
/// </summary>
/// <param name="spiffHeader">The header or null when no valid header was found.</param>
/// <returns>true if a SPIFF header was present and could be read.</returns>
/// <exception cref="InvalidDataException">Thrown when the JPEG-LS stream is not valid.</exception>
public bool TryReadSpiffHeader(out SpiffHeader? spiffHeader)
{
ThrowHelper.ThrowInvalidOperationIfFalse(_state == State.SourceSet);
_reader.ReadHeader(true);

spiffHeader = _reader.SpiffHeader;
if (spiffHeader == null)
{
_state = State.SpiffHeaderNotFound;
return false;
}

_state = State.SpiffHeaderRead;
return true;
}

/// <summary>
/// Validates a SPIFF header with the FrameInfo.
/// </summary>
/// <param name="spiffHeader">Reference to a SPIFF header that will be validated.</param>
/// <exception cref="InvalidDataException">Thrown when the SPIFF header is not valid.</exception>
public void ValidateSpiffHeader(SpiffHeader spiffHeader)
{
ThrowHelper.ThrowInvalidOperationIfFalse(_state >= State.HeaderRead);
if (!spiffHeader.IsValid(FrameInfo))
ThrowHelper.ThrowInvalidDataException(ErrorCode.InvalidSpiffHeader);
}

/// <summary>
/// Reads the header of the JPEG-LS stream.
/// After calling this method, the informational properties can be obtained.
/// </summary>
/// <exception cref="InvalidDataException">Thrown when the JPEG-LS stream is not valid.</exception>
public void ReadHeader()
public void ReadHeader(bool tryReadSpiffHeader = true)
{
CheckOperation(_state == State.SourceSet);

_reader.ReadHeader();
_state = State.HeaderRead;
ThrowHelper.ThrowInvalidOperationIfFalse(_state is >= State.SourceSet and < State.HeaderRead);

if (_reader.SpiffHeader != null && _reader.SpiffHeader.IsValid(FrameInfo))
if (_state != State.SpiffHeaderNotFound)
{
SpiffHeader = _reader.SpiffHeader;
_reader.ReadHeader(tryReadSpiffHeader);
if (_reader.SpiffHeader != null)
{
_reader.ReadHeader(false);
if (_reader.SpiffHeader.IsValid(FrameInfo))
{
SpiffHeader = _reader.SpiffHeader;
}
}
}

_state = State.HeaderRead;
}

/// <summary>
Expand All @@ -210,7 +262,7 @@ public void ReadHeader()
/// <returns>A byte array with the decoded JPEG-LS data.</returns>
/// <exception cref="InvalidDataException">Thrown when the JPEG-LS stream is not valid.</exception>
/// <exception cref="ObjectDisposedException">Thrown when the instance is used after being disposed.</exception>
/// <exception cref="InvalidOperationException">Thrown when this method is called before <see cref="ReadHeader()"/>.</exception>
/// <exception cref="InvalidOperationException">Thrown when this method is called before <see cref="ReadHeader(bool)"/>.</exception>
public byte[] Decode(int stride = 0)
{
var destination = new byte[GetDestinationSize()];
Expand Down Expand Up @@ -267,22 +319,14 @@ public void Decode(Span<byte> destination, int stride = 0)
_state = State.Completed;
}

private static void CheckOperation(bool expression)
{
if (!expression)
{
throw new InvalidOperationException("JPEG-LS Decoder in the incorrect state.");
}
}

private void CheckHeaderRead()
{
ThrowHelper.ThrowInvalidOperationIfFalse(_state >= State.HeaderRead);
}

private int CalculateMinimumStride()
{
int componentsInPlaneCount =
int componentsInPlaneCount =
_reader.InterleaveMode == InterleaveMode.None
? 1
: FrameInfo.ComponentCount;
Expand Down
Loading

0 comments on commit d772a8f

Please sign in to comment.