diff --git a/appveyor.yml b/appveyor.yml
index f784ef2876..9b1ce2b958 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,5 +1,5 @@
version: 1.0.0.{build}
-image: Visual Studio 2017
+image: Visual Studio 2017 Preview
# prevent the double build when a branch has an active PR
skip_branch_with_pr: true
diff --git a/run-tests.ps1 b/run-tests.ps1
index e13c8fa648..d774f7a61a 100644
--- a/run-tests.ps1
+++ b/run-tests.ps1
@@ -15,6 +15,32 @@ function VerifyPath($path, $errorMessage) {
}
}
+function CheckSubmoduleStatus() {
+ $submoduleStatus = (git submodule status) | Out-String
+ # if the result string is empty, the command failed to run (we didn't capture the error stream)
+ if ($submoduleStatus) {
+ # git has been called successfully, what about the status?
+ if (($submoduleStatus -match "\-") -or ($submoduleStatus -match "\(\(null\)\)"))
+ {
+ # submodule has not been initialized!
+ return 2;
+ }
+ elseif ($submoduleStatus -match "\+")
+ {
+ # submodule is not synced:
+ return 1;
+ }
+ else {
+ # everything fine:
+ return 0;
+ }
+ } else {
+ # git call failed, so we should warn
+ return 3;
+ }
+}
+
+
if ( ($targetFramework -eq "netcoreapp2.0") -and ($env:CI -eq "True") -and ($is32Bit -ne "True")) {
# We execute CodeCoverage.cmd only for one specific job on CI (netcoreapp2.0 + 64bit )
$testRunnerCmd = ".\tests\CodeCoverage\CodeCoverage.cmd"
@@ -64,4 +90,23 @@ Invoke-Expression $testRunnerCmd
cd $PSScriptRoot
-exit $LASTEXITCODE
+$exitCodeOfTests = $LASTEXITCODE;
+
+if (0 -ne ([int]$exitCodeOfTests)) {
+ # check submodule status
+ $submoduleStatus = CheckSubmoduleStatus
+ if ([int]$submoduleStatus -eq 1) {
+ # not synced
+ Write-Host -ForegroundColor Yellow "Check if submodules are up to date. You can use 'git submodule update' to fix this";
+ } elseif ($submoduleStatus -eq 2) {
+ # not initialized
+ Write-Host -ForegroundColor Yellow "Check if submodules are initialized. You can run 'git submodule init' to initialize them."
+ } elseif ($submoduleStatus -eq 3) {
+ # git not found, maybe submodules not synced?
+ Write-Host -ForegroundColor Yellow "Could not check if submodules are initialized correctly. Maybe git is not installed?"
+ } else {
+ #Write-Host "Submodules are up to date";
+ }
+}
+
+exit $exitCodeOfTests
diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
index a732d1da2c..40a929fe4a 100644
--- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
+++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
@@ -38,7 +38,7 @@
-
+
diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Brushes/BrushApplicator.cs b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/BrushApplicator.cs
index f665e8408c..c546663353 100644
--- a/src/ImageSharp.Drawing/Processing/Drawing/Brushes/BrushApplicator.cs
+++ b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/BrushApplicator.cs
@@ -79,6 +79,10 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
{
amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
}
+ else
+ {
+ amountSpan[i] = scanline[i];
+ }
overlaySpan[i] = this[x + i, y];
}
diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/ColorStop{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/ColorStop{TPixel}.cs
new file mode 100644
index 0000000000..298af5cb56
--- /dev/null
+++ b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/ColorStop{TPixel}.cs
@@ -0,0 +1,36 @@
+using System.Diagnostics;
+
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Processing.Drawing.Brushes.GradientBrushes
+{
+ ///
+ /// A struct that defines a single color stop.
+ ///
+ /// The pixel format.
+ [DebuggerDisplay("ColorStop({Ratio} -> {Color}")]
+ public struct ColorStop
+ where TPixel : struct, IPixel
+ {
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// Where should it be? 0 is at the start, 1 at the end of the Gradient.
+ /// What color should be used at that point?
+ public ColorStop(float ratio, TPixel color)
+ {
+ this.Ratio = ratio;
+ this.Color = color;
+ }
+
+ ///
+ /// Gets the point along the defined gradient axis.
+ ///
+ public float Ratio { get; }
+
+ ///
+ /// Gets the color to be used.
+ ///
+ public TPixel Color { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/EllipticGradientBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/EllipticGradientBrush{TPixel}.cs
new file mode 100644
index 0000000000..43f7fe04e9
--- /dev/null
+++ b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/EllipticGradientBrush{TPixel}.cs
@@ -0,0 +1,167 @@
+using System;
+
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.Primitives;
+
+namespace SixLabors.ImageSharp.Processing.Drawing.Brushes.GradientBrushes
+{
+ ///
+ /// Gradient Brush with elliptic shape.
+ /// The ellipse is defined by a center point,
+ /// a point on the longest extension of the ellipse and
+ /// the ratio between longest and shortest extension.
+ ///
+ /// The Pixel format that is used.
+ public sealed class EllipticGradientBrush : GradientBrushBase
+ where TPixel : struct, IPixel
+ {
+ private readonly Point center;
+
+ private readonly Point referenceAxisEnd;
+
+ private readonly float axisRatio;
+
+ ///
+ /// The center of the elliptical gradient and 0 for the color stops.
+ /// The end point of the reference axis of the ellipse.
+ ///
+ /// The ratio of the axis widths.
+ /// The second axis' is perpendicular to the reference axis and
+ /// it's length is the reference axis' length multiplied by this factor.
+ ///
+ /// Defines how the colors of the gradients are repeated.
+ /// the color stops as defined in base class.
+ public EllipticGradientBrush(
+ Point center,
+ Point referenceAxisEnd,
+ float axisRatio,
+ GradientRepetitionMode repetitionMode,
+ params ColorStop[] colorStops)
+ : base(repetitionMode, colorStops)
+ {
+ this.center = center;
+ this.referenceAxisEnd = referenceAxisEnd;
+ this.axisRatio = axisRatio;
+ }
+
+ ///
+ public override BrushApplicator CreateApplicator(
+ ImageFrame source,
+ RectangleF region,
+ GraphicsOptions options) =>
+ new RadialGradientBrushApplicator(
+ source,
+ options,
+ this.center,
+ this.referenceAxisEnd,
+ this.axisRatio,
+ this.ColorStops,
+ this.RepetitionMode);
+
+ ///
+ private sealed class RadialGradientBrushApplicator : GradientBrushApplicatorBase
+ {
+ private readonly Point center;
+
+ private readonly Point referenceAxisEnd;
+
+ private readonly float axisRatio;
+
+ private readonly double rotation;
+
+ private readonly float referenceRadius;
+
+ private readonly float secondRadius;
+
+ private readonly float cosRotation;
+
+ private readonly float sinRotation;
+
+ private readonly float secondRadiusSquared;
+
+ private readonly float referenceRadiusSquared;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The target image
+ /// The options
+ /// Center of the ellipse
+ /// Point on one angular points of the ellipse.
+ ///
+ /// Ratio of the axis length's. Used to determine the length of the second axis,
+ /// the first is defined by and .
+ /// Definition of colors
+ /// Defines how the gradient colors are repeated.
+ public RadialGradientBrushApplicator(
+ ImageFrame target,
+ GraphicsOptions options,
+ Point center,
+ Point referenceAxisEnd,
+ float axisRatio,
+ ColorStop[] colorStops,
+ GradientRepetitionMode repetitionMode)
+ : base(target, options, colorStops, repetitionMode)
+ {
+ this.center = center;
+ this.referenceAxisEnd = referenceAxisEnd;
+ this.axisRatio = axisRatio;
+ this.rotation = this.AngleBetween(
+ this.center,
+ new PointF(this.center.X + 1, this.center.Y),
+ this.referenceAxisEnd);
+ this.referenceRadius = this.DistanceBetween(this.center, this.referenceAxisEnd);
+ this.secondRadius = this.referenceRadius * this.axisRatio;
+
+ this.referenceRadiusSquared = this.referenceRadius * this.referenceRadius;
+ this.secondRadiusSquared = this.secondRadius * this.secondRadius;
+
+ this.sinRotation = (float)Math.Sin(this.rotation);
+ this.cosRotation = (float)Math.Cos(this.rotation);
+ }
+
+ ///
+ public override void Dispose()
+ {
+ }
+
+ ///
+ protected override float PositionOnGradient(int xt, int yt)
+ {
+ float x0 = xt - this.center.X;
+ float y0 = yt - this.center.Y;
+
+ float x = (x0 * this.cosRotation) - (y0 * this.sinRotation);
+ float y = (x0 * this.sinRotation) + (y0 * this.cosRotation);
+
+ float xSquared = x * x;
+ float ySquared = y * y;
+
+ var inBoundaryChecker = (xSquared / this.referenceRadiusSquared)
+ + (ySquared / this.secondRadiusSquared);
+
+ return inBoundaryChecker;
+ }
+
+ private float AngleBetween(PointF junction, PointF a, PointF b)
+ {
+ var vA = a - junction;
+ var vB = b - junction;
+ return (float)(Math.Atan2(vB.Y, vB.X)
+ - Math.Atan2(vA.Y, vA.X));
+ }
+
+ private float DistanceBetween(
+ PointF p1,
+ PointF p2)
+ {
+ float dX = p1.X - p2.X;
+ float dXsquared = dX * dX;
+
+ float dY = p1.Y - p2.Y;
+ float dYsquared = dY * dY;
+ return (float)Math.Sqrt(dXsquared + dYsquared);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/GradientBrushBase{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/GradientBrushBase{TPixel}.cs
new file mode 100644
index 0000000000..d0a1ef1c24
--- /dev/null
+++ b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/GradientBrushBase{TPixel}.cs
@@ -0,0 +1,174 @@
+using System;
+using System.Numerics;
+
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.PixelFormats.PixelBlenders;
+using SixLabors.Primitives;
+
+namespace SixLabors.ImageSharp.Processing.Drawing.Brushes.GradientBrushes
+{
+ ///
+ /// Base class for Gradient brushes
+ ///
+ /// The pixel format
+ public abstract class GradientBrushBase : IBrush
+ where TPixel : struct, IPixel
+ {
+ ///
+ /// Defines how the colors are repeated beyond the interval [0..1]
+ /// The gradient colors.
+ protected GradientBrushBase(
+ GradientRepetitionMode repetitionMode,
+ params ColorStop[] colorStops)
+ {
+ this.RepetitionMode = repetitionMode;
+ this.ColorStops = colorStops;
+ }
+
+ ///
+ /// Gets how the colors are repeated beyond the interval [0..1].
+ ///
+ protected GradientRepetitionMode RepetitionMode { get; }
+
+ ///
+ /// Gets the list of color stops for this gradient.
+ ///
+ protected ColorStop[] ColorStops { get; }
+
+ ///
+ public abstract BrushApplicator CreateApplicator(
+ ImageFrame source,
+ RectangleF region,
+ GraphicsOptions options);
+
+ ///
+ /// Base class for gradient brush applicators
+ ///
+ protected abstract class GradientBrushApplicatorBase : BrushApplicator
+ {
+ private readonly ColorStop[] colorStops;
+
+ private readonly GradientRepetitionMode repetitionMode;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The target.
+ /// The options.
+ /// An array of color stops sorted by their position.
+ /// Defines if and how the gradient should be repeated.
+ protected GradientBrushApplicatorBase(
+ ImageFrame target,
+ GraphicsOptions options,
+ ColorStop[] colorStops,
+ GradientRepetitionMode repetitionMode)
+ : base(target, options)
+ {
+ this.colorStops = colorStops; // TODO: requires colorStops to be sorted by position - should that be checked?
+ this.repetitionMode = repetitionMode;
+ }
+
+ ///
+ /// Base implementation of the indexer for gradients
+ /// (follows the facade pattern, using abstract methods)
+ ///
+ /// X coordinate of the Pixel.
+ /// Y coordinate of the Pixel.
+ internal override TPixel this[int x, int y]
+ {
+ get
+ {
+ float positionOnCompleteGradient = this.PositionOnGradient(x, y);
+
+ switch (this.repetitionMode)
+ {
+ case GradientRepetitionMode.None:
+ // do nothing. The following could be done, but is not necessary:
+ // onLocalGradient = Math.Min(0, Math.Max(1, onLocalGradient));
+ break;
+ case GradientRepetitionMode.Repeat:
+ positionOnCompleteGradient = positionOnCompleteGradient % 1;
+ break;
+ case GradientRepetitionMode.Reflect:
+ positionOnCompleteGradient = positionOnCompleteGradient % 2;
+ if (positionOnCompleteGradient > 1)
+ {
+ positionOnCompleteGradient = 2 - positionOnCompleteGradient;
+ }
+
+ break;
+ case GradientRepetitionMode.DontFill:
+ if (positionOnCompleteGradient > 1 || positionOnCompleteGradient < 0)
+ {
+ return NamedColors.Transparent;
+ }
+
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
+ var (from, to) = this.GetGradientSegment(positionOnCompleteGradient);
+
+ if (from.Color.Equals(to.Color))
+ {
+ return from.Color;
+ }
+ else
+ {
+ var fromAsVector = from.Color.ToVector4();
+ var toAsVector = to.Color.ToVector4();
+ float onLocalGradient = (positionOnCompleteGradient - from.Ratio) / to.Ratio;
+
+ // TODO: this should be changeble for different gradienting functions
+ Vector4 result = PorterDuffFunctions.Normal(
+ fromAsVector,
+ toAsVector,
+ onLocalGradient);
+
+ TPixel resultColor = default;
+ resultColor.PackFromVector4(result);
+ return resultColor;
+ }
+ }
+ }
+
+ ///
+ /// calculates the position on the gradient for a given pixel.
+ /// This method is abstract as it's content depends on the shape of the gradient.
+ ///
+ /// The x coordinate of the pixel
+ /// The y coordinate of the pixel
+ ///
+ /// The position the given pixel has on the gradient.
+ /// The position is not bound to the [0..1] interval.
+ /// Values outside of that interval may be treated differently,
+ /// e.g. for the enum.
+ ///
+ protected abstract float PositionOnGradient(int x, int y);
+
+ private (ColorStop from, ColorStop to) GetGradientSegment(
+ float positionOnCompleteGradient)
+ {
+ var localGradientFrom = this.colorStops[0];
+ ColorStop localGradientTo = default;
+
+ // TODO: ensure colorStops has at least 2 items (technically 1 would be okay, but that's no gradient)
+ foreach (var colorStop in this.colorStops)
+ {
+ localGradientTo = colorStop;
+
+ if (colorStop.Ratio > positionOnCompleteGradient)
+ {
+ // we're done here, so break it!
+ break;
+ }
+
+ localGradientFrom = localGradientTo;
+ }
+
+ return (localGradientFrom, localGradientTo);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/GradientRepetitionMode.cs b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/GradientRepetitionMode.cs
new file mode 100644
index 0000000000..adbc26ed43
--- /dev/null
+++ b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/GradientRepetitionMode.cs
@@ -0,0 +1,34 @@
+namespace SixLabors.ImageSharp.Processing.Drawing.Brushes.GradientBrushes
+{
+ ///
+ /// Modes to repeat a gradient.
+ ///
+ public enum GradientRepetitionMode
+ {
+ ///
+ /// don't repeat, keep the color of start and end beyond those points stable.
+ ///
+ None,
+
+ ///
+ /// Repeat the gradient.
+ /// If it's a black-white gradient, with Repeat it will be Black->{gray}->White|Black->{gray}->White|...
+ ///
+ Repeat,
+
+ ///
+ /// Reflect the gradient.
+ /// Similar to , but each other repetition uses inverse order of s.
+ /// Used on a Black-White gradient, Reflect leads to Black->{gray}->White->{gray}->White...
+ ///
+ Reflect,
+
+ ///
+ /// With DontFill a gradient does not touch any pixel beyond it's borders.
+ /// For the this is beyond the orthogonal through start and end,
+ /// TODO For the cref="PolygonalGradientBrush" it's outside the polygon,
+ /// For and it's beyond 1.0.
+ ///
+ DontFill
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/LinearGradientBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/LinearGradientBrush{TPixel}.cs
new file mode 100644
index 0000000000..09f816dd97
--- /dev/null
+++ b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/LinearGradientBrush{TPixel}.cs
@@ -0,0 +1,152 @@
+using System;
+
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.Primitives;
+
+namespace SixLabors.ImageSharp.Processing.Drawing.Brushes.GradientBrushes
+{
+ ///
+ /// Provides an implementation of a brush for painting linear gradients within areas.
+ /// Supported right now:
+ /// - a set of colors in relative distances to each other.
+ ///
+ /// The pixel format
+ public sealed class LinearGradientBrush : GradientBrushBase
+ where TPixel : struct, IPixel
+ {
+ private readonly Point p1;
+
+ private readonly Point p2;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Start point
+ /// End point
+ /// defines how colors are repeated.
+ ///
+ public LinearGradientBrush(
+ Point p1,
+ Point p2,
+ GradientRepetitionMode repetitionMode,
+ params ColorStop[] colorStops)
+ : base(repetitionMode, colorStops)
+ {
+ this.p1 = p1;
+ this.p2 = p2;
+ }
+
+ ///
+ public override BrushApplicator CreateApplicator(ImageFrame source, RectangleF region, GraphicsOptions options)
+ => new LinearGradientBrushApplicator(source, this.p1, this.p2, this.ColorStops, this.RepetitionMode, options);
+
+ ///
+ /// The linear gradient brush applicator.
+ ///
+ private sealed class LinearGradientBrushApplicator : GradientBrushApplicatorBase
+ {
+ private readonly Point start;
+
+ private readonly Point end;
+
+ ///
+ /// the vector along the gradient, x component
+ ///
+ private readonly float alongX;
+
+ ///
+ /// the vector along the gradient, y component
+ ///
+ private readonly float alongY;
+
+ ///
+ /// the vector perpendicular to the gradient, y component
+ ///
+ private readonly float acrossY;
+
+ ///
+ /// the vector perpendicular to the gradient, x component
+ ///
+ private readonly float acrossX;
+
+ ///
+ /// the result of ^2 + ^2
+ ///
+ private readonly float alongsSquared;
+
+ ///
+ /// the length of the defined gradient (between source and end)
+ ///
+ private readonly float length;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The source
+ /// start point of the gradient
+ /// end point of the gradient
+ /// tuple list of colors and their respective position between 0 and 1 on the line
+ /// defines how the gradient colors are repeated.
+ /// the graphics options
+ public LinearGradientBrushApplicator(
+ ImageFrame source,
+ Point start,
+ Point end,
+ ColorStop[] colorStops,
+ GradientRepetitionMode repetitionMode,
+ GraphicsOptions options)
+ : base(source, options, colorStops, repetitionMode)
+ {
+ this.start = start;
+ this.end = end;
+
+ // the along vector:
+ this.alongX = this.end.X - this.start.X;
+ this.alongY = this.end.Y - this.start.Y;
+
+ // the cross vector:
+ this.acrossX = this.alongY;
+ this.acrossY = -this.alongX;
+
+ // some helpers:
+ this.alongsSquared = (this.alongX * this.alongX) + (this.alongY * this.alongY);
+ this.length = (float)Math.Sqrt(this.alongsSquared);
+ }
+
+ protected override float PositionOnGradient(int x, int y)
+ {
+ if (this.acrossX == 0)
+ {
+ return (x - this.start.X) / (float)(this.end.X - this.start.X);
+ }
+ else if (this.acrossY == 0)
+ {
+ return (y - this.start.Y) / (float)(this.end.Y - this.start.Y);
+ }
+ else
+ {
+ float deltaX = x - this.start.X;
+ float deltaY = y - this.start.Y;
+ float k = ((this.alongY * deltaX) - (this.alongX * deltaY)) / this.alongsSquared;
+
+ // point on the line:
+ float x4 = x - (k * this.alongY);
+ float y4 = y + (k * this.alongX);
+
+ // get distance from (x4,y4) to start
+ float distance = (float)Math.Sqrt(
+ Math.Pow(x4 - this.start.X, 2)
+ + Math.Pow(y4 - this.start.Y, 2));
+
+ // get and return ratio
+ float ratio = distance / this.length;
+ return ratio;
+ }
+ }
+
+ public override void Dispose()
+ {
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/RadialGradientBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/RadialGradientBrush{TPixel}.cs
new file mode 100644
index 0000000000..5c0d8051ca
--- /dev/null
+++ b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/GradientBrushes/RadialGradientBrush{TPixel}.cs
@@ -0,0 +1,102 @@
+using System;
+
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.Primitives;
+
+namespace SixLabors.ImageSharp.Processing.Drawing.Brushes.GradientBrushes
+{
+ ///
+ /// A Circular Gradient Brush, defined by center point and radius.
+ ///
+ /// The pixel format.
+ public sealed class RadialGradientBrush : GradientBrushBase
+ where TPixel : struct, IPixel
+ {
+ private readonly Point center;
+
+ private readonly float radius;
+
+ ///
+ /// The center of the circular gradient and 0 for the color stops.
+ /// The radius of the circular gradient and 1 for the color stops.
+ /// Defines how the colors in the gradient are repeated.
+ /// the color stops as defined in base class.
+ public RadialGradientBrush(
+ Point center,
+ float radius,
+ GradientRepetitionMode repetitionMode,
+ params ColorStop[] colorStops)
+ : base(repetitionMode, colorStops)
+ {
+ this.center = center;
+ this.radius = radius;
+ }
+
+ ///
+ public override BrushApplicator CreateApplicator(
+ ImageFrame source,
+ RectangleF region,
+ GraphicsOptions options) =>
+ new RadialGradientBrushApplicator(
+ source,
+ options,
+ this.center,
+ this.radius,
+ this.ColorStops,
+ this.RepetitionMode);
+
+ ///
+ private sealed class RadialGradientBrushApplicator : GradientBrushApplicatorBase
+ {
+ private readonly Point center;
+
+ private readonly float radius;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The target image
+ /// The options.
+ /// Center point of the gradient.
+ /// Radius of the gradient.
+ /// Definition of colors.
+ /// How the colors are repeated beyond the first gradient.
+ public RadialGradientBrushApplicator(
+ ImageFrame target,
+ GraphicsOptions options,
+ Point center,
+ float radius,
+ ColorStop[] colorStops,
+ GradientRepetitionMode repetitionMode)
+ : base(target, options, colorStops, repetitionMode)
+ {
+ this.center = center;
+ this.radius = radius;
+ }
+
+ ///
+ public override void Dispose()
+ {
+ }
+
+ ///
+ /// As this is a circular gradient, the position on the gradient is based on
+ /// the distance of the point to the center.
+ ///
+ /// The X coordinate of the target pixel.
+ /// The Y coordinate of the target pixel.
+ /// the position on the color gradient.
+ protected override float PositionOnGradient(int x, int y)
+ {
+ float distance = (float)Math.Sqrt(Math.Pow(this.center.X - x, 2) + Math.Pow(this.center.Y - y, 2));
+ return distance / this.radius;
+ }
+
+ internal override void Apply(Span scanline, int x, int y)
+ {
+ // TODO: each row is symmetric across center, so we can calculate half of it and mirror it to improve performance.
+ base.Apply(scanline, x, y);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Processing/Drawing/FillPathExtensions.cs b/src/ImageSharp.Drawing/Processing/Drawing/FillPathExtensions.cs
index 36eef8d638..4273fd8bee 100644
--- a/src/ImageSharp.Drawing/Processing/Drawing/FillPathExtensions.cs
+++ b/src/ImageSharp.Drawing/Processing/Drawing/FillPathExtensions.cs
@@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
public static class FillPathExtensions
{
///
- /// Flood fills the image in the shape of the provided polygon with the specified brush..
+ /// Flood fills the image in the shape of the provided polygon with the specified brush.
///
/// The type of the color.
/// The image this method extends.
diff --git a/src/ImageSharp/Advanced/IConfigurable.cs b/src/ImageSharp/Advanced/IConfigurable.cs
index fd97ae921a..38fc83ae1d 100644
--- a/src/ImageSharp/Advanced/IConfigurable.cs
+++ b/src/ImageSharp/Advanced/IConfigurable.cs
@@ -4,7 +4,7 @@
namespace SixLabors.ImageSharp.Advanced
{
///
- /// Encapsulates the properties for configuration
+ /// Encapsulates the properties for configuration.
///
internal interface IConfigurable
{
diff --git a/src/ImageSharp/Common/Extensions/ByteExtensions.cs b/src/ImageSharp/Common/Extensions/ByteExtensions.cs
deleted file mode 100644
index b5b868deaa..0000000000
--- a/src/ImageSharp/Common/Extensions/ByteExtensions.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Runtime.CompilerServices;
-using SixLabors.ImageSharp.PixelFormats;
-
-namespace SixLabors.ImageSharp
-{
- ///
- /// Extension methods for the struct buffers.
- ///
- internal static class ByteExtensions
- {
- ///
- /// Returns a reference to the given position of the array unsafe casted to .
- ///
- /// The byte array.
- /// The offset in bytes.
- /// The reference at the given offset.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ref Rgb24 GetRgb24(this byte[] bytes, int offset)
- {
- DebugGuard.MustBeLessThan(offset + 2, bytes.Length, nameof(offset));
-
- return ref Unsafe.As(ref bytes[offset]);
- }
-
- ///
- /// Returns a reference to the given position of the span unsafe casted to .
- ///
- /// The byte span.
- /// The offset in bytes.
- /// The reference at the given offset.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ref Rgb24 GetRgb24(this Span bytes, int offset)
- {
- DebugGuard.MustBeLessThan(offset + 2, bytes.Length, nameof(offset));
-
- return ref Unsafe.As(ref bytes[offset]);
- }
-
- ///
- /// Returns a reference to the given position of the buffer pointed by `baseRef` unsafe casted to .
- ///
- /// A reference to the beginning of the buffer
- /// The offset in bytes.
- /// The reference at the given offset.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ref Rgb24 GetRgb24(ref byte baseRef, int offset)
- {
- return ref Unsafe.As(ref Unsafe.Add(ref baseRef, offset));
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs
index 9f0a46f80c..9258beb368 100644
--- a/src/ImageSharp/Common/Helpers/Guard.cs
+++ b/src/ImageSharp/Common/Helpers/Guard.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Linq;
namespace SixLabors.ImageSharp
{
@@ -15,78 +14,62 @@ namespace SixLabors.ImageSharp
internal static class Guard
{
///
- /// Verifies, that the method parameter with specified object value is not null
- /// and throws an exception if it is found to be so.
+ /// Ensures that the value is not null.
///
- /// The target object, which cannot be null.
+ /// The target object, which cannot be null.
/// The name of the parameter that is to be checked.
- /// The error message, if any to add to the exception.
- /// is null
- public static void NotNull(object target, string parameterName, string message = "")
+ /// is null
+ public static void NotNull(object value, string parameterName)
{
- if (target == null)
+ if (value == null)
{
- if (!string.IsNullOrWhiteSpace(message))
- {
- throw new ArgumentNullException(parameterName, message);
- }
-
throw new ArgumentNullException(parameterName);
}
}
///
- /// Verifies, that the string method parameter with specified object value and message
- /// is not null, not empty and does not contain only blanks and throws an exception
- /// if the object is null.
+ /// Ensures that the target value is not null, empty, or whitespace.
///
- /// The target string, which should be checked against being null or empty.
+ /// The target string, which should be checked against being null or empty.
/// Name of the parameter.
- /// The error message, if any to add to the exception.
- /// is null.
- /// is empty or contains only blanks.
- public static void NotNullOrEmpty(string target, string parameterName, string message = "")
+ /// is null.
+ /// is empty or contains only blanks.
+ public static void NotNullOrWhiteSpace(string value, string parameterName)
{
- NotNull(target, parameterName, message);
-
- if (string.IsNullOrWhiteSpace(target))
+ if (value == null)
{
- if (!string.IsNullOrWhiteSpace(message))
- {
- throw new ArgumentException(message, parameterName);
- }
+ throw new ArgumentNullException(parameterName);
+ }
- throw new ArgumentException("Value cannot be null or empty and cannot contain only blanks.", parameterName);
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ throw new ArgumentException("Must not be empty or whitespace.", parameterName);
}
}
///
- /// Verifies, that the enumeration is not null and not empty.
+ /// Ensures that the enumeration is not null or empty.
///
- /// The type of objects in the
- /// The target enumeration, which should be checked against being null or empty.
+ /// The type of objects in the
+ /// The target enumeration, which should be checked against being null or empty.
/// Name of the parameter.
- /// The error message, if any to add to the exception.
- /// is null.
- /// is empty.
- public static void NotNullOrEmpty(IEnumerable target, string parameterName, string message = "")
+ /// is null.
+ /// is empty.
+ public static void NotNullOrEmpty(ICollection value, string parameterName)
{
- NotNull(target, parameterName, message);
-
- if (!target.Any())
+ if (value == null)
{
- if (!string.IsNullOrWhiteSpace(message))
- {
- throw new ArgumentException(message, parameterName);
- }
+ throw new ArgumentNullException(parameterName);
+ }
- throw new ArgumentException("Value cannot be empty.", parameterName);
+ if (value.Count == 0)
+ {
+ throw new ArgumentException("Must not be empty.", parameterName);
}
}
///
- /// Verifies that the specified value is less than a maximum value
- /// and throws an exception if it is not.
+ /// Ensures that the specified value is less than a maximum value.
///
/// The target value, which should be validated.
/// The maximum value.
@@ -191,15 +174,9 @@ namespace SixLabors.ImageSharp
/// Verifies, that the method parameter with specified target value is true
/// and throws an exception if it is found to be so.
///
- ///
- /// The target value, which cannot be false.
- ///
- ///
- /// The name of the parameter that is to be checked.
- ///
- ///
- /// The error message, if any to add to the exception.
- ///
+ /// The target value, which cannot be false.
+ /// The name of the parameter that is to be checked.
+ /// The error message, if any to add to the exception.
///
/// is false
///
diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index 1900d0df05..4fbd4baf51 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -39,11 +39,6 @@ namespace SixLabors.ImageSharp.Formats.Gif
///
private IManagedByteBuffer globalColorTable;
- ///
- /// The global color table length
- ///
- private int globalColorTableLength;
-
///
/// The area to restore.
///
@@ -333,8 +328,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
indices = this.configuration.MemoryManager.AllocateManagedByteBuffer(imageDescriptor.Width * imageDescriptor.Height, true);
this.ReadFrameIndices(imageDescriptor, indices.Span);
- IManagedByteBuffer colorTable = localColorTable ?? this.globalColorTable;
- this.ReadFrameColors(ref image, ref previousFrame, indices.Span, colorTable.Span, imageDescriptor);
+ ReadOnlySpan colorTable = MemoryMarshal.Cast((localColorTable ?? this.globalColorTable).Span);
+ this.ReadFrameColors(ref image, ref previousFrame, indices.Span, colorTable, imageDescriptor);
// Skip any remaining blocks
this.Skip(0);
@@ -370,7 +365,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// The indexed pixels.
/// The color table containing the available colors.
/// The
- private void ReadFrameColors(ref Image image, ref ImageFrame previousFrame, Span indices, Span colorTable, in GifImageDescriptor descriptor)
+ private void ReadFrameColors(ref Image image, ref ImageFrame previousFrame, Span indices, ReadOnlySpan colorTable, in GifImageDescriptor descriptor)
where TPixel : struct, IPixel
{
ref byte indicesRef = ref MemoryMarshal.GetReference(indices);
@@ -458,11 +453,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
if (this.graphicsControlExtension.TransparencyFlag == false ||
this.graphicsControlExtension.TransparencyIndex != index)
{
- int indexOffset = index * 3;
-
ref TPixel pixel = ref Unsafe.Add(ref rowRef, x);
- rgba.Rgb = colorTable.GetRgb24(indexOffset);
-
+ rgba.Rgb = colorTable[index];
pixel.PackFromRgba32(rgba);
}
@@ -534,12 +526,12 @@ namespace SixLabors.ImageSharp.Formats.Gif
if (this.logicalScreenDescriptor.GlobalColorTableFlag)
{
- this.globalColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize * 3;
+ int globalColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize * 3;
- this.globalColorTable = this.MemoryManager.AllocateManagedByteBuffer(this.globalColorTableLength, true);
+ this.globalColorTable = this.MemoryManager.AllocateManagedByteBuffer(globalColorTableLength, true);
- // Read the global color table from the stream
- stream.Read(this.globalColorTable.Array, 0, this.globalColorTableLength);
+ // Read the global color table data from the stream
+ stream.Read(this.globalColorTable.Array, 0, globalColorTableLength);
}
}
}
diff --git a/src/ImageSharp/Formats/ImageFormatManager.cs b/src/ImageSharp/Formats/ImageFormatManager.cs
index 67ba111474..4e33a0445c 100644
--- a/src/ImageSharp/Formats/ImageFormatManager.cs
+++ b/src/ImageSharp/Formats/ImageFormatManager.cs
@@ -85,6 +85,13 @@ namespace SixLabors.ImageSharp.Formats
/// The if found otherwise null
public IImageFormat FindFormatByFileExtension(string extension)
{
+ Guard.NotNullOrWhiteSpace(extension, nameof(extension));
+
+ if (extension[0] == '.')
+ {
+ extension = extension.Substring(1);
+ }
+
return this.imageFormats.FirstOrDefault(x => x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase));
}
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
similarity index 99%
rename from src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
index efaa0b4a48..cb73ee9478 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
@@ -7,7 +7,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
///
/// Represents a Jpeg block with coefficiens.
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.CopyTo.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs
similarity index 99%
rename from src/ImageSharp/Formats/Jpeg/Common/Block8x8F.CopyTo.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs
index d8963a8b60..43cc3e9dba 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.CopyTo.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs
@@ -3,10 +3,11 @@
using System.Numerics;
using System.Runtime.CompilerServices;
+
using SixLabors.ImageSharp.Memory;
// ReSharper disable InconsistentNaming
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
internal partial struct Block8x8F
{
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
similarity index 99%
rename from src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
index 93e9e03885..e83896f587 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
@@ -5,7 +5,7 @@ using System.Numerics;
using System.Runtime.CompilerServices;
//
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
internal partial struct Block8x8F
{
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
similarity index 98%
rename from src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.tt
rename to src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
index dc0996b65d..82d82ef0c2 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.tt
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
@@ -18,7 +18,7 @@ using System.Runtime.CompilerServices;
<#
char[] coordz = {'X', 'Y', 'Z', 'W'};
#>
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
internal partial struct Block8x8F
{
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
similarity index 98%
rename from src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
index 53297ab550..38974cc76b 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
@@ -9,7 +9,7 @@ using System.Runtime.InteropServices;
using System.Text;
// ReSharper disable InconsistentNaming
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
///
/// Represents a Jpeg block with coefficients.
@@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
{
float val = result[i];
val /= value;
- result[i] = (float)val;
+ result[i] = val;
}
return result;
@@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
{
float val = result[i];
val += value;
- result[i] = (float)val;
+ result[i] = val;
}
return result;
@@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
{
float val = result[i];
val -= value;
- result[i] = (float)val;
+ result[i] = val;
}
return result;
@@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
public void Clear()
{
// The cheapest way to do this in C#:
- this = default(Block8x8F);
+ this = default;
}
///
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/AdobeMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs
similarity index 97%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/AdobeMarker.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs
index 40059c5a0f..af0938d302 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/AdobeMarker.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs
@@ -4,7 +4,7 @@
using System;
// ReSharper disable InconsistentNaming
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
///
/// Provides information about the Adobe marker segment.
@@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
return true;
}
- marker = default(AdobeMarker);
+ marker = default;
return false;
}
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs
similarity index 86%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs
index 86d5957846..bac77f905e 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs
@@ -4,18 +4,18 @@
using System;
using System.Numerics;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
internal abstract partial class JpegColorConverter
{
- internal class FromCmyk : ColorConverters.JpegColorConverter
+ internal class FromCmyk : JpegColorConverter
{
public FromCmyk()
: base(JpegColorSpace.Cmyk)
{
}
- public override void ConvertToRGBA(ComponentValues values, Span result)
+ public override void ConvertToRgba(ComponentValues values, Span result)
{
// TODO: We can optimize a lot here with Vector and SRCS.Unsafe()!
ReadOnlySpan cVals = values.Component0;
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs
similarity index 81%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs
index 4769bef1d7..b07e57e170 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs
@@ -4,18 +4,18 @@
using System;
using System.Numerics;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
internal abstract partial class JpegColorConverter
{
- internal class FromGrayscale : ColorConverters.JpegColorConverter
+ internal class FromGrayscale : JpegColorConverter
{
public FromGrayscale()
: base(JpegColorSpace.Grayscale)
{
}
- public override void ConvertToRGBA(ComponentValues values, Span result)
+ public override void ConvertToRgba(ComponentValues values, Span result)
{
// TODO: We can optimize a lot here with Vector and SRCS.Unsafe()!
ReadOnlySpan yVals = values.Component0;
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs
similarity index 84%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs
index 7f01eedadb..6b7e77e148 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs
@@ -4,18 +4,18 @@
using System;
using System.Numerics;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
internal abstract partial class JpegColorConverter
{
- internal class FromRgb : ColorConverters.JpegColorConverter
+ internal class FromRgb : JpegColorConverter
{
public FromRgb()
: base(JpegColorSpace.RGB)
{
}
- public override void ConvertToRGBA(ComponentValues values, Span result)
+ public override void ConvertToRgba(ComponentValues values, Span result)
{
// TODO: We can optimize a lot here with Vector and SRCS.Unsafe()!
ReadOnlySpan rVals = values.Component0;
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs
similarity index 87%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs
index ddd2197d4a..35700ea312 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs
@@ -4,18 +4,18 @@
using System;
using System.Numerics;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
internal abstract partial class JpegColorConverter
{
- internal class FromYCbCrBasic : ColorConverters.JpegColorConverter
+ internal class FromYCbCrBasic : JpegColorConverter
{
public FromYCbCrBasic()
: base(JpegColorSpace.YCbCr)
{
}
- public override void ConvertToRGBA(ComponentValues values, Span result)
+ public override void ConvertToRgba(ComponentValues values, Span result)
{
ConvertCore(values, result);
}
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs
similarity index 95%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs
index 2f214f88a9..fd2f17da9e 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs
@@ -5,20 +5,21 @@ using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+
using SixLabors.ImageSharp.Common.Tuples;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
internal abstract partial class JpegColorConverter
{
- internal class FromYCbCrSimd : ColorConverters.JpegColorConverter
+ internal class FromYCbCrSimd : JpegColorConverter
{
public FromYCbCrSimd()
: base(JpegColorSpace.YCbCr)
{
}
- public override void ConvertToRGBA(ComponentValues values, Span result)
+ public override void ConvertToRgba(ComponentValues values, Span result)
{
int remainder = result.Length % 8;
int simdCount = result.Length - remainder;
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs
similarity index 95%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs
index f8a4514221..c43713bf4c 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs
@@ -5,14 +5,15 @@ using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+
using SixLabors.ImageSharp.Common.Tuples;
// ReSharper disable ImpureMethodCallOnReadonlyValueField
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
internal abstract partial class JpegColorConverter
{
- internal class FromYCbCrSimdAvx2 : ColorConverters.JpegColorConverter
+ internal class FromYCbCrSimdAvx2 : JpegColorConverter
{
public FromYCbCrSimdAvx2()
: base(JpegColorSpace.YCbCr)
@@ -21,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
public static bool IsAvailable => Vector.IsHardwareAccelerated && SimdUtils.IsAvx2CompatibleArchitecture;
- public override void ConvertToRGBA(ComponentValues values, Span result)
+ public override void ConvertToRgba(ComponentValues values, Span result)
{
int remainder = result.Length % 8;
int simdCount = result.Length - remainder;
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs
similarity index 91%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs
index 6d8e6ef5a9..83feefa94a 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs
@@ -4,7 +4,7 @@
using System;
using System.Numerics;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
internal abstract partial class JpegColorConverter
{
@@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
{
}
- public override void ConvertToRGBA(ComponentValues values, Span result)
+ public override void ConvertToRgba(ComponentValues values, Span result)
{
// TODO: We can optimize a lot here with Vector and SRCS.Unsafe()!
ReadOnlySpan yVals = values.Component0;
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
similarity index 95%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
index 4391be5484..080bf83338 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ColorConverters/JpegColorConverter.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
@@ -5,10 +5,11 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
+
using SixLabors.ImageSharp.Common.Tuples;
using SixLabors.ImageSharp.Memory;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
///
/// Encapsulates the conversion of Jpeg channels to RGBA values packed in buffer.
@@ -55,13 +56,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters
///
/// The input as a stack-only struct
/// The destination buffer of values
- public abstract void ConvertToRGBA(ComponentValues values, Span result);
+ public abstract void ConvertToRgba(ComponentValues values, Span result);
///
/// Returns the for the YCbCr colorspace that matches the current CPU architecture.
///
private static JpegColorConverter GetYCbCrConverter() =>
- FromYCbCrSimdAvx2.IsAvailable ? (JpegColorConverter)new FromYCbCrSimdAvx2() : new FromYCbCrSimd();
+ JpegColorConverter.FromYCbCrSimdAvx2.IsAvailable ? (JpegColorConverter)new JpegColorConverter.FromYCbCrSimdAvx2() : new JpegColorConverter.FromYCbCrSimd();
///
/// A stack-only struct to reference the input buffers using -s.
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/IJpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs
similarity index 92%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/IJpegComponent.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs
index de9f75dc1f..efa746819d 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/IJpegComponent.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs
@@ -1,7 +1,10 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
///
/// Common interface to represent raw Jpeg components.
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/IRawJpegData.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs
similarity index 81%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/IRawJpegData.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs
index 3873656a4e..dace78b337 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/IRawJpegData.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs
@@ -1,13 +1,16 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
using System;
using System.Collections.Generic;
using SixLabors.Primitives;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
///
///
- /// Represents decompressed, unprocessed jpeg data with spectral space -s.
+ /// Represents decompressed, unprocessed jpeg data with spectral space -s.
///
internal interface IRawJpegData : IDisposable
{
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JFifMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs
similarity index 98%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/JFifMarker.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs
index afe4794a23..591af63442 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JFifMarker.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs
@@ -3,7 +3,7 @@
using System;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
///
/// Provides information about the JFIF marker segment
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs
similarity index 97%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs
index 2f59bcb822..b586d520a6 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs
@@ -2,10 +2,11 @@
// Licensed under the Apache License, Version 2.0.
using System.Runtime.InteropServices;
+
using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
///
/// Encapsulates the implementation of processing "raw" -s into Jpeg image channels.
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorSpace.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs
similarity index 59%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorSpace.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs
index abc93727e1..2861a2c2e9 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegColorSpace.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs
@@ -1,4 +1,7 @@
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
///
/// Identifies the colorspace of a Jpeg image
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegComponentPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs
similarity index 95%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegComponentPostProcessor.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs
index 1be637b6df..fe18f8438c 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegComponentPostProcessor.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs
@@ -1,8 +1,12 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
using System;
+
using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
///
/// Encapsulates postprocessing data for one component for .
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs
similarity index 89%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs
index 483242c768..38340b2380 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs
@@ -1,12 +1,18 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
using System;
using System.Linq;
using System.Numerics;
+
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
+using JpegColorConverter = SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters.JpegColorConverter;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
///
/// Encapsulates the execution od post-processing algorithms to be applied on a to produce a valid :
@@ -36,9 +42,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
private readonly IBuffer rgbaBuffer;
///
- /// The corresponding to the current determined by .
+ /// The corresponding to the current determined by .
///
- private ColorConverters.JpegColorConverter colorConverter;
+ private readonly JpegColorConverter colorConverter;
///
/// Initializes a new instance of the class.
@@ -54,7 +60,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
this.ComponentProcessors = rawJpeg.Components.Select(c => new JpegComponentPostProcessor(memoryManager, this, c)).ToArray();
this.rgbaBuffer = memoryManager.Allocate(rawJpeg.ImageSizeInPixels.Width);
- this.colorConverter = ColorConverters.JpegColorConverter.GetConverter(rawJpeg.ColorSpace);
+ this.colorConverter = JpegColorConverter.GetConverter(rawJpeg.ColorSpace);
}
///
@@ -148,8 +154,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
{
int y = yy - this.PixelRowCounter;
- var values = new ColorConverters.JpegColorConverter.ComponentValues(buffers, y);
- this.colorConverter.ConvertToRGBA(values, this.rgbaBuffer.Span);
+ var values = new JpegColorConverter.ComponentValues(buffers, y);
+ this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.Span);
Span destRow = destination.GetPixelRowSpan(yy);
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ProfileResolver.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs
similarity index 96%
rename from src/ImageSharp/Formats/Jpeg/Common/Decoder/ProfileResolver.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs
index 2030ad71b1..e5de4441c2 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/ProfileResolver.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs
@@ -4,7 +4,7 @@
using System;
using System.Text;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
///
/// Provides methods for identifying metadata and color profiles within jpeg images.
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/BlockQuad.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/BlockQuad.cs
similarity index 66%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/Components/BlockQuad.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Encoder/BlockQuad.cs
index 6b16ea824e..7a312138d0 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/BlockQuad.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/BlockQuad.cs
@@ -1,18 +1,16 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using Block8x8F = SixLabors.ImageSharp.Formats.Jpeg.Common.Block8x8F;
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{
///
- /// Poor man's stackalloc: Contains a value-type buffer sized for 4 instances.
+ /// Poor man's stackalloc: Contains a value-type buffer sized for 4 instances.
/// Useful for decoder/encoder operations allocating a block for each Jpeg component.
///
internal unsafe struct BlockQuad
{
///
- /// The value-type buffer sized for 4 instances.
+ /// The value-type buffer sized for 4 instances.
///
public fixed float Data[4 * Block8x8F.Size];
}
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/HuffIndex.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffIndex.cs
similarity index 91%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/HuffIndex.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffIndex.cs
index 23fcda2964..633d7ea80f 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/HuffIndex.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffIndex.cs
@@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{
///
/// Enumerates the Huffman tables
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/HuffmanLut.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanLut.cs
similarity index 96%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/HuffmanLut.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanLut.cs
index 7756a7e3ba..a31c4bf2f4 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/HuffmanLut.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanLut.cs
@@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{
///
/// A compiled look-up table representation of a huffmanSpec.
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/HuffmanSpec.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs
similarity index 98%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/HuffmanSpec.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs
index 1c8228aaa2..2e2ee9575c 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/HuffmanSpec.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs
@@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{
///
/// The Huffman encoding specifications.
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/QuantIndex.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs
similarity index 86%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/QuantIndex.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs
index 459d29f91f..d0933af0c4 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/QuantIndex.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs
@@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{
///
/// Enumerates the quantization tables
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/RgbToYCbCrTables.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs
similarity index 93%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/RgbToYCbCrTables.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs
index 923fe244eb..a0cc9ee8e5 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/RgbToYCbCrTables.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs
@@ -3,9 +3,7 @@
using System.Runtime.CompilerServices;
-using SixLabors.ImageSharp.Memory;
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{
///
/// Provides 8-bit lookup tables for converting from Rgb to YCbCr colorspace.
@@ -68,7 +66,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
/// The intialized
public static RgbToYCbCrTables Create()
{
- RgbToYCbCrTables tables = default(RgbToYCbCrTables);
+ RgbToYCbCrTables tables = default;
for (int i = 0; i <= 255; i++)
{
@@ -123,11 +121,5 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
{
return (int)((x * (1L << ScaleBits)) + 0.5F);
}
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int RightShift(int x)
- {
- return x >> ScaleBits;
- }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/YCbCrForwardConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs
similarity index 95%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/YCbCrForwardConverter{TPixel}.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs
index 3c95a85080..311ffed24b 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Encoder/YCbCrForwardConverter{TPixel}.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs
@@ -1,10 +1,10 @@
using System;
using System.Runtime.CompilerServices;
+
using SixLabors.ImageSharp.Advanced;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.PixelFormats;
-namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
{
///
/// On-stack worker struct to efficiently encapsulate the TPixel -> Rgb24 -> YCbCr conversion chain of 8x8 pixel blocks.
diff --git a/src/ImageSharp/Formats/Jpeg/Common/FastFloatingPointDCT.cs b/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs
similarity index 99%
rename from src/ImageSharp/Formats/Jpeg/Common/FastFloatingPointDCT.cs
rename to src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs
index 3ee6e72c5d..dcdc7e9ba7 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/FastFloatingPointDCT.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs
@@ -5,7 +5,7 @@ using System.Numerics;
using System.Runtime.CompilerServices;
// ReSharper disable InconsistentNaming
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
///
/// Contains inaccurate, but fast forward and inverse DCT implementations.
diff --git a/src/ImageSharp/Formats/Jpeg/Common/GenericBlock8x8.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.cs
similarity index 89%
rename from src/ImageSharp/Formats/Jpeg/Common/GenericBlock8x8.Generated.cs
rename to src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.cs
index 1bb37a7d32..0cc729371f 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/GenericBlock8x8.Generated.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.cs
@@ -1,11 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using System.Numerics;
-using System.Runtime.CompilerServices;
-
//
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
internal unsafe partial struct GenericBlock8x8
{
diff --git a/src/ImageSharp/Formats/Jpeg/Common/GenericBlock8x8.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.tt
similarity index 90%
rename from src/ImageSharp/Formats/Jpeg/Common/GenericBlock8x8.Generated.tt
rename to src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.tt
index d9b15b34fa..28bcea791b 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/GenericBlock8x8.Generated.tt
+++ b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.tt
@@ -11,11 +11,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using System.Numerics;
-using System.Runtime.CompilerServices;
-
//
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
internal unsafe partial struct GenericBlock8x8
{
diff --git a/src/ImageSharp/Formats/Jpeg/Common/GenericBlock8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs
similarity index 96%
rename from src/ImageSharp/Formats/Jpeg/Common/GenericBlock8x8.cs
rename to src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs
index 09a7eb73aa..9aceb78b2a 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/GenericBlock8x8.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs
@@ -1,13 +1,16 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
-using SixLabors.Primitives;
// ReSharper disable InconsistentNaming
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
///
/// A generic 8x8 block implementation, useful for manipulating custom 8x8 pixel data.
@@ -18,8 +21,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
{
public const int Size = 64;
- public const int SizeInBytes = Size * 3;
-
///
/// FOR TESTING ONLY!
/// Gets or sets a value at the given index
diff --git a/src/ImageSharp/Formats/Jpeg/Common/SizeExtensions.cs b/src/ImageSharp/Formats/Jpeg/Components/SizeExtensions.cs
similarity index 97%
rename from src/ImageSharp/Formats/Jpeg/Common/SizeExtensions.cs
rename to src/ImageSharp/Formats/Jpeg/Components/SizeExtensions.cs
index 978688673f..48ad188561 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/SizeExtensions.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/SizeExtensions.cs
@@ -3,9 +3,10 @@
using System;
using System.Numerics;
+
using SixLabors.Primitives;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
///
/// Extension methods for
diff --git a/src/ImageSharp/Formats/Jpeg/Common/ZigZag.cs b/src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs
similarity index 98%
rename from src/ImageSharp/Formats/Jpeg/Common/ZigZag.cs
rename to src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs
index cb035a8d3d..a3701f2c1b 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/ZigZag.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs
@@ -1,10 +1,11 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-namespace SixLabors.ImageSharp.Formats.Jpeg.Common
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
///
/// Holds the Jpeg UnZig array in a value/stack type.
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bits.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bits.cs
index 05bde78e65..353eb01fe2 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bits.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bits.cs
@@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void EnsureNBits(int n, ref InputProcessor inputProcessor)
{
- OrigDecoderErrorCode errorCode = this.EnsureNBitsUnsafe(n, ref inputProcessor);
+ GolangDecoderErrorCode errorCode = this.EnsureNBitsUnsafe(n, ref inputProcessor);
errorCode.EnsureNoError();
}
@@ -46,17 +46,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Reads bytes from the byte buffer to ensure that bits.UnreadBits is at
/// least n. For best performance (avoiding function calls inside hot loops),
/// the caller is the one responsible for first checking that bits.UnreadBits < n.
- /// This method does not throw. Returns instead.
+ /// This method does not throw. Returns instead.
///
/// The number of bits to ensure.
/// The
/// Error code
- public OrigDecoderErrorCode EnsureNBitsUnsafe(int n, ref InputProcessor inputProcessor)
+ public GolangDecoderErrorCode EnsureNBitsUnsafe(int n, ref InputProcessor inputProcessor)
{
while (true)
{
- OrigDecoderErrorCode errorCode = this.EnsureBitsStepImpl(ref inputProcessor);
- if (errorCode != OrigDecoderErrorCode.NoError || this.UnreadBits >= n)
+ GolangDecoderErrorCode errorCode = this.EnsureBitsStepImpl(ref inputProcessor);
+ if (errorCode != GolangDecoderErrorCode.NoError || this.UnreadBits >= n)
{
return errorCode;
}
@@ -67,8 +67,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Unrolled version of for n==8
///
/// The
- /// A
- public OrigDecoderErrorCode Ensure8BitsUnsafe(ref InputProcessor inputProcessor)
+ /// A
+ public GolangDecoderErrorCode Ensure8BitsUnsafe(ref InputProcessor inputProcessor)
{
return this.EnsureBitsStepImpl(ref inputProcessor);
}
@@ -77,8 +77,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Unrolled version of for n==1
///
/// The
- /// A
- public OrigDecoderErrorCode Ensure1BitUnsafe(ref InputProcessor inputProcessor)
+ /// A
+ public GolangDecoderErrorCode Ensure1BitUnsafe(ref InputProcessor inputProcessor)
{
return this.EnsureBitsStepImpl(ref inputProcessor);
}
@@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int ReceiveExtend(int t, ref InputProcessor inputProcessor)
{
- OrigDecoderErrorCode errorCode = this.ReceiveExtendUnsafe(t, ref inputProcessor, out int x);
+ GolangDecoderErrorCode errorCode = this.ReceiveExtendUnsafe(t, ref inputProcessor, out int x);
errorCode.EnsureNoError();
return x;
}
@@ -103,13 +103,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Byte
/// The
/// Read bits value
- /// The
- public OrigDecoderErrorCode ReceiveExtendUnsafe(int t, ref InputProcessor inputProcessor, out int x)
+ /// The
+ public GolangDecoderErrorCode ReceiveExtendUnsafe(int t, ref InputProcessor inputProcessor, out int x)
{
if (this.UnreadBits < t)
{
- OrigDecoderErrorCode errorCode = this.EnsureNBitsUnsafe(t, ref inputProcessor);
- if (errorCode != OrigDecoderErrorCode.NoError)
+ GolangDecoderErrorCode errorCode = this.EnsureNBitsUnsafe(t, ref inputProcessor);
+ if (errorCode != GolangDecoderErrorCode.NoError)
{
x = int.MaxValue;
return errorCode;
@@ -126,14 +126,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
x += ((-1) << t) + 1;
}
- return OrigDecoderErrorCode.NoError;
+ return GolangDecoderErrorCode.NoError;
}
- private OrigDecoderErrorCode EnsureBitsStepImpl(ref InputProcessor inputProcessor)
+ private GolangDecoderErrorCode EnsureBitsStepImpl(ref InputProcessor inputProcessor)
{
- OrigDecoderErrorCode errorCode = inputProcessor.Bytes.ReadByteStuffedByteUnsafe(inputProcessor.InputStream, out int c);
+ GolangDecoderErrorCode errorCode = inputProcessor.Bytes.ReadByteStuffedByteUnsafe(inputProcessor.InputStream, out int c);
- if (errorCode != OrigDecoderErrorCode.NoError)
+ if (errorCode != GolangDecoderErrorCode.NoError)
{
return errorCode;
}
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bytes.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bytes.cs
index 2a3817400c..c8c68aa7ea 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bytes.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/Bytes.cs
@@ -77,8 +77,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
///
/// Input stream
/// The result byte as
- /// The
- public OrigDecoderErrorCode ReadByteStuffedByteUnsafe(Stream inputStream, out int x)
+ /// The
+ public GolangDecoderErrorCode ReadByteStuffedByteUnsafe(Stream inputStream, out int x)
{
// Take the fast path if bytes.buf contains at least two bytes.
if (this.I + 2 <= this.J)
@@ -86,50 +86,50 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
x = this.BufferAsInt[this.I];
this.I++;
this.UnreadableBytes = 1;
- if (x != OrigJpegConstants.Markers.XFFInt)
+ if (x != JpegConstants.Markers.XFFInt)
{
- return OrigDecoderErrorCode.NoError;
+ return GolangDecoderErrorCode.NoError;
}
if (this.BufferAsInt[this.I] != 0x00)
{
- return OrigDecoderErrorCode.MissingFF00;
+ return GolangDecoderErrorCode.MissingFF00;
}
this.I++;
this.UnreadableBytes = 2;
- x = OrigJpegConstants.Markers.XFF;
- return OrigDecoderErrorCode.NoError;
+ x = JpegConstants.Markers.XFF;
+ return GolangDecoderErrorCode.NoError;
}
this.UnreadableBytes = 0;
- OrigDecoderErrorCode errorCode = this.ReadByteAsIntUnsafe(inputStream, out x);
+ GolangDecoderErrorCode errorCode = this.ReadByteAsIntUnsafe(inputStream, out x);
this.UnreadableBytes = 1;
- if (errorCode != OrigDecoderErrorCode.NoError)
+ if (errorCode != GolangDecoderErrorCode.NoError)
{
return errorCode;
}
- if (x != OrigJpegConstants.Markers.XFF)
+ if (x != JpegConstants.Markers.XFF)
{
- return OrigDecoderErrorCode.NoError;
+ return GolangDecoderErrorCode.NoError;
}
errorCode = this.ReadByteAsIntUnsafe(inputStream, out x);
this.UnreadableBytes = 2;
- if (errorCode != OrigDecoderErrorCode.NoError)
+ if (errorCode != GolangDecoderErrorCode.NoError)
{
return errorCode;
}
if (x != 0x00)
{
- return OrigDecoderErrorCode.MissingFF00;
+ return GolangDecoderErrorCode.MissingFF00;
}
- x = OrigJpegConstants.Markers.XFF;
- return OrigDecoderErrorCode.NoError;
+ x = JpegConstants.Markers.XFF;
+ return GolangDecoderErrorCode.NoError;
}
///
@@ -140,25 +140,25 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte ReadByte(Stream inputStream)
{
- OrigDecoderErrorCode errorCode = this.ReadByteUnsafe(inputStream, out byte result);
+ GolangDecoderErrorCode errorCode = this.ReadByteUnsafe(inputStream, out byte result);
errorCode.EnsureNoError();
return result;
}
///
/// Extracts the next byte, whether buffered or not buffered into the result out parameter. It does not care about byte stuffing.
- /// This method does not throw on format error, it returns a instead.
+ /// This method does not throw on format error, it returns a instead.
///
/// Input stream
/// The result as out parameter
- /// The
- public OrigDecoderErrorCode ReadByteUnsafe(Stream inputStream, out byte result)
+ /// The
+ public GolangDecoderErrorCode ReadByteUnsafe(Stream inputStream, out byte result)
{
- OrigDecoderErrorCode errorCode = OrigDecoderErrorCode.NoError;
+ GolangDecoderErrorCode errorCode = GolangDecoderErrorCode.NoError;
while (this.I == this.J)
{
errorCode = this.FillUnsafe(inputStream);
- if (errorCode != OrigDecoderErrorCode.NoError)
+ if (errorCode != GolangDecoderErrorCode.NoError)
{
result = 0;
return errorCode;
@@ -176,15 +176,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
///
/// The input stream
/// The result
- /// A
+ /// A
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public OrigDecoderErrorCode ReadByteAsIntUnsafe(Stream inputStream, out int result)
+ public GolangDecoderErrorCode ReadByteAsIntUnsafe(Stream inputStream, out int result)
{
- OrigDecoderErrorCode errorCode = OrigDecoderErrorCode.NoError;
+ GolangDecoderErrorCode errorCode = GolangDecoderErrorCode.NoError;
while (this.I == this.J)
{
errorCode = this.FillUnsafe(inputStream);
- if (errorCode != OrigDecoderErrorCode.NoError)
+ if (errorCode != GolangDecoderErrorCode.NoError)
{
result = 0;
return errorCode;
@@ -206,18 +206,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Fill(Stream inputStream)
{
- OrigDecoderErrorCode errorCode = this.FillUnsafe(inputStream);
+ GolangDecoderErrorCode errorCode = this.FillUnsafe(inputStream);
errorCode.EnsureNoError();
}
///
/// Fills up the bytes buffer from the underlying stream.
/// It should only be called when there are no unread bytes in bytes.
- /// This method does not throw , returns a instead!
+ /// This method does not throw , returns a instead!
///
/// Input stream
- /// The
- public OrigDecoderErrorCode FillUnsafe(Stream inputStream)
+ /// The
+ public GolangDecoderErrorCode FillUnsafe(Stream inputStream)
{
if (this.I != this.J)
{
@@ -239,7 +239,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
int n = inputStream.Read(this.Buffer, this.J, this.Buffer.Length - this.J);
if (n == 0)
{
- return OrigDecoderErrorCode.UnexpectedEndOfStream;
+ return GolangDecoderErrorCode.UnexpectedEndOfStream;
}
this.J += n;
@@ -249,7 +249,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.BufferAsInt[i] = this.Buffer[i];
}
- return OrigDecoderErrorCode.NoError;
+ return GolangDecoderErrorCode.NoError;
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/DecoderThrowHelper.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/DecoderThrowHelper.cs
index 904ce00dde..2b2bc61ba8 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/DecoderThrowHelper.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/DecoderThrowHelper.cs
@@ -12,22 +12,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
internal static class DecoderThrowHelper
{
///
- /// Throws an exception that belongs to the given
+ /// Throws an exception that belongs to the given
///
- /// The
+ /// The
[MethodImpl(MethodImplOptions.NoInlining)]
- public static void ThrowExceptionForErrorCode(this OrigDecoderErrorCode errorCode)
+ public static void ThrowExceptionForErrorCode(this GolangDecoderErrorCode errorCode)
{
// REMARK: If this method throws for an image that is expected to be decodable,
// consider using the ***Unsafe variant of the parsing method that asks for ThrowExceptionForErrorCode()
// then verify the error code + implement fallback logic manually!
switch (errorCode)
{
- case OrigDecoderErrorCode.NoError:
+ case GolangDecoderErrorCode.NoError:
throw new ArgumentException("ThrowExceptionForErrorCode() called with NoError!", nameof(errorCode));
- case OrigDecoderErrorCode.MissingFF00:
+ case GolangDecoderErrorCode.MissingFF00:
throw new MissingFF00Exception();
- case OrigDecoderErrorCode.UnexpectedEndOfStream:
+ case GolangDecoderErrorCode.UnexpectedEndOfStream:
throw new EOFException();
default:
throw new ArgumentOutOfRangeException(nameof(errorCode), errorCode, null);
@@ -35,26 +35,26 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
///
- /// Throws an exception if the given defines an error.
+ /// Throws an exception if the given defines an error.
///
- /// The
+ /// The
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void EnsureNoError(this OrigDecoderErrorCode errorCode)
+ public static void EnsureNoError(this GolangDecoderErrorCode errorCode)
{
- if (errorCode != OrigDecoderErrorCode.NoError)
+ if (errorCode != GolangDecoderErrorCode.NoError)
{
ThrowExceptionForErrorCode(errorCode);
}
}
///
- /// Throws an exception if the given is .
+ /// Throws an exception if the given is .
///
- /// The
+ /// The
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void EnsureNoEOF(this OrigDecoderErrorCode errorCode)
+ public static void EnsureNoEOF(this GolangDecoderErrorCode errorCode)
{
- if (errorCode == OrigDecoderErrorCode.UnexpectedEndOfStream)
+ if (errorCode == GolangDecoderErrorCode.UnexpectedEndOfStream)
{
errorCode.ThrowExceptionForErrorCode();
}
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponent.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangComponent.cs
similarity index 90%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponent.cs
rename to src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangComponent.cs
index 8445625bde..bb3bd01aa3 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponent.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangComponent.cs
@@ -3,8 +3,9 @@
using System;
using System.Runtime.CompilerServices;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
-using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
+
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives;
@@ -14,9 +15,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
///
/// Represents a single color component
///
- internal class OrigComponent : IDisposable, IJpegComponent
+ internal class GolangComponent : IDisposable, IJpegComponent
{
- public OrigComponent(byte identifier, int index)
+ public GolangComponent(byte identifier, int index)
{
this.Identifier = identifier;
this.Index = index;
@@ -56,9 +57,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Initializes
///
/// The to use for buffer allocations.
- /// The instance
- /// Whether to decode metadata only. If this is true, memory allocation for SpectralBlocks will not be necessary
- public void InitializeDerivedData(MemoryManager memoryManager, OrigJpegDecoderCore decoder, bool metadataOnly)
+ /// The instance
+ public void InitializeDerivedData(MemoryManager memoryManager, GolangJpegDecoderCore decoder)
{
// For 4-component images (either CMYK or YCbCrK), we only support two
// hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22].
@@ -77,21 +77,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
else
{
- OrigComponent c0 = decoder.Components[0];
+ GolangComponent c0 = decoder.Components[0];
this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors);
}
- if (!metadataOnly)
- {
- this.SpectralBlocks = memoryManager.Allocate2D(this.SizeInBlocks.Width, this.SizeInBlocks.Height, true);
- }
+ this.SpectralBlocks = memoryManager.Allocate2D(this.SizeInBlocks.Width, this.SizeInBlocks.Height, true);
}
///
/// Initializes all component data except .
///
- /// The instance
- public void InitializeCoreData(OrigJpegDecoderCore decoder)
+ /// The instance
+ public void InitializeCoreData(GolangJpegDecoderCore decoder)
{
// Section B.2.2 states that "the value of C_i shall be different from
// the values of C_1 through C_(i-1)".
@@ -106,7 +103,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
this.QuantizationTableIndex = decoder.Temp[8 + (3 * i)];
- if (this.QuantizationTableIndex > OrigJpegDecoderCore.MaxTq)
+ if (this.QuantizationTableIndex > GolangJpegDecoderCore.MaxTq)
{
throw new ImageFormatException("Bad Tq value");
}
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponentScan.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangComponentScan.cs
similarity index 94%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponentScan.cs
rename to src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangComponentScan.cs
index 0d98044045..6752768ffa 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponentScan.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangComponentScan.cs
@@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Represents a component scan
///
[StructLayout(LayoutKind.Sequential)]
- internal struct OrigComponentScan
+ internal struct GolangComponentScan
{
///
/// Gets or sets the component index.
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigDecoderErrorCode.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangDecoderErrorCode.cs
similarity index 93%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigDecoderErrorCode.cs
rename to src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangDecoderErrorCode.cs
index 02a8ea55e0..fa3364527c 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigDecoderErrorCode.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangDecoderErrorCode.cs
@@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
///
/// Represents "recoverable" decoder errors.
///
- internal enum OrigDecoderErrorCode
+ internal enum GolangDecoderErrorCode
{
///
/// NoError
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigHuffmanTree.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangHuffmanTree.cs
similarity index 95%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigHuffmanTree.cs
rename to src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangHuffmanTree.cs
index dbc7bb0f7f..dccce2aaa8 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigHuffmanTree.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangHuffmanTree.cs
@@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using System;
-using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -12,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Represents a Huffman tree
///
[StructLayout(LayoutKind.Sequential)]
- internal unsafe struct OrigHuffmanTree
+ internal unsafe struct GolangHuffmanTree
{
///
/// The index of the AC table row
@@ -95,12 +93,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
public FixedInt32Buffer16 Indices;
///
- /// Creates and initializes an array of instances of size
+ /// Creates and initializes an array of instances of size
///
- /// An array of instances representing the Huffman tables
- public static OrigHuffmanTree[] CreateHuffmanTrees()
+ /// An array of instances representing the Huffman tables
+ public static GolangHuffmanTree[] CreateHuffmanTrees()
{
- return new OrigHuffmanTree[NumberOfTrees];
+ return new GolangHuffmanTree[NumberOfTrees];
}
///
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.ComputationData.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.ComputationData.cs
similarity index 79%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.ComputationData.cs
rename to src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.ComputationData.cs
index c9bb898aa5..f1dd2526ae 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.ComputationData.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.ComputationData.cs
@@ -2,14 +2,15 @@
// Licensed under the Apache License, Version 2.0.
using System.Runtime.InteropServices;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
+
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{
///
/// Conains the definition of
///
- internal unsafe partial struct OrigJpegScanDecoder
+ internal unsafe partial struct GolangJpegScanDecoder
{
///
/// Holds the "large" data blocks needed for computations.
@@ -28,14 +29,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
public ZigZag Unzig;
///
- /// The buffer storing the -s for each component
+ /// The buffer storing the -s for each component
///
- public fixed byte ScanData[3 * OrigJpegDecoderCore.MaxComponents];
+ public fixed byte ScanData[3 * GolangJpegDecoderCore.MaxComponents];
///
/// The DC values for each component
///
- public fixed int Dc[OrigJpegDecoderCore.MaxComponents];
+ public fixed int Dc[GolangJpegDecoderCore.MaxComponents];
///
/// Creates and initializes a new instance
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.DataPointers.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.DataPointers.cs
similarity index 86%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.DataPointers.cs
rename to src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.DataPointers.cs
index 0207280e3e..a00da6fcaf 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.DataPointers.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.DataPointers.cs
@@ -1,14 +1,14 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{
///
/// Conains the definition of
///
- internal unsafe partial struct OrigJpegScanDecoder
+ internal unsafe partial struct GolangJpegScanDecoder
{
///
/// Contains pointers to the memory regions of so they can be easily passed around to pointer based utility methods of
@@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
///
/// Pointer to as Scan*
///
- public OrigComponentScan* ComponentScan;
+ public GolangComponentScan* ComponentScan;
///
/// Pointer to
@@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{
this.Block = &basePtr->Block;
this.Unzig = basePtr->Unzig.Data;
- this.ComponentScan = (OrigComponentScan*)basePtr->ScanData;
+ this.ComponentScan = (GolangComponentScan*)basePtr->ScanData;
this.Dc = basePtr->Dc;
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.cs
similarity index 89%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.cs
rename to src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.cs
index d10def3ce7..3a88cfad4b 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.cs
@@ -3,9 +3,8 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
-using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
-using SixLabors.ImageSharp.Memory;
+
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
@@ -29,7 +28,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// For baseline JPEGs, these parameters are hard-coded to 0/63/0/0.
///
[StructLayout(LayoutKind.Sequential)]
- internal unsafe partial struct OrigJpegScanDecoder
+ internal unsafe partial struct GolangJpegScanDecoder
{
// The JpegScanDecoder members should be ordered in a way that results in optimal memory layout.
#pragma warning disable SA1202 // ElementsMustBeOrderedByAccess
@@ -110,12 +109,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
private byte expectedRst;
///
- /// Initializes a default-constructed instance for reading data from -s stream.
+ /// Initializes a default-constructed instance for reading data from -s stream.
///
- /// Pointer to on the stack
- /// The instance
+ /// Pointer to on the stack
+ /// The instance
/// The remaining bytes in the segment block.
- public static void InitStreamReading(OrigJpegScanDecoder* p, OrigJpegDecoderCore decoder, int remaining)
+ public static void InitStreamReading(GolangJpegScanDecoder* p, GolangJpegDecoderCore decoder, int remaining)
{
p->data = ComputationData.Create();
p->pointers = new DataPointers(&p->data);
@@ -123,8 +122,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
///
- /// Read Huffman data from Jpeg scans in ,
- /// and decode it as into .
+ /// Read Huffman data from Jpeg scans in ,
+ /// and decode it as into .
///
/// The blocks are traversed one MCU at a time. For 4:2:0 chroma
/// subsampling, there are four Y 8x8 blocks in every 16x16 MCU.
@@ -149,14 +148,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// 0 1 2
/// 3 4 5
///
- /// The instance
- public void DecodeBlocks(OrigJpegDecoderCore decoder)
+ /// The instance
+ public void DecodeBlocks(GolangJpegDecoderCore decoder)
{
decoder.InputProcessor.ResetErrorState();
this.blockCounter = 0;
this.mcuCounter = 0;
- this.expectedRst = OrigJpegConstants.Markers.RST0;
+ this.expectedRst = JpegConstants.Markers.RST0;
for (int my = 0; my < decoder.MCUCountY; my++)
{
@@ -177,12 +176,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
}
- private void DecodeBlocksAtMcuIndex(OrigJpegDecoderCore decoder, int mx, int my)
+ private void DecodeBlocksAtMcuIndex(GolangJpegDecoderCore decoder, int mx, int my)
{
for (int scanIndex = 0; scanIndex < this.componentScanCount; scanIndex++)
{
this.ComponentIndex = this.pointers.ComponentScan[scanIndex].ComponentIndex;
- OrigComponent component = decoder.Components[this.ComponentIndex];
+ GolangComponent component = decoder.Components[this.ComponentIndex];
this.hi = component.HorizontalSamplingFactor;
int vi = component.VerticalSamplingFactor;
@@ -223,7 +222,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
}
- private void ProcessRSTMarker(OrigJpegDecoderCore decoder)
+ private void ProcessRSTMarker(GolangJpegDecoderCore decoder)
{
// Attempt to look for RST[0-7] markers to resynchronize from corrupt input.
if (!decoder.InputProcessor.ReachedEOF)
@@ -262,15 +261,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
this.expectedRst++;
- if (this.expectedRst == OrigJpegConstants.Markers.RST7 + 1)
+ if (this.expectedRst == JpegConstants.Markers.RST7 + 1)
{
- this.expectedRst = OrigJpegConstants.Markers.RST0;
+ this.expectedRst = JpegConstants.Markers.RST0;
}
}
}
}
- private void Reset(OrigJpegDecoderCore decoder)
+ private void Reset(GolangJpegDecoderCore decoder)
{
decoder.InputProcessor.ResetHuffmanDecoder();
@@ -285,15 +284,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
///
private void ResetDcValues()
{
- Unsafe.InitBlock(this.pointers.Dc, default(byte), sizeof(int) * OrigJpegDecoderCore.MaxComponents);
+ Unsafe.InitBlock(this.pointers.Dc, default, sizeof(int) * GolangJpegDecoderCore.MaxComponents);
}
///
/// The implementation part of as an instance method.
///
- /// The
+ /// The
/// The remaining bytes
- private void InitStreamReadingImpl(OrigJpegDecoderCore decoder, int remaining)
+ private void InitStreamReadingImpl(GolangJpegDecoderCore decoder, int remaining)
{
if (decoder.ComponentCount == 0)
{
@@ -360,10 +359,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
///
/// The decoder
/// The index of the scan
- private void DecodeBlock(OrigJpegDecoderCore decoder, int scanIndex)
+ private void DecodeBlock(GolangJpegDecoderCore decoder, int scanIndex)
{
Block8x8* b = this.pointers.Block;
- int huffmannIdx = (OrigHuffmanTree.AcTableIndex * OrigHuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].AcTableSelector;
+ int huffmannIdx = (GolangHuffmanTree.AcTableIndex * GolangHuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].AcTableSelector;
if (this.ah != 0)
{
this.Refine(ref decoder.InputProcessor, ref decoder.HuffmanTrees[huffmannIdx], 1 << this.al);
@@ -377,7 +376,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
zig++;
// Decode the DC coefficient, as specified in section F.2.2.1.
- int huffmanIndex = (OrigHuffmanTree.DcTableIndex * OrigHuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].DcTableSelector;
+ int huffmanIndex = (GolangHuffmanTree.DcTableIndex * GolangHuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].DcTableSelector;
decoder.InputProcessor.DecodeHuffmanUnsafe(
ref decoder.HuffmanTrees[huffmanIndex],
out int value);
@@ -467,7 +466,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
private void DecodeEobRun(int count, ref InputProcessor processor)
{
processor.DecodeBitsUnsafe(count, out int bitsResult);
- if (processor.LastErrorCode != OrigDecoderErrorCode.NoError)
+ if (processor.LastErrorCode != GolangDecoderErrorCode.NoError)
{
return;
}
@@ -475,7 +474,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.eobRun |= bitsResult;
}
- private void InitComponentScan(OrigJpegDecoderCore decoder, int i, ref OrigComponentScan currentComponentScan, ref int totalHv)
+ private void InitComponentScan(GolangJpegDecoderCore decoder, int i, ref GolangComponentScan currentComponentScan, ref int totalHv)
{
// Component selector.
int cs = decoder.Temp[1 + (2 * i)];
@@ -500,11 +499,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
private void ProcessComponentImpl(
- OrigJpegDecoderCore decoder,
+ GolangJpegDecoderCore decoder,
int i,
- ref OrigComponentScan currentComponentScan,
+ ref GolangComponentScan currentComponentScan,
ref int totalHv,
- OrigComponent currentComponent)
+ GolangComponent currentComponent)
{
// Section B.2.3 states that "the value of Cs_j shall be different from
// the values of Cs_1 through Cs_(j-1)". Since we have previously
@@ -522,13 +521,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
totalHv += currentComponent.HorizontalSamplingFactor * currentComponent.VerticalSamplingFactor;
currentComponentScan.DcTableSelector = (byte)(decoder.Temp[2 + (2 * i)] >> 4);
- if (currentComponentScan.DcTableSelector > OrigHuffmanTree.MaxTh)
+ if (currentComponentScan.DcTableSelector > GolangHuffmanTree.MaxTh)
{
throw new ImageFormatException("Bad DC table selector value");
}
currentComponentScan.AcTableSelector = (byte)(decoder.Temp[2 + (2 * i)] & 0x0f);
- if (currentComponentScan.AcTableSelector > OrigHuffmanTree.MaxTh)
+ if (currentComponentScan.AcTableSelector > GolangHuffmanTree.MaxTh)
{
throw new ImageFormatException("Bad AC table selector value");
}
@@ -540,7 +539,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// The instance
/// The Huffman tree
/// The low transform offset
- private void Refine(ref InputProcessor bp, ref OrigHuffmanTree h, int delta)
+ private void Refine(ref InputProcessor bp, ref GolangHuffmanTree h, int delta)
{
Block8x8* b = this.pointers.Block;
@@ -560,7 +559,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
if (bit)
{
- int stuff = (int)Block8x8.GetScalarAt(b, 0);
+ int stuff = Block8x8.GetScalarAt(b, 0);
// int stuff = (int)b[0];
stuff |= delta;
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/InputProcessor.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/InputProcessor.cs
index cb4b63cffd..c7e14ee4f2 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/InputProcessor.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/InputProcessor.cs
@@ -8,7 +8,7 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{
///
- /// Encapsulates stream reading and processing data and operations for .
+ /// Encapsulates stream reading and processing data and operations for .
/// It's a value type for imporved data locality, and reduced number of CALLVIRT-s
///
internal struct InputProcessor : IDisposable
@@ -27,14 +27,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Initializes a new instance of the struct.
///
/// The input
- /// Temporal buffer, same as
+ /// Temporal buffer, same as
public InputProcessor(Stream inputStream, byte[] temp)
{
- this.Bits = default(Bits);
+ this.Bits = default;
this.Bytes = Bytes.Create();
this.InputStream = inputStream;
this.Temp = temp;
- this.LastErrorCode = OrigDecoderErrorCode.NoError;
+ this.LastErrorCode = GolangDecoderErrorCode.NoError;
}
///
@@ -43,20 +43,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
public Stream InputStream { get; }
///
- /// Gets the temporary buffer, same instance as
+ /// Gets the temporary buffer, same instance as
///
public byte[] Temp { get; }
///
/// Gets a value indicating whether an unexpected EOF reached in .
///
- public bool ReachedEOF => this.LastErrorCode == OrigDecoderErrorCode.UnexpectedEndOfStream;
+ public bool ReachedEOF => this.LastErrorCode == GolangDecoderErrorCode.UnexpectedEndOfStream;
- public bool HasError => this.LastErrorCode != OrigDecoderErrorCode.NoError;
+ public bool HasError => this.LastErrorCode != GolangDecoderErrorCode.NoError;
- public OrigDecoderErrorCode LastErrorCode { get; private set; }
+ public GolangDecoderErrorCode LastErrorCode { get; private set; }
- public void ResetErrorState() => this.LastErrorCode = OrigDecoderErrorCode.NoError;
+ public void ResetErrorState() => this.LastErrorCode = GolangDecoderErrorCode.NoError;
///
/// If errorCode indicates unexpected EOF, sets to true and returns false.
@@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// A indicating whether EOF reached
public bool CheckEOFEnsureNoError()
{
- if (this.LastErrorCode == OrigDecoderErrorCode.UnexpectedEndOfStream)
+ if (this.LastErrorCode == GolangDecoderErrorCode.UnexpectedEndOfStream)
{
return false;
}
@@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// A indicating whether EOF reached
public bool CheckEOF()
{
- if (this.LastErrorCode == OrigDecoderErrorCode.UnexpectedEndOfStream)
+ if (this.LastErrorCode == GolangDecoderErrorCode.UnexpectedEndOfStream)
{
return false;
}
@@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public OrigDecoderErrorCode ReadByteUnsafe(out byte result)
+ public GolangDecoderErrorCode ReadByteUnsafe(out byte result)
{
this.LastErrorCode = this.Bytes.ReadByteUnsafe(this.InputStream, out result);
return this.LastErrorCode;
@@ -117,13 +117,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// TODO: This method (and also the usages) could be optimized by batching!
///
/// The decoded bit as a
- /// The
- public OrigDecoderErrorCode DecodeBitUnsafe(out bool result)
+ /// The
+ public GolangDecoderErrorCode DecodeBitUnsafe(out bool result)
{
if (this.Bits.UnreadBits == 0)
{
this.LastErrorCode = this.Bits.Ensure1BitUnsafe(ref this);
- if (this.LastErrorCode != OrigDecoderErrorCode.NoError)
+ if (this.LastErrorCode != GolangDecoderErrorCode.NoError)
{
result = false;
return this.LastErrorCode;
@@ -133,18 +133,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
result = (this.Bits.Accumulator & this.Bits.Mask) != 0;
this.Bits.UnreadBits--;
this.Bits.Mask >>= 1;
- return this.LastErrorCode = OrigDecoderErrorCode.NoError;
+ return this.LastErrorCode = GolangDecoderErrorCode.NoError;
}
///
/// Reads exactly length bytes into data. It does not care about byte stuffing.
- /// Does not throw on errors, returns instead!
+ /// Does not throw on errors, returns instead!
///
/// The data to write to.
/// The offset in the source buffer
/// The number of bytes to read
- /// The
- public OrigDecoderErrorCode ReadFullUnsafe(byte[] data, int offset, int length)
+ /// The
+ public GolangDecoderErrorCode ReadFullUnsafe(byte[] data, int offset, int length)
{
// Unread the overshot bytes, if any.
if (this.Bytes.UnreadableBytes != 0)
@@ -157,8 +157,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.Bytes.UnreadableBytes = 0;
}
- this.LastErrorCode = OrigDecoderErrorCode.NoError;
- while (length > 0 && this.LastErrorCode == OrigDecoderErrorCode.NoError)
+ this.LastErrorCode = GolangDecoderErrorCode.NoError;
+ while (length > 0 && this.LastErrorCode == GolangDecoderErrorCode.NoError)
{
if (this.Bytes.J - this.Bytes.I >= length)
{
@@ -185,13 +185,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
///
/// The number of bits to decode.
/// The result
- /// The
- public OrigDecoderErrorCode DecodeBitsUnsafe(int count, out int result)
+ /// The
+ public GolangDecoderErrorCode DecodeBitsUnsafe(int count, out int result)
{
if (this.Bits.UnreadBits < count)
{
this.LastErrorCode = this.Bits.EnsureNBitsUnsafe(count, ref this);
- if (this.LastErrorCode != OrigDecoderErrorCode.NoError)
+ if (this.LastErrorCode != GolangDecoderErrorCode.NoError)
{
result = 0;
return this.LastErrorCode;
@@ -202,7 +202,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
result = result & ((1 << count) - 1);
this.Bits.UnreadBits -= count;
this.Bits.Mask >>= count;
- return this.LastErrorCode = OrigDecoderErrorCode.NoError;
+ return this.LastErrorCode = GolangDecoderErrorCode.NoError;
}
///
@@ -210,8 +210,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
///
/// The huffman value
/// The decoded
- /// The
- public OrigDecoderErrorCode DecodeHuffmanUnsafe(ref OrigHuffmanTree huffmanTree, out int result)
+ /// The
+ public GolangDecoderErrorCode DecodeHuffmanUnsafe(ref GolangHuffmanTree huffmanTree, out int result)
{
result = 0;
@@ -224,9 +224,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{
this.LastErrorCode = this.Bits.Ensure8BitsUnsafe(ref this);
- if (this.LastErrorCode == OrigDecoderErrorCode.NoError)
+ if (this.LastErrorCode == GolangDecoderErrorCode.NoError)
{
- int lutIndex = (this.Bits.Accumulator >> (this.Bits.UnreadBits - OrigHuffmanTree.LutSizeLog2)) & 0xFF;
+ int lutIndex = (this.Bits.Accumulator >> (this.Bits.UnreadBits - GolangHuffmanTree.LutSizeLog2)) & 0xFF;
int v = huffmanTree.Lut[lutIndex];
if (v != 0)
@@ -246,7 +246,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
int code = 0;
- for (int i = 0; i < OrigHuffmanTree.MaxCodeLength; i++)
+ for (int i = 0; i < GolangHuffmanTree.MaxCodeLength; i++)
{
if (this.Bits.UnreadBits == 0)
{
@@ -269,7 +269,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
if (code <= huffmanTree.MaxCodes[i])
{
result = huffmanTree.GetValue(code, i);
- return this.LastErrorCode = OrigDecoderErrorCode.NoError;
+ return this.LastErrorCode = GolangDecoderErrorCode.NoError;
}
code <<= 1;
@@ -279,7 +279,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
DecoderThrowHelper.ThrowImageFormatException.BadHuffmanCode();
// DUMMY RETURN! C# doesn't know we have thrown an exception!
- return OrigDecoderErrorCode.NoError;
+ return GolangDecoderErrorCode.NoError;
}
///
@@ -295,11 +295,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
///
/// Skips the next n bytes.
- /// Does not throw, returns instead!
+ /// Does not throw, returns instead!
///
/// The number of bytes to ignore.
- /// The
- public OrigDecoderErrorCode SkipUnsafe(int count)
+ /// The
+ public GolangDecoderErrorCode SkipUnsafe(int count)
{
// Unread the overshot bytes, if any.
if (this.Bytes.UnreadableBytes != 0)
@@ -328,13 +328,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
this.LastErrorCode = this.Bytes.FillUnsafe(this.InputStream);
- if (this.LastErrorCode != OrigDecoderErrorCode.NoError)
+ if (this.LastErrorCode != GolangDecoderErrorCode.NoError)
{
return this.LastErrorCode;
}
}
- return this.LastErrorCode = OrigDecoderErrorCode.NoError;
+ return this.LastErrorCode = GolangDecoderErrorCode.NoError;
}
///
@@ -374,8 +374,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
///
/// Byte
/// Read bits value
- /// The
- public OrigDecoderErrorCode ReceiveExtendUnsafe(int t, out int x)
+ /// The
+ public GolangDecoderErrorCode ReceiveExtendUnsafe(int t, out int x)
{
this.LastErrorCode = this.Bits.ReceiveExtendUnsafe(t, ref this, out x);
return this.LastErrorCode;
@@ -386,7 +386,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
///
public void ResetHuffmanDecoder()
{
- this.Bits = default(Bits);
+ this.Bits = default;
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoder.cs
similarity index 80%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoder.cs
rename to src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoder.cs
index bf2f64b349..29255204b4 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoder.cs
@@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
///
/// Image decoder for generating an image out of a jpg stream.
///
- internal sealed class OrigJpegDecoder : IImageDecoder, IJpegDecoderOptions, IImageInfoDetector
+ internal sealed class GolangJpegDecoder : IImageDecoder, IJpegDecoderOptions, IImageInfoDetector
{
///
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
@@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{
Guard.NotNull(stream, nameof(stream));
- using (var decoder = new OrigJpegDecoderCore(configuration, this))
+ using (var decoder = new GolangJpegDecoderCore(configuration, this))
{
return decoder.Decode(stream);
}
@@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{
Guard.NotNull(stream, nameof(stream));
- using (var decoder = new OrigJpegDecoderCore(configuration, this))
+ using (var decoder = new GolangJpegDecoderCore(configuration, this))
{
return decoder.Identify(stream);
}
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs
similarity index 86%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs
rename to src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs
index 66b4601da9..fbcd265ac3 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs
@@ -3,8 +3,9 @@
using System.Collections.Generic;
using System.IO;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
-using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
+
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.MetaData.Profiles.Exif;
@@ -19,7 +20,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
///
/// Performs the jpeg decoding operation.
///
- internal sealed unsafe class OrigJpegDecoderCore : IRawJpegData
+ internal sealed unsafe class GolangJpegDecoderCore : IRawJpegData
{
///
/// The maximum number of color components
@@ -40,7 +41,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
#pragma warning disable SA1401 // FieldsMustBePrivate
///
- /// Encapsulates stream reading and processing data and operations for .
+ /// Encapsulates stream reading and processing data and operations for .
/// It's a value type for improved data locality, and reduced number of CALLVIRT-s
///
public InputProcessor InputProcessor;
@@ -79,16 +80,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private AdobeMarker adobe;
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// The configuration.
/// The options.
- public OrigJpegDecoderCore(Configuration configuration, IJpegDecoderOptions options)
+ public GolangJpegDecoderCore(Configuration configuration, IJpegDecoderOptions options)
{
this.IgnoreMetadata = options.IgnoreMetadata;
this.configuration = configuration ?? Configuration.Default;
- this.HuffmanTrees = OrigHuffmanTree.CreateHuffmanTrees();
- this.QuantizationTables = new Block8x8F[MaxTq + 1];
this.Temp = new byte[2 * Block8x8F.Size];
}
@@ -98,15 +97,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
///
/// Gets the component array
///
- public OrigComponent[] Components { get; private set; }
+ public GolangComponent[] Components { get; private set; }
///
/// Gets the huffman trees
///
- public OrigHuffmanTree[] HuffmanTrees { get; }
+ public GolangHuffmanTree[] HuffmanTrees { get; private set; }
///
- public Block8x8F[] QuantizationTables { get; }
+ public Block8x8F[] QuantizationTables { get; private set; }
///
/// Gets the temporary buffer used to store bytes read from the stream.
@@ -193,7 +192,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
where TPixel : struct, IPixel
{
this.ParseStream(stream);
-
return this.PostProcessIntoImage();
}
@@ -204,7 +202,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
public IImageInfo Identify(Stream stream)
{
this.ParseStream(stream, true);
-
return new ImageInfo(new PixelTypeInfo(this.BitsPerPixel), this.ImageWidth, this.ImageHeight, this.MetaData);
}
@@ -213,9 +210,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{
if (this.Components != null)
{
- foreach (OrigComponent component in this.Components)
+ foreach (GolangComponent component in this.Components)
{
- component.Dispose();
+ component?.Dispose();
}
}
@@ -223,7 +220,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
}
///
- /// Read metadata from stream and read the blocks in the scans into .
+ /// Read metadata from stream and read the blocks in the scans into .
///
/// The stream
/// Whether to decode metadata only.
@@ -233,10 +230,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.InputStream = stream;
this.InputProcessor = new InputProcessor(stream, this.Temp);
+ if (!metadataOnly)
+ {
+ this.HuffmanTrees = GolangHuffmanTree.CreateHuffmanTrees();
+ this.QuantizationTables = new Block8x8F[MaxTq + 1];
+ }
+
// Check for the Start Of Image marker.
this.InputProcessor.ReadFull(this.Temp, 0, 2);
- if (this.Temp[0] != OrigJpegConstants.Markers.XFF || this.Temp[1] != OrigJpegConstants.Markers.SOI)
+ if (this.Temp[0] != JpegConstants.Markers.XFF || this.Temp[1] != JpegConstants.Markers.SOI)
{
throw new ImageFormatException("Missing SOI marker.");
}
@@ -300,12 +303,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
}
// End Of Image.
- if (marker == OrigJpegConstants.Markers.EOI)
+ if (marker == JpegConstants.Markers.EOI)
{
break;
}
- if (marker >= OrigJpegConstants.Markers.RST0 && marker <= OrigJpegConstants.Markers.RST7)
+ if (marker >= JpegConstants.Markers.RST0 && marker <= JpegConstants.Markers.RST7)
{
// Figures B.2 and B.16 of the specification suggest that restart markers should
// only occur between Entropy Coded Segments and not after the final ECS.
@@ -327,18 +330,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
switch (marker)
{
- case OrigJpegConstants.Markers.SOF0:
- case OrigJpegConstants.Markers.SOF1:
- case OrigJpegConstants.Markers.SOF2:
- this.IsProgressive = marker == OrigJpegConstants.Markers.SOF2;
+ case JpegConstants.Markers.SOF0:
+ case JpegConstants.Markers.SOF1:
+ case JpegConstants.Markers.SOF2:
+ this.IsProgressive = marker == JpegConstants.Markers.SOF2;
this.ProcessStartOfFrameMarker(remaining, metadataOnly);
- if (metadataOnly && this.isJFif)
- {
- return;
- }
break;
- case OrigJpegConstants.Markers.DHT:
+ case JpegConstants.Markers.DHT:
if (metadataOnly)
{
this.InputProcessor.Skip(remaining);
@@ -349,7 +348,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
}
break;
- case OrigJpegConstants.Markers.DQT:
+ case JpegConstants.Markers.DQT:
if (metadataOnly)
{
this.InputProcessor.Skip(remaining);
@@ -360,21 +359,26 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
}
break;
- case OrigJpegConstants.Markers.SOS:
- if (metadataOnly)
+ case JpegConstants.Markers.SOS:
+ if (!metadataOnly)
{
- return;
+ this.ProcessStartOfScanMarker(remaining);
+ if (this.InputProcessor.ReachedEOF)
+ {
+ // If unexpected EOF reached. We can stop processing bytes as we now have the image data.
+ processBytes = false;
+ }
}
-
- this.ProcessStartOfScanMarker(remaining);
- if (this.InputProcessor.ReachedEOF)
+ else
{
- // If unexpected EOF reached. We can stop processing bytes as we now have the image data.
+ // It's highly unlikely that APPn related data will be found after the SOS marker
+ // We should have gathered everything we need by now.
processBytes = false;
}
break;
- case OrigJpegConstants.Markers.DRI:
+
+ case JpegConstants.Markers.DRI:
if (metadataOnly)
{
this.InputProcessor.Skip(remaining);
@@ -385,21 +389,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
}
break;
- case OrigJpegConstants.Markers.APP0:
+ case JpegConstants.Markers.APP0:
this.ProcessApplicationHeaderMarker(remaining);
break;
- case OrigJpegConstants.Markers.APP1:
+ case JpegConstants.Markers.APP1:
this.ProcessApp1Marker(remaining);
break;
- case OrigJpegConstants.Markers.APP2:
+ case JpegConstants.Markers.APP2:
this.ProcessApp2Marker(remaining);
break;
- case OrigJpegConstants.Markers.APP14:
+ case JpegConstants.Markers.APP14:
this.ProcessApp14Marker(remaining);
break;
default:
- if ((marker >= OrigJpegConstants.Markers.APP0 && marker <= OrigJpegConstants.Markers.APP15)
- || marker == OrigJpegConstants.Markers.COM)
+ if ((marker >= JpegConstants.Markers.APP0 && marker <= JpegConstants.Markers.APP15)
+ || marker == JpegConstants.Markers.COM)
{
this.InputProcessor.Skip(remaining);
}
@@ -425,7 +429,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
///
private void InitDerivedMetaDataProperties()
{
- if (this.isExif)
+ if (this.isJFif)
+ {
+ this.MetaData.HorizontalResolution = this.jFif.XDensity;
+ this.MetaData.VerticalResolution = this.jFif.YDensity;
+ }
+ else if (this.isExif)
{
double horizontalValue = this.MetaData.ExifProfile.TryGetValue(ExifTag.XResolution, out ExifValue horizonalTag)
? ((Rational)horizonalTag.Value).ToDouble()
@@ -441,11 +450,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.MetaData.VerticalResolution = verticalValue;
}
}
- else if (this.isJFif)
- {
- this.MetaData.HorizontalResolution = this.jFif.XDensity;
- this.MetaData.VerticalResolution = this.jFif.YDensity;
- }
}
///
@@ -675,26 +679,29 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
throw new ImageFormatException("SOF has wrong length");
}
- this.Components = new OrigComponent[this.ComponentCount];
-
- for (int i = 0; i < this.ComponentCount; i++)
+ if (!metadataOnly)
{
- byte componentIdentifier = this.Temp[6 + (3 * i)];
- var component = new OrigComponent(componentIdentifier, i);
- component.InitializeCoreData(this);
- this.Components[i] = component;
- }
+ this.Components = new GolangComponent[this.ComponentCount];
- int h0 = this.Components[0].HorizontalSamplingFactor;
- int v0 = this.Components[0].VerticalSamplingFactor;
+ for (int i = 0; i < this.ComponentCount; i++)
+ {
+ byte componentIdentifier = this.Temp[6 + (3 * i)];
+ var component = new GolangComponent(componentIdentifier, i);
+ component.InitializeCoreData(this);
+ this.Components[i] = component;
+ }
- this.ImageSizeInMCU = this.ImageSizeInPixels.DivideRoundUp(8 * h0, 8 * v0);
+ int h0 = this.Components[0].HorizontalSamplingFactor;
+ int v0 = this.Components[0].VerticalSamplingFactor;
- this.ColorSpace = this.DeduceJpegColorSpace();
+ this.ImageSizeInMCU = this.ImageSizeInPixels.DivideRoundUp(8 * h0, 8 * v0);
- foreach (OrigComponent component in this.Components)
- {
- component.InitializeDerivedData(this.configuration.MemoryManager, this, metadataOnly);
+ this.ColorSpace = this.DeduceJpegColorSpace();
+
+ foreach (GolangComponent component in this.Components)
+ {
+ component.InitializeDerivedData(this.configuration.MemoryManager, this);
+ }
}
}
@@ -715,18 +722,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.InputProcessor.ReadFull(this.Temp, 0, 17);
int tc = this.Temp[0] >> 4;
- if (tc > OrigHuffmanTree.MaxTc)
+ if (tc > GolangHuffmanTree.MaxTc)
{
throw new ImageFormatException("Bad Tc value");
}
int th = this.Temp[0] & 0x0f;
- if (th > OrigHuffmanTree.MaxTh)
+ if (th > GolangHuffmanTree.MaxTh)
{
throw new ImageFormatException("Bad Th value");
}
- int huffTreeIndex = (tc * OrigHuffmanTree.ThRowSize) + th;
+ int huffTreeIndex = (tc * GolangHuffmanTree.ThRowSize) + th;
this.HuffmanTrees[huffTreeIndex].ProcessDefineHuffmanTablesMarkerLoop(
ref this.InputProcessor,
this.Temp,
@@ -760,9 +767,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
///
private void ProcessStartOfScanMarker(int remaining)
{
- var scan = default(OrigJpegScanDecoder);
- OrigJpegScanDecoder.InitStreamReading(&scan, this, remaining);
- this.InputProcessor.Bits = default(Bits);
+ var scan = default(GolangJpegScanDecoder);
+ GolangJpegScanDecoder.InitStreamReading(&scan, this, remaining);
+ this.InputProcessor.Bits = default;
scan.DecodeBlocks(this);
}
@@ -773,19 +780,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
case 1:
return JpegColorSpace.Grayscale;
case 3:
- if (!this.isAdobe || this.adobe.ColorTransform == OrigJpegConstants.Adobe.ColorTransformYCbCr)
+ if (!this.isAdobe || this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYCbCr)
{
return JpegColorSpace.YCbCr;
}
- if (this.adobe.ColorTransform == OrigJpegConstants.Adobe.ColorTransformUnknown)
+ if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
{
return JpegColorSpace.RGB;
}
break;
case 4:
- if (this.adobe.ColorTransform == OrigJpegConstants.Adobe.ColorTransformYcck)
+ if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYcck)
{
return JpegColorSpace.Ycck;
}
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegConstants.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegConstants.cs
deleted file mode 100644
index be383d2120..0000000000
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegConstants.cs
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System.Collections.Generic;
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
-{
- ///
- /// Defines jpeg constants defined in the specification.
- ///
- internal static class OrigJpegConstants
- {
- ///
- /// The maximum allowable length in each dimension of a jpeg image.
- ///
- public const ushort MaxLength = 65535;
-
- ///
- /// The list of mimetypes that equate to a jpeg.
- ///
- public static readonly IEnumerable MimeTypes = new[] { "image/jpeg", "image/pjpeg" };
-
- ///
- /// The list of file extensions that equate to a jpeg.
- ///
- public static readonly IEnumerable FileExtensions = new[] { "jpg", "jpeg", "jfif" };
-
- ///
- /// Describes common Jpeg markers
- ///
- internal static class Markers
- {
- ///
- /// Marker prefix. Next byte is a marker.
- ///
- public const byte XFF = 0xff;
-
- ///
- /// Same as but of type
- ///
- public const int XFFInt = XFF;
-
- ///
- /// Start of Image
- ///
- public const byte SOI = 0xd8;
-
- ///
- /// Start of Frame (baseline DCT)
- ///
- /// Indicates that this is a baseline DCT-based JPEG, and specifies the width, height, number of components,
- /// and component subsampling (e.g., 4:2:0).
- ///
- ///
- public const byte SOF0 = 0xc0;
-
- ///
- /// Start Of Frame (Extended Sequential DCT)
- ///
- /// Indicates that this is a progressive DCT-based JPEG, and specifies the width, height, number of components,
- /// and component subsampling (e.g., 4:2:0).
- ///
- ///
- public const byte SOF1 = 0xc1;
-
- ///
- /// Start Of Frame (progressive DCT)
- ///
- /// Indicates that this is a progressive DCT-based JPEG, and specifies the width, height, number of components,
- /// and component subsampling (e.g., 4:2:0).
- ///
- ///
- public const byte SOF2 = 0xc2;
-
- ///
- /// Define Huffman Table(s)
- ///
- /// Specifies one or more Huffman tables.
- ///
- ///
- public const byte DHT = 0xc4;
-
- ///
- /// Define Quantization Table(s)
- ///
- /// Specifies one or more quantization tables.
- ///
- ///
- public const byte DQT = 0xdb;
-
- ///
- /// Define Restart Interval
- ///
- /// Specifies the interval between RSTn markers, in macroblocks. This marker is followed by two bytes
- /// indicating the fixed size so it can be treated like any other variable size segment.
- ///
- ///
- public const byte DRI = 0xdd;
-
- ///
- /// Define First Restart
- ///
- /// Inserted every r macroblocks, where r is the restart interval set by a DRI marker.
- /// Not used if there was no DRI marker. The low three bits of the marker code cycle in value from 0 to 7.
- ///
- ///
- public const byte RST0 = 0xd0;
-
- ///
- /// Define Eigth Restart
- ///
- /// Inserted every r macroblocks, where r is the restart interval set by a DRI marker.
- /// Not used if there was no DRI marker. The low three bits of the marker code cycle in value from 0 to 7.
- ///
- ///
- public const byte RST7 = 0xd7;
-
- ///
- /// Start of Scan
- ///
- /// Begins a top-to-bottom scan of the image. In baseline DCT JPEG images, there is generally a single scan.
- /// Progressive DCT JPEG images usually contain multiple scans. This marker specifies which slice of data it
- /// will contain, and is immediately followed by entropy-coded data.
- ///
- ///
- public const byte SOS = 0xda;
-
- ///
- /// Comment
- ///
- /// Contains a text comment.
- ///
- ///
- public const byte COM = 0xfe;
-
- ///
- /// End of Image
- ///
- public const byte EOI = 0xd9;
-
- ///
- /// Application specific marker for marking the jpeg format.
- ///
- ///
- public const byte APP0 = 0xe0;
-
- ///
- /// Application specific marker for marking where to store metadata.
- ///
- public const byte APP1 = 0xe1;
-
- ///
- /// Application specific marker for marking where to store ICC profile information.
- ///
- public const byte APP2 = 0xe2;
-
- ///
- /// Application specific marker used by Adobe for storing encoding information for DCT filters.
- ///
- public const byte APP14 = 0xee;
-
- ///
- /// Application specific marker used by GraphicConverter to store JPEG quality.
- ///
- public const byte APP15 = 0xef;
- }
-
- ///
- /// Describes Adobe specific markers
- ///
- internal static class Adobe
- {
- ///
- /// The color transform is unknown.(RGB or CMYK)
- ///
- public const int ColorTransformUnknown = 0;
-
- ///
- /// The color transform is YCbCr (luminance, red chroma, blue chroma)
- ///
- public const int ColorTransformYCbCr = 1;
-
- ///
- /// The color transform is YCCK (luminance, red chroma, blue chroma, keyline)
- ///
- public const int ColorTransformYcck = 2;
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegConstants.cs b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs
similarity index 64%
rename from src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegConstants.cs
rename to src/ImageSharp/Formats/Jpeg/JpegConstants.cs
index 2c369d3908..49e3b41704 100644
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegConstants.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs
@@ -1,119 +1,141 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-// ReSharper disable InconsistentNaming
-namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
+using System.Collections.Generic;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg
{
///
- /// Contains jpeg constant values
+ /// Contains jpeg constant values defined in the specification.
///
- internal static class PdfJsJpegConstants
+ internal static class JpegConstants
{
+ ///
+ /// The maximum allowable length in each dimension of a jpeg image.
+ ///
+ public const ushort MaxLength = 65535;
+
+ ///
+ /// The list of mimetypes that equate to a jpeg.
+ ///
+ public static readonly IEnumerable MimeTypes = new[] { "image/jpeg", "image/pjpeg" };
+
+ ///
+ /// The list of file extensions that equate to a jpeg.
+ ///
+ public static readonly IEnumerable FileExtensions = new[] { "jpg", "jpeg", "jfif" };
+
///
/// Contains marker specific constants
///
- public static class Markers
+ // ReSharper disable InconsistentNaming
+ internal static class Markers
{
///
/// The prefix used for all markers.
///
- public const byte Prefix = 0xFF;
+ public const byte XFF = 0xFF;
+
+ ///
+ /// Same as but of type
+ ///
+ public const int XFFInt = XFF;
///
/// The Start of Image marker
///
- public const ushort SOI = 0xFFD8;
+ public const byte SOI = 0xD8;
///
/// The End of Image marker
///
- public const ushort EOI = 0xFFD9;
+ public const byte EOI = 0xD9;
///
/// Application specific marker for marking the jpeg format.
///
///
- public const ushort APP0 = 0xFFE0;
+ public const byte APP0 = 0xE0;
///
/// Application specific marker for marking where to store metadata.
///
- public const ushort APP1 = 0xFFE1;
+ public const byte APP1 = 0xE1;
///
/// Application specific marker for marking where to store ICC profile information.
///
- public const ushort APP2 = 0xFFE2;
+ public const byte APP2 = 0xE2;
///
/// Application specific marker.
///
- public const ushort APP3 = 0xFFE3;
+ public const byte APP3 = 0xE3;
///
/// Application specific marker.
///
- public const ushort APP4 = 0xFFE4;
+ public const byte APP4 = 0xE4;
///
/// Application specific marker.
///
- public const ushort APP5 = 0xFFE5;
+ public const byte APP5 = 0xE5;
///
/// Application specific marker.
///
- public const ushort APP6 = 0xFFE6;
+ public const byte APP6 = 0xE6;
///
/// Application specific marker.
///
- public const ushort APP7 = 0xFFE7;
+ public const byte APP7 = 0xE7;
///
/// Application specific marker.
///
- public const ushort APP8 = 0xFFE8;
+ public const byte APP8 = 0xE8;
///
/// Application specific marker.
///
- public const ushort APP9 = 0xFFE9;
+ public const byte APP9 = 0xE9;
///
/// Application specific marker.
///
- public const ushort APP10 = 0xFFEA;
+ public const byte APP10 = 0xEA;
///
/// Application specific marker.
///
- public const ushort APP11 = 0xFFEB;
+ public const byte APP11 = 0xEB;
///
/// Application specific marker.
///
- public const ushort APP12 = 0xFFEC;
+ public const byte APP12 = 0xEC;
///
/// Application specific marker.
///
- public const ushort APP13 = 0xFFED;
+ public const byte APP13 = 0xED;
///
/// Application specific marker used by Adobe for storing encoding information for DCT filters.
///
- public const ushort APP14 = 0xFFEE;
+ public const byte APP14 = 0xEE;
///
/// Application specific marker used by GraphicConverter to store JPEG quality.
///
- public const ushort APP15 = 0xFFEF;
+ public const byte APP15 = 0xEF;
///
/// The text comment marker
///
- public const ushort COM = 0xFFFE;
+ public const byte COM = 0xFE;
///
/// Define Quantization Table(s) marker
@@ -121,7 +143,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// Specifies one or more quantization tables.
///
///
- public const ushort DQT = 0xFFDB;
+ public const byte DQT = 0xDB;
///
/// Start of Frame (baseline DCT)
@@ -130,7 +152,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// and component subsampling (e.g., 4:2:0).
///
///
- public const ushort SOF0 = 0xFFC0;
+ public const byte SOF0 = 0xC0;
///
/// Start Of Frame (Extended Sequential DCT)
@@ -139,7 +161,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// and component subsampling (e.g., 4:2:0).
///
///
- public const ushort SOF1 = 0xFFC1;
+ public const byte SOF1 = 0xC1;
///
/// Start Of Frame (progressive DCT)
@@ -148,7 +170,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// and component subsampling (e.g., 4:2:0).
///
///
- public const ushort SOF2 = 0xFFC2;
+ public const byte SOF2 = 0xC2;
///
/// Define Huffman Table(s)
@@ -156,15 +178,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// Specifies one or more Huffman tables.
///
///
- public const ushort DHT = 0xFFC4;
+ public const byte DHT = 0xC4;
///
/// Define Restart Interval
///
- /// Specifies the interval between RSTn markers, in macroblocks.This marker is followed by two bytes indicating the fixed size so it can be treated like any other variable size segment.
+ /// Specifies the interval between RSTn markers, in macroblocks.This marker is followed by two bytes indicating the fixed size so
+ /// it can be treated like any other variable size segment.
///
///
- public const ushort DRI = 0xFFDD;
+ public const byte DRI = 0xDD;
///
/// Start of Scan
@@ -174,7 +197,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// will contain, and is immediately followed by entropy-coded data.
///
///
- public const ushort SOS = 0xFFDA;
+ public const byte SOS = 0xDA;
///
/// Define First Restart
@@ -183,7 +206,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// Not used if there was no DRI marker. The low three bits of the marker code cycle in value from 0 to 7.
///
///
- public const ushort RST0 = 0xFFD0;
+ public const byte RST0 = 0xD0;
///
/// Define Eigth Restart
@@ -192,28 +215,28 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// Not used if there was no DRI marker. The low three bits of the marker code cycle in value from 0 to 7.
///
///
- public const ushort RST7 = 0xFFD7;
+ public const byte RST7 = 0xD7;
+ }
+ ///
+ /// Contains Adobe specific constants
+ ///
+ internal static class Adobe
+ {
///
- /// Contains Adobe specific markers
+ /// The color transform is unknown.(RGB or CMYK)
///
- public static class Adobe
- {
- ///
- /// The color transform is unknown.(RGB or CMYK)
- ///
- public const byte ColorTransformUnknown = 0;
+ public const byte ColorTransformUnknown = 0;
- ///
- /// The color transform is YCbCr (luminance, red chroma, blue chroma)
- ///
- public const byte ColorTransformYCbCr = 1;
+ ///
+ /// The color transform is YCbCr (luminance, red chroma, blue chroma)
+ ///
+ public const byte ColorTransformYCbCr = 1;
- ///
- /// The color transform is YCCK (luminance, red chroma, blue chroma, keyline)
- ///
- public const byte ColorTransformYcck = 2;
- }
+ ///
+ /// The color transform is YCCK (luminance, red chroma, blue chroma, keyline)
+ ///
+ public const byte ColorTransformYcck = 2;
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
index 91835b5d71..e738982cba 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
@@ -3,7 +3,7 @@
using System.IO;
-using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
+using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Jpeg
@@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
{
Guard.NotNull(stream, nameof(stream));
- using (var decoder = new OrigJpegDecoderCore(configuration, this))
+ using (var decoder = new PdfJsJpegDecoderCore(configuration, this))
{
return decoder.Decode(stream);
}
@@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
{
Guard.NotNull(stream, "stream");
- using (var decoder = new OrigJpegDecoderCore(configuration, this))
+ using (var decoder = new PdfJsJpegDecoderCore(configuration, this))
{
return decoder.Identify(stream);
}
diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs
index 60b00c0f5b..0f389dee0f 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.IO;
-using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Jpeg
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
similarity index 93%
rename from src/ImageSharp/Formats/Jpeg/GolangPort/JpegEncoderCore.cs
rename to src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
index 4fbb20ee82..37279d5263 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/JpegEncoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
@@ -1,19 +1,16 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
-using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components;
-using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Encoder;
-using SixLabors.ImageSharp.Memory;
+
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder;
using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.MetaData.Profiles.Icc;
using SixLabors.ImageSharp.PixelFormats;
-using Block8x8F = SixLabors.ImageSharp.Formats.Jpeg.Common.Block8x8F;
-namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
+namespace SixLabors.ImageSharp.Formats.Jpeg
{
///
/// Image encoder for writing an image to a stream as a jpeg.
@@ -58,7 +55,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
///
private static readonly byte[] SosHeaderYCbCr =
{
- OrigJpegConstants.Markers.XFF, OrigJpegConstants.Markers.SOS,
+ JpegConstants.Markers.XFF, JpegConstants.Markers.SOS,
// Marker
0x00, 0x0c,
@@ -104,11 +101,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
}
};
- ///
- /// Lookup tables for converting Rgb to YCbCr
- ///
- private static RgbToYCbCrTables rgbToYCbCrTables = RgbToYCbCrTables.Create();
-
///
/// A scratch buffer to reduce allocations.
///
@@ -190,7 +182,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
- ushort max = OrigJpegConstants.MaxLength;
+ ushort max = JpegConstants.MaxLength;
if (image.Width >= max || image.Height >= max)
{
throw new ImageFormatException($"Image is too large to encode at {image.Width}x{image.Height}.");
@@ -234,8 +226,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.WriteStartOfScan(image);
// Write the End Of Image marker.
- this.buffer[0] = OrigJpegConstants.Markers.XFF;
- this.buffer[1] = OrigJpegConstants.Markers.EOI;
+ this.buffer[0] = JpegConstants.Markers.XFF;
+ this.buffer[1] = JpegConstants.Markers.EOI;
stream.Write(this.buffer, 0, 2);
stream.Flush();
}
@@ -382,18 +374,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{
// TODO: Need a JpegScanEncoder class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.)
// (Partially done with YCbCrForwardConverter)
- Block8x8F temp1 = default(Block8x8F);
- Block8x8F temp2 = default(Block8x8F);
+ Block8x8F temp1 = default;
+ Block8x8F temp2 = default;
Block8x8F onStackLuminanceQuantTable = this.luminanceQuantTable;
Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable;
- ZigZag unzig = ZigZag.CreateUnzigTable();
+ var unzig = ZigZag.CreateUnzigTable();
// ReSharper disable once InconsistentNaming
int prevDCY = 0, prevDCCb = 0, prevDCCr = 0;
- YCbCrForwardConverter pixelConverter = YCbCrForwardConverter.Create();
+ var pixelConverter = YCbCrForwardConverter.Create();
for (int y = 0; y < pixels.Height; y += 8)
{
@@ -437,12 +429,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void WriteApplicationHeader(short horizontalResolution, short verticalResolution)
{
// Write the start of image marker. Markers are always prefixed with with 0xff.
- this.buffer[0] = OrigJpegConstants.Markers.XFF;
- this.buffer[1] = OrigJpegConstants.Markers.SOI;
+ this.buffer[0] = JpegConstants.Markers.XFF;
+ this.buffer[1] = JpegConstants.Markers.SOI;
// Write the JFIF headers
- this.buffer[2] = OrigJpegConstants.Markers.XFF;
- this.buffer[3] = OrigJpegConstants.Markers.APP0; // Application Marker
+ this.buffer[2] = JpegConstants.Markers.XFF;
+ this.buffer[3] = JpegConstants.Markers.APP0; // Application Marker
this.buffer[4] = 0x00;
this.buffer[5] = 0x10;
this.buffer[6] = 0x4a; // J
@@ -502,7 +494,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.EmitHuffRLE((HuffIndex)((2 * (int)index) + 0), 0, dc - prevDC);
// Emit the AC components.
- HuffIndex h = (HuffIndex)((2 * (int)index) + 1);
+ var h = (HuffIndex)((2 * (int)index) + 1);
int runLength = 0;
for (int zig = 1; zig < Block8x8F.Size; zig++)
@@ -556,7 +548,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
markerlen += 1 + 16 + s.Values.Length;
}
- this.WriteMarkerHeader(OrigJpegConstants.Markers.DHT, markerlen);
+ this.WriteMarkerHeader(JpegConstants.Markers.DHT, markerlen);
for (int i = 0; i < specs.Length; i++)
{
HuffmanSpec spec = specs[i];
@@ -590,7 +582,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{
// Marker + quantization table lengths
int markerlen = 2 + (QuantizationTableCount * (1 + Block8x8F.Size));
- this.WriteMarkerHeader(OrigJpegConstants.Markers.DQT, markerlen);
+ this.WriteMarkerHeader(JpegConstants.Markers.DQT, markerlen);
// Loop through and collect the tables as one array.
// This allows us to reduce the number of writes to the stream.
@@ -627,8 +619,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
int length = data.Length + 2;
- this.buffer[0] = OrigJpegConstants.Markers.XFF;
- this.buffer[1] = OrigJpegConstants.Markers.APP1; // Application Marker
+ this.buffer[0] = JpegConstants.Markers.XFF;
+ this.buffer[1] = JpegConstants.Markers.APP1; // Application Marker
this.buffer[2] = (byte)((length >> 8) & 0xFF);
this.buffer[3] = (byte)(length & 0xFF);
@@ -686,8 +678,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
dataLength -= length;
- this.buffer[0] = OrigJpegConstants.Markers.XFF;
- this.buffer[1] = OrigJpegConstants.Markers.APP2; // Application Marker
+ this.buffer[0] = JpegConstants.Markers.XFF;
+ this.buffer[1] = JpegConstants.Markers.APP2; // Application Marker
int markerLength = length + 16;
this.buffer[2] = (byte)((markerLength >> 8) & 0xFF);
this.buffer[3] = (byte)(markerLength & 0xFF);
@@ -759,7 +751,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
// Length (high byte, low byte), 8 + components * 3.
int markerlen = 8 + (3 * componentCount);
- this.WriteMarkerHeader(OrigJpegConstants.Markers.SOF0, markerlen);
+ this.WriteMarkerHeader(JpegConstants.Markers.SOF0, markerlen);
this.buffer[0] = 8; // Data Precision. 8 for now, 12 and 16 bit jpegs not supported
this.buffer[1] = (byte)(height >> 8);
this.buffer[2] = (byte)(height & 0xff); // (2 bytes, Hi-Lo), must be > 0 if DNL not supported
@@ -827,20 +819,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
where TPixel : struct, IPixel
{
// TODO: Need a JpegScanEncoder class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.)
- Block8x8F b = default(Block8x8F);
+ Block8x8F b = default;
- BlockQuad cb = default(BlockQuad);
- BlockQuad cr = default(BlockQuad);
- Block8x8F* cbPtr = (Block8x8F*)cb.Data;
- Block8x8F* crPtr = (Block8x8F*)cr.Data;
+ BlockQuad cb = default;
+ BlockQuad cr = default;
+ var cbPtr = (Block8x8F*)cb.Data;
+ var crPtr = (Block8x8F*)cr.Data;
- Block8x8F temp1 = default(Block8x8F);
- Block8x8F temp2 = default(Block8x8F);
+ Block8x8F temp1 = default;
+ Block8x8F temp2 = default;
Block8x8F onStackLuminanceQuantTable = this.luminanceQuantTable;
Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable;
- ZigZag unzig = ZigZag.CreateUnzigTable();
+ var unzig = ZigZag.CreateUnzigTable();
var pixelConverter = YCbCrForwardConverter.Create();
@@ -902,7 +894,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void WriteMarkerHeader(byte marker, int length)
{
// Markers are always prefixed with with 0xff.
- this.buffer[0] = OrigJpegConstants.Markers.XFF;
+ this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = marker;
this.buffer[2] = (byte)(length >> 8);
this.buffer[3] = (byte)(length & 0xff);
diff --git a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs
index 4f368dcdee..9a18f14d30 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
-using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
namespace SixLabors.ImageSharp.Formats.Jpeg
{
@@ -18,9 +17,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
public string DefaultMimeType => "image/jpeg";
///
- public IEnumerable MimeTypes => OrigJpegConstants.MimeTypes;
+ public IEnumerable MimeTypes => JpegConstants.MimeTypes;
///
- public IEnumerable FileExtensions => OrigJpegConstants.FileExtensions;
+ public IEnumerable FileExtensions => JpegConstants.FileExtensions;
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/DoubleBufferedStreamReader.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/DoubleBufferedStreamReader.cs
new file mode 100644
index 0000000000..eb91590e81
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/DoubleBufferedStreamReader.cs
@@ -0,0 +1,238 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using SixLabors.ImageSharp.Memory;
+
+// TODO: This could be useful elsewhere.
+namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
+{
+ ///
+ /// A stream reader that add a secondary level buffer in addition to native stream buffered reading
+ /// to reduce the overhead of small incremental reads.
+ ///
+ internal class DoubleBufferedStreamReader : IDisposable
+ {
+ ///
+ /// The length, in bytes, of the buffering chunk
+ ///
+ public const int ChunkLength = 4096;
+
+ private const int ChunkLengthMinusOne = ChunkLength - 1;
+
+ private readonly Stream stream;
+
+ private readonly IManagedByteBuffer managedBuffer;
+
+ private readonly byte[] bufferChunk;
+
+ private readonly int length;
+
+ private int bytesRead;
+
+ private int position;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to use for buffer allocations.
+ /// The input stream.
+ public DoubleBufferedStreamReader(MemoryManager memoryManager, Stream stream)
+ {
+ this.stream = stream;
+ this.length = (int)stream.Length;
+ this.managedBuffer = memoryManager.AllocateCleanManagedByteBuffer(ChunkLength);
+ this.bufferChunk = this.managedBuffer.Array;
+ }
+
+ ///
+ /// Gets the length, in bytes, of the stream
+ ///
+ public long Length => this.length;
+
+ ///
+ /// Gets or sets the current position within the stream
+ ///
+ public long Position
+ {
+ get => this.position;
+
+ set
+ {
+ // Reset everything. It's easier than tracking.
+ this.position = (int)value;
+ this.stream.Seek(this.position, SeekOrigin.Begin);
+ this.bytesRead = ChunkLength;
+ }
+ }
+
+ ///
+ /// Reads a byte from the stream and advances the position within the stream by one
+ /// byte, or returns -1 if at the end of the stream.
+ ///
+ /// The unsigned byte cast to an , or -1 if at the end of the stream.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public int ReadByte()
+ {
+ if (this.position >= this.length)
+ {
+ return -1;
+ }
+
+ if (this.position == 0 || this.bytesRead > ChunkLengthMinusOne)
+ {
+ return this.ReadByteSlow();
+ }
+
+ this.position++;
+ return this.bufferChunk[this.bytesRead++];
+ }
+
+ ///
+ /// Skips the number of bytes in the stream
+ ///
+ /// The number of bytes to skip
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Skip(int count)
+ {
+ this.Position += count;
+ }
+
+ ///
+ /// Reads a sequence of bytes from the current stream and advances the position within the stream
+ /// by the number of bytes read.
+ ///
+ ///
+ /// An array of bytes. When this method returns, the buffer contains the specified
+ /// byte array with the values between offset and (offset + count - 1) replaced by
+ /// the bytes read from the current source.
+ ///
+ ///
+ /// The zero-based byte offset in buffer at which to begin storing the data read
+ /// from the current stream.
+ ///
+ /// The maximum number of bytes to be read from the current stream.
+ ///
+ /// The total number of bytes read into the buffer. This can be less than the number
+ /// of bytes requested if that many bytes are not currently available, or zero (0)
+ /// if the end of the stream has been reached.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public int Read(byte[] buffer, int offset, int count)
+ {
+ if (buffer.Length > ChunkLength)
+ {
+ return this.ReadToBufferSlow(buffer, offset, count);
+ }
+
+ if (this.position == 0 || count + this.bytesRead > ChunkLength)
+ {
+ return this.ReadToChunkSlow(buffer, offset, count);
+ }
+
+ int n = this.GetCount(count);
+ this.CopyBytes(buffer, offset, n);
+
+ this.position += n;
+ this.bytesRead += n;
+
+ return n;
+ }
+
+ ///
+ public void Dispose()
+ {
+ this.managedBuffer?.Dispose();
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private int ReadByteSlow()
+ {
+ if (this.position != this.stream.Position)
+ {
+ this.stream.Seek(this.position, SeekOrigin.Begin);
+ }
+
+ this.stream.Read(this.bufferChunk, 0, ChunkLength);
+ this.bytesRead = 0;
+
+ this.position++;
+ return this.bufferChunk[this.bytesRead++];
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private int ReadToChunkSlow(byte[] buffer, int offset, int count)
+ {
+ // Refill our buffer then copy.
+ if (this.position != this.stream.Position)
+ {
+ this.stream.Seek(this.position, SeekOrigin.Begin);
+ }
+
+ this.stream.Read(this.bufferChunk, 0, ChunkLength);
+ this.bytesRead = 0;
+
+ int n = this.GetCount(count);
+ this.CopyBytes(buffer, offset, n);
+
+ this.position += n;
+ this.bytesRead += n;
+
+ return n;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private int ReadToBufferSlow(byte[] buffer, int offset, int count)
+ {
+ // Read to target but don't copy to our chunk.
+ if (this.position != this.stream.Position)
+ {
+ this.stream.Seek(this.position, SeekOrigin.Begin);
+ }
+
+ int n = this.stream.Read(buffer, offset, count);
+ this.Position += n;
+ return n;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private int GetCount(int count)
+ {
+ int n = this.length - this.position;
+ if (n > count)
+ {
+ n = count;
+ }
+
+ if (n < 0)
+ {
+ n = 0;
+ }
+
+ return n;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void CopyBytes(byte[] buffer, int offset, int count)
+ {
+ if (count < 9)
+ {
+ int byteCount = count;
+ int read = this.bytesRead;
+ byte[] chunk = this.bufferChunk;
+
+ while (--byteCount > -1)
+ {
+ buffer[offset + byteCount] = chunk[read + byteCount];
+ }
+ }
+ else
+ {
+ Buffer.BlockCopy(this.bufferChunk, this.bytesRead, buffer, offset, count);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFileMarker.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFileMarker.cs
index 8e51c0b7cc..85c9f94666 100644
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFileMarker.cs
+++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFileMarker.cs
@@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using System.Runtime.CompilerServices;
+
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
///
@@ -13,7 +15,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
///
/// The marker
/// The position within the stream
- public PdfJsFileMarker(ushort marker, long position)
+ public PdfJsFileMarker(byte marker, long position)
{
this.Marker = marker;
this.Position = position;
@@ -26,7 +28,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// The marker
/// The position within the stream
/// Whether the current marker is invalid
- public PdfJsFileMarker(ushort marker, long position, bool invalid)
+ public PdfJsFileMarker(byte marker, long position, bool invalid)
{
this.Marker = marker;
this.Position = position;
@@ -36,17 +38,29 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
///
/// Gets a value indicating whether the current marker is invalid
///
- public bool Invalid { get; }
+ public bool Invalid
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get;
+ }
///
/// Gets the position of the marker within a stream
///
- public ushort Marker { get; }
+ public byte Marker
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get;
+ }
///
/// Gets the position of the marker within a stream
///
- public long Position { get; }
+ public long Position
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get;
+ }
///
public override string ToString()
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs
index 7f50a8529c..ccbb5c6c01 100644
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs
+++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs
@@ -4,8 +4,9 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
-using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
+
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives;
@@ -36,9 +37,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
public byte Id { get; }
///
- /// Gets or sets Pred TODO: What does pred stand for?
+ /// Gets or sets DC coefficient predictor
///
- public int Pred { get; set; }
+ public int DcPredictor { get; set; }
///
/// Gets the horizontal sampling factor.
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs
index 5fcaa6cea2..49bc105391 100644
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs
@@ -5,10 +5,10 @@ using System;
#if DEBUG
using System.Diagnostics;
#endif
-using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
+
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
@@ -21,6 +21,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
private byte[] markerBuffer;
+ private int mcuToRead;
+
+ private int mcusPerLine;
+
+ private int mcu;
+
private int bitsData;
private int bitsCount;
@@ -60,7 +66,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// The successive approximation bit low end
public void DecodeScan(
PdfJsFrame frame,
- Stream stream,
+ DoubleBufferedStreamReader stream,
PdfJsHuffmanTables dcHuffmanTables,
PdfJsHuffmanTables acHuffmanTables,
PdfJsFrameComponent[] components,
@@ -82,9 +88,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
this.unexpectedMarkerReached = false;
bool progressive = frame.Progressive;
- int mcusPerLine = frame.McusPerLine;
+ this.mcusPerLine = frame.McusPerLine;
- int mcu = 0;
+ this.mcu = 0;
int mcuExpected;
if (componentsLength == 1)
{
@@ -92,51 +98,46 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
}
else
{
- mcuExpected = mcusPerLine * frame.McusPerColumn;
+ mcuExpected = this.mcusPerLine * frame.McusPerColumn;
}
- PdfJsFileMarker fileMarker;
- while (mcu < mcuExpected)
+ while (this.mcu < mcuExpected)
{
// Reset interval stuff
- int mcuToRead = resetInterval != 0 ? Math.Min(mcuExpected - mcu, resetInterval) : mcuExpected;
+ this.mcuToRead = resetInterval != 0 ? Math.Min(mcuExpected - this.mcu, resetInterval) : mcuExpected;
for (int i = 0; i < components.Length; i++)
{
PdfJsFrameComponent c = components[i];
- c.Pred = 0;
+ c.DcPredictor = 0;
}
this.eobrun = 0;
if (!progressive)
{
- this.DecodeScanBaseline(dcHuffmanTables, acHuffmanTables, components, componentsLength, mcusPerLine, mcuToRead, ref mcu, stream);
+ this.DecodeScanBaseline(dcHuffmanTables, acHuffmanTables, components, componentsLength, stream);
}
else
{
bool isAc = this.specStart != 0;
bool isFirst = successivePrev == 0;
PdfJsHuffmanTables huffmanTables = isAc ? acHuffmanTables : dcHuffmanTables;
- this.DecodeScanProgressive(huffmanTables, isAc, isFirst, components, componentsLength, mcusPerLine, mcuToRead, ref mcu, stream);
+ this.DecodeScanProgressive(huffmanTables, isAc, isFirst, components, componentsLength, stream);
}
- // Find marker
+ // Reset
+ // TODO: I do not understand why these values are reset? We should surely be tracking the bits across mcu's?
this.bitsCount = 0;
- fileMarker = PdfJsJpegDecoderCore.FindNextFileMarker(this.markerBuffer, stream);
-
- // Some bad images seem to pad Scan blocks with e.g. zero bytes, skip past
- // those to attempt to find a valid marker (fixes issue4090.pdf) in original code.
- if (fileMarker.Invalid)
- {
-#if DEBUG
- Debug.WriteLine($"DecodeScan - Unexpected MCU data at {stream.Position}, next marker is: {fileMarker.Marker:X}");
-#endif
- }
+ this.bitsData = 0;
+ this.unexpectedMarkerReached = false;
- ushort marker = fileMarker.Marker;
+ // Some images include more scan blocks than expected, skip past those and
+ // attempt to find the next valid marker
+ PdfJsFileMarker fileMarker = PdfJsJpegDecoderCore.FindNextFileMarker(this.markerBuffer, stream);
+ byte marker = fileMarker.Marker;
// RSTn - We've already read the bytes and altered the position so no need to skip
- if (marker >= PdfJsJpegConstants.Markers.RST0 && marker <= PdfJsJpegConstants.Markers.RST7)
+ if (marker >= JpegConstants.Markers.RST0 && marker <= JpegConstants.Markers.RST7)
{
continue;
}
@@ -148,24 +149,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
stream.Position = fileMarker.Position;
break;
}
- }
-
- fileMarker = PdfJsJpegDecoderCore.FindNextFileMarker(this.markerBuffer, stream);
- // Some images include more Scan blocks than expected, skip past those and
- // attempt to find the next valid marker (fixes issue8182.pdf) ref original code.
- if (fileMarker.Invalid)
- {
#if DEBUG
Debug.WriteLine($"DecodeScan - Unexpected MCU data at {stream.Position}, next marker is: {fileMarker.Marker:X}");
#endif
}
- else
- {
- // We've found a valid marker.
- // Rewind the stream to the position of the marker
- stream.Position = fileMarker.Position;
- }
}
private void DecodeScanBaseline(
@@ -173,10 +161,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
PdfJsHuffmanTables acHuffmanTables,
PdfJsFrameComponent[] components,
int componentsLength,
- int mcusPerLine,
- int mcuToRead,
- ref int mcu,
- Stream stream)
+ DoubleBufferedStreamReader stream)
{
if (componentsLength == 1)
{
@@ -185,20 +170,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
- for (int n = 0; n < mcuToRead; n++)
+ for (int n = 0; n < this.mcuToRead; n++)
{
if (this.endOfStreamReached || this.unexpectedMarkerReached)
{
continue;
}
- this.DecodeBlockBaseline(ref dcHuffmanTable, ref acHuffmanTable, component, ref blockDataRef, mcu, stream);
- mcu++;
+ this.DecodeBlockBaseline(ref dcHuffmanTable, ref acHuffmanTable, component, ref blockDataRef, stream);
+ this.mcu++;
}
}
else
{
- for (int n = 0; n < mcuToRead; n++)
+ for (int n = 0; n < this.mcuToRead; n++)
{
for (int i = 0; i < componentsLength; i++)
{
@@ -218,12 +203,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
continue;
}
- this.DecodeMcuBaseline(ref dcHuffmanTable, ref acHuffmanTable, component, ref blockDataRef, mcusPerLine, mcu, j, k, stream);
+ this.DecodeMcuBaseline(ref dcHuffmanTable, ref acHuffmanTable, component, ref blockDataRef, j, k, stream);
}
}
}
- mcu++;
+ this.mcu++;
}
}
}
@@ -234,10 +219,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
bool isFirst,
PdfJsFrameComponent[] components,
int componentsLength,
- int mcusPerLine,
- int mcuToRead,
- ref int mcu,
- Stream stream)
+ DoubleBufferedStreamReader stream)
{
if (componentsLength == 1)
{
@@ -245,7 +227,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(component.SpectralBlocks.Span));
ref PdfJsHuffmanTable huffmanTable = ref huffmanTables[isAC ? component.ACHuffmanTableId : component.DCHuffmanTableId];
- for (int n = 0; n < mcuToRead; n++)
+ for (int n = 0; n < this.mcuToRead; n++)
{
if (this.endOfStreamReached || this.unexpectedMarkerReached)
{
@@ -256,31 +238,31 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
if (isFirst)
{
- this.DecodeBlockACFirst(ref huffmanTable, component, ref blockDataRef, mcu, stream);
+ this.DecodeBlockACFirst(ref huffmanTable, component, ref blockDataRef, stream);
}
else
{
- this.DecodeBlockACSuccessive(ref huffmanTable, component, ref blockDataRef, mcu, stream);
+ this.DecodeBlockACSuccessive(ref huffmanTable, component, ref blockDataRef, stream);
}
}
else
{
if (isFirst)
{
- this.DecodeBlockDCFirst(ref huffmanTable, component, ref blockDataRef, mcu, stream);
+ this.DecodeBlockDCFirst(ref huffmanTable, component, ref blockDataRef, stream);
}
else
{
- this.DecodeBlockDCSuccessive(component, ref blockDataRef, mcu, stream);
+ this.DecodeBlockDCSuccessive(component, ref blockDataRef, stream);
}
}
- mcu++;
+ this.mcu++;
}
}
else
{
- for (int n = 0; n < mcuToRead; n++)
+ for (int n = 0; n < this.mcuToRead; n++)
{
for (int i = 0; i < componentsLength; i++)
{
@@ -294,56 +276,57 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
for (int k = 0; k < h; k++)
{
+ // No need to continue here.
if (this.endOfStreamReached || this.unexpectedMarkerReached)
{
- continue;
+ break;
}
if (isAC)
{
if (isFirst)
{
- this.DecodeMcuACFirst(ref huffmanTable, component, ref blockDataRef, mcusPerLine, mcu, j, k, stream);
+ this.DecodeMcuACFirst(ref huffmanTable, component, ref blockDataRef, j, k, stream);
}
else
{
- this.DecodeMcuACSuccessive(ref huffmanTable, component, ref blockDataRef, mcusPerLine, mcu, j, k, stream);
+ this.DecodeMcuACSuccessive(ref huffmanTable, component, ref blockDataRef, j, k, stream);
}
}
else
{
if (isFirst)
{
- this.DecodeMcuDCFirst(ref huffmanTable, component, ref blockDataRef, mcusPerLine, mcu, j, k, stream);
+ this.DecodeMcuDCFirst(ref huffmanTable, component, ref blockDataRef, j, k, stream);
}
else
{
- this.DecodeMcuDCSuccessive(component, ref blockDataRef, mcusPerLine, mcu, j, k, stream);
+ this.DecodeMcuDCSuccessive(component, ref blockDataRef, j, k, stream);
}
}
}
}
}
- mcu++;
+ this.mcu++;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeBlockBaseline(ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcu, Stream stream)
+ private void DecodeBlockBaseline(ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, DoubleBufferedStreamReader stream)
{
- int blockRow = mcu / component.WidthInBlocks;
- int blockCol = mcu % component.WidthInBlocks;
+ int blockRow = this.mcu / component.WidthInBlocks;
+ int blockCol = this.mcu % component.WidthInBlocks;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeBaseline(component, ref blockDataRef, offset, ref dcHuffmanTable, ref acHuffmanTable, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeMcuBaseline(ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcusPerLine, int mcu, int row, int col, Stream stream)
+ private void DecodeMcuBaseline(ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int row, int col, DoubleBufferedStreamReader stream)
{
- int mcuRow = mcu / mcusPerLine;
- int mcuCol = mcu % mcusPerLine;
+ int mcuRow = this.mcu / this.mcusPerLine;
+ int mcuCol = this.mcu % this.mcusPerLine;
int blockRow = (mcuRow * component.VerticalSamplingFactor) + row;
int blockCol = (mcuCol * component.HorizontalSamplingFactor) + col;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
@@ -351,19 +334,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeBlockDCFirst(ref PdfJsHuffmanTable dcHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcu, Stream stream)
+ private void DecodeBlockDCFirst(ref PdfJsHuffmanTable dcHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, DoubleBufferedStreamReader stream)
{
- int blockRow = mcu / component.WidthInBlocks;
- int blockCol = mcu % component.WidthInBlocks;
+ int blockRow = this.mcu / component.WidthInBlocks;
+ int blockCol = this.mcu % component.WidthInBlocks;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeDCFirst(component, ref blockDataRef, offset, ref dcHuffmanTable, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeMcuDCFirst(ref PdfJsHuffmanTable dcHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcusPerLine, int mcu, int row, int col, Stream stream)
+ private void DecodeMcuDCFirst(ref PdfJsHuffmanTable dcHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int row, int col, DoubleBufferedStreamReader stream)
{
- int mcuRow = mcu / mcusPerLine;
- int mcuCol = mcu % mcusPerLine;
+ int mcuRow = this.mcu / this.mcusPerLine;
+ int mcuCol = this.mcu % this.mcusPerLine;
int blockRow = (mcuRow * component.VerticalSamplingFactor) + row;
int blockCol = (mcuCol * component.HorizontalSamplingFactor) + col;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
@@ -371,19 +354,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeBlockDCSuccessive(PdfJsFrameComponent component, ref short blockDataRef, int mcu, Stream stream)
+ private void DecodeBlockDCSuccessive(PdfJsFrameComponent component, ref short blockDataRef, DoubleBufferedStreamReader stream)
{
- int blockRow = mcu / component.WidthInBlocks;
- int blockCol = mcu % component.WidthInBlocks;
+ int blockRow = this.mcu / component.WidthInBlocks;
+ int blockCol = this.mcu % component.WidthInBlocks;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeDCSuccessive(component, ref blockDataRef, offset, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeMcuDCSuccessive(PdfJsFrameComponent component, ref short blockDataRef, int mcusPerLine, int mcu, int row, int col, Stream stream)
+ private void DecodeMcuDCSuccessive(PdfJsFrameComponent component, ref short blockDataRef, int row, int col, DoubleBufferedStreamReader stream)
{
- int mcuRow = mcu / mcusPerLine;
- int mcuCol = mcu % mcusPerLine;
+ int mcuRow = this.mcu / this.mcusPerLine;
+ int mcuCol = this.mcu % this.mcusPerLine;
int blockRow = (mcuRow * component.VerticalSamplingFactor) + row;
int blockCol = (mcuCol * component.HorizontalSamplingFactor) + col;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
@@ -391,169 +374,257 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeBlockACFirst(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcu, Stream stream)
+ private void DecodeBlockACFirst(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, DoubleBufferedStreamReader stream)
{
- int blockRow = mcu / component.WidthInBlocks;
- int blockCol = mcu % component.WidthInBlocks;
+ int blockRow = this.mcu / component.WidthInBlocks;
+ int blockCol = this.mcu % component.WidthInBlocks;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
- this.DecodeACFirst(component, ref blockDataRef, offset, ref acHuffmanTable, stream);
+ this.DecodeACFirst(ref blockDataRef, offset, ref acHuffmanTable, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeMcuACFirst(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcusPerLine, int mcu, int row, int col, Stream stream)
+ private void DecodeMcuACFirst(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int row, int col, DoubleBufferedStreamReader stream)
{
- int mcuRow = mcu / mcusPerLine;
- int mcuCol = mcu % mcusPerLine;
+ int mcuRow = this.mcu / this.mcusPerLine;
+ int mcuCol = this.mcu % this.mcusPerLine;
int blockRow = (mcuRow * component.VerticalSamplingFactor) + row;
int blockCol = (mcuCol * component.HorizontalSamplingFactor) + col;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
- this.DecodeACFirst(component, ref blockDataRef, offset, ref acHuffmanTable, stream);
+ this.DecodeACFirst(ref blockDataRef, offset, ref acHuffmanTable, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeBlockACSuccessive(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcu, Stream stream)
+ private void DecodeBlockACSuccessive(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, DoubleBufferedStreamReader stream)
{
- int blockRow = mcu / component.WidthInBlocks;
- int blockCol = mcu % component.WidthInBlocks;
+ int blockRow = this.mcu / component.WidthInBlocks;
+ int blockCol = this.mcu % component.WidthInBlocks;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
- this.DecodeACSuccessive(component, ref blockDataRef, offset, ref acHuffmanTable, stream);
+ this.DecodeACSuccessive(ref blockDataRef, offset, ref acHuffmanTable, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeMcuACSuccessive(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcusPerLine, int mcu, int row, int col, Stream stream)
+ private void DecodeMcuACSuccessive(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int row, int col, DoubleBufferedStreamReader stream)
{
- int mcuRow = mcu / mcusPerLine;
- int mcuCol = mcu % mcusPerLine;
+ int mcuRow = this.mcu / this.mcusPerLine;
+ int mcuCol = this.mcu % this.mcusPerLine;
int blockRow = (mcuRow * component.VerticalSamplingFactor) + row;
int blockCol = (mcuCol * component.HorizontalSamplingFactor) + col;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
- this.DecodeACSuccessive(component, ref blockDataRef, offset, ref acHuffmanTable, stream);
+ this.DecodeACSuccessive(ref blockDataRef, offset, ref acHuffmanTable, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private int ReadBit(Stream stream)
+ private bool TryReadBit(DoubleBufferedStreamReader stream, out int bit)
{
- // TODO: I wonder if we can do this two bytes at a time; libjpeg turbo seems to do that?
- if (this.bitsCount > 0)
+ if (this.bitsCount == 0)
{
- this.bitsCount--;
- return (this.bitsData >> this.bitsCount) & 1;
+ if (!this.TryFillBits(stream))
+ {
+ bit = 0;
+ return false;
+ }
}
- this.bitsData = stream.ReadByte();
+ this.bitsCount--;
+ bit = (this.bitsData >> this.bitsCount) & 1;
+ return true;
+ }
- if (this.bitsData == -0x1)
- {
- // We've encountered the end of the file stream which means there's no EOI marker ref the image
- this.endOfStreamReached = true;
- }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private bool TryFillBits(DoubleBufferedStreamReader stream)
+ {
+ // TODO: Read more then 1 byte at a time.
+ // In LibJpegTurbo this is be 25 bits (32-7) but I cannot get this to work
+ // for some images, I'm assuming because I am crossing MCU boundaries and not maintining the correct buffer state.
+ const int MinGetBits = 7;
- if (this.bitsData == PdfJsJpegConstants.Markers.Prefix)
+ if (!this.unexpectedMarkerReached)
{
- int nextByte = stream.ReadByte();
- if (nextByte != 0)
+ // Attempt to load to the minimum bit count.
+ while (this.bitsCount < MinGetBits)
{
+ int c = stream.ReadByte();
+
+ switch (c)
+ {
+ case -0x1:
+
+ // We've encountered the end of the file stream which means there's no EOI marker in the image.
+ this.endOfStreamReached = true;
+ return false;
+
+ case JpegConstants.Markers.XFF:
+ int nextByte = stream.ReadByte();
+
+ if (nextByte == -0x1)
+ {
+ this.endOfStreamReached = true;
+ return false;
+ }
+
+ if (nextByte != 0)
+ {
#if DEBUG
- Debug.WriteLine($"DecodeScan - Unexpected marker {(this.bitsData << 8) | nextByte:X} at {stream.Position}");
+ Debug.WriteLine($"DecodeScan - Unexpected marker {(c << 8) | nextByte:X} at {stream.Position}");
#endif
- // We've encountered an unexpected marker. Reverse the stream and exit.
- this.unexpectedMarkerReached = true;
- stream.Position -= 2;
- }
+ // We've encountered an unexpected marker. Reverse the stream and exit.
+ this.unexpectedMarkerReached = true;
+ stream.Position -= 2;
+
+ // TODO: double check we need this.
+ // Fill buffer with zero bits.
+ if (this.bitsCount == 0)
+ {
+ this.bitsData <<= MinGetBits;
+ this.bitsCount = MinGetBits;
+ }
+
+ return true;
+ }
+
+ break;
+ }
- // Unstuff 0
+ // OK, load the next byte into bitsData
+ this.bitsData = (this.bitsData << 8) | c;
+ this.bitsCount += 8;
+ }
}
- this.bitsCount = 7;
+ return true;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private int PeekBits(int count)
+ {
+ return this.bitsData >> (this.bitsCount - count) & ((1 << count) - 1);
+ }
- return this.bitsData >> 7;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void DropBits(int count)
+ {
+ this.bitsCount -= count;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private short DecodeHuffman(ref PdfJsHuffmanTable tree, Stream stream)
+ private bool TryDecodeHuffman(ref PdfJsHuffmanTable tree, DoubleBufferedStreamReader stream, out short value)
{
+ value = -1;
+
// TODO: Implement fast Huffman decoding.
- // NOTES # During investigation of the libjpeg implementation it appears that they pull 32bits at a time and operate on those bits
- // using 3 methods: FillBits, PeekBits, and ReadBits. We should attempt to do the same.
- short code = (short)this.ReadBit(stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
+ // In LibJpegTurbo a minimum of 25 bits (32-7) is collected from the stream
+ // Then a LUT is used to avoid the loop when decoding the Huffman value.
+ // using 3 methods: FillBits, PeekBits, and DropBits.
+ // The LUT has been ported from LibJpegTurbo as has this code but it doesn't work.
+ // this.TryFillBits(stream);
+ //
+ // const int LookAhead = 8;
+ // int look = this.PeekBits(LookAhead);
+ // look = tree.Lookahead[look];
+ // int bits = look >> LookAhead;
+ //
+ // if (bits <= LookAhead)
+ // {
+ // this.DropBits(bits);
+ // value = (short)(look & ((1 << LookAhead) - 1));
+ // return true;
+ // }
+ if (!this.TryReadBit(stream, out int bit))
{
- return -1;
+ return false;
}
+ short code = (short)bit;
+
// "DECODE", section F.2.2.3, figure F.16, page 109 of T.81
int i = 1;
while (code > tree.MaxCode[i])
{
- code <<= 1;
- code |= (short)this.ReadBit(stream);
-
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
+ if (!this.TryReadBit(stream, out bit))
{
- return -1;
+ return false;
}
+ code <<= 1;
+ code |= (short)bit;
i++;
}
int j = tree.ValOffset[i];
- return tree.HuffVal[(j + code) & 0xFF];
+ value = tree.HuffVal[(j + code) & 0xFF];
+ return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private int Receive(int length, Stream stream)
+ private bool TryReceive(int length, DoubleBufferedStreamReader stream, out int value)
{
- int n = 0;
+ value = 0;
while (length > 0)
{
- int bit = this.ReadBit(stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
+ if (!this.TryReadBit(stream, out int bit))
{
- return -1;
+ return false;
}
- n = (n << 1) | bit;
+ value = (value << 1) | bit;
length--;
}
- return n;
+ return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private int ReceiveAndExtend(int length, Stream stream)
+ private bool TryReceiveAndExtend(int length, DoubleBufferedStreamReader stream, out int value)
{
if (length == 1)
{
- return this.ReadBit(stream) == 1 ? 1 : -1;
- }
+ if (!this.TryReadBit(stream, out value))
+ {
+ return false;
+ }
- int n = this.Receive(length, stream);
- if (n >= 1 << (length - 1))
+ value = value == 1 ? 1 : -1;
+ }
+ else
{
- return n;
+ if (!this.TryReceive(length, stream, out value))
+ {
+ return false;
+ }
+
+ if (value < 1 << (length - 1))
+ {
+ value += (-1 << length) + 1;
+ }
}
- return n + (-1 << length) + 1;
+ return true;
}
- private void DecodeBaseline(PdfJsFrameComponent component, ref short blockDataRef, int offset, ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsHuffmanTable acHuffmanTable, Stream stream)
+ private void DecodeBaseline(PdfJsFrameComponent component, ref short blockDataRef, int offset, ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsHuffmanTable acHuffmanTable, DoubleBufferedStreamReader stream)
{
- short t = this.DecodeHuffman(ref dcHuffmanTable, stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
+ if (!this.TryDecodeHuffman(ref dcHuffmanTable, stream, out short t))
{
return;
}
- int diff = t == 0 ? 0 : this.ReceiveAndExtend(t, stream);
- Unsafe.Add(ref blockDataRef, offset) = (short)(component.Pred += diff);
+ int diff = 0;
+ if (t != 0)
+ {
+ if (!this.TryReceiveAndExtend(t, stream, out diff))
+ {
+ return;
+ }
+ }
+
+ Unsafe.Add(ref blockDataRef, offset) = (short)(component.DcPredictor += diff);
int k = 1;
while (k < 64)
{
- short rs = this.DecodeHuffman(ref acHuffmanTable, stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
+ if (!this.TryDecodeHuffman(ref acHuffmanTable, stream, out short rs))
{
return;
}
@@ -574,36 +645,42 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
k += r;
- if (k > 63)
+ byte z = this.dctZigZag[k];
+
+ if (!this.TryReceiveAndExtend(s, stream, out int re))
{
- break;
+ return;
}
- byte z = this.dctZigZag[k];
- short re = (short)this.ReceiveAndExtend(s, stream);
- Unsafe.Add(ref blockDataRef, offset + z) = re;
+ Unsafe.Add(ref blockDataRef, offset + z) = (short)re;
k++;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeDCFirst(PdfJsFrameComponent component, ref short blockDataRef, int offset, ref PdfJsHuffmanTable dcHuffmanTable, Stream stream)
+ private void DecodeDCFirst(PdfJsFrameComponent component, ref short blockDataRef, int offset, ref PdfJsHuffmanTable dcHuffmanTable, DoubleBufferedStreamReader stream)
{
- short t = this.DecodeHuffman(ref dcHuffmanTable, stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
+ if (!this.TryDecodeHuffman(ref dcHuffmanTable, stream, out short t))
{
return;
}
- int diff = t == 0 ? 0 : this.ReceiveAndExtend(t, stream) << this.successiveState;
- Unsafe.Add(ref blockDataRef, offset) = (short)(component.Pred += diff);
+ int diff = 0;
+ if (t != 0)
+ {
+ if (!this.TryReceiveAndExtend(t, stream, out diff))
+ {
+ return;
+ }
+ }
+
+ Unsafe.Add(ref blockDataRef, offset) = (short)(component.DcPredictor += diff << this.successiveState);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeDCSuccessive(PdfJsFrameComponent component, ref short blockDataRef, int offset, Stream stream)
+ private void DecodeDCSuccessive(PdfJsFrameComponent component, ref short blockDataRef, int offset, DoubleBufferedStreamReader stream)
{
- int bit = this.ReadBit(stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
+ if (!this.TryReadBit(stream, out int bit))
{
return;
}
@@ -611,7 +688,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
Unsafe.Add(ref blockDataRef, offset) |= (short)(bit << this.successiveState);
}
- private void DecodeACFirst(PdfJsFrameComponent component, ref short blockDataRef, int offset, ref PdfJsHuffmanTable acHuffmanTable, Stream stream)
+ private void DecodeACFirst(ref short blockDataRef, int offset, ref PdfJsHuffmanTable acHuffmanTable, DoubleBufferedStreamReader stream)
{
if (this.eobrun > 0)
{
@@ -623,8 +700,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
int e = this.specEnd;
while (k <= e)
{
- short rs = this.DecodeHuffman(ref acHuffmanTable, stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
+ if (!this.TryDecodeHuffman(ref acHuffmanTable, stream, out short rs))
{
return;
}
@@ -636,7 +712,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
if (r < 15)
{
- this.eobrun = this.Receive(r, stream) + (1 << r) - 1;
+ if (!this.TryReceive(r, stream, out int eob))
+ {
+ return;
+ }
+
+ this.eobrun = eob + (1 << r) - 1;
break;
}
@@ -647,12 +728,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
k += r;
byte z = this.dctZigZag[k];
- Unsafe.Add(ref blockDataRef, offset + z) = (short)(this.ReceiveAndExtend(s, stream) * (1 << this.successiveState));
+
+ if (!this.TryReceiveAndExtend(s, stream, out int v))
+ {
+ return;
+ }
+
+ Unsafe.Add(ref blockDataRef, offset + z) = (short)(v * (1 << this.successiveState));
k++;
}
}
- private void DecodeACSuccessive(PdfJsFrameComponent component, ref short blockDataRef, int offset, ref PdfJsHuffmanTable acHuffmanTable, Stream stream)
+ private void DecodeACSuccessive(ref short blockDataRef, int offset, ref PdfJsHuffmanTable acHuffmanTable, DoubleBufferedStreamReader stream)
{
int k = this.specStart;
int e = this.specEnd;
@@ -667,8 +754,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
switch (this.successiveACState)
{
case 0: // Initial state
- short rs = this.DecodeHuffman(ref acHuffmanTable, stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
+
+ if (!this.TryDecodeHuffman(ref acHuffmanTable, stream, out short rs))
{
return;
}
@@ -679,7 +766,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
if (r < 15)
{
- this.eobrun = this.Receive(r, stream) + (1 << r);
+ if (!this.TryReceive(r, stream, out int eob))
+ {
+ return;
+ }
+
+ this.eobrun = eob + (1 << r);
this.successiveACState = 4;
}
else
@@ -695,7 +787,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
throw new ImageFormatException("Invalid ACn encoding");
}
- this.successiveACNextValue = this.ReceiveAndExtend(s, stream);
+ if (!this.TryReceiveAndExtend(s, stream, out int v))
+ {
+ return;
+ }
+
+ this.successiveACNextValue = v;
this.successiveACState = r > 0 ? 2 : 3;
}
@@ -704,8 +801,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
case 2:
if (blockOffsetZRef != 0)
{
- int bit = this.ReadBit(stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
+ if (!this.TryReadBit(stream, out int bit))
{
return;
}
@@ -725,8 +821,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
case 3: // Set value for a zero item
if (blockOffsetZRef != 0)
{
- int bit = this.ReadBit(stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
+ if (!this.TryReadBit(stream, out int bit))
{
return;
}
@@ -743,8 +838,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
case 4: // Eob
if (blockOffsetZRef != 0)
{
- int bit = this.ReadBit(stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
+ if (!this.TryReadBit(stream, out int bit))
{
return;
}
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
index 244d97fba0..3dda253d2b 100644
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
@@ -7,8 +7,9 @@ using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
-using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
+
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData;
@@ -22,7 +23,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
{
///
/// Performs the jpeg decoding operation.
- /// Ported from with additional fixes to handle common encoding errors
+ /// Originally ported from
+ /// with additional fixes for both performance and common encoding errors.
///
internal sealed class PdfJsJpegDecoderCore : IRawJpegData
{
@@ -31,7 +33,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
///
public const int SupportedPrecision = 8;
-#pragma warning disable SA1401 // Fields should be private
///
/// The global configuration
///
@@ -93,15 +94,23 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
///
public PdfJsFrame Frame { get; private set; }
+ ///
+ public Size ImageSizeInPixels { get; private set; }
+
+ ///
+ /// Gets the number of MCU blocks in the image as .
+ ///
+ public Size ImageSizeInMCU { get; private set; }
+
///
/// Gets the image width
///
- public int ImageWidth { get; private set; }
+ public int ImageWidth => this.ImageSizeInPixels.Width;
///
/// Gets the image height
///
- public int ImageHeight { get; private set; }
+ public int ImageHeight => this.ImageSizeInPixels.Height;
///
/// Gets the color depth, in number of bits per pixel.
@@ -111,7 +120,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
///
/// Gets the input stream.
///
- public Stream InputStream { get; private set; }
+ public DoubleBufferedStreamReader InputStream { get; private set; }
///
/// Gets a value indicating whether the metadata should be ignored when the image is being decoded.
@@ -123,17 +132,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
///
public ImageMetaData MetaData { get; private set; }
- ///
- public Size ImageSizeInPixels => new Size(this.ImageWidth, this.ImageHeight);
-
///
public int ComponentCount { get; private set; }
///
public JpegColorSpace ColorSpace { get; private set; }
+ ///
+ /// Gets the components.
+ ///
+ public PdfJsFrameComponent[] Components => this.Frame.Components;
+
///
- public IEnumerable Components => this.Frame.Components;
+ IEnumerable IRawJpegData.Components => this.Components;
///
public Block8x8F[] QuantizationTables { get; private set; }
@@ -144,34 +155,35 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// The buffer to read file markers to
/// The input stream
/// The
- public static PdfJsFileMarker FindNextFileMarker(byte[] marker, Stream stream)
+ public static PdfJsFileMarker FindNextFileMarker(byte[] marker, DoubleBufferedStreamReader stream)
{
int value = stream.Read(marker, 0, 2);
if (value == 0)
{
- return new PdfJsFileMarker(PdfJsJpegConstants.Markers.EOI, stream.Length - 2);
+ return new PdfJsFileMarker(JpegConstants.Markers.EOI, stream.Length - 2);
}
- if (marker[0] == PdfJsJpegConstants.Markers.Prefix)
+ if (marker[0] == JpegConstants.Markers.XFF)
{
// According to Section B.1.1.2:
// "Any marker may optionally be preceded by any number of fill bytes, which are bytes assigned code 0xFF."
- while (marker[1] == PdfJsJpegConstants.Markers.Prefix)
+ int m = marker[1];
+ while (m == JpegConstants.Markers.XFF)
{
int suffix = stream.ReadByte();
if (suffix == -1)
{
- return new PdfJsFileMarker(PdfJsJpegConstants.Markers.EOI, stream.Length - 2);
+ return new PdfJsFileMarker(JpegConstants.Markers.EOI, stream.Length - 2);
}
- marker[1] = (byte)suffix;
+ m = suffix;
}
- return new PdfJsFileMarker(BinaryPrimitives.ReadUInt16BigEndian(marker), stream.Position - 2);
+ return new PdfJsFileMarker((byte)m, stream.Position - 2);
}
- return new PdfJsFileMarker(BinaryPrimitives.ReadUInt16BigEndian(marker), stream.Position - 2, true);
+ return new PdfJsFileMarker(marker[1], stream.Position - 2, true);
}
///
@@ -184,6 +196,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
where TPixel : struct, IPixel
{
this.ParseStream(stream);
+ this.AssignResolution();
return this.PostProcessIntoImage();
}
@@ -206,136 +219,142 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
public void ParseStream(Stream stream, bool metadataOnly = false)
{
this.MetaData = new ImageMetaData();
- this.InputStream = stream;
+ this.InputStream = new DoubleBufferedStreamReader(this.configuration.MemoryManager, stream);
// Check for the Start Of Image marker.
- var fileMarker = new PdfJsFileMarker(this.ReadUint16(), 0);
- if (fileMarker.Marker != PdfJsJpegConstants.Markers.SOI)
+ this.InputStream.Read(this.markerBuffer, 0, 2);
+ var fileMarker = new PdfJsFileMarker(this.markerBuffer[1], 0);
+ if (fileMarker.Marker != JpegConstants.Markers.SOI)
{
throw new ImageFormatException("Missing SOI marker.");
}
- ushort marker = this.ReadUint16();
+ this.InputStream.Read(this.markerBuffer, 0, 2);
+ byte marker = this.markerBuffer[1];
fileMarker = new PdfJsFileMarker(marker, (int)this.InputStream.Position - 2);
- this.QuantizationTables = new Block8x8F[4];
-
- // this.quantizationTables = new PdfJsQuantizationTables(this.configuration.MemoryManager);
- this.dcHuffmanTables = new PdfJsHuffmanTables();
- this.acHuffmanTables = new PdfJsHuffmanTables();
-
- while (fileMarker.Marker != PdfJsJpegConstants.Markers.EOI)
+ // Only assign what we need
+ if (!metadataOnly)
{
- // Get the marker length
- int remaining = this.ReadUint16() - 2;
+ this.QuantizationTables = new Block8x8F[4];
+ this.dcHuffmanTables = new PdfJsHuffmanTables();
+ this.acHuffmanTables = new PdfJsHuffmanTables();
+ }
- switch (fileMarker.Marker)
+ while (fileMarker.Marker != JpegConstants.Markers.EOI)
+ {
+ if (!fileMarker.Invalid)
{
- case PdfJsJpegConstants.Markers.APP0:
- this.ProcessApplicationHeaderMarker(remaining);
- break;
-
- case PdfJsJpegConstants.Markers.APP1:
- this.ProcessApp1Marker(remaining);
- break;
-
- case PdfJsJpegConstants.Markers.APP2:
- this.ProcessApp2Marker(remaining);
- break;
- case PdfJsJpegConstants.Markers.APP3:
- case PdfJsJpegConstants.Markers.APP4:
- case PdfJsJpegConstants.Markers.APP5:
- case PdfJsJpegConstants.Markers.APP6:
- case PdfJsJpegConstants.Markers.APP7:
- case PdfJsJpegConstants.Markers.APP8:
- case PdfJsJpegConstants.Markers.APP9:
- case PdfJsJpegConstants.Markers.APP10:
- case PdfJsJpegConstants.Markers.APP11:
- case PdfJsJpegConstants.Markers.APP12:
- case PdfJsJpegConstants.Markers.APP13:
- this.InputStream.Skip(remaining);
- break;
+ // Get the marker length
+ int remaining = this.ReadUint16() - 2;
- case PdfJsJpegConstants.Markers.APP14:
- this.ProcessApp14Marker(remaining);
- break;
+ switch (fileMarker.Marker)
+ {
+ case JpegConstants.Markers.SOF0:
+ case JpegConstants.Markers.SOF1:
+ case JpegConstants.Markers.SOF2:
+ this.ProcessStartOfFrameMarker(remaining, fileMarker, metadataOnly);
+ break;
+
+ case JpegConstants.Markers.SOS:
+ if (!metadataOnly)
+ {
+ this.ProcessStartOfScanMarker();
+ break;
+ }
+ else
+ {
+ // It's highly unlikely that APPn related data will be found after the SOS marker
+ // We should have gathered everything we need by now.
+ return;
+ }
- case PdfJsJpegConstants.Markers.APP15:
- case PdfJsJpegConstants.Markers.COM:
- this.InputStream.Skip(remaining);
- break;
+ case JpegConstants.Markers.DHT:
+ if (metadataOnly)
+ {
+ this.InputStream.Skip(remaining);
+ }
+ else
+ {
+ this.ProcessDefineHuffmanTablesMarker(remaining);
+ }
- case PdfJsJpegConstants.Markers.DQT:
- if (metadataOnly)
- {
- this.InputStream.Skip(remaining);
- }
- else
- {
- this.ProcessDefineQuantizationTablesMarker(remaining);
- }
+ break;
- break;
+ case JpegConstants.Markers.DQT:
+ if (metadataOnly)
+ {
+ this.InputStream.Skip(remaining);
+ }
+ else
+ {
+ this.ProcessDefineQuantizationTablesMarker(remaining);
+ }
- case PdfJsJpegConstants.Markers.SOF0:
- case PdfJsJpegConstants.Markers.SOF1:
- case PdfJsJpegConstants.Markers.SOF2:
- this.ProcessStartOfFrameMarker(remaining, fileMarker);
- if (metadataOnly && !this.jFif.Equals(default))
- {
- this.InputStream.Skip(remaining);
- }
+ break;
- break;
+ case JpegConstants.Markers.DRI:
+ if (metadataOnly)
+ {
+ this.InputStream.Skip(remaining);
+ }
+ else
+ {
+ this.ProcessDefineRestartIntervalMarker(remaining);
+ }
- case PdfJsJpegConstants.Markers.DHT:
- if (metadataOnly)
- {
+ break;
+
+ case JpegConstants.Markers.APP0:
+ this.ProcessApplicationHeaderMarker(remaining);
+ break;
+
+ case JpegConstants.Markers.APP1:
+ this.ProcessApp1Marker(remaining);
+ break;
+
+ case JpegConstants.Markers.APP2:
+ this.ProcessApp2Marker(remaining);
+ break;
+
+ case JpegConstants.Markers.APP3:
+ case JpegConstants.Markers.APP4:
+ case JpegConstants.Markers.APP5:
+ case JpegConstants.Markers.APP6:
+ case JpegConstants.Markers.APP7:
+ case JpegConstants.Markers.APP8:
+ case JpegConstants.Markers.APP9:
+ case JpegConstants.Markers.APP10:
+ case JpegConstants.Markers.APP11:
+ case JpegConstants.Markers.APP12:
+ case JpegConstants.Markers.APP13:
this.InputStream.Skip(remaining);
- }
- else
- {
- this.ProcessDefineHuffmanTablesMarker(remaining);
- }
+ break;
- break;
+ case JpegConstants.Markers.APP14:
+ this.ProcessApp14Marker(remaining);
+ break;
- case PdfJsJpegConstants.Markers.DRI:
- if (metadataOnly)
- {
+ case JpegConstants.Markers.APP15:
+ case JpegConstants.Markers.COM:
this.InputStream.Skip(remaining);
- }
- else
- {
- this.ProcessDefineRestartIntervalMarker(remaining);
- }
-
- break;
-
- case PdfJsJpegConstants.Markers.SOS:
- if (!metadataOnly)
- {
- this.ProcessStartOfScanMarker();
- }
-
- break;
+ break;
+ }
}
// Read on.
fileMarker = FindNextFileMarker(this.markerBuffer, this.InputStream);
}
-
- this.ImageWidth = this.Frame.SamplesPerLine;
- this.ImageHeight = this.Frame.Scanlines;
- this.ComponentCount = this.Frame.ComponentCount;
}
///
public void Dispose()
{
+ this.InputStream?.Dispose();
this.Frame?.Dispose();
// Set large fields to null.
+ this.InputStream = null;
this.Frame = null;
this.dcHuffmanTables = null;
this.acHuffmanTables = null;
@@ -354,11 +373,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
if (this.ComponentCount == 3)
{
- if (this.adobe.Equals(default) || this.adobe.ColorTransform == PdfJsJpegConstants.Markers.Adobe.ColorTransformYCbCr)
+ if (this.adobe.Equals(default) || this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYCbCr)
{
return JpegColorSpace.YCbCr;
}
- else if (this.adobe.ColorTransform == PdfJsJpegConstants.Markers.Adobe.ColorTransformUnknown)
+
+ if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
{
return JpegColorSpace.RGB;
}
@@ -366,7 +386,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
if (this.ComponentCount == 4)
{
- return this.adobe.ColorTransform == PdfJsJpegConstants.Markers.Adobe.ColorTransformYcck
+ return this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYcck
? JpegColorSpace.Ycck
: JpegColorSpace.Cmyk;
}
@@ -379,7 +399,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
///
private void AssignResolution()
{
- if (this.isExif)
+ if (this.jFif.XDensity > 0 && this.jFif.YDensity > 0)
+ {
+ this.MetaData.HorizontalResolution = this.jFif.XDensity;
+ this.MetaData.VerticalResolution = this.jFif.YDensity;
+ }
+ else if (this.isExif)
{
double horizontalValue = this.MetaData.ExifProfile.TryGetValue(ExifTag.XResolution, out ExifValue horizontalTag)
? ((Rational)horizontalTag.Value).ToDouble()
@@ -395,11 +420,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
this.MetaData.VerticalResolution = verticalValue;
}
}
- else if (this.jFif.XDensity > 0 && this.jFif.YDensity > 0)
- {
- this.MetaData.HorizontalResolution = this.jFif.XDensity;
- this.MetaData.VerticalResolution = this.jFif.YDensity;
- }
}
///
@@ -593,7 +613,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
///
/// The remaining bytes in the segment block.
/// The current frame marker.
- private void ProcessStartOfFrameMarker(int remaining, PdfJsFileMarker frameMarker)
+ /// Whether to parse metadata only
+ private void ProcessStartOfFrameMarker(int remaining, PdfJsFileMarker frameMarker, bool metadataOnly)
{
if (this.Frame != null)
{
@@ -610,49 +631,59 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
this.Frame = new PdfJsFrame
{
- Extended = frameMarker.Marker == PdfJsJpegConstants.Markers.SOF1,
- Progressive = frameMarker.Marker == PdfJsJpegConstants.Markers.SOF2,
+ Extended = frameMarker.Marker == JpegConstants.Markers.SOF1,
+ Progressive = frameMarker.Marker == JpegConstants.Markers.SOF2,
Precision = this.temp[0],
Scanlines = (short)((this.temp[1] << 8) | this.temp[2]),
SamplesPerLine = (short)((this.temp[3] << 8) | this.temp[4]),
ComponentCount = this.temp[5]
};
+ this.ImageSizeInPixels = new Size(this.Frame.SamplesPerLine, this.Frame.Scanlines);
+
int maxH = 0;
int maxV = 0;
int index = 6;
- // No need to pool this. They max out at 4
- this.Frame.ComponentIds = new byte[this.Frame.ComponentCount];
- this.Frame.Components = new PdfJsFrameComponent[this.Frame.ComponentCount];
+ this.ComponentCount = this.Frame.ComponentCount;
- for (int i = 0; i < this.Frame.Components.Length; i++)
+ if (!metadataOnly)
{
- byte hv = this.temp[index + 1];
- int h = hv >> 4;
- int v = hv & 15;
+ // No need to pool this. They max out at 4
+ this.Frame.ComponentIds = new byte[this.Frame.ComponentCount];
+ this.Frame.Components = new PdfJsFrameComponent[this.Frame.ComponentCount];
+ this.ColorSpace = this.DeduceJpegColorSpace();
- if (maxH < h)
+ for (int i = 0; i < this.Frame.ComponentCount; i++)
{
- maxH = h;
- }
+ byte hv = this.temp[index + 1];
+ int h = hv >> 4;
+ int v = hv & 15;
- if (maxV < v)
- {
- maxV = v;
- }
+ if (maxH < h)
+ {
+ maxH = h;
+ }
+
+ if (maxV < v)
+ {
+ maxV = v;
+ }
- var component = new PdfJsFrameComponent(this.configuration.MemoryManager, this.Frame, this.temp[index], h, v, this.temp[index + 2], i);
+ var component = new PdfJsFrameComponent(this.configuration.MemoryManager, this.Frame, this.temp[index], h, v, this.temp[index + 2], i);
- this.Frame.Components[i] = component;
- this.Frame.ComponentIds[i] = component.Id;
+ this.Frame.Components[i] = component;
+ this.Frame.ComponentIds[i] = component.Id;
- index += 3;
- }
+ index += 3;
+ }
- this.Frame.MaxHorizontalFactor = maxH;
- this.Frame.MaxVerticalFactor = maxV;
- this.Frame.InitComponents();
+ this.Frame.MaxHorizontalFactor = maxH;
+ this.Frame.MaxVerticalFactor = maxV;
+ this.ColorSpace = this.DeduceJpegColorSpace();
+ this.Frame.InitComponents();
+ this.ImageSizeInMCU = new Size(this.Frame.McusPerLine, this.Frame.McusPerColumn);
+ }
}
///
@@ -798,8 +829,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
private Image PostProcessIntoImage()
where TPixel : struct, IPixel
{
- this.ColorSpace = this.DeduceJpegColorSpace();
- this.AssignResolution();
using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryManager, this))
{
var image = new Image(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData);
diff --git a/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs b/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs
index 0164ceafaa..97e16ef233 100644
--- a/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs
+++ b/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs
@@ -3,7 +3,6 @@
using System;
using System.Runtime.CompilerServices;
-using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Png.Filters
{
@@ -20,12 +19,12 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
/// The scanline to encode
/// The filtered scanline result.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void Encode(Span scanline, Span result)
+ public static void Encode(ReadOnlySpan scanline, Span result)
{
// Insert a byte before the data.
result[0] = 0;
result = result.Slice(1);
- SpanHelper.Copy(scanline, result);
+ scanline.Slice(0, Math.Min(scanline.Length, result.Length)).CopyTo(result);
}
}
-}
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index 8fefcb480c..cc98b8450b 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -853,7 +853,7 @@ namespace SixLabors.ImageSharp.Formats.Png
where TPixel : struct, IPixel
{
ReadOnlySpan newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth);
- byte[] pal = this.palette;
+ ReadOnlySpan pal = MemoryMarshal.Cast(this.palette);
var color = default(TPixel);
var rgba = default(Rgba32);
@@ -865,10 +865,9 @@ namespace SixLabors.ImageSharp.Formats.Png
for (int x = 0; x < this.header.Width; x++)
{
int index = newScanline[x];
- int pixelOffset = index * 3;
rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255;
- rgba.Rgb = pal.GetRgb24(pixelOffset);
+ rgba.Rgb = pal[index];
color.PackFromRgba32(rgba);
row[x] = color;
@@ -881,9 +880,8 @@ namespace SixLabors.ImageSharp.Formats.Png
for (int x = 0; x < this.header.Width; x++)
{
int index = newScanline[x];
- int pixelOffset = index * 3;
- rgba.Rgb = pal.GetRgb24(pixelOffset);
+ rgba.Rgb = pal[index];
color.PackFromRgba32(rgba);
row[x] = color;
@@ -946,6 +944,7 @@ namespace SixLabors.ImageSharp.Formats.Png
ReadOnlySpan newScanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth);
var rgba = default(Rgba32);
+ Span pal = MemoryMarshal.Cast(this.palette);
if (this.paletteAlpha != null && this.paletteAlpha.Length > 0)
{
@@ -954,10 +953,9 @@ namespace SixLabors.ImageSharp.Formats.Png
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++)
{
int index = newScanline[o];
- int offset = index * 3;
rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255;
- rgba.Rgb = this.palette.GetRgb24(offset);
+ rgba.Rgb = pal[index];
color.PackFromRgba32(rgba);
rowSpan[x] = color;
@@ -970,10 +968,8 @@ namespace SixLabors.ImageSharp.Formats.Png
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++)
{
int index = newScanline[o];
- int offset = index * 3;
-
- rgba.Rgb = this.palette.GetRgb24(offset);
+ rgba.Rgb = pal[index];
color.PackFromRgba32(rgba);
rowSpan[x] = color;
}
diff --git a/src/ImageSharp/Image.LoadPixelData.cs b/src/ImageSharp/Image.LoadPixelData.cs
index 0179e62acc..282f980865 100644
--- a/src/ImageSharp/Image.LoadPixelData.cs
+++ b/src/ImageSharp/Image.LoadPixelData.cs
@@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp
/// The height of the final image.
/// The pixel format.
/// A new .
- private static Image LoadPixelData(Span data, int width, int height)
+ public static Image LoadPixelData(ReadOnlySpan data, int width, int height)
where TPixel : struct, IPixel
=> LoadPixelData(Configuration.Default, data, width, height);
@@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp
/// The height of the final image.
/// The pixel format.
/// A new .
- private static Image LoadPixelData(Span data, int width, int height)
+ public static Image LoadPixelData(ReadOnlySpan data, int width, int height)
where TPixel : struct, IPixel
=> LoadPixelData(Configuration.Default, data, width, height);
@@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp
/// A new .
public static Image LoadPixelData(Configuration config, byte[] data, int width, int height)
where TPixel : struct, IPixel
- => LoadPixelData(config, MemoryMarshal.Cast(data.AsSpan()), width, height);
+ => LoadPixelData(config, MemoryMarshal.Cast(new ReadOnlySpan(data)), width, height);
///
/// Create a new instance of the class from the given byte array in format.
@@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp
/// The height of the final image.
/// The pixel format.
/// A new .
- private static Image LoadPixelData(Configuration config, Span data, int width, int height)
+ public static Image LoadPixelData(Configuration config, ReadOnlySpan data, int width, int height)
where TPixel : struct, IPixel
=> LoadPixelData(config, MemoryMarshal.Cast(data), width, height);
@@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp
public static Image LoadPixelData(Configuration config, TPixel[] data, int width, int height)
where TPixel : struct, IPixel
{
- return LoadPixelData(config, data.AsSpan(), width, height);
+ return LoadPixelData(config, new ReadOnlySpan(data), width, height);
}
///
@@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp
/// The height of the final image.
/// The pixel format.
/// A new .
- private static Image LoadPixelData(Configuration config, Span data, int width, int height)
+ public static Image LoadPixelData(Configuration config, ReadOnlySpan data, int width, int height)
where TPixel : struct, IPixel
{
int count = width * height;
diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs
index 2cdb71fc0e..d8cda2f8fc 100644
--- a/src/ImageSharp/ImageExtensions.cs
+++ b/src/ImageSharp/ImageExtensions.cs
@@ -4,13 +4,11 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.PixelFormats;
-using SixLabors.Primitives;
namespace SixLabors.ImageSharp
{
@@ -21,18 +19,18 @@ namespace SixLabors.ImageSharp
{
#if !NETSTANDARD1_1
///
- /// Saves the image to the given stream using the currently loaded image format.
+ /// Writes the image to the given stream using the currently loaded image format.
///
- /// The Pixel format.
- /// The source image
+ /// The pixel format.
+ /// The source image.
/// The file path to save the image to.
/// Thrown if the stream is null.
public static void Save(this Image source, string filePath)
where TPixel : struct, IPixel
{
- Guard.NotNullOrEmpty(filePath, nameof(filePath));
+ Guard.NotNullOrWhiteSpace(filePath, nameof(filePath));
- string ext = Path.GetExtension(filePath).Trim('.');
+ string ext = Path.GetExtension(filePath);
IImageFormat format = source.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext);
if (format == null)
{
@@ -64,13 +62,13 @@ namespace SixLabors.ImageSharp
}
///
- /// Saves the image to the given stream using the currently loaded image format.
+ /// Writes the image to the given stream using the currently loaded image format.
///
- /// The Pixel format.
- /// The source image
+ /// The pixel format.
+ /// The source image.
/// The file path to save the image to.
/// The encoder to save the image with.
- /// Thrown if the encoder is null.
+ /// Thrown if the encoder is null.
public static void Save(this Image source, string filePath, IImageEncoder encoder)
where TPixel : struct, IPixel
{
@@ -83,13 +81,13 @@ namespace SixLabors.ImageSharp
#endif
///
- /// Saves the image to the given stream using the currently loaded image format.
+ /// Writes the image to the given stream using the currently loaded image format.
///
/// The Pixel format.
- /// The source image
+ /// The source image.
/// The stream to save the image to.
- /// The format to save the image to.
- /// Thrown if the stream is null.
+ /// The format to save the image in.
+ /// Thrown if the stream is null.
public static void Save(this Image source, Stream stream, IImageFormat format)
where TPixel : struct, IPixel
{
@@ -113,67 +111,67 @@ namespace SixLabors.ImageSharp
}
///
- /// Saves the raw image pixels to a byte array in row-major order.
+ /// Returns the a copy of the image pixels as a byte array in row-major order.
///
- /// The Pixel format.
+ /// The pixel format.
/// The source image
/// A copy of the pixel data as bytes from this frame.
- /// Thrown if the stream is null.
+ /// Thrown if the stream is null.
public static byte[] SavePixelData(this ImageFrame source)
where TPixel : struct, IPixel
=> MemoryMarshal.AsBytes(source.GetPixelSpan()).ToArray();
///
- /// Saves the raw image pixels to the given byte array in row-major order.
+ /// Writes the raw image pixels to the given byte array in row-major order.
///
- /// The Pixel format.
- /// The source image
+ /// The pixel format.
+ /// The source image.
/// The buffer to save the raw pixel data to.
- /// Thrown if the stream is null.
+ /// Thrown if the stream is null.
public static void SavePixelData(this ImageFrame source, byte[] buffer)
where TPixel : struct, IPixel
=> SavePixelData(source, MemoryMarshal.Cast(buffer.AsSpan()));
///
- /// Saves the raw image pixels to the given TPixel array in row-major order.
+ /// Writes the raw image pixels to the given TPixel array in row-major order.
///
- /// The Pixel format.
+ /// The pixel format.
/// The source image
/// The buffer to save the raw pixel data to.
- /// Thrown if the stream is null.
+ /// Thrown if the stream is null.
public static void SavePixelData(this ImageFrame source, TPixel[] buffer)
where TPixel : struct, IPixel
=> SavePixelData(source, buffer.AsSpan());
///
- /// Saves the raw image pixels to a byte array in row-major order.
+ /// Returns a copy of the raw image pixels as a byte array in row-major order.
///
- /// The Pixel format.
- /// The source image
+ /// The pixel format.
+ /// The source image.
/// A copy of the pixel data from the first frame as bytes.
- /// Thrown if the stream is null.
+ /// Thrown if the stream is null.
public static byte[] SavePixelData(this Image source)
where TPixel : struct, IPixel
=> source.Frames.RootFrame.SavePixelData();
///
- /// Saves the raw image pixels to the given byte array in row-major order.
+ /// Writes the raw image pixels to the given byte array in row-major order.
///
- /// The Pixel format.
- /// The source image
+ /// The pixel format.
+ /// The source image.
/// The buffer to save the raw pixel data to.
- /// Thrown if the stream is null.
+ /// Thrown if the stream is null.
public static void SavePixelData(this Image source, byte[] buffer)
where TPixel : struct, IPixel
=> source.Frames.RootFrame.SavePixelData(buffer);
///
- /// Saves the raw image pixels to the given TPixel array in row-major order.
+ /// Writes the raw image pixels to the given TPixel array in row-major order.
///
- /// The Pixel format.
+ /// The pixel format.
/// The source image
/// The buffer to save the raw pixel data to.
- /// Thrown if the stream is null.
+ /// Thrown if the stream is null.
public static void SavePixelData(this Image source, TPixel[] buffer)
where TPixel : struct, IPixel
=> source.Frames.RootFrame.SavePixelData(buffer);
@@ -182,7 +180,7 @@ namespace SixLabors.ImageSharp
/// Returns a Base64 encoded string from the given image.
///
///
- /// The Pixel format.
+ /// The pixel format.
/// The source image
/// The format.
/// The
@@ -198,24 +196,24 @@ namespace SixLabors.ImageSharp
}
///
- /// Saves the raw image to the given bytes.
+ /// Writes the raw image bytes to the given byte span.
///
- /// The Pixel format.
+ /// The pixel format.
/// The source image
- /// The buffer to save the raw pixel data to.
+ /// The span to save the raw pixel data to.
/// Thrown if the stream is null.
- internal static void SavePixelData(this Image source, Span buffer)
+ public static void SavePixelData(this Image source, Span buffer)
where TPixel : struct, IPixel
=> source.Frames.RootFrame.SavePixelData(MemoryMarshal.Cast(buffer));
///
- /// Saves the raw image to the given bytes.
+ /// Writes the raw image pixels to the given TPixel span.
///
- /// The Pixel format.
+ /// The pixel format.
/// The source image
- /// The buffer to save the raw pixel data to.
+ /// The span to save the raw pixel data to.
/// Thrown if the stream is null.
- internal static void SavePixelData(this ImageFrame source, Span buffer)
+ public static void SavePixelData(this ImageFrame source, Span buffer)
where TPixel : struct, IPixel
{
Span sourceBuffer = source.GetPixelSpan();
@@ -224,4 +222,4 @@ namespace SixLabors.ImageSharp
sourceBuffer.CopyTo(buffer);
}
}
-}
+}
\ No newline at end of file
diff --git a/src/ImageSharp/ImageFrame.LoadPixelData.cs b/src/ImageSharp/ImageFrame.LoadPixelData.cs
index 1306c28367..4639a104b1 100644
--- a/src/ImageSharp/ImageFrame.LoadPixelData.cs
+++ b/src/ImageSharp/ImageFrame.LoadPixelData.cs
@@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp
/// The height of the final image.
/// The pixel format.
/// A new .
- public static ImageFrame LoadPixelData(MemoryManager memoryManager, Span data, int width, int height)
+ public static ImageFrame LoadPixelData(MemoryManager memoryManager, ReadOnlySpan data, int width, int height)
where TPixel : struct, IPixel
=> LoadPixelData(memoryManager, MemoryMarshal.Cast(data), width, height);
@@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp
/// The height of the final image.
/// The pixel format.
/// A new .
- public static ImageFrame LoadPixelData(MemoryManager memoryManager, Span data, int width, int height)
+ public static ImageFrame LoadPixelData(MemoryManager memoryManager, ReadOnlySpan data, int width, int height)
where TPixel : struct, IPixel
{
int count = width * height;
diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs
index 0318a7068d..be15a6527c 100644
--- a/src/ImageSharp/ImageFrameCollection.cs
+++ b/src/ImageSharp/ImageFrameCollection.cs
@@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp
internal ImageFrameCollection(Image parent, IEnumerable> frames)
{
Guard.NotNull(parent, nameof(parent));
- Guard.NotNullOrEmpty(frames, nameof(frames));
+ Guard.NotNull(frames, nameof(frames));
this.parent = parent;
@@ -42,6 +42,12 @@ namespace SixLabors.ImageSharp
this.ValidateFrame(f);
this.frames.Add(f);
}
+
+ // Ensure at least 1 frame was added to the frames collection
+ if (this.frames.Count == 0)
+ {
+ throw new ArgumentException("Must not be empty.", nameof(frames));
+ }
}
///
@@ -111,7 +117,7 @@ namespace SixLabors.ImageSharp
var frame = ImageFrame.LoadPixelData(
this.parent.GetMemoryManager(),
- new Span(source),
+ new ReadOnlySpan(source),
this.RootFrame.Width,
this.RootFrame.Height);
this.frames.Add(frame);
diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj
index 63b1f61708..0c793d4bc3 100644
--- a/src/ImageSharp/ImageSharp.csproj
+++ b/src/ImageSharp/ImageSharp.csproj
@@ -41,8 +41,8 @@
All
-
-
+
+
@@ -57,11 +57,11 @@
true
-
+
TextTemplatingFileGenerator
Block8x8F.Generated.cs
-
+
TextTemplatingFileGenerator
GenericBlock8x8.Generated.cs
@@ -87,12 +87,12 @@
-
+
True
True
Block8x8F.Generated.tt
-
+
True
True
GenericBlock8x8.Generated.tt
@@ -123,4 +123,7 @@
PorterDuffFunctions.Generated.tt
+
+
+
\ No newline at end of file
diff --git a/src/ImageSharp/Memory/SpanHelper.cs b/src/ImageSharp/Memory/SpanHelper.cs
deleted file mode 100644
index 592e2a885b..0000000000
--- a/src/ImageSharp/Memory/SpanHelper.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Runtime.CompilerServices;
-
-namespace SixLabors.ImageSharp.Memory
-{
- ///
- /// Utility methods for
- ///
- internal static class SpanHelper
- {
- ///
- /// Copy all elements of 'source' into 'destination'.
- ///
- /// The element type.
- /// The to copy elements from.
- /// The destination .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void Copy(ReadOnlySpan source, Span destination)
- where T : struct
- {
- source.Slice(0, Math.Min(source.Length, destination.Length)).CopyTo(destination);
- }
-
- ///
- /// Gets the size of `count` elements in bytes.
- ///
- /// The element type.
- /// The count of the elements
- /// The size in bytes as int
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int SizeOf(int count)
- where T : struct => Unsafe.SizeOf() * count;
-
- ///
- /// Gets the size of `count` elements in bytes as UInt32
- ///
- /// The element type.
- /// The count of the elements
- /// The size in bytes as UInt32
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static uint USizeOf(int count)
- where T : struct
- => (uint)SizeOf(count);
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/MetaData/ImageProperty.cs b/src/ImageSharp/MetaData/ImageProperty.cs
index c67c1f3cf9..3e0cccd422 100644
--- a/src/ImageSharp/MetaData/ImageProperty.cs
+++ b/src/ImageSharp/MetaData/ImageProperty.cs
@@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.MetaData
/// The value of the property.
public ImageProperty(string name, string value)
{
- Guard.NotNullOrEmpty(name, nameof(name));
+ Guard.NotNullOrWhiteSpace(name, nameof(name));
this.Name = name;
this.Value = value;
diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs
index c00eec6010..4f28449d64 100644
--- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs
+++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs
@@ -387,7 +387,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
value = this.ConvertValue(dataType, offsetBuffer, numberOfComponents);
}
- exifValue = new ExifValue(tag, dataType, value, isArray: value != null && numberOfComponents > 1);
+ exifValue = new ExifValue(tag, dataType, value, isArray: value != null && numberOfComponents != 1);
return true;
}
diff --git a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs
index 184928d0e4..c2c0277f9e 100644
--- a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs
+++ b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Buffers.Binary;
using System.Globalization;
namespace SixLabors.ImageSharp.PixelFormats
@@ -23,21 +24,17 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Returns a that represents the color defined by the provided RGBA heax string.
public static TPixel FromHex(string hex)
{
- Guard.NotNullOrEmpty(hex, nameof(hex));
+ Guard.NotNullOrWhiteSpace(hex, nameof(hex));
hex = ToRgbaHex(hex);
- uint packedValue;
- if (hex == null || !uint.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out packedValue))
+
+ if (hex == null || !uint.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint packedValue))
{
throw new ArgumentException("Hexadecimal string is not in the correct format.", nameof(hex));
}
TPixel result = default;
- var rgba = new Rgba32(
- (byte)(packedValue >> 24),
- (byte)(packedValue >> 16),
- (byte)(packedValue >> 8),
- (byte)(packedValue >> 0));
+ var rgba = new Rgba32(BinaryPrimitives.ReverseEndianness(packedValue));
result.PackFromRgba32(rgba);
return result;
@@ -76,7 +73,10 @@ namespace SixLabors.ImageSharp.PixelFormats
///
private static string ToRgbaHex(string hex)
{
- hex = hex.StartsWith("#") ? hex.Substring(1) : hex;
+ if (hex[0] == '#')
+ {
+ hex = hex.Substring(1);
+ }
if (hex.Length == 8)
{
@@ -93,12 +93,12 @@ namespace SixLabors.ImageSharp.PixelFormats
return null;
}
- string red = char.ToString(hex[0]);
- string green = char.ToString(hex[1]);
- string blue = char.ToString(hex[2]);
- string alpha = hex.Length == 3 ? "F" : char.ToString(hex[3]);
+ char r = hex[0];
+ char g = hex[1];
+ char b = hex[2];
+ char a = hex.Length == 3 ? 'F' : hex[3];
- return string.Concat(red, red, green, green, blue, blue, alpha, alpha);
+ return new string(new[] { r, r, g, g, b, b, a, a });
}
}
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs
index 47325476cf..f86919dd15 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs
@@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
using (var memoryStream = new MemoryStream(this.jpegBytes))
{
- using (var image = Image.Load(memoryStream, new OrigJpegDecoder()))
+ using (var image = Image.Load(memoryStream, new GolangJpegDecoder()))
{
return new CoreSize(image.Width, image.Height);
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs
index a1083e8ebf..c4ee732f5e 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs
@@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
[Benchmark(Description = "DecodeJpegMultiple - ImageSharp")]
public void DecodeJpegImageSharpOrig()
{
- this.ForEachStream(ms => Image.Load(ms, new OrigJpegDecoder()));
+ this.ForEachStream(ms => Image.Load(ms, new GolangJpegDecoder()));
}
[Benchmark(Description = "DecodeJpegMultiple - ImageSharp PDFJs")]
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DoubleBufferedStreams.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DoubleBufferedStreams.cs
new file mode 100644
index 0000000000..1d76d58a51
--- /dev/null
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DoubleBufferedStreams.cs
@@ -0,0 +1,114 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.IO;
+using BenchmarkDotNet.Attributes;
+using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components;
+
+namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
+{
+ [Config(typeof(Config.ShortClr))]
+ public class DoubleBufferedStreams
+ {
+ private byte[] buffer = CreateTestBytes();
+ private byte[] chunk1 = new byte[2];
+ private byte[] chunk2 = new byte[2];
+
+ private MemoryStream stream1;
+ private MemoryStream stream2;
+ private MemoryStream stream3;
+ private MemoryStream stream4;
+ DoubleBufferedStreamReader reader1;
+ DoubleBufferedStreamReader reader2;
+
+ [GlobalSetup]
+ public void CreateStreams()
+ {
+ this.stream1 = new MemoryStream(this.buffer);
+ this.stream2 = new MemoryStream(this.buffer);
+ this.stream3 = new MemoryStream(this.buffer);
+ this.stream4 = new MemoryStream(this.buffer);
+ this.reader1 = new DoubleBufferedStreamReader(Configuration.Default.MemoryManager, this.stream2);
+ this.reader2 = new DoubleBufferedStreamReader(Configuration.Default.MemoryManager, this.stream2);
+ }
+
+ [GlobalCleanup]
+ public void DestroyStreams()
+ {
+ this.stream1?.Dispose();
+ this.stream2?.Dispose();
+ this.stream3?.Dispose();
+ this.stream4?.Dispose();
+ this.reader1?.Dispose();
+ this.reader2?.Dispose();
+ }
+
+ [Benchmark(Baseline = true)]
+ public int StandardStreamReadByte()
+ {
+ int r = 0;
+ Stream stream = this.stream1;
+
+ for (int i = 0; i < stream.Length; i++)
+ {
+ r += stream.ReadByte();
+ }
+
+ return r;
+ }
+
+ [Benchmark]
+ public int StandardStreamRead()
+ {
+ int r = 0;
+ Stream stream = this.stream1;
+ byte[] b = this.chunk1;
+
+ for (int i = 0; i < stream.Length / 2; i++)
+ {
+ r += stream.Read(b, 0, 2);
+ }
+
+ return r;
+ }
+
+ [Benchmark]
+ public int DoubleBufferedStreamReadByte()
+ {
+ int r = 0;
+ DoubleBufferedStreamReader reader = this.reader1;
+
+ for (int i = 0; i < reader.Length; i++)
+ {
+ r += reader.ReadByte();
+ }
+
+ return r;
+ }
+
+ [Benchmark]
+ public int DoubleBufferedStreamRead()
+ {
+ int r = 0;
+ DoubleBufferedStreamReader reader = this.reader2;
+ byte[] b = this.chunk2;
+
+ for (int i = 0; i < reader.Length / 2; i++)
+ {
+ r += reader.Read(b, 0, 2);
+ }
+
+ return r;
+ }
+
+ private static byte[] CreateTestBytes()
+ {
+ byte[] buffer = new byte[DoubleBufferedStreamReader.ChunkLength * 3];
+ var random = new Random();
+ random.NextBytes(buffer);
+
+ return buffer;
+ }
+ }
+}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs
new file mode 100644
index 0000000000..b6ad20d128
--- /dev/null
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs
@@ -0,0 +1,52 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+using BenchmarkDotNet.Attributes;
+using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
+using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort;
+using SixLabors.ImageSharp.Tests;
+
+namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
+{
+ [Config(typeof(Config.ShortClr))]
+ public class IdentifyJpeg
+ {
+ private byte[] jpegBytes;
+
+ private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
+
+ [Params(TestImages.Jpeg.Baseline.Jpeg420Exif, TestImages.Jpeg.Baseline.Calliphora)]
+ public string TestImage { get; set; }
+
+ [GlobalSetup]
+ public void ReadImages()
+ {
+ if (this.jpegBytes == null)
+ {
+ this.jpegBytes = File.ReadAllBytes(this.TestImageFullPath);
+ }
+ }
+
+ [Benchmark]
+ public IImageInfo IdentifyGolang()
+ {
+ using (var memoryStream = new MemoryStream(this.jpegBytes))
+ {
+ var decoder = new GolangJpegDecoder();
+
+ return decoder.Identify(Configuration.Default, memoryStream);
+ }
+ }
+
+ [Benchmark]
+ public IImageInfo IdentifyPdfJs()
+ {
+ using (var memoryStream = new MemoryStream(this.jpegBytes))
+ {
+ var decoder = new PdfJsJpegDecoder();
+ return decoder.Identify(Configuration.Default, memoryStream);
+ }
+ }
+ }
+}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs
index 5f902ff64d..ef0d55765a 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs
@@ -1,14 +1,14 @@
-namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters;
+
+namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
using System;
using System.Numerics;
using BenchmarkDotNet.Attributes;
- using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
- using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters;
using SixLabors.ImageSharp.Memory;
-
+
[Config(typeof(Config.ShortClr))]
public class YCbCrColorConversion
{
@@ -57,7 +57,7 @@
JpegColorConverter.FromYCbCrSimdAvx2.ConvertCore(values, this.output);
}
-
+
private static Buffer2D[] CreateRandomValues(
int componentCount,
int inputBufferLength,
@@ -81,6 +81,6 @@
return buffers;
}
-
+
}
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs b/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs
index c4a77acc26..07ae17d754 100644
--- a/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs
+++ b/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs
@@ -1,13 +1,12 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using System;
-using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
+
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Benchmarks
{
@@ -104,14 +103,14 @@ namespace SixLabors.ImageSharp.Benchmarks
}
}
}
-
+
public struct Result
{
internal Block8x8F Y;
internal Block8x8F Cb;
internal Block8x8F Cr;
}
-
+
// The operation is defined as "RGBA -> YCbCr Transform a stream of bytes into a stream of floats"
// We need to benchmark the whole operation, to get true results, not missing any side effects!
private byte[] inputSourceRGB = null;
@@ -200,11 +199,11 @@ namespace SixLabors.ImageSharp.Benchmarks
float* cbPtr = (float*)&result.Cb;
float* crPtr = (float*)&result.Cr;
// end of code-bloat block :)
-
+
Vector yCoeffs = new Vector(ScaledCoeffs.Y);
Vector cbCoeffs = new Vector(ScaledCoeffs.Cb);
Vector crCoeffs = new Vector(ScaledCoeffs.Cr);
-
+
for (int i = 0; i < this.inputSourceRGB.Length; i++)
{
this.inputSourceRGBAsInteger[i] = this.inputSourceRGB[i];
@@ -217,7 +216,7 @@ namespace SixLabors.ImageSharp.Benchmarks
Vector y = yCoeffs * rgb;
Vector cb = cbCoeffs * rgb;
Vector cr = crCoeffs * rgb;
-
+
*yPtr++ = (y[0] + y[1] + y[2]) >> 10;
*cbPtr++ = 128 + ((cb[0] - cb[1] + cb[2]) >> 10);
*crPtr++ = 128 + ((cr[0] - cr[1] - cr[2]) >> 10);
@@ -335,7 +334,7 @@ namespace SixLabors.ImageSharp.Benchmarks
*crPtr++ = 128 + ((cr0 - cr1 - cr2) >> 10);
}
}
-
+
[Benchmark(Description = "Scaled Integer LUT Conversion")]
public unsafe void RgbaToYcbCrScaledIntegerLut()
{
diff --git a/tests/ImageSharp.Benchmarks/General/Block8x8F_DivideRound.cs b/tests/ImageSharp.Benchmarks/General/Block8x8F_DivideRound.cs
index bad87cc11a..fcc5f9a592 100644
--- a/tests/ImageSharp.Benchmarks/General/Block8x8F_DivideRound.cs
+++ b/tests/ImageSharp.Benchmarks/General/Block8x8F_DivideRound.cs
@@ -5,7 +5,9 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
+
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
+
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.General
diff --git a/tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs b/tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs
index d101bf0509..200af64c25 100644
--- a/tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs
+++ b/tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs
@@ -6,8 +6,7 @@ using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
-using SixLabors.ImageSharp;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Benchmarks.General
{
diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
index 6a723f9281..9dbd680efd 100644
--- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
+++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
@@ -18,9 +18,7 @@
-
-
-
+
diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj
index 3cbe2071db..266b905a04 100644
--- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj
+++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj
@@ -21,7 +21,6 @@
-
@@ -33,7 +32,4 @@
-
-
-
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs
index 88aabfe337..d870b7bf78 100644
--- a/tests/ImageSharp.Tests/ConfigurationTests.cs
+++ b/tests/ImageSharp.Tests/ConfigurationTests.cs
@@ -1,95 +1,95 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using SixLabors.ImageSharp.Formats;
-using SixLabors.ImageSharp.IO;
-using SixLabors.ImageSharp.PixelFormats;
-using Moq;
-using Xunit;
-
-namespace SixLabors.ImageSharp.Tests
-{
- ///
- /// Tests the configuration class.
- ///
- public class ConfigurationTests
- {
- public Configuration ConfigurationEmpty { get; private set; }
- public Configuration DefaultConfiguration { get; private set; }
-
- public ConfigurationTests()
- {
- // the shallow copy of configuration should behave exactly like the default configuration,
- // so by using the copy, we test both the default and the copy.
- this.DefaultConfiguration = Configuration.CreateDefaultInstance().ShallowCopy();
- this.ConfigurationEmpty = new Configuration();
- }
-
- [Fact]
- public void DefaultsToLocalFileSystem()
- {
- Assert.IsType(this.DefaultConfiguration.FileSystem);
- Assert.IsType(this.ConfigurationEmpty.FileSystem);
- }
-
- ///
- /// Test that the default configuration is not null.
- ///
- [Fact]
- public void TestDefultConfigurationIsNotNull()
- {
- Assert.True(Configuration.Default != null);
- }
-
- ///
- /// Test that the default configuration parallel options is not null.
- ///
- [Fact]
- public void TestDefultConfigurationParallelOptionsIsNotNull()
- {
- Assert.True(Configuration.Default.ParallelOptions != null);
- }
-
- ///
- /// Test that the default configuration read origin options is set to begin.
- ///
- [Fact]
- public void TestDefultConfigurationReadOriginIsCurrent()
- {
- Assert.True(Configuration.Default.ReadOrigin == ReadOrigin.Current);
- }
-
- ///
- /// Test that the default configuration parallel options max degrees of parallelism matches the
- /// environment processor count.
- ///
- [Fact]
- public void TestDefultConfigurationMaxDegreeOfParallelism()
- {
- Assert.True(Configuration.Default.ParallelOptions.MaxDegreeOfParallelism == Environment.ProcessorCount);
- }
-
- [Fact]
- public void ConstructorCallConfigureOnFormatProvider()
- {
- var provider = new Mock();
- var config = new Configuration(provider.Object);
-
- provider.Verify(x => x.Configure(config));
- }
-
- [Fact]
- public void AddFormatCallsConfig()
- {
- var provider = new Mock();
- var config = new Configuration();
- config.Configure(provider.Object);
-
- provider.Verify(x => x.Configure(config));
- }
- }
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using SixLabors.ImageSharp.Formats;
+using SixLabors.ImageSharp.IO;
+using SixLabors.ImageSharp.PixelFormats;
+using Moq;
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests
+{
+ ///
+ /// Tests the configuration class.
+ ///
+ public class ConfigurationTests
+ {
+ public Configuration ConfigurationEmpty { get; private set; }
+ public Configuration DefaultConfiguration { get; private set; }
+
+ public ConfigurationTests()
+ {
+ // the shallow copy of configuration should behave exactly like the default configuration,
+ // so by using the copy, we test both the default and the copy.
+ this.DefaultConfiguration = Configuration.CreateDefaultInstance().ShallowCopy();
+ this.ConfigurationEmpty = new Configuration();
+ }
+
+ [Fact]
+ public void DefaultsToLocalFileSystem()
+ {
+ Assert.IsType(this.DefaultConfiguration.FileSystem);
+ Assert.IsType(this.ConfigurationEmpty.FileSystem);
+ }
+
+ ///
+ /// Test that the default configuration is not null.
+ ///
+ [Fact]
+ public void TestDefaultConfigurationIsNotNull()
+ {
+ Assert.True(Configuration.Default != null);
+ }
+
+ ///
+ /// Test that the default configuration parallel options is not null.
+ ///
+ [Fact]
+ public void TestDefaultConfigurationParallelOptionsIsNotNull()
+ {
+ Assert.True(Configuration.Default.ParallelOptions != null);
+ }
+
+ ///
+ /// Test that the default configuration read origin options is set to begin.
+ ///
+ [Fact]
+ public void TestDefaultConfigurationReadOriginIsCurrent()
+ {
+ Assert.True(Configuration.Default.ReadOrigin == ReadOrigin.Current);
+ }
+
+ ///
+ /// Test that the default configuration parallel options max degrees of parallelism matches the
+ /// environment processor count.
+ ///
+ [Fact]
+ public void TestDefaultConfigurationMaxDegreeOfParallelism()
+ {
+ Assert.True(Configuration.Default.ParallelOptions.MaxDegreeOfParallelism == Environment.ProcessorCount);
+ }
+
+ [Fact]
+ public void ConstructorCallConfigureOnFormatProvider()
+ {
+ var provider = new Mock();
+ var config = new Configuration(provider.Object);
+
+ provider.Verify(x => x.Configure(config));
+ }
+
+ [Fact]
+ public void AddFormatCallsConfig()
+ {
+ var provider = new Mock();
+ var config = new Configuration();
+ config.Configure(provider.Object);
+
+ provider.Verify(x => x.Configure(config));
+ }
+ }
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Drawing/FillEllipticGradientBrushTest.cs b/tests/ImageSharp.Tests/Drawing/FillEllipticGradientBrushTest.cs
new file mode 100644
index 0000000000..7c9fa20884
--- /dev/null
+++ b/tests/ImageSharp.Tests/Drawing/FillEllipticGradientBrushTest.cs
@@ -0,0 +1,149 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing;
+using SixLabors.ImageSharp.Processing.Drawing;
+using SixLabors.ImageSharp.Processing.Drawing.Brushes.GradientBrushes;
+
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Drawing
+{
+ using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
+
+ [GroupOutput("Drawing/GradientBrushes")]
+ public class FillEllipticGradientBrushTests
+ {
+ public static ImageComparer TolerantComparer = ImageComparer.TolerantPercentage(0.01f);
+
+ [Theory]
+ [WithBlankImages(10, 10, PixelTypes.Rgba32)]
+ public void WithEqualColorsReturnsUnicolorImage(
+ TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ TPixel red = NamedColors.Red;
+
+ using (Image image = provider.GetImage())
+ {
+ var unicolorLinearGradientBrush =
+ new EllipticGradientBrush(
+ new SixLabors.Primitives.Point(0, 0),
+ new SixLabors.Primitives.Point(10, 0),
+ 1.0f,
+ GradientRepetitionMode.None,
+ new ColorStop(0, red),
+ new ColorStop(1, red));
+
+ image.Mutate(x => x.Fill(unicolorLinearGradientBrush));
+
+ image.DebugSave(provider, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false);
+
+ // no need for reference image in this test:
+ image.ComparePixelBufferTo(red);
+ }
+ }
+
+ [Theory]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0.1)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0.4)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0.8)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 1.0)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 1.2)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 1.6)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 2.0)]
+ public void AxisParallelEllipsesWithDifferentRatio(
+ TestImageProvider provider,
+ float ratio)
+ where TPixel : struct, IPixel
+ {
+ TPixel yellow = NamedColors.Yellow;
+ TPixel red = NamedColors.Red;
+ TPixel black = NamedColors.Black;
+
+ provider.VerifyOperation(
+ TolerantComparer,
+ image =>
+ {
+ var unicolorLinearGradientBrush = new EllipticGradientBrush(
+ new SixLabors.Primitives.Point(image.Width / 2, image.Height / 2),
+ new SixLabors.Primitives.Point(image.Width / 2, (image.Width * 2) / 3),
+ ratio,
+ GradientRepetitionMode.None,
+ new ColorStop(0, yellow),
+ new ColorStop(1, red),
+ new ColorStop(1, black));
+
+ image.Mutate(x => x.Fill(unicolorLinearGradientBrush));
+ },
+ $"{ratio:F2}",
+ false,
+ false);
+ }
+
+ [Theory]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0.1, 0)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0.4, 0)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0.8, 0)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 1.0, 0)]
+
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0.1, 45)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0.4, 45)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0.8, 45)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 1.0, 45)]
+
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0.1, 90)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0.4, 90)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0.8, 90)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 1.0, 90)]
+
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0.1, 30)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0.4, 30)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0.8, 30)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 1.0, 30)]
+ public void RotatedEllipsesWithDifferentRatio(
+ TestImageProvider provider,
+ float ratio,
+ float rotationInDegree)
+ where TPixel: struct, IPixel
+ {
+ FormattableString variant = $"{ratio:F2}_AT_{rotationInDegree:00}deg";
+
+ provider.VerifyOperation(
+ TolerantComparer,
+ image =>
+ {
+ TPixel yellow = NamedColors.Yellow;
+ TPixel red = NamedColors.Red;
+ TPixel black = NamedColors.Black;
+
+ var center = new SixLabors.Primitives.Point(image.Width / 2, image.Height / 2);
+
+ double rotation = (Math.PI * rotationInDegree) / 180.0;
+ double cos = Math.Cos(rotation);
+ double sin = Math.Sin(rotation);
+
+ int offsetY = image.Height / 6;
+ int axisX = center.X + (int)-(offsetY * sin);
+ int axisY = center.Y + (int)(offsetY * cos);
+
+ var unicolorLinearGradientBrush = new EllipticGradientBrush(
+ center,
+ new SixLabors.Primitives.Point(axisX, axisY),
+ ratio,
+ GradientRepetitionMode.None,
+ new ColorStop(0, yellow),
+ new ColorStop(1, red),
+ new ColorStop(1, black));
+
+ image.Mutate(x => x.Fill(unicolorLinearGradientBrush));
+ },
+ variant,
+ false,
+ false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs
new file mode 100644
index 0000000000..9e7af1e578
--- /dev/null
+++ b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs
@@ -0,0 +1,351 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing;
+using SixLabors.ImageSharp.Processing.Drawing;
+using SixLabors.ImageSharp.Processing.Drawing.Brushes.GradientBrushes;
+
+using Xunit;
+// ReSharper disable InconsistentNaming
+
+namespace SixLabors.ImageSharp.Tests.Drawing
+{
+ using SixLabors.ImageSharp.Advanced;
+ using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
+
+ [GroupOutput("Drawing/GradientBrushes")]
+ public class FillLinearGradientBrushTests
+ {
+ public static ImageComparer TolerantComparer = ImageComparer.TolerantPercentage(0.01f);
+
+ [Theory]
+ [WithBlankImages(10, 10, PixelTypes.Rgba32)]
+ public void WithEqualColorsReturnsUnicolorImage(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ using (Image image = provider.GetImage())
+ {
+ TPixel red = NamedColors.Red;
+
+ var unicolorLinearGradientBrush = new LinearGradientBrush(
+ new SixLabors.Primitives.Point(0, 0),
+ new SixLabors.Primitives.Point(10, 0),
+ GradientRepetitionMode.None,
+ new ColorStop(0, red),
+ new ColorStop(1, red));
+
+ image.Mutate(x => x.Fill(unicolorLinearGradientBrush));
+
+ image.DebugSave(provider, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false);
+
+ // no need for reference image in this test:
+ image.ComparePixelBufferTo(red);
+ }
+ }
+
+ [Theory]
+ [WithBlankImages(20, 10, PixelTypes.Rgba32)]
+ [WithBlankImages(20, 10, PixelTypes.Argb32)]
+ [WithBlankImages(20, 10, PixelTypes.Rgb24)]
+ public void DoesNotDependOnSinglePixelType(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ provider.VerifyOperation(
+ TolerantComparer,
+ image =>
+ {
+ var unicolorLinearGradientBrush = new LinearGradientBrush(
+ new SixLabors.Primitives.Point(0, 0),
+ new SixLabors.Primitives.Point(image.Width, 0),
+ GradientRepetitionMode.None,
+ new ColorStop(0, NamedColors.Blue),
+ new ColorStop(1, NamedColors.Yellow));
+
+ image.Mutate(x => x.Fill(unicolorLinearGradientBrush));
+ },
+ appendSourceFileOrDescription: false);
+ }
+
+ [Theory]
+ [WithBlankImages(500, 10, PixelTypes.Rgba32)]
+ public void HorizontalReturnsUnicolorColumns(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ provider.VerifyOperation(
+ TolerantComparer,
+ image =>
+ {
+ TPixel red = NamedColors.Red;
+ TPixel yellow = NamedColors.Yellow;
+
+ var unicolorLinearGradientBrush = new LinearGradientBrush(
+ new SixLabors.Primitives.Point(0, 0),
+ new SixLabors.Primitives.Point(image.Width, 0),
+ GradientRepetitionMode.None,
+ new ColorStop(0, red),
+ new ColorStop(1, yellow));
+
+ image.Mutate(x => x.Fill(unicolorLinearGradientBrush));
+ },
+ false,
+ false);
+ }
+
+ [Theory]
+ [WithBlankImages(500, 10, PixelTypes.Rgba32, GradientRepetitionMode.DontFill)]
+ [WithBlankImages(500, 10, PixelTypes.Rgba32, GradientRepetitionMode.None)]
+ [WithBlankImages(500, 10, PixelTypes.Rgba32, GradientRepetitionMode.Repeat)]
+ [WithBlankImages(500, 10, PixelTypes.Rgba32, GradientRepetitionMode.Reflect)]
+ public void HorizontalGradientWithRepMode(
+ TestImageProvider provider,
+ GradientRepetitionMode repetitionMode)
+ where TPixel : struct, IPixel
+ {
+ provider.VerifyOperation(
+ TolerantComparer,
+ image =>
+ {
+ TPixel red = NamedColors.Red;
+ TPixel yellow = NamedColors.Yellow;
+
+ var unicolorLinearGradientBrush = new LinearGradientBrush(
+ new SixLabors.Primitives.Point(0, 0),
+ new SixLabors.Primitives.Point(image.Width / 10, 0),
+ repetitionMode,
+ new ColorStop(0, red),
+ new ColorStop(1, yellow));
+
+ image.Mutate(x => x.Fill(unicolorLinearGradientBrush));
+ },
+ $"{repetitionMode}",
+ false,
+ false);
+ }
+
+ [Theory]
+ [WithBlankImages(200, 100, PixelTypes.Rgba32, new[] { 0.5f })]
+ [WithBlankImages(200, 100, PixelTypes.Rgba32, new[] { 0.2f, 0.4f, 0.6f, 0.8f })]
+ [WithBlankImages(200, 100, PixelTypes.Rgba32, new[] { 0.1f, 0.3f, 0.6f })]
+ public void WithDoubledStopsProduceDashedPatterns(
+ TestImageProvider provider,
+ float[] pattern)
+ where TPixel : struct, IPixel
+ {
+ string variant = string.Join("_", pattern.Select(i => i.ToString(CultureInfo.InvariantCulture)));
+
+ // ensure the input data is valid
+ Assert.True(pattern.Length > 0);
+
+ TPixel black = NamedColors.Black;
+ TPixel white = NamedColors.White;
+
+ // create the input pattern: 0, followed by each of the arguments twice, followed by 1.0 - toggling black and white.
+ ColorStop[] colorStops =
+ Enumerable.Repeat(new ColorStop(0, black), 1)
+ .Concat(
+ pattern
+ .SelectMany((f, index) => new[]
+ {
+ new ColorStop(f, index % 2 == 0 ? black : white),
+ new ColorStop(f, index % 2 == 0 ? white : black)
+ }))
+ .Concat(Enumerable.Repeat(new ColorStop(1, pattern.Length % 2 == 0 ? black : white), 1))
+ .ToArray();
+
+ using (Image image = provider.GetImage())
+ {
+ var unicolorLinearGradientBrush =
+ new LinearGradientBrush(
+ new SixLabors.Primitives.Point(0, 0),
+ new SixLabors.Primitives.Point(image.Width, 0),
+ GradientRepetitionMode.None,
+ colorStops);
+
+ image.Mutate(x => x.Fill(unicolorLinearGradientBrush));
+
+ image.DebugSave(
+ provider,
+ variant,
+ appendPixelTypeToFileName: false,
+ appendSourceFileOrDescription: false);
+
+ // the result must be a black and white pattern, no other color should occur:
+ Assert.All(
+ Enumerable.Range(0, image.Width).Select(i => image[i, 0]),
+ color => Assert.True(color.Equals(black) || color.Equals(white)));
+
+ image.CompareToReferenceOutput(
+ TolerantComparer,
+ provider,
+ variant,
+ appendPixelTypeToFileName: false,
+ appendSourceFileOrDescription: false);
+ }
+ }
+
+ [Theory]
+ [WithBlankImages(10, 500, PixelTypes.Rgba32)]
+ public void VerticalBrushReturnsUnicolorRows(
+ TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ provider.VerifyOperation(
+ image =>
+ {
+ TPixel red = NamedColors.Red;
+ TPixel yellow = NamedColors.Yellow;
+
+ var unicolorLinearGradientBrush = new LinearGradientBrush(
+ new SixLabors.Primitives.Point(0, 0),
+ new SixLabors.Primitives.Point(0, image.Height),
+ GradientRepetitionMode.None,
+ new ColorStop(0, red),
+ new ColorStop(1, yellow));
+
+ image.Mutate(x => x.Fill(unicolorLinearGradientBrush));
+
+ VerifyAllRowsAreUnicolor(image);
+ },
+ false,
+ false);
+
+ void VerifyAllRowsAreUnicolor(Image image)
+ {
+ for (int y = 0; y < image.Height; y++)
+ {
+ Span row = image.GetPixelRowSpan(y);
+ TPixel firstColorOfRow = row[0];
+ foreach (TPixel p in row)
+ {
+ Assert.Equal(firstColorOfRow, p);
+ }
+ }
+ }
+ }
+
+ public enum ImageCorner
+ {
+ TopLeft = 0,
+ TopRight = 1,
+ BottomLeft = 2,
+ BottomRight = 3
+ }
+
+ [Theory]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, ImageCorner.TopLeft)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, ImageCorner.TopRight)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, ImageCorner.BottomLeft)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, ImageCorner.BottomRight)]
+ public void DiagonalReturnsCorrectImages(
+ TestImageProvider provider,
+ ImageCorner startCorner)
+ where TPixel : struct, IPixel
+ {
+ using (Image image = provider.GetImage())
+ {
+ Assert.True(image.Height == image.Width, "For the math check block at the end the image must be squared, but it is not.");
+
+ int startX = (int)startCorner % 2 == 0 ? 0 : image.Width - 1;
+ int startY = startCorner > ImageCorner.TopRight ? 0 : image.Height - 1;
+ int endX = image.Height - startX - 1;
+ int endY = image.Width - startY - 1;
+
+ TPixel red = NamedColors.Red;
+ TPixel yellow = NamedColors.Yellow;
+
+ var unicolorLinearGradientBrush =
+ new LinearGradientBrush(
+ new SixLabors.Primitives.Point(startX, startY),
+ new SixLabors.Primitives.Point(endX, endY),
+ GradientRepetitionMode.None,
+ new ColorStop(0, red),
+ new ColorStop(1, yellow));
+
+ image.Mutate(x => x.Fill(unicolorLinearGradientBrush));
+ image.DebugSave(
+ provider,
+ startCorner,
+ appendPixelTypeToFileName: false,
+ appendSourceFileOrDescription: false);
+
+ int verticalSign = startY == 0 ? 1 : -1;
+ int horizontalSign = startX == 0 ? 1 : -1;
+
+ // check first and last pixel, these are known:
+ Assert.Equal(red, image[startX, startY]);
+ Assert.Equal(yellow, image[endX, endY]);
+
+ for (int i = 0; i < image.Height; i++)
+ {
+ // it's diagonal, so for any (a, a) on the gradient line, for all (a-x, b+x) - +/- depending on the diagonal direction - must be the same color)
+ TPixel colorOnDiagonal = image[i, i];
+ int orthoCount = 0;
+ for (int offset = -orthoCount; offset < orthoCount; offset++)
+ {
+ Assert.Equal(colorOnDiagonal, image[i + horizontalSign * offset, i + verticalSign * offset]);
+ }
+ }
+
+ image.CompareToReferenceOutput(
+ TolerantComparer,
+ provider,
+ startCorner,
+ appendPixelTypeToFileName: false,
+ appendSourceFileOrDescription: false);
+ }
+ }
+
+ [Theory]
+ [WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 0, 499, 499, new[] { 0f, .2f, .5f, .9f }, new[] { 0, 0, 1, 1 })]
+ [WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 499, 499, 0, new[] { 0f, 0.2f, 0.5f, 0.9f }, new[] { 0, 1, 2, 3 })]
+ [WithBlankImages(500, 500, PixelTypes.Rgba32, 499, 499, 0, 0, new[] { 0f, 0.7f, 0.8f, 0.9f}, new[] { 0, 1, 2, 0 })]
+ [WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 0, 499, 499, new[] { 0f, .5f, 1f}, new[]{0, 1, 3})]
+ public void ArbitraryGradients(
+ TestImageProvider provider,
+ int startX, int startY,
+ int endX, int endY,
+ float[] stopPositions,
+ int[] stopColorCodes)
+ where TPixel : struct, IPixel
+ {
+ TPixel[] colors = {
+ NamedColors.Navy, NamedColors.LightGreen, NamedColors.Yellow,
+ NamedColors.Red
+ };
+
+ var coloringVariant = new StringBuilder();
+ ColorStop[] colorStops = new ColorStop[stopPositions.Length];
+ for (int i = 0; i < stopPositions.Length; i++)
+ {
+ TPixel color = colors[stopColorCodes[i % colors.Length]];
+ float position = stopPositions[i];
+
+ colorStops[i] = new ColorStop(position, color);
+ coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", color, position);
+ }
+
+ FormattableString variant = $"({startX},{startY})_TO_({endX},{endY})__[{coloringVariant}]";
+
+ provider.VerifyOperation(
+ image =>
+ {
+ var unicolorLinearGradientBrush = new LinearGradientBrush(
+ new SixLabors.Primitives.Point(startX, startY),
+ new SixLabors.Primitives.Point(endX, endY),
+ GradientRepetitionMode.None,
+ colorStops);
+
+ image.Mutate(x => x.Fill(unicolorLinearGradientBrush));
+ },
+ variant,
+ false,
+ false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Drawing/FillRadialGradientBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillRadialGradientBrushTests.cs
new file mode 100644
index 0000000000..eafbf3df19
--- /dev/null
+++ b/tests/ImageSharp.Tests/Drawing/FillRadialGradientBrushTests.cs
@@ -0,0 +1,76 @@
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing;
+using SixLabors.ImageSharp.Processing.Drawing;
+using SixLabors.ImageSharp.Processing.Drawing.Brushes.GradientBrushes;
+
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Drawing
+{
+ using System;
+
+ using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
+
+ [GroupOutput("Drawing/GradientBrushes")]
+ public class FillRadialGradientBrushTests
+ {
+ public static ImageComparer TolerantComparer = ImageComparer.TolerantPercentage(0.01f);
+
+ [Theory]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32)]
+ public void WithEqualColorsReturnsUnicolorImage(
+ TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ using (Image image = provider.GetImage())
+ {
+ TPixel red = NamedColors.Red;
+
+ var unicolorRadialGradientBrush =
+ new RadialGradientBrush(
+ new SixLabors.Primitives.Point(0, 0),
+ 100,
+ GradientRepetitionMode.None,
+ new ColorStop(0, red),
+ new ColorStop(1, red));
+
+ image.Mutate(x => x.Fill(unicolorRadialGradientBrush));
+
+ image.DebugSave(provider, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false);
+
+ // no need for reference image in this test:
+ image.ComparePixelBufferTo(red);
+ }
+ }
+
+ [Theory]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 100, 100)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0, 0)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 100, 0)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, 0, 100)]
+ [WithBlankImages(200, 200, PixelTypes.Rgba32, -40, 100)]
+ public void WithDifferentCentersReturnsImage(
+ TestImageProvider provider,
+ int centerX,
+ int centerY)
+ where TPixel : struct, IPixel
+ {
+ provider.VerifyOperation(
+ TolerantComparer,
+ image =>
+ {
+ var brush = new RadialGradientBrush(
+ new SixLabors.Primitives.Point(centerX, centerY),
+ image.Width / 2f,
+ GradientRepetitionMode.None,
+ new ColorStop(0, NamedColors.Red),
+ new ColorStop(1, NamedColors.Yellow));
+
+ image.Mutate(x => x.Fill(brush));
+ },
+ $"center({centerX},{centerY})",
+ false,
+ false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/AdobeMarkerTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/AdobeMarkerTests.cs
index 2ee9498e09..8b0e89f59d 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/AdobeMarkerTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/AdobeMarkerTests.cs
@@ -1,8 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
-using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
+using SixLabors.ImageSharp.Formats.Jpeg;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using Xunit;
@@ -25,29 +25,29 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void MarkerReturnsCorrectParsedValue()
{
- bool isAdobe = AdobeMarker.TryParse(this.bytes, out var marker);
+ bool isAdobe = AdobeMarker.TryParse(this.bytes, out AdobeMarker marker);
Assert.True(isAdobe);
Assert.Equal(100, marker.DCTEncodeVersion);
Assert.Equal(0, marker.APP14Flags0);
Assert.Equal(0, marker.APP14Flags1);
- Assert.Equal(OrigJpegConstants.Adobe.ColorTransformYcck, marker.ColorTransform);
+ Assert.Equal(JpegConstants.Adobe.ColorTransformYcck, marker.ColorTransform);
}
[Fact]
public void MarkerIgnoresIncorrectValue()
{
- bool isAdobe = AdobeMarker.TryParse(new byte[] { 0, 0, 0, 0 }, out var marker);
+ bool isAdobe = AdobeMarker.TryParse(new byte[] { 0, 0, 0, 0 }, out AdobeMarker marker);
Assert.False(isAdobe);
- Assert.Equal(default(AdobeMarker), marker);
+ Assert.Equal(default, marker);
}
[Fact]
public void MarkerEqualityIsCorrect()
{
- AdobeMarker.TryParse(this.bytes, out var marker);
- AdobeMarker.TryParse(this.bytes, out var marker2);
+ AdobeMarker.TryParse(this.bytes, out AdobeMarker marker);
+ AdobeMarker.TryParse(this.bytes, out AdobeMarker marker2);
Assert.True(marker.Equals(marker2));
}
@@ -55,8 +55,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void MarkerInEqualityIsCorrect()
{
- AdobeMarker.TryParse(this.bytes, out var marker);
- AdobeMarker.TryParse(this.bytes2, out var marker2);
+ AdobeMarker.TryParse(this.bytes, out AdobeMarker marker);
+ AdobeMarker.TryParse(this.bytes2, out AdobeMarker marker2);
Assert.False(marker.Equals(marker2));
}
@@ -64,8 +64,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void MarkerHashCodeIsReplicable()
{
- AdobeMarker.TryParse(this.bytes, out var marker);
- AdobeMarker.TryParse(this.bytes, out var marker2);
+ AdobeMarker.TryParse(this.bytes, out AdobeMarker marker);
+ AdobeMarker.TryParse(this.bytes, out AdobeMarker marker2);
Assert.True(marker.GetHashCode().Equals(marker2.GetHashCode()));
}
@@ -73,8 +73,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void MarkerHashCodeIsUnique()
{
- AdobeMarker.TryParse(this.bytes, out var marker);
- AdobeMarker.TryParse(this.bytes2, out var marker2);
+ AdobeMarker.TryParse(this.bytes, out AdobeMarker marker);
+ AdobeMarker.TryParse(this.bytes2, out AdobeMarker marker2);
Assert.False(marker.GetHashCode().Equals(marker2.GetHashCode()));
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs
index 4b5cf526b0..aa7d101c0d 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs
@@ -4,7 +4,7 @@
// Uncomment this to turn unit tests into benchmarks:
//#define BENCHMARKING
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using SixLabors.Primitives;
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
index ac8bed13b0..e72f4945b7 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
@@ -7,7 +7,7 @@
using System;
using System.Diagnostics;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using Xunit;
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs
index c7869a6ba8..3df927aeb0 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs
@@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using Xunit;
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs
index 1c18df76c6..92b92eb100 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs
@@ -1,7 +1,7 @@
// ReSharper disable InconsistentNaming
using System;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using Xunit;
@@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
var temp = default(Block8x8F);
var actual = default(Block8x8F);
FastFloatingPointDCT.TransformIDCT(ref source, ref actual, ref temp);
-
+
this.CompareBlocks(expected, actual, 1f);
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/DoubleBufferedStreamReaderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/DoubleBufferedStreamReaderTests.cs
new file mode 100644
index 0000000000..be71e554f1
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Jpg/DoubleBufferedStreamReaderTests.cs
@@ -0,0 +1,159 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.IO;
+using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components;
+using SixLabors.ImageSharp.Memory;
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Jpg
+{
+ public class DoubleBufferedStreamReaderTests
+ {
+ private readonly MemoryManager manager = Configuration.Default.MemoryManager;
+
+ [Fact]
+ public void DoubleBufferedStreamReaderCanReadSingleByteFromOrigin()
+ {
+ using (MemoryStream stream = this.CreateTestStream())
+ {
+ byte[] expected = stream.ToArray();
+ var reader = new DoubleBufferedStreamReader(this.manager, stream);
+
+ Assert.Equal(expected[0], reader.ReadByte());
+
+ // We've read a whole chunk but increment by 1 in our reader.
+ Assert.Equal(stream.Position, DoubleBufferedStreamReader.ChunkLength);
+ Assert.Equal(1, reader.Position);
+ }
+ }
+
+ [Fact]
+ public void DoubleBufferedStreamReaderCanReadSubsequentSingleByteCorrectly()
+ {
+ using (MemoryStream stream = this.CreateTestStream())
+ {
+ byte[] expected = stream.ToArray();
+ var reader = new DoubleBufferedStreamReader(this.manager, stream);
+
+ for (int i = 0; i < expected.Length; i++)
+ {
+ Assert.Equal(expected[i], reader.ReadByte());
+ Assert.Equal(i + 1, reader.Position);
+
+ if (i < DoubleBufferedStreamReader.ChunkLength)
+ {
+ Assert.Equal(stream.Position, DoubleBufferedStreamReader.ChunkLength);
+ }
+ else if (i >= DoubleBufferedStreamReader.ChunkLength && i < DoubleBufferedStreamReader.ChunkLength * 2)
+ {
+ // We should have advanced to the second chunk now.
+ Assert.Equal(stream.Position, DoubleBufferedStreamReader.ChunkLength * 2);
+ }
+ else
+ {
+ // We should have advanced to the third chunk now.
+ Assert.Equal(stream.Position, DoubleBufferedStreamReader.ChunkLength * 3);
+ }
+ }
+ }
+ }
+
+ [Fact]
+ public void DoubleBufferedStreamReaderCanReadMultipleBytesFromOrigin()
+ {
+ using (MemoryStream stream = this.CreateTestStream())
+ {
+ byte[] buffer = new byte[2];
+ byte[] expected = stream.ToArray();
+ var reader = new DoubleBufferedStreamReader(this.manager, stream);
+
+ Assert.Equal(2, reader.Read(buffer, 0, 2));
+ Assert.Equal(expected[0], buffer[0]);
+ Assert.Equal(expected[1], buffer[1]);
+
+ // We've read a whole chunk but increment by the buffer length in our reader.
+ Assert.Equal(stream.Position, DoubleBufferedStreamReader.ChunkLength);
+ Assert.Equal(buffer.Length, reader.Position);
+ }
+ }
+
+ [Fact]
+ public void DoubleBufferedStreamReaderCanReadSubsequentMultipleByteCorrectly()
+ {
+ using (MemoryStream stream = this.CreateTestStream())
+ {
+ byte[] buffer = new byte[2];
+ byte[] expected = stream.ToArray();
+ var reader = new DoubleBufferedStreamReader(this.manager, stream);
+
+ for (int i = 0, o = 0; i < expected.Length / 2; i++, o += 2)
+ {
+
+ Assert.Equal(2, reader.Read(buffer, 0, 2));
+ Assert.Equal(expected[o], buffer[0]);
+ Assert.Equal(expected[o + 1], buffer[1]);
+ Assert.Equal(o + 2, reader.Position);
+
+ int offset = i * 2;
+ if (offset < DoubleBufferedStreamReader.ChunkLength)
+ {
+ Assert.Equal(stream.Position, DoubleBufferedStreamReader.ChunkLength);
+ }
+ else if (offset >= DoubleBufferedStreamReader.ChunkLength && offset < DoubleBufferedStreamReader.ChunkLength * 2)
+ {
+ // We should have advanced to the second chunk now.
+ Assert.Equal(stream.Position, DoubleBufferedStreamReader.ChunkLength * 2);
+ }
+ else
+ {
+ // We should have advanced to the third chunk now.
+ Assert.Equal(stream.Position, DoubleBufferedStreamReader.ChunkLength * 3);
+ }
+ }
+ }
+ }
+
+ [Fact]
+ public void DoubleBufferedStreamReaderCanSkip()
+ {
+ using (MemoryStream stream = this.CreateTestStream())
+ {
+ byte[] expected = stream.ToArray();
+ var reader = new DoubleBufferedStreamReader(this.manager, stream);
+
+ int skip = 50;
+ int plusOne = 1;
+ int skip2 = DoubleBufferedStreamReader.ChunkLength;
+
+ // Skip
+ reader.Skip(skip);
+ Assert.Equal(skip, reader.Position);
+ Assert.Equal(stream.Position, reader.Position);
+
+ // Read
+ Assert.Equal(expected[skip], reader.ReadByte());
+
+ // Skip Again
+ reader.Skip(skip2);
+
+ // First Skap + First Read + Second Skip
+ int position = skip + plusOne + skip2;
+
+ Assert.Equal(position, reader.Position);
+ Assert.Equal(stream.Position, reader.Position);
+ Assert.Equal(expected[position], reader.ReadByte());
+ }
+ }
+
+ private MemoryStream CreateTestStream()
+ {
+ byte[] buffer = new byte[DoubleBufferedStreamReader.ChunkLength * 3];
+ var random = new Random();
+ random.NextBytes(buffer);
+
+ return new MemoryStream(buffer);
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs b/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs
index 5bb3ded0b1..05ded4341d 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs
@@ -3,7 +3,7 @@
using System;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JFifMarkerTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JFifMarkerTests.cs
index 4e63c97dec..332899e8df 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JFifMarkerTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JFifMarkerTests.cs
@@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using Xunit;
@@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void MarkerReturnsCorrectParsedValue()
{
- bool isJFif = JFifMarker.TryParse(this.bytes, out var marker);
+ bool isJFif = JFifMarker.TryParse(this.bytes, out JFifMarker marker);
Assert.True(isJFif);
Assert.Equal(1, marker.MajorVersion);
@@ -40,26 +40,26 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void MarkerIgnoresIncorrectValue()
{
- bool isJFif = JFifMarker.TryParse(new byte[] { 0, 0, 0, 0 }, out var marker);
+ bool isJFif = JFifMarker.TryParse(new byte[] { 0, 0, 0, 0 }, out JFifMarker marker);
Assert.False(isJFif);
- Assert.Equal(default(JFifMarker), marker);
+ Assert.Equal(default, marker);
}
[Fact]
public void MarkerIgnoresCorrectHeaderButInvalidDensities()
{
- bool isJFif = JFifMarker.TryParse(this.bytes3, out var marker);
+ bool isJFif = JFifMarker.TryParse(this.bytes3, out JFifMarker marker);
Assert.False(isJFif);
- Assert.Equal(default(JFifMarker), marker);
+ Assert.Equal(default, marker);
}
[Fact]
public void MarkerEqualityIsCorrect()
{
- JFifMarker.TryParse(this.bytes, out var marker);
- JFifMarker.TryParse(this.bytes, out var marker2);
+ JFifMarker.TryParse(this.bytes, out JFifMarker marker);
+ JFifMarker.TryParse(this.bytes, out JFifMarker marker2);
Assert.True(marker.Equals(marker2));
}
@@ -67,8 +67,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void MarkerInEqualityIsCorrect()
{
- JFifMarker.TryParse(this.bytes, out var marker);
- JFifMarker.TryParse(this.bytes2, out var marker2);
+ JFifMarker.TryParse(this.bytes, out JFifMarker marker);
+ JFifMarker.TryParse(this.bytes2, out JFifMarker marker2);
Assert.False(marker.Equals(marker2));
}
@@ -76,8 +76,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void MarkerHashCodeIsReplicable()
{
- JFifMarker.TryParse(this.bytes, out var marker);
- JFifMarker.TryParse(this.bytes, out var marker2);
+ JFifMarker.TryParse(this.bytes, out JFifMarker marker);
+ JFifMarker.TryParse(this.bytes, out JFifMarker marker2);
Assert.True(marker.GetHashCode().Equals(marker2.GetHashCode()));
}
@@ -85,8 +85,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void MarkerHashCodeIsUnique()
{
- JFifMarker.TryParse(this.bytes, out var marker);
- JFifMarker.TryParse(this.bytes2, out var marker2);
+ JFifMarker.TryParse(this.bytes, out JFifMarker marker);
+ JFifMarker.TryParse(this.bytes2, out JFifMarker marker2);
Assert.False(marker.GetHashCode().Equals(marker2.GetHashCode()));
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs
index d2f0641756..c97d625535 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs
@@ -6,8 +6,8 @@ using System.Numerics;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
-using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
-using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder.ColorConverters;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters;
using SixLabors.ImageSharp.Memory;
using Xunit;
@@ -140,13 +140,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter converter = simd ? (JpegColorConverter)new JpegColorConverter.FromYCbCrSimd() : new JpegColorConverter.FromYCbCrBasic();
// Warm up:
- converter.ConvertToRGBA(values, result);
+ converter.ConvertToRgba(values, result);
using (new MeasureGuard(this.Output, $"{converter.GetType().Name} x {times}"))
{
for (int i = 0; i < times; i++)
{
- converter.ConvertToRGBA(values, result);
+ converter.ConvertToRgba(values, result);
}
}
}
@@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter.ComponentValues values = CreateRandomValues(4, inputBufferLength, seed);
var result = new Vector4[resultBufferLength];
- converter.ConvertToRGBA(values, result);
+ converter.ConvertToRgba(values, result);
for (int i = 0; i < resultBufferLength; i++)
{
@@ -195,7 +195,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter.ComponentValues values = CreateRandomValues(1, inputBufferLength, seed);
var result = new Vector4[resultBufferLength];
- converter.ConvertToRGBA(values, result);
+ converter.ConvertToRgba(values, result);
for (int i = 0; i < resultBufferLength; i++)
{
@@ -217,7 +217,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter.ComponentValues values = CreateRandomValues(3, inputBufferLength, seed);
var result = new Vector4[resultBufferLength];
- converter.ConvertToRGBA(values, result);
+ converter.ConvertToRgba(values, result);
for (int i = 0; i < resultBufferLength; i++)
{
@@ -244,7 +244,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter.ComponentValues values = CreateRandomValues(4, inputBufferLength, seed);
var result = new Vector4[resultBufferLength];
- converter.ConvertToRGBA(values, result);
+ converter.ConvertToRgba(values, result);
for (int i = 0; i < resultBufferLength; i++)
{
@@ -320,7 +320,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
JpegColorConverter.ComponentValues values = CreateRandomValues(componentCount, inputBufferLength, seed);
var result = new Vector4[resultBufferLength];
- converter.ConvertToRGBA(values, result);
+ converter.ConvertToRgba(values, result);
for (int i = 0; i < resultBufferLength; i++)
{
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs
new file mode 100644
index 0000000000..778459775a
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs
@@ -0,0 +1,89 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.PixelFormats;
+using Xunit;
+// ReSharper disable InconsistentNaming
+
+namespace SixLabors.ImageSharp.Tests.Formats.Jpg
+{
+ public partial class JpegDecoderTests
+ {
+ [Theory]
+ [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
+ public void DecodeBaselineJpeg_Orig(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ if (SkipTest(provider))
+ {
+ return;
+ }
+
+ // For 32 bit test enviroments:
+ provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling();
+
+ using (Image image = provider.GetImage(GolangJpegDecoder))
+ {
+ image.DebugSave(provider);
+ provider.Utility.TestName = DecodeBaselineJpegOutputName;
+ image.CompareToReferenceOutput(
+ this.GetImageComparer(provider),
+ provider,
+ appendPixelTypeToFileName: false);
+ }
+
+ provider.Configuration.MemoryManager.ReleaseRetainedResources();
+ }
+
+ [Theory]
+ [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
+ public void DecodeBaselineJpeg_PdfJs(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ if (TestEnvironment.RunsOnCI && !TestEnvironment.Is64BitProcess)
+ {
+ // skipping to avoid OutOfMemoryException on CI
+ return;
+ }
+
+ using (Image image = provider.GetImage(PdfJsJpegDecoder))
+ {
+ image.DebugSave(provider);
+
+ provider.Utility.TestName = DecodeBaselineJpegOutputName;
+ image.CompareToReferenceOutput(
+ this.GetImageComparer(provider),
+ provider,
+ appendPixelTypeToFileName: false);
+ }
+ }
+
+ [Theory]
+ [WithFile(TestImages.Jpeg.Issues.CriticalEOF214, PixelTypes.Rgba32)]
+ public void DecodeBaselineJpeg_CriticalEOF_ShouldThrow_Golang(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ // TODO: We need a public ImageDecoderException class in ImageSharp!
+ Assert.ThrowsAny(() => provider.GetImage(GolangJpegDecoder));
+ }
+
+ [Theory]
+ [WithFile(TestImages.Jpeg.Issues.CriticalEOF214, PixelTypes.Rgba32)]
+ public void DecodeBaselineJpeg_CriticalEOF_ShouldThrow_PdfJs(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ // TODO: We need a public ImageDecoderException class in ImageSharp!
+ Assert.ThrowsAny(() => provider.GetImage(PdfJsJpegDecoder));
+ }
+
+ [Theory(Skip = "Debug only, enable manually!")]
+ [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
+ public void CompareJpegDecoders_Baseline(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ this.CompareJpegDecodersImpl(provider, DecodeBaselineJpegOutputName);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs
new file mode 100644
index 0000000000..539ab73195
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs
@@ -0,0 +1,72 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.Collections.Generic;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Jpg
+{
+ public partial class JpegDecoderTests
+ {
+ public static string[] BaselineTestJpegs =
+ {
+ TestImages.Jpeg.Baseline.Calliphora,
+ TestImages.Jpeg.Baseline.Cmyk, TestImages.Jpeg.Baseline.Ycck,
+ TestImages.Jpeg.Baseline.Jpeg400,
+ TestImages.Jpeg.Baseline.Testorig420,
+
+ // BUG: The following image has a high difference compared to the expected output:
+ // TestImages.Jpeg.Baseline.Jpeg420Small,
+
+ TestImages.Jpeg.Baseline.Jpeg444,
+ TestImages.Jpeg.Baseline.Bad.BadEOF,
+ TestImages.Jpeg.Issues.MultiHuffmanBaseline394,
+ TestImages.Jpeg.Baseline.MultiScanBaselineCMYK,
+ TestImages.Jpeg.Baseline.Bad.BadRST
+ };
+
+ public static string[] ProgressiveTestJpegs =
+ {
+ TestImages.Jpeg.Progressive.Fb,
+ TestImages.Jpeg.Progressive.Progress,
+ TestImages.Jpeg.Progressive.Festzug,
+ TestImages.Jpeg.Progressive.Bad.BadEOF,
+ TestImages.Jpeg.Issues.BadCoeffsProgressive178,
+ TestImages.Jpeg.Issues.MissingFF00ProgressiveGirl159,
+ TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159,
+ TestImages.Jpeg.Issues.BadZigZagProgressive385,
+ TestImages.Jpeg.Progressive.Bad.ExifUndefType,
+ TestImages.Jpeg.Issues.NoEoiProgressive517,
+ TestImages.Jpeg.Issues.BadRstProgressive518,
+ TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159,
+ };
+
+ ///
+ /// Golang decoder is unable to decode these
+ ///
+ public static string[] PdfJsOnly =
+ {
+ TestImages.Jpeg.Issues.NoEoiProgressive517, TestImages.Jpeg.Issues.BadRstProgressive518,
+ TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159
+ };
+
+ private static readonly Dictionary CustomToleranceValues =
+ new Dictionary
+ {
+ // Baseline:
+ [TestImages.Jpeg.Baseline.Calliphora] = 0.00002f / 100,
+ [TestImages.Jpeg.Baseline.Bad.BadEOF] = 0.38f / 100,
+ [TestImages.Jpeg.Baseline.Testorig420] = 0.38f / 100,
+ [TestImages.Jpeg.Baseline.Bad.BadRST] = 0.0589f / 100,
+
+ // Progressive:
+ [TestImages.Jpeg.Issues.MissingFF00ProgressiveGirl159] = 0.34f / 100,
+ [TestImages.Jpeg.Issues.BadCoeffsProgressive178] = 0.38f / 100,
+ [TestImages.Jpeg.Progressive.Bad.BadEOF] = 0.3f / 100,
+ [TestImages.Jpeg.Progressive.Festzug] = 0.02f / 100,
+ [TestImages.Jpeg.Progressive.Fb] = 0.16f / 100,
+ [TestImages.Jpeg.Progressive.Progress] = 0.31f / 100,
+ [TestImages.Jpeg.Issues.BadZigZagProgressive385] = 0.23f / 100,
+ [TestImages.Jpeg.Progressive.Bad.ExifUndefType] = 0.011f / 100,
+ };
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.MetaData.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.MetaData.cs
new file mode 100644
index 0000000000..10b098d924
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.MetaData.cs
@@ -0,0 +1,196 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+using SixLabors.ImageSharp.Formats;
+using SixLabors.ImageSharp.MetaData.Profiles.Exif;
+using SixLabors.ImageSharp.MetaData.Profiles.Icc;
+using SixLabors.ImageSharp.PixelFormats;
+using Xunit;
+
+// ReSharper disable InconsistentNaming
+namespace SixLabors.ImageSharp.Tests.Formats.Jpg
+{
+ using System;
+ using System.Runtime.CompilerServices;
+
+ using SixLabors.ImageSharp.Formats.Jpeg;
+
+ public partial class JpegDecoderTests
+ {
+ // TODO: A JPEGsnoop & metadata expert should review if the Exif/Icc expectations are correct.
+ // I'm seeing several entries with Exif-related names in images where we do not decode an exif profile. (- Anton)
+ public static readonly TheoryData MetaDataTestData =
+ new TheoryData
+ {
+ { false, TestImages.Jpeg.Progressive.Progress, 24, false, false },
+ { false, TestImages.Jpeg.Progressive.Fb, 24, false, true },
+ { false, TestImages.Jpeg.Baseline.Cmyk, 32, false, true },
+ { false, TestImages.Jpeg.Baseline.Ycck, 32, true, true },
+ { false, TestImages.Jpeg.Baseline.Jpeg400, 8, false, false },
+ { false, TestImages.Jpeg.Baseline.Snake, 24, true, true },
+ { false, TestImages.Jpeg.Baseline.Jpeg420Exif, 24, true, false },
+
+ { true, TestImages.Jpeg.Progressive.Progress, 24, false, false },
+ { true, TestImages.Jpeg.Progressive.Fb, 24, false, true },
+ { true, TestImages.Jpeg.Baseline.Cmyk, 32, false, true },
+ { true, TestImages.Jpeg.Baseline.Ycck, 32, true, true },
+ { true, TestImages.Jpeg.Baseline.Jpeg400, 8, false, false },
+ { true, TestImages.Jpeg.Baseline.Snake, 24, true, true },
+ { true, TestImages.Jpeg.Baseline.Jpeg420Exif, 24, true, false },
+ };
+
+ [Theory]
+ [MemberData(nameof(MetaDataTestData))]
+ public void MetaDataIsParsedCorrectly_Orig(
+ bool useIdentify,
+ string imagePath,
+ int expectedPixelSize,
+ bool exifProfilePresent,
+ bool iccProfilePresent)
+ {
+ TestMetaDataImpl(
+ useIdentify,
+ GolangJpegDecoder,
+ imagePath,
+ expectedPixelSize,
+ exifProfilePresent,
+ iccProfilePresent);
+ }
+
+ [Theory]
+ [MemberData(nameof(MetaDataTestData))]
+ public void MetaDataIsParsedCorrectly_PdfJs(
+ bool useIdentify,
+ string imagePath,
+ int expectedPixelSize,
+ bool exifProfilePresent,
+ bool iccProfilePresent)
+ {
+ TestMetaDataImpl(
+ useIdentify,
+ PdfJsJpegDecoder,
+ imagePath,
+ expectedPixelSize,
+ exifProfilePresent,
+ iccProfilePresent);
+ }
+
+ private static void TestImageInfo(string imagePath, IImageDecoder decoder, bool useIdentify, Action test)
+ {
+ var testFile = TestFile.Create(imagePath);
+ using (var stream = new MemoryStream(testFile.Bytes, false))
+ {
+ IImageInfo imageInfo = useIdentify
+ ? ((IImageInfoDetector)decoder).Identify(Configuration.Default, stream)
+ : decoder.Decode(Configuration.Default, stream);
+ test(imageInfo);
+ }
+ }
+
+ private static void TestMetaDataImpl(
+ bool useIdentify,
+ IImageDecoder decoder,
+ string imagePath,
+ int expectedPixelSize,
+ bool exifProfilePresent,
+ bool iccProfilePresent)
+ {
+ TestImageInfo(
+ imagePath,
+ decoder,
+ useIdentify,
+ imageInfo =>
+ {
+ Assert.NotNull(imageInfo);
+ Assert.NotNull(imageInfo.PixelType);
+
+ if (useIdentify)
+ {
+ Assert.Equal(expectedPixelSize, imageInfo.PixelType.BitsPerPixel);
+ }
+ else
+ {
+ // When full Image decoding is performed, BitsPerPixel will match TPixel
+ int bpp32 = Unsafe.SizeOf() * 8;
+ Assert.Equal(bpp32, imageInfo.PixelType.BitsPerPixel);
+ }
+
+ ExifProfile exifProfile = imageInfo.MetaData.ExifProfile;
+
+ if (exifProfilePresent)
+ {
+ Assert.NotNull(exifProfile);
+ Assert.NotEmpty(exifProfile.Values);
+ }
+ else
+ {
+ Assert.Null(exifProfile);
+ }
+
+ IccProfile iccProfile = imageInfo.MetaData.IccProfile;
+
+ if (iccProfilePresent)
+ {
+ Assert.NotNull(iccProfile);
+ Assert.NotEmpty(iccProfile.Entries);
+ }
+ else
+ {
+ Assert.Null(iccProfile);
+ }
+ });
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void IgnoreMetaData_ControlsWhetherMetaDataIsParsed(bool ignoreMetaData)
+ {
+ var decoder = new JpegDecoder() { IgnoreMetadata = ignoreMetaData };
+
+ // Snake.jpg has both Exif and ICC profiles defined:
+ var testFile = TestFile.Create(TestImages.Jpeg.Baseline.Snake);
+
+ using (Image image = testFile.CreateImage(decoder))
+ {
+ if (ignoreMetaData)
+ {
+ Assert.Null(image.MetaData.ExifProfile);
+ Assert.Null(image.MetaData.IccProfile);
+ }
+ else
+ {
+ Assert.NotNull(image.MetaData.ExifProfile);
+ Assert.NotNull(image.MetaData.IccProfile);
+ }
+ }
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void Decoder_Reads_Correct_Resolution_From_Jfif(bool useIdentify)
+ {
+ TestImageInfo(TestImages.Jpeg.Baseline.Floorplan, DefaultJpegDecoder, useIdentify,
+ imageInfo =>
+ {
+ Assert.Equal(300, imageInfo.MetaData.HorizontalResolution);
+ Assert.Equal(300, imageInfo.MetaData.VerticalResolution);
+ });
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void Decoder_Reads_Correct_Resolution_From_Exif(bool useIdentify)
+ {
+ TestImageInfo(TestImages.Jpeg.Baseline.Jpeg420Exif, DefaultJpegDecoder, useIdentify,
+ imageInfo =>
+ {
+ Assert.Equal(72, imageInfo.MetaData.HorizontalResolution);
+ Assert.Equal(72, imageInfo.MetaData.VerticalResolution);
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs
new file mode 100644
index 0000000000..83983691e2
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs
@@ -0,0 +1,81 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.Linq;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.PixelFormats;
+using Xunit;
+// ReSharper disable InconsistentNaming
+
+namespace SixLabors.ImageSharp.Tests.Formats.Jpg
+{
+ public partial class JpegDecoderTests
+ {
+ public const string DecodeProgressiveJpegOutputName = "DecodeProgressiveJpeg";
+
+ [Theory]
+ [WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)]
+ public void DecodeProgressiveJpeg_Orig(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ if (TestEnvironment.RunsOnCI && !TestEnvironment.Is64BitProcess)
+ {
+ // skipping to avoid OutOfMemoryException on CI
+ return;
+ }
+
+ // Golang decoder is unable to decode these:
+ if (PdfJsOnly.Any(fn => fn.Contains(provider.SourceFileOrDescription)))
+ {
+ return;
+ }
+
+ // For 32 bit test enviroments:
+ provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling();
+
+ using (Image image = provider.GetImage(GolangJpegDecoder))
+ {
+ image.DebugSave(provider);
+
+ provider.Utility.TestName = DecodeProgressiveJpegOutputName;
+ image.CompareToReferenceOutput(
+ this.GetImageComparer(provider),
+ provider,
+ appendPixelTypeToFileName: false);
+ }
+
+ provider.Configuration.MemoryManager.ReleaseRetainedResources();
+ }
+
+ [Theory]
+ [WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)]
+ public void DecodeProgressiveJpeg_PdfJs(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ if (SkipTest(provider))
+ {
+ // skipping to avoid OutOfMemoryException on CI
+ return;
+ }
+
+ using (Image image = provider.GetImage(PdfJsJpegDecoder))
+ {
+ image.DebugSave(provider);
+
+ provider.Utility.TestName = DecodeProgressiveJpegOutputName;
+ image.CompareToReferenceOutput(
+ this.GetImageComparer(provider),
+ provider,
+ appendPixelTypeToFileName: false);
+ }
+ }
+
+ [Theory(Skip = "Debug only, enable manually!")]
+ [WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)]
+ public void CompareJpegDecoders_Progressive(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ this.CompareJpegDecodersImpl(provider, DecodeProgressiveJpegOutputName);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
index 0b8daac72d..cfd5989f58 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
@@ -22,61 +22,8 @@ using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
// TODO: Scatter test cases into multiple test classes
- public class JpegDecoderTests
+ public partial class JpegDecoderTests
{
- public static string[] BaselineTestJpegs =
- {
- TestImages.Jpeg.Baseline.Calliphora,
- TestImages.Jpeg.Baseline.Cmyk,
- TestImages.Jpeg.Baseline.Ycck,
- TestImages.Jpeg.Baseline.Jpeg400,
- TestImages.Jpeg.Baseline.Testorig420,
-
- // BUG: The following image has a high difference compared to the expected output:
- // TestImages.Jpeg.Baseline.Jpeg420Small,
-
- TestImages.Jpeg.Baseline.Jpeg444,
- TestImages.Jpeg.Baseline.Bad.BadEOF,
- TestImages.Jpeg.Issues.MultiHuffmanBaseline394,
- TestImages.Jpeg.Baseline.MultiScanBaselineCMYK,
- TestImages.Jpeg.Baseline.Bad.BadRST
- };
-
- public static string[] ProgressiveTestJpegs =
- {
- TestImages.Jpeg.Progressive.Fb, TestImages.Jpeg.Progressive.Progress,
- TestImages.Jpeg.Progressive.Festzug, TestImages.Jpeg.Progressive.Bad.BadEOF,
- TestImages.Jpeg.Issues.BadCoeffsProgressive178,
- TestImages.Jpeg.Issues.MissingFF00ProgressiveGirl159,
- TestImages.Jpeg.Issues.BadZigZagProgressive385,
- TestImages.Jpeg.Progressive.Bad.ExifUndefType
- };
-
- public static string[] FalsePositiveIssueJpegs =
- {
- TestImages.Jpeg.Issues.NoEOI517,
- TestImages.Jpeg.Issues.BadRST518,
- };
-
- private static readonly Dictionary CustomToleranceValues = new Dictionary
- {
- // Baseline:
- [TestImages.Jpeg.Baseline.Calliphora] = 0.00002f / 100,
- [TestImages.Jpeg.Baseline.Bad.BadEOF] = 0.38f / 100,
- [TestImages.Jpeg.Baseline.Testorig420] = 0.38f / 100,
- [TestImages.Jpeg.Baseline.Bad.BadRST] = 0.0589f / 100,
-
- // Progressive:
- [TestImages.Jpeg.Issues.MissingFF00ProgressiveGirl159] = 0.34f / 100,
- [TestImages.Jpeg.Issues.BadCoeffsProgressive178] = 0.38f / 100,
- [TestImages.Jpeg.Progressive.Bad.BadEOF] = 0.3f / 100,
- [TestImages.Jpeg.Progressive.Festzug] = 0.02f / 100,
- [TestImages.Jpeg.Progressive.Fb] = 0.16f / 100,
- [TestImages.Jpeg.Progressive.Progress] = 0.31f / 100,
- [TestImages.Jpeg.Issues.BadZigZagProgressive385] = 0.23f / 100,
- [TestImages.Jpeg.Progressive.Bad.ExifUndefType] = 0.011f / 100,
- };
-
public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.RgbaVector;
private const float BaselineTolerance = 0.001F / 100;
@@ -115,9 +62,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
private ITestOutputHelper Output { get; }
- private static IImageDecoder OrigJpegDecoder => new OrigJpegDecoder();
+ private static GolangJpegDecoder GolangJpegDecoder => new GolangJpegDecoder();
+
+ private static PdfJsJpegDecoder PdfJsJpegDecoder => new PdfJsJpegDecoder();
- private static IImageDecoder PdfJsJpegDecoder => new PdfJsJpegDecoder();
+ private static JpegDecoder DefaultJpegDecoder => new JpegDecoder();
[Fact]
public void ParseStream_BasicPropertiesAreCorrect1_PdfJs()
@@ -151,7 +100,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
// For 32 bit test enviroments:
provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling();
- IImageDecoder decoder = useOldDecoder ? OrigJpegDecoder : PdfJsJpegDecoder;
+ IImageDecoder decoder = useOldDecoder ? (IImageDecoder)GolangJpegDecoder : PdfJsJpegDecoder;
using (Image image = provider.GetImage(decoder))
{
image.DebugSave(provider);
@@ -163,142 +112,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
provider.Configuration.MemoryManager.ReleaseRetainedResources();
}
- [Theory]
- [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
- public void DecodeBaselineJpeg_Orig(TestImageProvider provider)
- where TPixel : struct, IPixel
- {
- if (SkipTest(provider))
- {
- return;
- }
-
- // For 32 bit test enviroments:
- provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling();
-
- using (Image image = provider.GetImage(OrigJpegDecoder))
- {
- image.DebugSave(provider);
- provider.Utility.TestName = DecodeBaselineJpegOutputName;
- image.CompareToReferenceOutput(
- this.GetImageComparer(provider),
- provider,
- appendPixelTypeToFileName: false);
- }
-
- provider.Configuration.MemoryManager.ReleaseRetainedResources();
- }
-
- [Theory]
- [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
- public void DecodeBaselineJpeg_PdfJs(TestImageProvider provider)
- where TPixel : struct, IPixel
- {
- if (TestEnvironment.RunsOnCI && !TestEnvironment.Is64BitProcess)
- {
- // skipping to avoid OutOfMemoryException on CI
- return;
- }
-
- using (Image image = provider.GetImage(PdfJsJpegDecoder))
- {
- image.DebugSave(provider);
-
- provider.Utility.TestName = DecodeBaselineJpegOutputName;
- image.CompareToReferenceOutput(
- this.GetImageComparer(provider),
- provider,
- appendPixelTypeToFileName: false);
- }
- }
-
- ///
- /// Only can decode these images.
- ///
- /// The pixel format
- /// The test image provider
- [Theory]
- [WithFileCollection(nameof(FalsePositiveIssueJpegs), PixelTypes.Rgba32)]
- public void DecodeFalsePositiveJpeg_PdfJs(TestImageProvider provider)
- where TPixel : struct, IPixel
- {
- if (TestEnvironment.RunsOnCI && !TestEnvironment.Is64BitProcess)
- {
- // skipping to avoid OutOfMemoryException on CI
- return;
- }
-
- using (Image image = provider.GetImage(PdfJsJpegDecoder))
- {
- image.DebugSave(provider);
- image.CompareToReferenceOutput(
- ImageComparer.Tolerant(BaselineTolerance),
- provider,
- appendPixelTypeToFileName: true);
- }
- }
-
- [Theory]
- [WithFile(TestImages.Jpeg.Issues.CriticalEOF214, PixelTypes.Rgba32)]
- public void DecodeBaselineJpeg_CriticalEOF_ShouldThrow_Orig(TestImageProvider provider)
- where TPixel : struct, IPixel
- {
- // TODO: We need a public ImageDecoderException class in ImageSharp!
- Assert.ThrowsAny(() => provider.GetImage(OrigJpegDecoder));
- }
-
- public const string DecodeProgressiveJpegOutputName = "DecodeProgressiveJpeg";
-
- [Theory]
- [WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)]
- public void DecodeProgressiveJpeg_Orig(TestImageProvider provider)
- where TPixel : struct, IPixel
- {
- if (SkipTest(provider))
- {
- return;
- }
-
- // For 32 bit test enviroments:
- provider.Configuration.MemoryManager = ArrayPoolMemoryManager.CreateWithModeratePooling();
-
- using (Image image = provider.GetImage(OrigJpegDecoder))
- {
- image.DebugSave(provider);
-
- provider.Utility.TestName = DecodeProgressiveJpegOutputName;
- image.CompareToReferenceOutput(
- this.GetImageComparer(provider),
- provider,
- appendPixelTypeToFileName: false);
- }
-
- provider.Configuration.MemoryManager.ReleaseRetainedResources();
- }
-
- [Theory]
- [WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)]
- public void DecodeProgressiveJpeg_PdfJs(TestImageProvider provider)
- where TPixel : struct, IPixel
- {
- if (TestEnvironment.RunsOnCI && !TestEnvironment.Is64BitProcess)
- {
- // skipping to avoid OutOfMemoryException on CI
- return;
- }
-
- using (Image image = provider.GetImage(PdfJsJpegDecoder))
- {
- image.DebugSave(provider);
-
- provider.Utility.TestName = DecodeProgressiveJpegOutputName;
- image.CompareToReferenceOutput(
- this.GetImageComparer(provider),
- provider,
- appendPixelTypeToFileName: false);
- }
- }
-
private string GetDifferenceInPercentageString(Image image, TestImageProvider provider)
where TPixel : struct, IPixel
{
@@ -321,15 +134,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
private void CompareJpegDecodersImpl(TestImageProvider provider, string testName)
where TPixel : struct, IPixel
{
- if (TestEnvironment.RunsOnCI) // Debug only test
- {
- return;
- }
-
this.Output.WriteLine(provider.SourceFileOrDescription);
provider.Utility.TestName = testName;
- using (Image image = provider.GetImage(OrigJpegDecoder))
+ using (Image image = provider.GetImage(GolangJpegDecoder))
{
string d = this.GetDifferenceInPercentageString(image, provider);
@@ -343,102 +151,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}
}
- [Theory]
- [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
- public void CompareJpegDecoders_Baseline(TestImageProvider provider)
- where TPixel : struct, IPixel
- {
- this.CompareJpegDecodersImpl(provider, DecodeBaselineJpegOutputName);
- }
-
- [Theory]
- [WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Rgba32)]
- public void CompareJpegDecoders_Progressive(TestImageProvider provider)
- where TPixel : struct, IPixel
- {
- this.CompareJpegDecodersImpl(provider, DecodeProgressiveJpegOutputName);
- }
-
- [Theory]
- [WithSolidFilledImages(16, 16, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio420, 75)]
- [WithSolidFilledImages(16, 16, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio420, 100)]
- [WithSolidFilledImages(16, 16, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio444, 75)]
- [WithSolidFilledImages(16, 16, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio444, 100)]
- [WithSolidFilledImages(8, 8, 255, 0, 0, PixelTypes.Rgba32, JpegSubsample.Ratio444, 100)]
- public void DecodeGenerated_Orig(
- TestImageProvider provider,
- JpegSubsample subsample,
- int quality)
- where TPixel : struct, IPixel
- {
- byte[] data;
- using (Image image = provider.GetImage())
- {
- var encoder = new JpegEncoder { Subsample = subsample, Quality = quality };
-
- data = new byte[65536];
- using (var ms = new MemoryStream(data))
- {
- image.Save(ms, encoder);
- }
- }
-
- var mirror = Image.Load(data, OrigJpegDecoder);
- mirror.DebugSave(provider, $"_{subsample}_Q{quality}");
- }
-
- [Fact]
- public void Decoder_Reads_Correct_Resolution_From_Jfif()
- {
- using (Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateImage())
- {
- Assert.Equal(300, image.MetaData.HorizontalResolution);
- Assert.Equal(300, image.MetaData.VerticalResolution);
- }
- }
-
- [Fact]
- public void Decoder_Reads_Correct_Resolution_From_Exif()
- {
- using (Image image = TestFile.Create(TestImages.Jpeg.Baseline.Jpeg420Exif).CreateImage())
- {
- Assert.Equal(72, image.MetaData.HorizontalResolution);
- Assert.Equal(72, image.MetaData.VerticalResolution);
- }
- }
-
- [Fact]
- public void Decode_IgnoreMetadataIsFalse_ExifProfileIsRead()
- {
- var decoder = new JpegDecoder()
- {
- IgnoreMetadata = false
- };
-
- var testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan);
-
- using (Image image = testFile.CreateImage(decoder))
- {
- Assert.NotNull(image.MetaData.ExifProfile);
- }
- }
-
- [Fact]
- public void Decode_IgnoreMetadataIsTrue_ExifProfileIgnored()
- {
- var options = new JpegDecoder()
- {
- IgnoreMetadata = true
- };
-
- var testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan);
-
- using (Image image = testFile.CreateImage(options))
- {
- Assert.Null(image.MetaData.ExifProfile);
- }
- }
-
// DEBUG ONLY!
// The PDF.js output should be saved by "tests\ImageSharp.Tests\Formats\Jpg\pdfjs\jpeg-converter.htm"
// into "\tests\Images\ActualOutput\JpegDecoderTests\"
@@ -470,37 +182,5 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
this.Output.WriteLine($"Difference for PORT: {portReport.DifferencePercentageString}");
}
}
-
- [Theory]
- [InlineData(TestImages.Jpeg.Progressive.Progress, 24)]
- [InlineData(TestImages.Jpeg.Progressive.Fb, 24)]
- [InlineData(TestImages.Jpeg.Baseline.Cmyk, 32)]
- [InlineData(TestImages.Jpeg.Baseline.Ycck, 32)]
- [InlineData(TestImages.Jpeg.Baseline.Jpeg400, 8)]
- [InlineData(TestImages.Jpeg.Baseline.Snake, 24)]
- public void DetectPixelSizeGolang(string imagePath, int expectedPixelSize)
- {
- var testFile = TestFile.Create(imagePath);
- using (var stream = new MemoryStream(testFile.Bytes, false))
- {
- Assert.Equal(expectedPixelSize, ((IImageInfoDetector)OrigJpegDecoder).Identify(Configuration.Default, stream)?.PixelType?.BitsPerPixel);
- }
- }
-
- [Theory]
- [InlineData(TestImages.Jpeg.Progressive.Progress, 24)]
- [InlineData(TestImages.Jpeg.Progressive.Fb, 24)]
- [InlineData(TestImages.Jpeg.Baseline.Cmyk, 32)]
- [InlineData(TestImages.Jpeg.Baseline.Ycck, 32)]
- [InlineData(TestImages.Jpeg.Baseline.Jpeg400, 8)]
- [InlineData(TestImages.Jpeg.Baseline.Snake, 24)]
- public void DetectPixelSizePdfJs(string imagePath, int expectedPixelSize)
- {
- var testFile = TestFile.Create(imagePath);
- using (var stream = new MemoryStream(testFile.Bytes, false))
- {
- Assert.Equal(expectedPixelSize, ((IImageInfoDetector)PdfJsJpegDecoder).Identify(Configuration.Default, stream)?.PixelType?.BitsPerPixel);
- }
- }
}
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs
index ffaccb3f77..7e7518fd44 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs
@@ -1,8 +1,9 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
+using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
@@ -21,16 +22,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
TestImages.Jpeg.Baseline.Ycck,
TestImages.Jpeg.Baseline.Jpeg400,
TestImages.Jpeg.Baseline.Testorig420,
- TestImages.Jpeg.Baseline.Jpeg420Small,
TestImages.Jpeg.Baseline.Jpeg444,
- TestImages.Jpeg.Baseline.Bad.BadEOF,
- };
-
- public static string[] ProgressiveTestJpegs =
- {
- TestImages.Jpeg.Progressive.Fb, TestImages.Jpeg.Progressive.Progress,
- TestImages.Jpeg.Progressive.Festzug, TestImages.Jpeg.Progressive.Bad.BadEOF,
- TestImages.Jpeg.Progressive.Bad.ExifUndefType,
};
public JpegImagePostProcessorTests(ITestOutputHelper output)
@@ -47,7 +39,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
image.DebugSave(provider, $"-C{cp.Component.Index}-");
}
-
}
[Theory]
@@ -57,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
where TPixel : struct, IPixel
{
string imageFile = provider.SourceFileOrDescription;
- using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(imageFile))
+ using (PdfJsJpegDecoderCore decoder = JpegFixture.ParsePdfJsStream(imageFile))
using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryManager, decoder))
using (var imageFrame = new ImageFrame(Configuration.Default.MemoryManager, decoder.ImageWidth, decoder.ImageHeight))
{
@@ -70,16 +61,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
SaveBuffer(cp[2], provider);
}
}
-
+
[Theory]
- [WithFile(TestImages.Jpeg.Baseline.Calliphora, PixelTypes.Rgba32)]
- [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgba32)]
- [WithFile(TestImages.Jpeg.Baseline.Testorig420, PixelTypes.Rgba32)]
+ [WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
public void PostProcess(TestImageProvider provider)
where TPixel : struct, IPixel
{
string imageFile = provider.SourceFileOrDescription;
- using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(imageFile))
+ using (PdfJsJpegDecoderCore decoder = JpegFixture.ParsePdfJsStream(imageFile))
using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryManager, decoder))
using (var image = new Image(decoder.ImageWidth, decoder.ImageHeight))
{
@@ -97,7 +86,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
ImageSimilarityReport report = ImageComparer.Exact.CompareImagesOrFrames(referenceImage, image);
this.Output.WriteLine($"*** {imageFile} ***");
- this.Output.WriteLine($"Difference: "+ report.DifferencePercentageString);
+ this.Output.WriteLine($"Difference: {report.DifferencePercentageString}");
// ReSharper disable once PossibleInvalidOperationException
Assert.True(report.TotalNormalizedDifference.Value < 0.005f);
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs
index 49c76dc4ec..b0f342f5ab 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs
@@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
//[MemberData(nameof(DecodeJpegData))]
public void DecodeJpeg_Original(string fileName)
{
- this.DecodeJpegBenchmarkImpl(fileName, new OrigJpegDecoder());
+ this.DecodeJpegBenchmarkImpl(fileName, new GolangJpegDecoder());
}
// [Theory] // Benchmark, enable manually
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs
index 0d563a7b77..827a459cde 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs
@@ -2,11 +2,12 @@
// Licensed under the Apache License, Version 2.0.
using System.Text;
-
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
-using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder;
+using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort;
+using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using SixLabors.Primitives;
@@ -29,30 +30,63 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[InlineData(TestImages.Jpeg.Baseline.Jpeg400, JpegColorSpace.Grayscale)]
[InlineData(TestImages.Jpeg.Baseline.Ycck, JpegColorSpace.Ycck)]
[InlineData(TestImages.Jpeg.Baseline.Cmyk, JpegColorSpace.Cmyk)]
- public void ColorSpace_IsDeducedCorrectly(string imageFile, object expectedColorSpaceValue)
+ public void ColorSpace_IsDeducedCorrectlyGolang(string imageFile, object expectedColorSpaceValue)
{
var expecteColorSpace = (JpegColorSpace)expectedColorSpaceValue;
- using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(imageFile, true))
+ using (GolangJpegDecoderCore decoder = JpegFixture.ParseGolangStream(imageFile))
{
Assert.Equal(expecteColorSpace, decoder.ColorSpace);
}
}
+ [Theory]
+ [InlineData(TestImages.Jpeg.Baseline.Testorig420, JpegColorSpace.YCbCr)]
+ [InlineData(TestImages.Jpeg.Baseline.Jpeg400, JpegColorSpace.Grayscale)]
+ [InlineData(TestImages.Jpeg.Baseline.Ycck, JpegColorSpace.Ycck)]
+ [InlineData(TestImages.Jpeg.Baseline.Cmyk, JpegColorSpace.Cmyk)]
+ public void ColorSpace_IsDeducedCorrectlyPdfJs(string imageFile, object expectedColorSpaceValue)
+ {
+ var expecteColorSpace = (JpegColorSpace)expectedColorSpaceValue;
+
+ using (PdfJsJpegDecoderCore decoder = JpegFixture.ParsePdfJsStream(imageFile))
+ {
+ Assert.Equal(expecteColorSpace, decoder.ColorSpace);
+ }
+ }
+
+ [Fact]
+ public void ComponentScalingIsCorrect_1ChannelJpegGolang()
+ {
+ using (GolangJpegDecoderCore decoder = JpegFixture.ParseGolangStream(TestImages.Jpeg.Baseline.Jpeg400))
+ {
+ Assert.Equal(1, decoder.ComponentCount);
+ Assert.Equal(1, decoder.Components.Length);
+
+ Size expectedSizeInBlocks = decoder.ImageSizeInPixels.DivideRoundUp(8);
+
+ Assert.Equal(expectedSizeInBlocks, decoder.ImageSizeInMCU);
+
+ var uniform1 = new Size(1, 1);
+ GolangComponent c0 = decoder.Components[0];
+ VerifyJpeg.VerifyComponent(c0, expectedSizeInBlocks, uniform1, uniform1);
+ }
+ }
+
[Fact]
- public void ComponentScalingIsCorrect_1ChannelJpeg()
+ public void ComponentScalingIsCorrect_1ChannelJpegPdfJs()
{
- using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(TestImages.Jpeg.Baseline.Jpeg400, true))
+ using (PdfJsJpegDecoderCore decoder = JpegFixture.ParsePdfJsStream(TestImages.Jpeg.Baseline.Jpeg400))
{
Assert.Equal(1, decoder.ComponentCount);
Assert.Equal(1, decoder.Components.Length);
-
+
Size expectedSizeInBlocks = decoder.ImageSizeInPixels.DivideRoundUp(8);
Assert.Equal(expectedSizeInBlocks, decoder.ImageSizeInMCU);
var uniform1 = new Size(1, 1);
- OrigComponent c0 = decoder.Components[0];
+ PdfJsFrameComponent c0 = decoder.Components[0];
VerifyJpeg.VerifyComponent(c0, expectedSizeInBlocks, uniform1, uniform1);
}
}
@@ -64,16 +98,40 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[InlineData(TestImages.Jpeg.Baseline.Testorig420)]
[InlineData(TestImages.Jpeg.Baseline.Ycck)]
[InlineData(TestImages.Jpeg.Baseline.Cmyk)]
- public void PrintComponentData(string imageFile)
+ public void PrintComponentDataGolang(string imageFile)
+ {
+ var sb = new StringBuilder();
+
+ using (GolangJpegDecoderCore decoder = JpegFixture.ParseGolangStream(imageFile))
+ {
+ sb.AppendLine(imageFile);
+ sb.AppendLine($"Size:{decoder.ImageSizeInPixels} MCU:{decoder.ImageSizeInMCU}");
+ GolangComponent c0 = decoder.Components[0];
+ GolangComponent c1 = decoder.Components[1];
+
+ sb.AppendLine($"Luma: SAMP: {c0.SamplingFactors} BLOCKS: {c0.SizeInBlocks}");
+ sb.AppendLine($"Chroma: {c1.SamplingFactors} BLOCKS: {c1.SizeInBlocks}");
+ }
+ this.Output.WriteLine(sb.ToString());
+ }
+
+ [Theory]
+ [InlineData(TestImages.Jpeg.Baseline.Jpeg444)]
+ [InlineData(TestImages.Jpeg.Baseline.Jpeg420Exif)]
+ [InlineData(TestImages.Jpeg.Baseline.Jpeg420Small)]
+ [InlineData(TestImages.Jpeg.Baseline.Testorig420)]
+ [InlineData(TestImages.Jpeg.Baseline.Ycck)]
+ [InlineData(TestImages.Jpeg.Baseline.Cmyk)]
+ public void PrintComponentDataPdfJs(string imageFile)
{
var sb = new StringBuilder();
- using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(imageFile, true))
+ using (PdfJsJpegDecoderCore decoder = JpegFixture.ParsePdfJsStream(imageFile))
{
sb.AppendLine(imageFile);
sb.AppendLine($"Size:{decoder.ImageSizeInPixels} MCU:{decoder.ImageSizeInMCU}");
- OrigComponent c0 = decoder.Components[0];
- OrigComponent c1 = decoder.Components[1];
+ PdfJsFrameComponent c0 = decoder.Components[0];
+ PdfJsFrameComponent c1 = decoder.Components[1];
sb.AppendLine($"Luma: SAMP: {c0.SamplingFactors} BLOCKS: {c0.SizeInBlocks}");
sb.AppendLine($"Chroma: {c1.SamplingFactors} BLOCKS: {c1.SizeInBlocks}");
@@ -94,39 +152,80 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Theory]
[MemberData(nameof(ComponentVerificationData))]
- public void ComponentScalingIsCorrect_MultiChannelJpeg(
+ public void ComponentScalingIsCorrect_MultiChannelJpegGolang(
+ string imageFile,
+ int componentCount,
+ object expectedLumaFactors,
+ object expectedChromaFactors)
+ {
+ var fLuma = (Size)expectedLumaFactors;
+ var fChroma = (Size)expectedChromaFactors;
+
+ using (GolangJpegDecoderCore decoder = JpegFixture.ParseGolangStream(imageFile))
+ {
+ Assert.Equal(componentCount, decoder.ComponentCount);
+ Assert.Equal(componentCount, decoder.Components.Length);
+
+ GolangComponent c0 = decoder.Components[0];
+ GolangComponent c1 = decoder.Components[1];
+ GolangComponent c2 = decoder.Components[2];
+
+ var uniform1 = new Size(1, 1);
+
+ Size expectedLumaSizeInBlocks = decoder.ImageSizeInMCU.MultiplyBy(fLuma);
+
+ Size divisor = fLuma.DivideBy(fChroma);
+
+ Size expectedChromaSizeInBlocks = expectedLumaSizeInBlocks.DivideRoundUp(divisor);
+
+ VerifyJpeg.VerifyComponent(c0, expectedLumaSizeInBlocks, fLuma, uniform1);
+ VerifyJpeg.VerifyComponent(c1, expectedChromaSizeInBlocks, fChroma, divisor);
+ VerifyJpeg.VerifyComponent(c2, expectedChromaSizeInBlocks, fChroma, divisor);
+
+ if (componentCount == 4)
+ {
+ GolangComponent c3 = decoder.Components[2];
+ VerifyJpeg.VerifyComponent(c3, expectedLumaSizeInBlocks, fLuma, uniform1);
+ }
+ }
+ }
+
+
+ [Theory]
+ [MemberData(nameof(ComponentVerificationData))]
+ public void ComponentScalingIsCorrect_MultiChannelJpegPdfJs(
string imageFile,
int componentCount,
object expectedLumaFactors,
object expectedChromaFactors)
{
- Size fLuma = (Size)expectedLumaFactors;
- Size fChroma = (Size)expectedChromaFactors;
+ var fLuma = (Size)expectedLumaFactors;
+ var fChroma = (Size)expectedChromaFactors;
- using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(imageFile, true))
+ using (PdfJsJpegDecoderCore decoder = JpegFixture.ParsePdfJsStream(imageFile))
{
Assert.Equal(componentCount, decoder.ComponentCount);
Assert.Equal(componentCount, decoder.Components.Length);
-
- OrigComponent c0 = decoder.Components[0];
- OrigComponent c1 = decoder.Components[1];
- OrigComponent c2 = decoder.Components[2];
+
+ PdfJsFrameComponent c0 = decoder.Components[0];
+ PdfJsFrameComponent c1 = decoder.Components[1];
+ PdfJsFrameComponent c2 = decoder.Components[2];
var uniform1 = new Size(1, 1);
- Size expectedLumaSizeInBlocks = decoder.ImageSizeInMCU.MultiplyBy(fLuma) ;
+ Size expectedLumaSizeInBlocks = decoder.ImageSizeInMCU.MultiplyBy(fLuma);
Size divisor = fLuma.DivideBy(fChroma);
Size expectedChromaSizeInBlocks = expectedLumaSizeInBlocks.DivideRoundUp(divisor);
-
+
VerifyJpeg.VerifyComponent(c0, expectedLumaSizeInBlocks, fLuma, uniform1);
VerifyJpeg.VerifyComponent(c1, expectedChromaSizeInBlocks, fChroma, divisor);
VerifyJpeg.VerifyComponent(c2, expectedChromaSizeInBlocks, fChroma, divisor);
if (componentCount == 4)
{
- OrigComponent c3 = decoder.Components[2];
+ PdfJsFrameComponent c3 = decoder.Components[2];
VerifyJpeg.VerifyComponent(c3, expectedLumaSizeInBlocks, fLuma, uniform1);
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs
index fa06f91dab..c908abc505 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs
@@ -3,7 +3,7 @@
using System.Text;
-using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using Xunit;
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs
index b9ae97409c..dd2113624e 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs
@@ -1,4 +1,7 @@
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using Xunit;
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs
index 11612d3e2b..ce6f0a744f 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs
@@ -1,8 +1,8 @@
-// ReSharper disable InconsistentNaming
-
-using System;
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
+// ReSharper disable InconsistentNaming
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using Xunit;
@@ -36,13 +36,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
this.CompareBlocks(original, src, 0.1f);
}
-
+
// [Fact]
public void LLM_CalcConstants()
{
ReferenceImplementations.LLM_FloatingPoint_DCT.PrintConstants(this.Output);
}
-
+
[Theory]
[InlineData(42, 1000)]
[InlineData(1, 1000)]
@@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Block8x8F fExpected = iExpected.AsFloatBlock();
Block8x8F fActual = ReferenceImplementations.LLM_FloatingPoint_DCT.TransformIDCT(ref fSource);
-
+
this.CompareBlocks(fExpected, fActual, 2);
}
@@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
ReferenceImplementations.AccurateDCT.TransformIDCTInplace(intData);
float[] dest = new float[64];
-
+
ReferenceImplementations.GT_FloatingPoint_DCT.iDCT8x8GT(floatSrc, dest);
this.CompareBlocks(intData.ConvertAllToFloat(), dest, 1f);
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs
index f249aa93bf..f299807fc7 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs
@@ -2,7 +2,7 @@
using System;
-using SixLabors.ImageSharp.Formats.Jpeg.Common;
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using Xunit;
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs
index 9c134ada9d..811af96757 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs
@@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public static readonly string[] AllTestJpegs = BaselineTestJpegs.Concat(ProgressiveTestJpegs).ToArray();
- [Theory]
+ [Theory(Skip = "Debug only, enable manually!")]
[WithFileCollection(nameof(AllTestJpegs), PixelTypes.Rgba32)]
public void PdfJsDecoder_ParseStream_SaveSpectralResult(TestImageProvider provider)
where TPixel : struct, IPixel
@@ -58,12 +58,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}
}
- [Theory]
+ [Theory(Skip = "Debug only, enable manually!")]
[WithFileCollection(nameof(AllTestJpegs), PixelTypes.Rgba32)]
public void OriginalDecoder_ParseStream_SaveSpectralResult(TestImageProvider provider)
where TPixel : struct, IPixel
{
- var decoder = new OrigJpegDecoderCore(Configuration.Default, new JpegDecoder());
+ var decoder = new GolangJpegDecoderCore(Configuration.Default, new JpegDecoder());
byte[] sourceBytes = TestFile.Create(provider.SourceFileOrDescription).Bytes;
@@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
LibJpegTools.SpectralData imageSharpData)
where TPixel : struct, IPixel
{
- var libJpegData = LibJpegTools.ExtractSpectralData(provider.SourceFileOrDescription);
+ LibJpegTools.SpectralData libJpegData = LibJpegTools.ExtractSpectralData(provider.SourceFileOrDescription);
bool equality = libJpegData.Equals(imageSharpData);
this.Output.WriteLine("Spectral data equality: " + equality);
@@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Theory]
[WithFileCollection(nameof(AllTestJpegs), PixelTypes.Rgba32)]
- public void VerifySpectralResults_OriginalDecoder(TestImageProvider provider)
+ public void VerifySpectralCorrectness_Golang(TestImageProvider